Skip to content

Commit c553307

Browse files
authored
refactor: udpate test runner detection (#96)
1 parent ed6ffa2 commit c553307

File tree

3 files changed

+98
-13
lines changed

3 files changed

+98
-13
lines changed

.github/workflows/node.js.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
node-version: [18.x]
14+
node-version: [20.x]
1515
fail-fast: false
1616
steps:
1717
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

src/utils/getTestFrameworkName.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
import type { PackageJSON } from "@nodesecure/npm-types";
33

44
// CONSTANTS
5-
const kNodeTestRunnerRegex = /(?:node\s+--test|tsx)/;
5+
const kNodeTestRunnerRegex = /[node|tsx]\s+.*--test/;
66

77
export function getTestFrameworkName(packageJson: PackageJSON): string {
88
const { devDependencies: deps = {}, scripts = {} } = packageJson;
99

10-
if (kNodeTestRunnerRegex.test(scripts.test)) {
10+
if (isUsingNodeTestRunner(scripts, "test")) {
1111
return "node:test";
1212
}
1313
if ("ava" in deps) {
@@ -16,7 +16,7 @@ export function getTestFrameworkName(packageJson: PackageJSON): string {
1616
if ("jest" in deps) {
1717
return "jest";
1818
}
19-
if ("japa" in deps) {
19+
if ("@japa/runner" in deps) {
2020
return "japa";
2121
}
2222
if ("tape" in deps) {
@@ -28,3 +28,38 @@ export function getTestFrameworkName(packageJson: PackageJSON): string {
2828

2929
return "N/A";
3030
}
31+
32+
function isUsingNodeTestRunner(scripts: Record<string, string>, scriptName: string, visited = new Set<string>()): boolean {
33+
if (visited.has(scriptName)) {
34+
return false;
35+
}
36+
37+
const scriptCommand = scripts[scriptName];
38+
if (scriptCommand && kNodeTestRunnerRegex.test(scriptCommand)) {
39+
return true;
40+
}
41+
42+
const calledScripts = extractCalledScripts(scriptCommand);
43+
44+
for (const calledScript of calledScripts) {
45+
if (isUsingNodeTestRunner(scripts, calledScript, visited)) {
46+
return true;
47+
}
48+
}
49+
50+
return false;
51+
}
52+
53+
function extractCalledScripts(scriptCommand: string): string[] {
54+
const npmRunRegex = /npm run (\S+)/g;
55+
56+
const calledScripts: string[] = [];
57+
58+
let match: RegExpExecArray | null;
59+
60+
while ((match = npmRunRegex.exec(scriptCommand)) !== null) {
61+
calledScripts.push(match[1]);
62+
}
63+
64+
return calledScripts;
65+
}

test/getTestFrameworkName.spec.ts

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import { getTestFrameworkName } from "../src/utils";
77

88
describe("getTestFrameworkName()", () => {
99
it("Should return N/A", () => {
10-
assert.equal(getTestFrameworkName({ test: "2.0.0", test2: "3.0.0" }), "N/A");
10+
assert.equal(getTestFrameworkName({ name: "test", version: "1.0.0", test: "2.0.0", test2: "3.0.0" }), "N/A");
1111
});
1212

1313
it("Should return ava", () => {
1414
const packageJson = {
15+
name: "test",
16+
version: "1.0.0",
1517
devDependencies: {
1618
ava: "^2.0.0"
1719
}
@@ -21,6 +23,8 @@ describe("getTestFrameworkName()", () => {
2123

2224
it("Should return jest", () => {
2325
const packageJson = {
26+
name: "test",
27+
version: "1.0.0",
2428
devDependencies: {
2529
jest: "^2.0.0"
2630
}
@@ -30,15 +34,19 @@ describe("getTestFrameworkName()", () => {
3034

3135
it("Should return japa", () => {
3236
const packageJson = {
37+
name: "test",
38+
version: "1.0.0",
3339
devDependencies: {
34-
japa: "^2.0.0"
40+
"@japa/runner": "^2.0.0"
3541
}
3642
};
3743
assert.equal(getTestFrameworkName(packageJson), "japa");
3844
});
3945

4046
it("Should return tape", () => {
4147
const packageJson = {
48+
name: "test",
49+
version: "1.0.0",
4250
devDependencies: {
4351
tape: "^2.0.0"
4452
}
@@ -48,6 +56,8 @@ describe("getTestFrameworkName()", () => {
4856

4957
it("Should return mocha", () => {
5058
const packageJson = {
59+
name: "test",
60+
version: "1.0.0",
5161
devDependencies: {
5262
mocha: "^2.0.0"
5363
}
@@ -56,12 +66,52 @@ describe("getTestFrameworkName()", () => {
5666
assert.equal(getTestFrameworkName(packageJson), "mocha");
5767
});
5868

59-
it("Should return node:test", () => {
60-
const packageJson = {
61-
scripts: {
62-
test: "node --test"
63-
}
64-
};
65-
assert.equal(getTestFrameworkName(packageJson), "node:test");
69+
describe("node:test", () => {
70+
it("Should return node:test for test script", () => {
71+
const packageJson = {
72+
name: "test",
73+
version: "1.0.0",
74+
scripts: {
75+
test: "node --test"
76+
}
77+
};
78+
assert.equal(getTestFrameworkName(packageJson), "node:test");
79+
});
80+
81+
it("Should return node:test when a nested script uses node --test", () => {
82+
const packageJson = {
83+
name: "test",
84+
version: "1.0.0",
85+
scripts: {
86+
test: "c8 --all --src ./src -r html npm run test-only",
87+
"test-only": "glob -c \"node --loader=esmock --no-warnings --test-concurrency 1 --test\" \"test/**/*.test.js\""
88+
}
89+
};
90+
assert.equal(getTestFrameworkName(packageJson), "node:test");
91+
});
92+
93+
it("Should return node:test when a nested script uses node --test, recursively", () => {
94+
const packageJson = {
95+
name: "test",
96+
version: "1.0.0",
97+
scripts: {
98+
test: "npm run foo",
99+
foo: "npm run bar",
100+
bar: "node --test"
101+
}
102+
};
103+
assert.equal(getTestFrameworkName(packageJson), "node:test");
104+
});
105+
106+
it("Should return node:test for test script when using tsx", () => {
107+
const packageJson = {
108+
name: "test",
109+
version: "1.0.0",
110+
scripts: {
111+
test: "tsx --test"
112+
}
113+
};
114+
assert.equal(getTestFrameworkName(packageJson), "node:test");
115+
});
66116
});
67117
});

0 commit comments

Comments
 (0)