test: refactor the example tests to esm, add bun:test => ava polyfill (#1730)
This commit is contained in:
parent
ebc48cf6c4
commit
2e03db1fec
24 changed files with 234 additions and 64 deletions
1
.github/workflows/memory-test.yml
vendored
1
.github/workflows/memory-test.yml
vendored
|
@ -17,6 +17,7 @@ jobs:
|
|||
build_and_test:
|
||||
name: Memory leak detect job
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 40
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
39
.github/workflows/test-release.yaml
vendored
39
.github/workflows/test-release.yaml
vendored
|
@ -400,7 +400,7 @@ jobs:
|
|||
- name: Install ziglang
|
||||
uses: goto-bus-stop/setup-zig@v2
|
||||
with:
|
||||
version: 0.10.1
|
||||
version: 0.11.0
|
||||
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v3
|
||||
|
@ -486,6 +486,43 @@ jobs:
|
|||
- name: Check build
|
||||
run: cargo check -p ${{ matrix.settings.package }} -F ${{ matrix.settings.features }}
|
||||
|
||||
test-latest-bun:
|
||||
runs-on: ubuntu-latest
|
||||
name: Test latest bun
|
||||
timeout-minutes: 10
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'yarn'
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: x86_64-unknown-linux-gnu
|
||||
- name: Cache cargo
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: stable-x86_64-unknown-linux-gnu-node@18-cargo-cache
|
||||
- name: Install dependencies
|
||||
run: yarn install --immutable --mode=skip-build
|
||||
- name: Build
|
||||
run: |
|
||||
bun run build
|
||||
bun run build:test
|
||||
- name: Test
|
||||
run: bun run test:bun
|
||||
|
||||
release-npm:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
export default {
|
||||
extensions: {
|
||||
ts: 'module',
|
||||
},
|
||||
files: ['**/__tests__/**/*.spec.ts'],
|
||||
}
|
|
@ -95,5 +95,13 @@
|
|||
"build": "tsc && yarn build:cjs",
|
||||
"build:cjs": "node ./esbuild.mjs",
|
||||
"test": "node --loader ts-node/esm/transpile-only ../node_modules/ava/entrypoints/cli.mjs"
|
||||
},
|
||||
"ava": {
|
||||
"extensions": {
|
||||
"ts": "module"
|
||||
},
|
||||
"files": [
|
||||
"**/__tests__/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "nodenext",
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
|
|
|
@ -12,6 +12,8 @@ Generated by [AVA](https://avajs.dev).
|
|||
'@napi-rs/cli',
|
||||
'@types/lodash',
|
||||
'ava',
|
||||
'cross-env',
|
||||
'electron',
|
||||
'lodash',
|
||||
'sinon',
|
||||
]
|
||||
|
|
Binary file not shown.
3
examples/napi/__tests__/bun-test.js
Normal file
3
examples/napi/__tests__/bun-test.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { test, expect } from 'bun:test'
|
||||
|
||||
export { test, expect }
|
|
@ -1,6 +1,10 @@
|
|||
import { createRequire } from 'node:module'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { receiveString } from '..'
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const { receiveString }: typeof import('../index.js') = require('../index.node')
|
||||
|
||||
test('Function message', (t) => {
|
||||
// @ts-expect-error
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
import { createRequire } from 'node:module'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { Fib, Fib2, Fib3 } from '..'
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const {
|
||||
Fib,
|
||||
Fib2,
|
||||
Fib3,
|
||||
}: typeof import('../index.js') = require('../index.node')
|
||||
|
||||
for (const [index, factory] of [
|
||||
() => new Fib(),
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { createRequire } from 'node:module'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import { NotWritableClass } from '..'
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const {
|
||||
NotWritableClass,
|
||||
}: typeof import('../index.js') = require('../index.node')
|
||||
|
||||
test('Not Writable Class', (t) => {
|
||||
const obj = new NotWritableClass('1')
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import { createRequire } from 'node:module'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import {
|
||||
const require = createRequire(import.meta.url)
|
||||
|
||||
const {
|
||||
validateArray,
|
||||
validateTypedArray,
|
||||
validateBigint,
|
||||
|
@ -20,7 +24,7 @@ import {
|
|||
returnUndefinedIfInvalid,
|
||||
returnUndefinedIfInvalidPromise,
|
||||
validateOptional,
|
||||
} from '..'
|
||||
}: typeof import('../index.d.ts') = require('../index.node')
|
||||
|
||||
test('should validate array', (t) => {
|
||||
t.is(validateArray([1, 2, 3]), 3)
|
||||
|
|
67
examples/napi/__tests__/test.framework.js
Normal file
67
examples/napi/__tests__/test.framework.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
const { bun } = process.versions
|
||||
|
||||
/**@type {import('ava').TestFn} */
|
||||
let testRunner
|
||||
|
||||
if (bun) {
|
||||
const { test, expect } = await import('./bun-test.js')
|
||||
const testContext = {
|
||||
is: (actual, expected) => {
|
||||
expect(actual).toEqual(expected)
|
||||
},
|
||||
deepEqual: (actual, expected) => {
|
||||
expect(actual).toEqual(expected)
|
||||
},
|
||||
throws: (fn, expected) => {
|
||||
if (expected) {
|
||||
expect(fn).toThrow(expected)
|
||||
} else {
|
||||
expect(fn).toThrow()
|
||||
}
|
||||
},
|
||||
notThrows: (fn, expected) => {
|
||||
if (expected) {
|
||||
expect(fn).not.toThrow(expected)
|
||||
} else {
|
||||
expect(fn).not.toThrow()
|
||||
}
|
||||
},
|
||||
throwsAsync: async (fn, expected) => {
|
||||
if (expected) {
|
||||
expect(fn instanceof Promise ? fn : await fn()).rejects.toEqual(
|
||||
expected,
|
||||
)
|
||||
} else {
|
||||
expect(fn instanceof Promise ? fn : await fn()).rejects.toBeTruthy()
|
||||
}
|
||||
},
|
||||
notThrowsAsync: async (fn, expected) => {
|
||||
if (expected) {
|
||||
expect(fn instanceof Promise ? fn : await fn()).resolves.toBe(expected)
|
||||
} else {
|
||||
expect(fn instanceof Promise ? fn : await fn()).resolves.toBeTruthy()
|
||||
}
|
||||
},
|
||||
true: (actual, message) => {
|
||||
expect(actual).toBe(true, message)
|
||||
},
|
||||
false: (actual, message) => {
|
||||
expect(actual).toBe(false, message)
|
||||
},
|
||||
}
|
||||
testRunner = (title, spec) => {
|
||||
test(title, async () => {
|
||||
await Promise.resolve(spec(testContext))
|
||||
})
|
||||
}
|
||||
testRunner.skip = (label, fn) => {
|
||||
test.skip(label, () => {
|
||||
fn(testContext)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const test = (await import('ava')).default
|
||||
testRunner = test
|
||||
}
|
||||
|
||||
export { testRunner as test }
|
|
@ -1,8 +1,11 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
const __dirname = join(fileURLToPath(import.meta.url), '..')
|
||||
|
||||
test('should generate correct type def file', (t) => {
|
||||
t.snapshot(readFileSync(join(__dirname, '..', 'index.d.ts'), 'utf8'))
|
||||
})
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
// use the commonjs syntax to prevent compiler from transpiling the module syntax
|
||||
|
||||
const path = require('path')
|
||||
import { createRequire } from 'node:module'
|
||||
import * as path from 'node:path'
|
||||
|
||||
const test = require('ava').default
|
||||
import test from 'ava'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const __dirname = path.dirname(new URL(import.meta.url).pathname)
|
||||
|
||||
test('unload module', (t) => {
|
||||
const { add } = require('../index.node')
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
import { exec } from 'child_process'
|
||||
import { join } from 'path'
|
||||
import { exec } from 'node:child_process'
|
||||
import { createRequire } from 'node:module'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import test from 'ava'
|
||||
import { spy } from 'sinon'
|
||||
|
||||
import {
|
||||
import type { AliasedStruct } from '../index.js'
|
||||
|
||||
import { test } from './test.framework.js'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const __dirname = join(fileURLToPath(import.meta.url), '..')
|
||||
|
||||
const {
|
||||
DEFAULT_COST,
|
||||
add,
|
||||
fibonacci,
|
||||
|
@ -78,7 +86,6 @@ import {
|
|||
receiveAllOptionalObject,
|
||||
fnReceivedAliased,
|
||||
ALIAS,
|
||||
AliasedStruct,
|
||||
appendBuffer,
|
||||
returnNull,
|
||||
returnUndefined,
|
||||
|
@ -134,7 +141,7 @@ import {
|
|||
chronoNativeDateTime,
|
||||
chronoNativeDateTimeReturn,
|
||||
throwAsyncError,
|
||||
} from '..'
|
||||
}: typeof import('../index.d.ts') = require('../index.node')
|
||||
|
||||
test('export const', (t) => {
|
||||
t.is(DEFAULT_COST, 12)
|
||||
|
@ -251,7 +258,7 @@ test('class factory', (t) => {
|
|||
|
||||
const error = t.throws(() => new ClassWithFactory())
|
||||
t.true(
|
||||
error!.message.startsWith(
|
||||
error?.message.startsWith(
|
||||
'Class contains no `constructor`, can not new it!',
|
||||
),
|
||||
)
|
||||
|
@ -463,7 +470,7 @@ test('should throw if object type is not matched', (t) => {
|
|||
// @ts-expect-error
|
||||
const err1 = t.throws(() => receiveStrictObject({ name: 1 }))
|
||||
t.is(
|
||||
err1!.message,
|
||||
err1?.message,
|
||||
'Failed to convert JavaScript value `Number 1 ` into rust type `String`',
|
||||
)
|
||||
// @ts-expect-error
|
||||
|
@ -472,7 +479,7 @@ test('should throw if object type is not matched', (t) => {
|
|||
})
|
||||
|
||||
test('aliased rust struct and enum', (t) => {
|
||||
const a: ALIAS = ALIAS.A
|
||||
const a = ALIAS.A
|
||||
const b: AliasedStruct = {
|
||||
a,
|
||||
b: 1,
|
||||
|
@ -506,7 +513,7 @@ test('serde-roundtrip', (t) => {
|
|||
t.is(testSerdeRoundtrip(null), null)
|
||||
|
||||
let err = t.throws(() => testSerdeRoundtrip(undefined))
|
||||
t.is(err!.message, 'undefined cannot be represented as a serde_json::Value')
|
||||
t.is(err?.message, 'undefined cannot be represented as a serde_json::Value')
|
||||
|
||||
err = t.throws(() => testSerdeRoundtrip(() => {}))
|
||||
t.is(
|
||||
|
@ -681,7 +688,7 @@ test('external', (t) => {
|
|||
// @ts-expect-error
|
||||
const e = t.throws(() => getExternal(ext2))
|
||||
t.is(
|
||||
e!.message,
|
||||
e?.message,
|
||||
'T on `get_value_external` is not the type of wrapped object',
|
||||
)
|
||||
})
|
||||
|
@ -783,7 +790,7 @@ Napi4Test('throw error from thread safe function', async (t) => {
|
|||
threadsafeFunctionThrowError(reject)
|
||||
})
|
||||
const err = await t.throwsAsync(throwPromise)
|
||||
t.is(err!.message, 'ThrowFromNative')
|
||||
t.is(err?.message, 'ThrowFromNative')
|
||||
})
|
||||
|
||||
Napi4Test('thread safe function closure capture data', (t) => {
|
||||
|
@ -803,7 +810,7 @@ Napi4Test('resolve value from thread safe function fatal mode', async (t) => {
|
|||
})
|
||||
|
||||
Napi4Test('throw error from thread safe function fatal mode', (t) => {
|
||||
const p = exec('node ./tsfn-error.js', {
|
||||
const p = exec('node ./tsfn-error.cjs', {
|
||||
cwd: __dirname,
|
||||
})
|
||||
let stderr = Buffer.from([])
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { join } from 'path'
|
||||
import { Worker } from 'worker_threads'
|
||||
const { join } = require('node:path')
|
||||
const { Worker } = require('node:worker_threads')
|
||||
|
||||
import test from 'ava'
|
||||
const test = require('ava').default
|
||||
|
||||
import { Animal, Kind, DEFAULT_COST } from '..'
|
||||
const { Animal, Kind, DEFAULT_COST } = require('../index.node')
|
||||
|
||||
// aarch64-unknown-linux-gnu is extremely slow in CI, skip it or it will timeout
|
||||
const t =
|
||||
|
@ -12,8 +12,10 @@ const t =
|
|||
t('should be able to require in worker thread', async (t) => {
|
||||
await Promise.all(
|
||||
Array.from({ length: 100 }).map(() => {
|
||||
const w = new Worker(join(__dirname, 'worker.js'))
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||
execArgv: []
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
w.postMessage({ type: 'require' })
|
||||
w.on('message', (msg) => {
|
||||
t.is(msg, Animal.withKind(Kind.Cat).whoami() + DEFAULT_COST)
|
||||
|
@ -35,8 +37,10 @@ t('custom GC works on worker_threads', async (t) => {
|
|||
await Promise.all(
|
||||
Array.from({ length: 50 }).map(() =>
|
||||
Promise.all([
|
||||
new Promise<Worker>((resolve, reject) => {
|
||||
const w = new Worker(join(__dirname, 'worker.js'))
|
||||
new Promise((resolve, reject) => {
|
||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||
execArgv: []
|
||||
})
|
||||
w.postMessage({
|
||||
type: 'async:buffer',
|
||||
})
|
||||
|
@ -50,8 +54,10 @@ t('custom GC works on worker_threads', async (t) => {
|
|||
}).then((w) => {
|
||||
return w.terminate()
|
||||
}),
|
||||
new Promise<Worker>((resolve, reject) => {
|
||||
const w = new Worker(join(__dirname, 'worker.js'))
|
||||
new Promise((resolve, reject) => {
|
||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||
execArgv: []
|
||||
})
|
||||
w.postMessage({
|
||||
type: 'async:arraybuffer',
|
||||
})
|
||||
|
@ -73,8 +79,10 @@ t('custom GC works on worker_threads', async (t) => {
|
|||
t('should be able to new Class in worker thread concurrently', async (t) => {
|
||||
await Promise.all(
|
||||
Array.from({ length: 100 }).map(() => {
|
||||
const w = new Worker(join(__dirname, 'worker.js'))
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const w = new Worker(join(__dirname, 'worker.cjs'), {
|
||||
execArgv: []
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
w.postMessage({ type: 'constructor' })
|
||||
w.on('message', (msg) => {
|
||||
t.is(msg, 'Ellie')
|
|
@ -2,35 +2,34 @@
|
|||
"name": "@examples/napi",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"main": "./index.node",
|
||||
"types": "./index.d.ts",
|
||||
"scripts": {
|
||||
"build": "napi-raw build --no-js",
|
||||
"test": "ava"
|
||||
"test": "cross-env TS_NODE_PROJECT=./tsconfig.json node --es-module-specifier-resolution=node --loader ts-node/esm/transpile-only ../../node_modules/ava/entrypoints/cli.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@napi-rs/cli": "workspace:*",
|
||||
"@types/lodash": "^4.14.195",
|
||||
"ava": "^5.3.1",
|
||||
"cross-env": "7.0.3",
|
||||
"electron": "^26.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"sinon": "^15.2.0"
|
||||
},
|
||||
"ava": {
|
||||
"extensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js"
|
||||
],
|
||||
"require": [
|
||||
"ts-node/register/transpile-only"
|
||||
],
|
||||
"extensions": {
|
||||
"ts": "module",
|
||||
"cts": "commonjs",
|
||||
"cjs": true
|
||||
},
|
||||
"files": [
|
||||
"__tests__/**/*.spec.ts",
|
||||
"__tests__/**/*.spec.js"
|
||||
"__tests__/**/*.spec.cts",
|
||||
"__tests__/**/*.spec.js",
|
||||
"__tests__/**/*.spec.cjs"
|
||||
],
|
||||
"environmentVariables": {
|
||||
"TS_NODE_PROJECT": "../tsconfig.json"
|
||||
},
|
||||
"timeout": "10m"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
"include": ["."],
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "__tests__",
|
||||
"target": "ES2018",
|
||||
"rootDir": ".",
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": false,
|
||||
"noEmit": true
|
||||
"noEmit": true,
|
||||
"types": ["bun-types"],
|
||||
"importHelpers": false
|
||||
},
|
||||
"exclude": ["dist", "electron.js", "electron-renderer"]
|
||||
"exclude": ["dist", "electron.cjs", "electron-renderer", "node_modules"]
|
||||
}
|
||||
|
|
|
@ -28,8 +28,9 @@
|
|||
"format:toml": "taplo format",
|
||||
"lint": "eslint -c .eslintrc.yml .",
|
||||
"test": "lerna run test --concurrency=1 --ignore @napi-rs/cli",
|
||||
"test:bun": "bun test examples/napi/__tests__/values.spec.ts",
|
||||
"test:cli": "yarn workspace @napi-rs/cli test",
|
||||
"test:electron": "electron examples/napi/electron.js",
|
||||
"test:electron": "electron examples/napi/electron.cjs",
|
||||
"test:macro": "cargo test -p napi-examples",
|
||||
"test:memory": "node memory-testing/index.mjs",
|
||||
"postinstall": "husky install",
|
||||
|
@ -75,9 +76,10 @@
|
|||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"ava": "^5.3.1",
|
||||
"bun-types": "^1.0.2",
|
||||
"c8": "^8.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "26.2.1",
|
||||
"electron": "^26.2.1",
|
||||
"esbuild": "^0.19.0",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -338,6 +338,8 @@ __metadata:
|
|||
"@napi-rs/cli": "workspace:*"
|
||||
"@types/lodash": ^4.14.195
|
||||
ava: ^5.3.1
|
||||
cross-env: 7.0.3
|
||||
electron: ^26.2.1
|
||||
lodash: ^4.17.21
|
||||
sinon: ^15.2.0
|
||||
languageName: unknown
|
||||
|
@ -2309,6 +2311,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bun-types@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "bun-types@npm:1.0.2"
|
||||
checksum: 02f9b6b37a7c3d6199e9cb990a635f374967a4a9708e525ca5f895268ced52e3bdb90d3252f3fd90d85287fd75a07b0ecbc5bcb9e003cba63c10aaa99ac9e070
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"byte-size@npm:8.1.1":
|
||||
version: 8.1.1
|
||||
resolution: "byte-size@npm:8.1.1"
|
||||
|
@ -2983,7 +2992,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-env@npm:^7.0.3":
|
||||
"cross-env@npm:7.0.3, cross-env@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "cross-env@npm:7.0.3"
|
||||
dependencies:
|
||||
|
@ -3306,7 +3315,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"electron@npm:26.2.1":
|
||||
"electron@npm:^26.2.1":
|
||||
version: 26.2.1
|
||||
resolution: "electron@npm:26.2.1"
|
||||
dependencies:
|
||||
|
@ -6493,9 +6502,10 @@ __metadata:
|
|||
"@typescript-eslint/eslint-plugin": ^6.0.0
|
||||
"@typescript-eslint/parser": ^6.0.0
|
||||
ava: ^5.3.1
|
||||
bun-types: ^1.0.2
|
||||
c8: ^8.0.0
|
||||
cross-env: ^7.0.3
|
||||
electron: 26.2.1
|
||||
electron: ^26.2.1
|
||||
esbuild: ^0.19.0
|
||||
eslint: ^8.45.0
|
||||
eslint-config-prettier: ^9.0.0
|
||||
|
|
Loading…
Reference in a new issue