-
Notifications
You must be signed in to change notification settings - Fork 198
Expand file tree
/
Copy pathrun-tests.js
More file actions
208 lines (189 loc) · 6.38 KB
/
Copy pathrun-tests.js
File metadata and controls
208 lines (189 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/**
* Test Runner
*
* Usage:
* node run-tests.js [type] [extra-args...]
*
* Types:
* all - Run all tests (default)
* integration - Run integration tests only
* verbose - Run all tests with verbose output
* ci - Run tests in CI mode with reporters
* watch - Run tests in watch mode
* skill - Run tests for a specific skill (requires pattern arg)
*
* Examples:
* node run-tests.js # Run all tests
* node run-tests.js integration # Run integration tests
* node run-tests.js integration azure-deploy # Run integration tests for azure-deploy
* node run-tests.js integration azure-deploy static-web-apps-deploy # Run integration tests for a sub group
* node run-tests.js skill azure-ai # Run tests for azure-ai skill
*/
import { spawn } from "child_process";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const isCI = !!(process.env.CI || process.env.GITHUB_ACTIONS);
// Parse arguments
// The first two args are "node" and path to this script file.
const args = process.argv.slice(2);
const testType = args[0] && !args[0].startsWith("-") ? args[0] : "all";
const extraArgs = args[0] && !args[0].startsWith("-") ? args.slice(1) : args;
// Test type configurations
const testConfigs = {
all: {
description: "all tests",
jestArgs: []
},
integration: {
description: "integration tests",
jestArgs: [
"--testMatch=**/*integration*.ts",
"--testPathIgnorePatterns=\"node_modules|_template\""
],
optionalPattern: true
},
verbose: {
description: "all tests (verbose)",
jestArgs: ["--verbose"]
},
ci: {
description: "tests in CI mode",
jestArgs: [
"--ci",
"--reporters=default",
"--reporters=jest-junit",
"--testPathIgnorePatterns=\"node_modules|_template|integration\""
]
},
watch: {
description: "tests in watch mode",
jestArgs: ["--watch"]
},
skill: {
description: "skill-specific tests",
jestArgs: ["--testPathPatterns"],
requiresPattern: true
}
};
// Validate test type
if (!testConfigs[testType]) {
console.error(`Unknown test type: ${testType}`);
console.error(`Available types: ${Object.keys(testConfigs).join(", ")}`);
process.exit(1);
}
const config = testConfigs[testType];
// Handle skill type which requires a pattern
if (config.requiresPattern && extraArgs.length === 0) {
console.error(`Test type "${testType}" requires a pattern argument.`);
console.error("Example: node run-tests.js skill azure-ai");
process.exit(1);
}
// Build jest command args
let jestArgs = [...config.jestArgs];
// For skill type, append the pattern to --testPathPatterns
if (config.requiresPattern && extraArgs.length > 0) {
jestArgs = [`--testPathPatterns=${extraArgs[0]}`, ...extraArgs.slice(1)];
} else if (config.optionalPattern && extraArgs.length > 0 && !extraArgs[0].startsWith("-")) {
const skillPattern = extraArgs[0];
const remaining = extraArgs.slice(1);
// If there's a second positional arg (not a flag), use it as --testNamePattern
if (remaining.length > 0 && !remaining[0].startsWith("-")) {
jestArgs = [...jestArgs, `--testPathPatterns=${skillPattern}`, `--testNamePattern="${remaining[0]}"`, ...remaining.slice(1)];
} else {
jestArgs = [...jestArgs, `--testPathPatterns=${skillPattern}`, ...remaining];
}
} else {
jestArgs = [...jestArgs, ...extraArgs];
}
console.log(`Running ${config.description}${isCI ? " (CI mode)" : ""}...`);
console.log(`jest ${jestArgs.join(" ")}\n`);
console.log("Env:NODE_OPTIONS", process.env.NODE_OPTIONS);
// Set NODE_OPTIONS for ESM support (append to existing if present)
const existingNodeOptions = process.env.NODE_OPTIONS || "";
const env = {
...process.env,
NODE_OPTIONS: existingNodeOptions
? `${existingNodeOptions} --experimental-vm-modules`
: "--experimental-vm-modules"
};
// Run jest
const jest = spawn("npx", ["jest", ...jestArgs], {
stdio: "inherit",
shell: true,
env,
cwd: path.resolve(__dirname, "..")
});
jest.on("error", (err) => {
console.error("Failed to start jest:", err.message);
process.exit(1);
});
jest.on("close", (code) => {
const jestExitCode = code || 0;
// Write run metadata when running in GitHub Actions
const runUrl =
process.env.GITHUB_SERVER_URL && process.env.GITHUB_RUN_ID
? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`
: null;
if (runUrl) {
const reportsDir = path.resolve(__dirname, "..", "reports");
try {
const dirs = fs
.readdirSync(reportsDir)
.filter((d) => d.startsWith("test-run-"))
.sort()
.reverse();
if (dirs.length > 0) {
const metadataPath = path.join(
reportsDir,
dirs[0],
"run-metadata.json",
);
fs.writeFileSync(
metadataPath,
JSON.stringify(
{
runUrl,
runId: process.env.GITHUB_RUN_ID,
repository: process.env.GITHUB_REPOSITORY,
workflow: process.env.GITHUB_WORKFLOW || null,
actor: process.env.GITHUB_ACTOR || null,
ref: process.env.GITHUB_REF || null,
sha: process.env.GITHUB_SHA || null,
timestamp: new Date().toISOString(),
},
null,
2,
),
);
console.log(`\u{1F4CE} Run metadata saved: ${metadataPath}`);
}
} catch (err) {
// Non-fatal — log and continue
console.warn(
"\u26A0\uFE0F Could not write run metadata:",
err.message,
);
}
}
// Show results table if not in CI and not in watch mode
if (!isCI && testType !== "watch") {
console.log("\n");
const results = spawn("node", [path.join(__dirname, "show-test-results.js")], {
stdio: "inherit",
cwd: path.resolve(__dirname, "..")
});
results.on("error", (err) => {
console.error("Failed to display results:", err.message);
process.exit(jestExitCode);
});
results.on("close", () => {
// Always use jest exit code, not results script exit code
process.exit(jestExitCode);
});
} else {
process.exit(jestExitCode);
}
});