Skip to content

Commit 56b4f87

Browse files
committed
Merge branch 'main' into feat/port-test-finalizer
PORTING.md: keep both new "Ported" rows (test_finalizer from this branch, test_function from main). implementors/node/tests.ts: take this branch's spawnTest-based design. implementors/node/child_process.js: extend HARNESS_MODULE_PATHS with the skip-test.js and napi-version.js harness modules main introduced. tests/harness/spawn-test.js: forward --expose-gc to spawnTest children that should succeed, since main tightened gc.js to refuse loading without it.
2 parents a0fb4d0 + 32311d1 commit 56b4f87

16 files changed

Lines changed: 335 additions & 32 deletions

File tree

PORTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Tests covering the engine-specific part of Node-API, defined in `js_native_api.h
5757
| `test_error` | Ported ✅ | Medium |
5858
| `test_exception` | Not ported | Medium |
5959
| `test_finalizer` | Ported ✅ | Medium |
60-
| `test_function` | Not ported | Medium |
60+
| `test_function` | Ported ✅ | Medium |
6161
| `test_general` | Not ported | Hard |
6262
| `test_handle_scope` | Ported ✅ | Easy |
6363
| `test_instance_data` | Not ported | Medium |

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default defineConfig([
2121
loadAddon: "readonly",
2222
mustCall: "readonly",
2323
mustNotCall: "readonly",
24+
gc: "readonly",
2425
gcUntil: "readonly",
2526
spawnTest: "readonly",
2627
experimentalFeatures: "readonly",

implementors/node/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Harness of Node.js
2+
3+
## Build addons
4+
5+
To build the addons, run the following command:
6+
7+
```bash
8+
$ npm run addons:configure
9+
$ npm run addons:build
10+
```
11+
12+
## Running tests
13+
14+
Run the following command to run the tests:
15+
16+
```bash
17+
$ npm run node:test
18+
```
19+
20+
To run a specific test file, use the `--test-name-pattern` flag:
21+
22+
```bash
23+
$ NODE_OPTIONS=--test-name-pattern=js-native-api/test_constructor/test_null npm run node:test
24+
```
25+
26+
The test names are their relative path to the `tests` folder, with file extensions.
27+
The pattern can be a regular expression.

implementors/node/child_process.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const HARNESS_MODULE_PATHS = [
77
"load-addon.js",
88
"gc.js",
99
"must-call.js",
10+
"skip-test.js",
11+
"napi-version.js",
1012
"child_process.js",
1113
].map((file) => path.join(import.meta.dirname, file));
1214

implementors/node/features.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,3 @@ globalThis.experimentalFeatures = {
77
setPrototype: true,
88
postFinalizer: true,
99
};
10-
11-
globalThis.napiVersion = Number(process.versions.napi);
12-
13-
globalThis.skipTest = () => {
14-
process.exit(0);
15-
};

implementors/node/gc.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1+
// Capture the engine-provided gc (Node exposes it under --expose-gc) before
2+
// we overwrite globalThis.gc with the harness wrapper below.
3+
const engineGc = globalThis.gc;
4+
if (typeof engineGc !== "function") {
5+
throw new Error(
6+
"Node harness expects globalThis.gc to be available (run with --expose-gc)",
7+
);
8+
}
9+
10+
const gc = () => {
11+
engineGc();
12+
};
13+
114
const gcUntil = async (name, condition) => {
215
let count = 0;
316
while (!condition()) {
417
await new Promise((resolve) => setImmediate(resolve));
518
if (++count < 10) {
6-
globalThis.gc();
19+
engineGc();
720
} else {
821
throw new Error(`GC test "${name}" failed after ${count} attempts`);
922
}
1023
}
1124
};
1225

13-
Object.assign(globalThis, { gcUntil });
26+
Object.assign(globalThis, { gc, gcUntil });

implementors/node/napi-version.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
globalThis.napiVersion = Number(process.versions.napi);

implementors/node/run-tests.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,25 @@
11
import path from "node:path";
2-
import { test, type TestContext } from "node:test";
2+
import { test } from "node:test";
33

44
import { listDirectoryEntries, runFileInSubprocess } from "./tests.ts";
55

66
const ROOT_PATH = path.resolve(import.meta.dirname, "..", "..");
77
const TESTS_ROOT_PATH = path.join(ROOT_PATH, "tests");
88

9-
async function populateSuite(
10-
testContext: TestContext,
9+
function populateSuite(
1110
dir: string
12-
): Promise<void> {
11+
) {
1312
const { directories, files } = listDirectoryEntries(dir);
1413

1514
for (const file of files) {
16-
await testContext.test(file, () => runFileInSubprocess(dir, file));
15+
test(path.relative(TESTS_ROOT_PATH, path.join(dir, file)), () => runFileInSubprocess(dir, file));
1716
}
1817

1918
for (const directory of directories) {
20-
await testContext.test(directory, async (subTest) => {
21-
await populateSuite(subTest, path.join(dir, directory));
22-
});
19+
populateSuite(path.join(dir, directory));
2320
}
2421
}
2522

26-
test("harness", async (t) => {
27-
await populateSuite(t, path.join(TESTS_ROOT_PATH, "harness"));
28-
});
29-
30-
test("js-native-api", async (t) => {
31-
await populateSuite(t, path.join(TESTS_ROOT_PATH, "js-native-api"));
32-
});
33-
34-
test("node-api", async (t) => {
35-
await populateSuite(t, path.join(TESTS_ROOT_PATH, "node-api"));
36-
});
23+
populateSuite(path.join(TESTS_ROOT_PATH, "harness"));
24+
populateSuite(path.join(TESTS_ROOT_PATH, "js-native-api"));
25+
populateSuite(path.join(TESTS_ROOT_PATH, "node-api"));

implementors/node/skip-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
globalThis.skipTest = () => {
2+
process.exit(0);
3+
};

tests/harness/gc.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
if (typeof gc !== 'function') {
2+
throw new Error('Expected a global gc function');
3+
}
4+
15
if (typeof gcUntil !== 'function') {
26
throw new Error('Expected a global gcUntil function');
37
}
48

9+
// gc should run synchronously without throwing
10+
gc();
11+
512
// gcUntil should resolve once the condition becomes true
613
let count = 0;
714
await gcUntil('test-passes', () => {

0 commit comments

Comments
 (0)