@empiricalrun/test-run 0.8.5 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @empiricalrun/test-run
2
2
 
3
+ ## 0.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 24d672a: feat: use playwright --list to get project names
8
+
9
+ ## 0.9.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 72f4577: feat: stop marking files as only and move to cmd builder approach
14
+
15
+ ### Patch Changes
16
+
17
+ - 97cef16: test: add memfs mocks for fs, remove unused config utils
18
+ - 28682e2: feat: use test-run cmd builder in test-gen, remove test.only marking
19
+
3
20
  ## 0.8.5
4
21
 
5
22
  ### Patch Changes
package/README.md CHANGED
@@ -104,26 +104,6 @@ This is useful for omitting teardown steps during certain runs or local developm
104
104
 
105
105
  ---
106
106
 
107
- ## 8. Using a “.rc” File or Token
108
-
109
- You can optionally define a configuration in `empiricalrc.json` or pass the same data as a base64-encoded `--token`. For example:
110
-
111
- ```json
112
- {
113
- "tests": [
114
- {
115
- "name": "some-test",
116
- "filePath": "tests/abc.spec.ts",
117
- "suites": ["suiteA"]
118
- }
119
- ]
120
- }
121
- ```
122
-
123
- If both are missing or do not define tests, the CLI uses command-line parameters (`-n`, `--file`, etc.).
124
-
125
- ---
126
-
127
107
  ## 9. Environment & Build (Optional)
128
108
 
129
109
  If `TEST_RUN_ENVIRONMENT` is defined:
@@ -172,23 +152,6 @@ This flow makes sure tests run against the relevant environment or a fresh build
172
152
 
173
153
  ---
174
154
 
175
- ## 12. Changelog
176
-
177
- For version history and patch notes, see [CHANGELOG.md]
178
-
179
- ---
180
-
181
- ## 13. Contributing
182
-
183
- - **Lint** with `pnpm lint`.
184
- - **Test** with `pnpm test`.
185
- - **Build** with `pnpm build`.
186
- - **Dev** watch mode with `pnpm dev`.
187
-
188
- Feel free to open issues or pull requests for enhancements or clarifications.
189
-
190
- ---
191
-
192
155
  ## 14. Conclusion
193
156
 
194
157
  @test-run simplifies orchestrating Playwright tests, especially for:
package/dist/bin/index.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
8
  const dotenv_1 = __importDefault(require("dotenv"));
9
9
  const dashboard_1 = require("../dashboard");
10
+ const cmd_1 = require("../lib/cmd");
10
11
  const run_all_tests_1 = require("../lib/run-all-tests");
11
12
  const run_specific_test_1 = require("../lib/run-specific-test");
12
13
  const types_1 = require("../types");
@@ -16,7 +17,6 @@ dotenv_1.default.config({
16
17
  path: [".env.local", ".env"],
17
18
  });
18
19
  (async function main() {
19
- // TODO: add documentation of the test run
20
20
  commander_1.program
21
21
  .option("-n, --name <test-name>", "Name of the test to run")
22
22
  .option("-s, --suites <suites>", "Suites under which the test is defined")
@@ -67,8 +67,7 @@ dotenv_1.default.config({
67
67
  const suites = options.suites && options.suites.trim() !== ""
68
68
  ? options.suites?.split(",")
69
69
  : undefined;
70
- let tests = (await (0, config_parser_1.parseRcConfig)())?.tests ||
71
- (0, config_parser_1.parseToken)(options.payload)?.tests ||
70
+ let tests = (0, config_parser_1.parseToken)(options.payload)?.tests ||
72
71
  (options.name
73
72
  ? [
74
73
  {
@@ -101,23 +100,24 @@ dotenv_1.default.config({
101
100
  await (0, utils_1.handleTeardownSkipFlag)(directory);
102
101
  }
103
102
  const hasTestsFilter = tests && tests.length > 0;
104
- let testResult;
103
+ let commandToRun;
105
104
  if (hasTestsFilter) {
106
- testResult = await (0, run_specific_test_1.runSpecificTests)({
105
+ commandToRun = await (0, run_specific_test_1.runSpecificTestsCmd)({
107
106
  tests,
108
107
  projects: projectFilters,
109
- pwOptions: pwOptions.join(" "),
108
+ passthroughArgs: pwOptions.join(" "),
110
109
  platform,
111
110
  });
112
111
  }
113
112
  else {
114
- testResult = await (0, run_all_tests_1.runAllTests)({
113
+ commandToRun = (0, run_all_tests_1.runAllTestsCmd)({
115
114
  projects: projectFilters,
116
- pwOptions: pwOptions.join(" "),
115
+ passthroughArgs: pwOptions.join(" "),
117
116
  platform,
118
117
  });
119
118
  }
120
- if (!testResult.hasTestPassed) {
119
+ const { hasTestPassed } = await (0, cmd_1.runTestsForCmd)(commandToRun);
120
+ if (!hasTestPassed) {
121
121
  process.exit(1);
122
122
  }
123
123
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
+ import { runSpecificTestsCmd } from "./lib/run-specific-test";
1
2
  import { TestCase } from "./types";
3
+ export { runSpecificTestsCmd };
2
4
  export declare function runSingleTest({ testName, suites, fileName, projects, envOverrides, }: {
3
5
  testName: string;
4
6
  suites: string[];
@@ -9,5 +11,8 @@ export declare function runSingleTest({ testName, suites, fileName, projects, en
9
11
  hasTestPassed: boolean;
10
12
  summaryJson: any;
11
13
  }>;
12
- export declare function listAllTests(cwd?: string): Promise<Record<string, TestCase>>;
14
+ export declare function getAllPlaywrightProjects(repoDir: string): Promise<{
15
+ projects: string[];
16
+ projectsToTestCases: Record<string, TestCase[]>;
17
+ }>;
13
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAY,QAAQ,EAAE,MAAM,SAAS,CAAC;AAO7C,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,YAAY,GACb,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;;;GAqBA;AAED,wBAAsB,YAAY,CAChC,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CA6CnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAY,QAAQ,EAAE,MAAM,SAAS,CAAC;AAO7C,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,YAAY,GACb,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;;;GAqBA;AAED,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACvE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjD,CAAC,CAaD"}
package/dist/index.js CHANGED
@@ -3,11 +3,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runSpecificTestsCmd = void 0;
6
7
  exports.runSingleTest = runSingleTest;
7
- exports.listAllTests = listAllTests;
8
+ exports.getAllPlaywrightProjects = getAllPlaywrightProjects;
8
9
  const promises_1 = __importDefault(require("fs/promises"));
9
10
  const path_1 = __importDefault(require("path"));
11
+ const cmd_1 = require("./lib/cmd");
10
12
  const run_specific_test_1 = require("./lib/run-specific-test");
13
+ Object.defineProperty(exports, "runSpecificTestsCmd", { enumerable: true, get: function () { return run_specific_test_1.runSpecificTestsCmd; } });
14
+ const parser_1 = require("./parser");
11
15
  const types_1 = require("./types");
12
16
  const utils_1 = require("./utils");
13
17
  // For test-run package, the library entrypoint, we only support web platform
@@ -16,60 +20,32 @@ const supportedPlatform = types_1.Platform.WEB;
16
20
  async function runSingleTest({ testName, suites, fileName, projects, envOverrides, }) {
17
21
  const testDir = "tests";
18
22
  const filePath = path_1.default.relative(process.cwd(), fileName);
19
- const result = await (0, run_specific_test_1.runSpecificTests)({
23
+ const commandToRun = await (0, run_specific_test_1.runSpecificTestsCmd)({
20
24
  tests: [{ name: testName, dir: testDir, filePath, suites }],
21
- pwOptions: "",
22
25
  projects,
23
26
  envOverrides,
24
27
  platform: supportedPlatform,
25
28
  });
29
+ const { hasTestPassed } = await (0, cmd_1.runTestsForCmd)(commandToRun);
26
30
  const jsonFilePath = path_1.default.join(process.cwd(), "playwright-report", `summary.json`);
27
31
  const jsonFileContents = await promises_1.default.readFile(jsonFilePath, "utf8");
28
32
  const summaryJson = JSON.parse(jsonFileContents);
29
33
  return {
30
- hasTestPassed: result.hasTestPassed,
34
+ hasTestPassed,
31
35
  summaryJson,
32
36
  };
33
37
  }
34
- async function listAllTests(cwd) {
38
+ async function getAllPlaywrightProjects(repoDir) {
35
39
  const testRunner = (0, utils_1.getTestRunner)(types_1.Platform.WEB);
36
40
  const env = Object({ ...process.env });
37
- const command = ["npx", testRunner, "test", "--list"];
38
- const { output } = await (0, utils_1.cmdWithOutput)(command, {
41
+ const args = [testRunner, "test", "--list"];
42
+ const { output, code } = await (0, cmd_1.spawnCmd)("npx", args, {
39
43
  env,
40
- cwd,
44
+ cwd: repoDir,
45
+ captureOutput: true,
41
46
  });
42
- // Parse the output to extract test information
43
- // Example format: "[chromium] home.spec.ts:9:9 describe 1 › describe 2 › has title"
44
- const result = {};
45
- output
46
- .split("\n")
47
- .filter((line) => line.trim() &&
48
- line.trim().startsWith("[") &&
49
- line.includes(".spec.ts:"))
50
- .forEach((line) => {
51
- // Extract project, file, line, and test name with suites
52
- const match = line.match(/\[(.*?)\]\s+›\s+(.*?):(\d+):\d+\s+›\s+(.*)/);
53
- if (!match || !match[1] || !match[2] || !match[3] || !match[4]) {
54
- return;
55
- }
56
- const file = match[2];
57
- const testPath = match[4];
58
- const parts = testPath.split("›").map((p) => p.trim());
59
- if (parts.length === 0) {
60
- return;
61
- }
62
- const name = parts[parts.length - 1];
63
- if (!name) {
64
- return;
65
- }
66
- const suites = parts.length > 1 ? parts.slice(0, -1) : undefined;
67
- const testCase = {
68
- name,
69
- filePath: file,
70
- suites,
71
- };
72
- result[line.trim()] = testCase;
73
- });
74
- return result;
47
+ if (!output) {
48
+ throw new Error(`Failed to run list command; exit code: ${code}`);
49
+ }
50
+ return (0, parser_1.parseTestListOutput)(output);
75
51
  }
@@ -0,0 +1,17 @@
1
+ import { CommandToRun } from "../types";
2
+ export declare function getCommandFromString(command: string): {
3
+ command: string;
4
+ args: string[];
5
+ };
6
+ export declare function runTestsForCmd({ command, args, env }: CommandToRun): Promise<{
7
+ hasTestPassed: boolean;
8
+ }>;
9
+ export declare function spawnCmd(command: string, args: string[], options: {
10
+ env?: Record<string, string>;
11
+ cwd?: string;
12
+ captureOutput?: boolean;
13
+ }): Promise<{
14
+ code: number;
15
+ output?: string;
16
+ }>;
17
+ //# sourceMappingURL=cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/lib/cmd.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAeA;AAED,wBAAsB,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,YAAY;;GASxE;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6C5C"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCommandFromString = getCommandFromString;
4
+ exports.runTestsForCmd = runTestsForCmd;
5
+ exports.spawnCmd = spawnCmd;
6
+ const child_process_1 = require("child_process");
7
+ function getCommandFromString(command) {
8
+ const regex = /[^\s"']+|"([^"]*)"|'([^']*)'/g;
9
+ const matches = command.match(regex) || [];
10
+ return {
11
+ command: matches[0],
12
+ args: matches.slice(1).map((match) => {
13
+ if ((match.startsWith('"') && match.endsWith('"')) ||
14
+ (match.startsWith("'") && match.endsWith("'"))) {
15
+ return match.slice(1, -1);
16
+ }
17
+ return match;
18
+ }),
19
+ };
20
+ }
21
+ async function runTestsForCmd({ command, args, env }) {
22
+ console.log(`Running cmd: ${command} with args: ${args}`);
23
+ let hasTestPassed = true;
24
+ try {
25
+ await spawnCmd(command, args, { env });
26
+ }
27
+ catch (e) {
28
+ hasTestPassed = false;
29
+ }
30
+ return { hasTestPassed };
31
+ }
32
+ async function spawnCmd(command, args, options) {
33
+ let output = options.captureOutput ? "" : undefined;
34
+ let errorLogs = [];
35
+ return new Promise((resolveFunc, rejectFunc) => {
36
+ const p = (0, child_process_1.spawn)(command, args, {
37
+ env: { ...process.env, ...options.env },
38
+ cwd: options.cwd,
39
+ // Ensure child process receives signals
40
+ detached: false,
41
+ });
42
+ // Setup signal handlers and get cleanup function
43
+ const cleanupSignalHandlers = setupProcessSignalHandlers(p);
44
+ p.stdout.on("data", (x) => {
45
+ const log = x.toString();
46
+ if (options.captureOutput) {
47
+ output += log;
48
+ }
49
+ else {
50
+ process.stdout.write(log);
51
+ }
52
+ if (log.includes("Error")) {
53
+ errorLogs.push(log);
54
+ }
55
+ });
56
+ p.stderr.on("data", (x) => {
57
+ const log = x.toString();
58
+ process.stderr.write(log);
59
+ errorLogs.push(log);
60
+ });
61
+ p.on("exit", (code) => {
62
+ // Clean up signal handlers when the process exits
63
+ cleanupSignalHandlers();
64
+ if (code != 0) {
65
+ // assuming last log is the error message before exiting
66
+ rejectFunc(errorLogs.slice(-3).join("\n"));
67
+ }
68
+ else {
69
+ resolveFunc({ code: code, output: output });
70
+ }
71
+ });
72
+ });
73
+ }
74
+ function setupProcessSignalHandlers(proc) {
75
+ const handleSignal = async (signal) => {
76
+ console.log(`\nReceived ${signal}, gracefully shutting down...`);
77
+ if (proc && !proc.killed) {
78
+ // Forward the signal to the child process
79
+ proc.kill(signal);
80
+ // Wait for the child process to exit
81
+ await new Promise((resolve) => {
82
+ proc.once("exit", () => {
83
+ resolve();
84
+ });
85
+ });
86
+ }
87
+ process.exit(0);
88
+ };
89
+ const sigintHandler = async () => await handleSignal("SIGINT");
90
+ const sigtermHandler = async () => await handleSignal("SIGTERM");
91
+ const otherSignalHandlers = ["SIGABRT", "SIGHUP", "SIGQUIT"].map((signal) => {
92
+ const handler = () => console.log(`Received ${signal}, which is a no-op`);
93
+ process.once(signal, handler);
94
+ return { signal, handler };
95
+ });
96
+ process.once("SIGINT", sigintHandler);
97
+ process.once("SIGTERM", sigtermHandler);
98
+ // Return a cleanup function that removes all signal handlers
99
+ return () => {
100
+ process.removeListener("SIGINT", sigintHandler);
101
+ process.removeListener("SIGTERM", sigtermHandler);
102
+ otherSignalHandlers.forEach(({ signal, handler }) => {
103
+ process.removeListener(signal, handler);
104
+ });
105
+ };
106
+ }
@@ -0,0 +1,3 @@
1
+ export declare function readHelloWorld(path: string): string;
2
+ export declare function verifyDirectory(path: string): boolean;
3
+ //# sourceMappingURL=read-hello-world.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-hello-world.d.ts","sourceRoot":"","sources":["../../../src/lib/memfs/read-hello-world.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,UAE1C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,WAE3C"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readHelloWorld = readHelloWorld;
7
+ exports.verifyDirectory = verifyDirectory;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ function readHelloWorld(path) {
10
+ return fs_1.default.readFileSync(path, "utf-8");
11
+ }
12
+ function verifyDirectory(path) {
13
+ return fs_1.default.existsSync(path) && fs_1.default.statSync(path).isDirectory();
14
+ }
@@ -1,5 +1,11 @@
1
- import { TestRunParameters } from "../types";
2
- export declare function runAllTests({ projects, pwOptions, filesFilter, envOverrides, platform, }: TestRunParameters): Promise<{
3
- hasTestPassed: boolean;
4
- }>;
1
+ import { CommandToRun, Platform, TestCase } from "../types";
2
+ export declare function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides, platform, }: {
3
+ tests?: TestCase[];
4
+ projects: string[];
5
+ passthroughArgs?: string;
6
+ platform: Platform;
7
+ filesFilter?: string;
8
+ envOverrides?: Record<string, string>;
9
+ patternsToGrep?: string[];
10
+ }): CommandToRun;
5
11
  //# sourceMappingURL=run-all-tests.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-all-tests.d.ts","sourceRoot":"","sources":["../../src/lib/run-all-tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG7C,wBAAsB,WAAW,CAAC,EAChC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CAoBD"}
1
+ {"version":3,"file":"run-all-tests.d.ts","sourceRoot":"","sources":["../../src/lib/run-all-tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQ5D,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GAAG,YAAY,CAmBf"}
@@ -1,23 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runAllTests = runAllTests;
3
+ exports.runAllTestsCmd = runAllTestsCmd;
4
4
  const utils_1 = require("../utils");
5
- async function runAllTests({ projects, pwOptions, filesFilter, envOverrides, platform, }) {
6
- let hasTestPassed = true;
7
- try {
8
- const testRunner = (0, utils_1.getTestRunner)(platform);
9
- let pwOptionsWithProjects = `${pwOptions} ${projects?.map((project) => `--project ${project}`).join(" ")}`;
10
- const env = Object.assign({ ...process.env, PW_TEST_HTML_REPORT_OPEN: "never" }, envOverrides);
11
- const testRunCmd = `npx ${testRunner} test ${filesFilter || ""} ${pwOptionsWithProjects}`;
12
- console.log(`Running cmd:`, testRunCmd);
13
- await (0, utils_1.cmd)(testRunCmd.split(" "), {
14
- env,
15
- });
16
- }
17
- catch (e) {
18
- hasTestPassed = false;
19
- }
5
+ const cmd_1 = require("./cmd");
6
+ function normalizeSpaces(command) {
7
+ return command.trim().replace(/ +/g, " ");
8
+ }
9
+ function runAllTestsCmd({ projects, passthroughArgs, patternsToGrep, filesFilter, envOverrides, platform, }) {
10
+ const testRunner = (0, utils_1.getTestRunner)(platform);
11
+ const projectsArg = (projects || [])
12
+ .map((project) => `--project ${project}`)
13
+ .join(" ");
14
+ const grepArgs = (patternsToGrep || [])
15
+ .map((pattern) => ` -g "${pattern}"`)
16
+ .join(" ");
17
+ let args = ` ${filesFilter || ""} ${grepArgs} ${projectsArg} ${passthroughArgs || ""}`;
18
+ const env = Object.assign({ ...process.env, PW_TEST_HTML_REPORT_OPEN: "never" }, envOverrides);
19
+ const testRunCmd = normalizeSpaces(`npx ${testRunner} test ${args}`);
20
20
  return {
21
- hasTestPassed,
21
+ ...(0, cmd_1.getCommandFromString)(testRunCmd),
22
+ env,
22
23
  };
23
24
  }
@@ -1,5 +1,10 @@
1
- import { TestRunParameters } from "../types";
2
- export declare function runSpecificTests({ tests, projects, pwOptions, platform, envOverrides, }: TestRunParameters): Promise<{
3
- hasTestPassed: boolean;
4
- }>;
1
+ import { CommandToRun, Platform, TestCase } from "../types";
2
+ export declare function runSpecificTestsCmd({ tests, projects, passthroughArgs, platform, envOverrides, }: {
3
+ tests?: TestCase[];
4
+ projects: string[];
5
+ passthroughArgs?: string;
6
+ platform: Platform;
7
+ filesFilter?: string;
8
+ envOverrides?: Record<string, string>;
9
+ }): Promise<CommandToRun>;
5
10
  //# sourceMappingURL=run-specific-test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-specific-test.d.ts","sourceRoot":"","sources":["../../src/lib/run-specific-test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAoB7C,wBAAsB,gBAAgB,CAAC,EACrC,KAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,GACb,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CA+FD"}
1
+ {"version":3,"file":"run-specific-test.d.ts","sourceRoot":"","sources":["../../src/lib/run-specific-test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAY5D,wBAAsB,mBAAmB,CAAC,EACxC,KAAU,EACV,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,YAAY,GACb,EAAE;IACD,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,GAAG,OAAO,CAAC,YAAY,CAAC,CAiFxB"}
@@ -1,50 +1,14 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runSpecificTests = runSpecificTests;
7
- const fs_1 = require("fs");
8
- const promises_1 = __importDefault(require("fs/promises"));
3
+ exports.runSpecificTestsCmd = runSpecificTestsCmd;
9
4
  const utils_1 = require("../utils");
10
5
  const run_all_tests_1 = require("./run-all-tests");
11
- function setupProcessListeners(cleanup) {
12
- const events = ["beforeExit", "exit", "SIGINT", "SIGTERM"];
13
- events.forEach((event) => process.on(event, cleanup));
14
- return () => {
15
- events.forEach((event) => process.removeListener(event, cleanup));
16
- };
17
- }
18
- async function runSpecificTests({ tests = [], projects, pwOptions, platform, envOverrides, }) {
6
+ async function runSpecificTestsCmd({ tests = [], projects, passthroughArgs, platform, envOverrides, }) {
19
7
  if (!tests || tests.length === 0) {
20
8
  throw new Error("No tests found");
21
9
  }
22
- let disableTestOnlyMarking = false;
23
- const teardownLabels = await (0, utils_1.labelTeardownProjects)(projects, platform);
24
- const isRunningForTeardownProjectOnly = teardownLabels && teardownLabels.every((label) => label.isTeardown);
25
- if (isRunningForTeardownProjectOnly) {
26
- // To run teardown projects, we need to run the `setup` project first, and playwright runs
27
- // teardown automatically, when the corresponding setup project is run.
28
- // We also disable marking files with test.only, because we want all of the setup to run
29
- // before running the teardown tests.
30
- disableTestOnlyMarking = true;
31
- projects = teardownLabels
32
- .map((label) => label.correspondingSetupProject)
33
- .filter((project) => project !== undefined);
34
- }
35
- const touchedFiles = {};
36
- // revert the changes made to the file to mark tests as only
37
- // these needs to handle by listening to process exit/kill events
38
- const revertFileContent = () => {
39
- try {
40
- Object.keys(touchedFiles).forEach((filePath) => {
41
- (0, fs_1.writeFileSync)(filePath, touchedFiles[filePath], "utf-8");
42
- });
43
- }
44
- catch (error) {
45
- console.error("Error while cleaning up test file:", error);
46
- }
47
- };
10
+ let patternsToGrep = [];
11
+ let filesToRun = [];
48
12
  for (const testCase of tests) {
49
13
  const files = await (0, utils_1.getAllFilePaths)(testCase.dir, {
50
14
  filePath: testCase.filePath,
@@ -62,41 +26,55 @@ async function runSpecificTests({ tests = [], projects, pwOptions, platform, env
62
26
  }
63
27
  }
64
28
  if (!matchingFilePath) {
65
- const message = `No test block found for the given test name: ${testCase.name} in file ${testCase.filePath} with suites: ${testCase.suites}`;
66
- revertFileContent();
29
+ const suitesPrefix = testCase.suites
30
+ ? `${testCase.suites.join(" > ")} > `
31
+ : "";
32
+ const fullTestName = `${suitesPrefix}${testCase.name}`;
33
+ const message = `No test block found for name: "${fullTestName}" in "${testCase.filePath}"`;
67
34
  throw Error(message);
68
35
  }
69
- const { testCaseNode, sourceFile } = await (0, utils_1.getTestCaseNode)({
36
+ else {
37
+ filesToRun.push(matchingFilePath);
38
+ }
39
+ const { testCaseNode } = await (0, utils_1.getTestCaseNode)({
70
40
  filePath: matchingFilePath,
71
41
  scenarioName: testCase.name,
72
42
  suites: testCase.suites,
73
43
  });
74
- const parentDescribe = (0, utils_1.findFirstSerialDescribeBlock)(testCaseNode);
75
44
  const isFileMarkedSerial = await (0, utils_1.hasTopLevelDescribeConfigureWithSerialMode)(matchingFilePath);
76
- const currentFileContent = await promises_1.default.readFile(matchingFilePath, "utf-8");
77
- // if file is not marked as touched, mark it as touched
78
- if (!touchedFiles[matchingFilePath]) {
79
- touchedFiles[matchingFilePath] = currentFileContent;
80
- }
81
- // if the file is not marked serial, we need to mark the test or describe block as only
82
- if (!isFileMarkedSerial && testCaseNode && !disableTestOnlyMarking) {
83
- await (0, utils_1.markTestAsOnly)({
84
- sourceFile,
85
- parentDescribeNode: parentDescribe,
86
- testCaseNode: testCaseNode,
87
- filePath: matchingFilePath,
88
- });
45
+ if (!isFileMarkedSerial && testCaseNode) {
46
+ const parentDescribe = (0, utils_1.findFirstSerialDescribeBlock)(testCaseNode);
47
+ if (!parentDescribe) {
48
+ patternsToGrep.push(testCase.name);
49
+ }
50
+ else {
51
+ const parentDescribeName = (0, utils_1.getDescribeBlockName)(parentDescribe);
52
+ if (parentDescribeName) {
53
+ patternsToGrep.push(parentDescribeName);
54
+ }
55
+ }
89
56
  }
90
57
  }
91
- const removeListeners = setupProcessListeners(revertFileContent);
92
- const result = await (0, run_all_tests_1.runAllTests)({
93
- filesFilter: Object.keys(touchedFiles).join(" "),
94
- pwOptions,
58
+ const teardownLabels = await (0, utils_1.labelTeardownProjects)(projects, platform);
59
+ const isRunningForTeardownProjectOnly = teardownLabels && teardownLabels.every((label) => label.isTeardown);
60
+ if (isRunningForTeardownProjectOnly) {
61
+ // To run teardown projects, we need to run the `setup` project first, and playwright runs
62
+ // teardown automatically, when the corresponding setup project is run.
63
+ projects = teardownLabels
64
+ .map((label) => label.correspondingSetupProject)
65
+ .filter((project) => project !== undefined);
66
+ // We also remove any files or grep filters, because we want setup and teardown to run completely
67
+ // We could add a grep invert flag for other teardown tests to reduce the number of tests that run
68
+ filesToRun = [];
69
+ patternsToGrep = [];
70
+ }
71
+ const commandToRun = (0, run_all_tests_1.runAllTestsCmd)({
72
+ filesFilter: [...new Set(filesToRun)].join(" "),
73
+ passthroughArgs,
95
74
  projects,
96
75
  envOverrides,
97
76
  platform,
77
+ patternsToGrep,
98
78
  });
99
- removeListeners();
100
- revertFileContent();
101
- return result;
79
+ return commandToRun;
102
80
  }
@@ -0,0 +1,6 @@
1
+ import { TestCase } from "../types";
2
+ export declare function parseTestListOutput(output: string): {
3
+ projects: string[];
4
+ projectsToTestCases: Record<string, TestCase[]>;
5
+ };
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG;IACnD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;CACjD,CA0CA"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTestListOutput = parseTestListOutput;
4
+ function parseTestListOutput(output) {
5
+ // Parse the output to extract test information
6
+ // Example format: "[chromium] › home.spec.ts:9:9 › describe 1 › describe 2 › has title"
7
+ let projectsToTestCases = {};
8
+ let projects = [];
9
+ output
10
+ .split("\n")
11
+ .filter((line) => line.trim() && line.trim().startsWith("[") && line.includes(".ts:"))
12
+ .forEach((line) => {
13
+ // Extract project, file, line, and test name with suites
14
+ const match = line.match(/\[(.*?)\]\s+›\s+(.*?):(\d+):\d+\s+›\s+(.*)/);
15
+ if (!match || !match[1] || !match[2] || !match[3] || !match[4]) {
16
+ return;
17
+ }
18
+ const project = match[1];
19
+ if (!projects.includes(project)) {
20
+ projects.push(project);
21
+ projectsToTestCases[project] = [];
22
+ }
23
+ const file = match[2];
24
+ const fullTestName = match[4];
25
+ const parts = fullTestName.split("›").map((p) => p.trim());
26
+ if (parts.length === 0) {
27
+ throw new Error(`Invalid test name: ${fullTestName}`);
28
+ }
29
+ const name = parts[parts.length - 1];
30
+ if (!name) {
31
+ throw new Error(`Invalid test name: ${fullTestName}`);
32
+ }
33
+ const describeBlockNames = parts.length > 1 ? parts.slice(0, -1) : undefined;
34
+ const testCase = {
35
+ name,
36
+ filePath: file,
37
+ suites: describeBlockNames,
38
+ };
39
+ projectsToTestCases[project].push(testCase);
40
+ });
41
+ return { projects, projectsToTestCases };
42
+ }
@@ -7,14 +7,6 @@ export type TestCase = {
7
7
  export type Config = {
8
8
  tests: TestCase[];
9
9
  } | undefined;
10
- export type TestRunParameters = {
11
- tests?: TestCase[];
12
- projects: string[];
13
- pwOptions: string;
14
- platform: Platform;
15
- filesFilter?: string;
16
- envOverrides?: Record<string, string>;
17
- };
18
10
  export type Environment = {
19
11
  id: number;
20
12
  project_id: number;
@@ -44,4 +36,9 @@ export type PlaywProjectConfig = {
44
36
  teardown?: string;
45
37
  testMatch: string | RegExp;
46
38
  };
39
+ export type CommandToRun = {
40
+ command: string;
41
+ args: string[];
42
+ env: Record<string, string>;
43
+ };
47
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,MAAM,GACd;IACE,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,GACD,SAAS,CAAC;AAEd,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,oBAAY,QAAQ;IAClB,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,GAAG,QAAQ;CACZ;AAED,oBAAY,aAAa;IACvB,UAAU,eAAe;IACzB,SAAS,cAAc;CACxB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,oBAAY,QAAQ;IAClB,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,GAAG,QAAQ;CACZ;AAED,oBAAY,aAAa;IACvB,UAAU,eAAe;IACzB,SAAS,cAAc;CACxB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC"}
@@ -1,5 +1,4 @@
1
1
  import { Config } from "../types";
2
- export declare function parseRcConfig(): Promise<Config>;
3
2
  export declare function parseToken(token: string): Config;
4
3
  export declare function buildConfigFromCliArgs(): void;
5
4
  //# sourceMappingURL=config-parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../../src/utils/config-parser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAerD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAchD;AAED,wBAAgB,sBAAsB,SAAK"}
1
+ {"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../../src/utils/config-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAchD;AAED,wBAAgB,sBAAsB,SAAK"}
@@ -1,29 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.parseRcConfig = parseRcConfig;
7
3
  exports.parseToken = parseToken;
8
4
  exports.buildConfigFromCliArgs = buildConfigFromCliArgs;
9
- const fs_1 = require("fs");
10
- const promises_1 = __importDefault(require("fs/promises"));
11
- async function parseRcConfig() {
12
- // check if file exists
13
- if (!(0, fs_1.existsSync)("empiricalrc.json")) {
14
- return undefined;
15
- }
16
- try {
17
- const rcConfig = await promises_1.default.readFile("empiricalrc.json", "utf-8");
18
- const json = JSON.parse(rcConfig);
19
- // TODO: validate the json
20
- return json;
21
- }
22
- catch (e) {
23
- console.error("Error parsing rc file:", e);
24
- }
25
- return undefined;
26
- }
27
5
  function parseToken(token) {
28
6
  if (!token) {
29
7
  return undefined;
@@ -0,0 +1,11 @@
1
+ import { Platform } from "../types";
2
+ type PlaywrightProject = {
3
+ name: string;
4
+ use: any;
5
+ testMatch: string[] | string | undefined;
6
+ testIgnore: string[] | string | undefined;
7
+ teardown: string | undefined;
8
+ };
9
+ export declare function getProjectsFromPlaywrightConfig(platform: Platform): Promise<PlaywrightProject[]>;
10
+ export {};
11
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAqC9B"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getProjectsFromPlaywrightConfig = getProjectsFromPlaywrightConfig;
7
+ const path_1 = __importDefault(require("path"));
8
+ // For TypeScript type safety
9
+ let tsxImport = null;
10
+ const types_1 = require("../types");
11
+ async function getProjectsFromPlaywrightConfig(platform) {
12
+ const configName = platform === types_1.Platform.WEB ? "playwright.config.ts" : "appwright.config.ts";
13
+ const directoryPath = ".";
14
+ const pwFile = path_1.default.resolve(directoryPath, configName);
15
+ if (typeof window !== "undefined") {
16
+ throw new Error("readPlaywrightConfig cannot be used in browser environments");
17
+ }
18
+ else {
19
+ // Only initialize on server side
20
+ // This will only execute on the server
21
+ await import("tsx/cjs/api")
22
+ .then((module) => {
23
+ tsxImport = module;
24
+ })
25
+ .catch(() => {
26
+ console.warn("Failed to import tsx: --->");
27
+ });
28
+ }
29
+ if (!tsxImport) {
30
+ console.warn("tsx module not available");
31
+ return [];
32
+ }
33
+ const repoDir = process.cwd();
34
+ const [lastDir] = repoDir.split("/").reverse();
35
+ try {
36
+ const playwrightConfig = (await tsxImport.require(pwFile, `${repoDir}/${lastDir}`)).default;
37
+ return playwrightConfig.projects;
38
+ }
39
+ catch (err) {
40
+ console.error("Error getting project list from playwright config", err);
41
+ }
42
+ return [];
43
+ }
@@ -1,33 +1,5 @@
1
1
  import { Node, SourceFile } from "ts-morph";
2
2
  import { Platform, TestFramework } from "../types";
3
- type PlaywrightProject = {
4
- name: string;
5
- use: any;
6
- testMatch: string[] | string | undefined;
7
- testIgnore: string[] | string | undefined;
8
- teardown: string | undefined;
9
- };
10
- export declare function cmd(command: string[], options: {
11
- env?: Record<string, string>;
12
- cwd?: string;
13
- captureOutput?: boolean;
14
- }): Promise<number | {
15
- code: number;
16
- output: string;
17
- }>;
18
- export declare function cmdWithOutput(command: string[], options: {
19
- env?: Record<string, string>;
20
- cwd?: string;
21
- }): Promise<{
22
- code: number;
23
- output: string;
24
- }>;
25
- /**
26
- *
27
- *
28
- * @param {string} [directoryPath=""]
29
- * @return {*} {Promise<string[]>}
30
- */
31
3
  export declare function getAllFilePaths(directoryPath?: string, filters?: {
32
4
  filePath?: string;
33
5
  }): Promise<string[]>;
@@ -45,6 +17,7 @@ export declare function hasTestBlock({ filePath, scenarioName, suites, }: {
45
17
  scenarioName: string;
46
18
  suites?: string[];
47
19
  }): Promise<boolean>;
20
+ export declare function getDescribeBlockName(node: Node): string | undefined;
48
21
  export declare function findFirstSerialDescribeBlock(node: Node | undefined): Node | undefined;
49
22
  export declare function hasTopLevelDescribeConfigureWithSerialMode(filePath: string): Promise<boolean>;
50
23
  export declare function markTestAsOnly({ sourceFile, parentDescribeNode, testCaseNode, filePath, }: {
@@ -53,7 +26,6 @@ export declare function markTestAsOnly({ sourceFile, parentDescribeNode, testCas
53
26
  testCaseNode: Node;
54
27
  filePath: string;
55
28
  }): Promise<void>;
56
- export declare function getProjectsFromPlaywrightConfig(platform: Platform): Promise<PlaywrightProject[]>;
57
29
  export declare const filterArrayByGlobMatchersSet: (input: string[], globMatcherSets: string[][]) => string[];
58
30
  export declare function labelTeardownProjects(projectNames: string[], platform: Platform): Promise<{
59
31
  isTeardown: boolean;
@@ -85,5 +57,4 @@ export declare function getTypescriptTestBlock({ scenarioName, suites, content,
85
57
  testAlias: string;
86
58
  sourceFile: SourceFile;
87
59
  };
88
- export {};
89
60
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
@@ -4,113 +4,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.handleTeardownSkipFlag = exports.getTestRunner = exports.downloadBuild = exports.pickNameFromPackageJson = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.getTestModuleAliasFromSourceFile = void 0;
7
- exports.cmd = cmd;
8
- exports.cmdWithOutput = cmdWithOutput;
9
7
  exports.getAllFilePaths = getAllFilePaths;
10
8
  exports.getTestCaseNode = getTestCaseNode;
11
9
  exports.hasTestBlock = hasTestBlock;
10
+ exports.getDescribeBlockName = getDescribeBlockName;
12
11
  exports.findFirstSerialDescribeBlock = findFirstSerialDescribeBlock;
13
12
  exports.hasTopLevelDescribeConfigureWithSerialMode = hasTopLevelDescribeConfigureWithSerialMode;
14
13
  exports.markTestAsOnly = markTestAsOnly;
15
- exports.getProjectsFromPlaywrightConfig = getProjectsFromPlaywrightConfig;
16
14
  exports.labelTeardownProjects = labelTeardownProjects;
17
15
  exports.buildRepoName = buildRepoName;
18
16
  exports.getTypescriptTestBlock = getTypescriptTestBlock;
19
- const child_process_1 = require("child_process");
20
17
  const fs_1 = require("fs");
21
18
  const promises_1 = __importDefault(require("fs/promises"));
22
19
  const minimatch_1 = require("minimatch");
23
20
  const path_1 = __importDefault(require("path"));
24
21
  const ts_morph_1 = require("ts-morph");
25
- // For TypeScript type safety
26
- let tsxImport = null;
27
22
  const util_1 = require("util");
23
+ const cmd_1 = require("../lib/cmd");
28
24
  const types_1 = require("../types");
29
- function setupProcessSignalHandlers(proc) {
30
- const handleSignal = async (signal) => {
31
- console.log(`\nReceived ${signal}, gracefully shutting down...`);
32
- if (proc && !proc.killed) {
33
- // Forward the signal to the child process
34
- proc.kill(signal);
35
- // Wait for the child process to exit
36
- await new Promise((resolve) => {
37
- proc.once("exit", () => {
38
- resolve();
39
- });
40
- });
41
- }
42
- process.exit(0);
43
- };
44
- const sigintHandler = async () => await handleSignal("SIGINT");
45
- const sigtermHandler = async () => await handleSignal("SIGTERM");
46
- const otherSignalHandlers = ["SIGABRT", "SIGHUP", "SIGQUIT"].map((signal) => {
47
- const handler = () => console.log(`Received ${signal}, which is a no-op`);
48
- process.once(signal, handler);
49
- return { signal, handler };
50
- });
51
- process.once("SIGINT", sigintHandler);
52
- process.once("SIGTERM", sigtermHandler);
53
- // Return a cleanup function that removes all signal handlers
54
- return () => {
55
- process.removeListener("SIGINT", sigintHandler);
56
- process.removeListener("SIGTERM", sigtermHandler);
57
- otherSignalHandlers.forEach(({ signal, handler }) => {
58
- process.removeListener(signal, handler);
59
- });
60
- };
61
- }
62
- async function cmd(command, options) {
63
- let output = options.captureOutput ? "" : undefined;
64
- let errorLogs = [];
65
- return new Promise((resolveFunc, rejectFunc) => {
66
- const p = (0, child_process_1.spawn)(command[0], command.slice(1), {
67
- env: { ...process.env, ...options.env },
68
- cwd: options.cwd,
69
- // Ensure child process receives signals
70
- detached: false,
71
- });
72
- // Setup signal handlers and get cleanup function
73
- const cleanupSignalHandlers = setupProcessSignalHandlers(p);
74
- p.stdout.on("data", (x) => {
75
- const log = x.toString();
76
- if (options.captureOutput) {
77
- output += log;
78
- }
79
- else {
80
- process.stdout.write(log);
81
- }
82
- if (log.includes("Error")) {
83
- errorLogs.push(log);
84
- }
85
- });
86
- p.stderr.on("data", (x) => {
87
- const log = x.toString();
88
- process.stderr.write(log);
89
- errorLogs.push(log);
90
- });
91
- p.on("exit", (code) => {
92
- // Clean up signal handlers when the process exits
93
- cleanupSignalHandlers();
94
- if (code != 0) {
95
- // assuming last log is the error message before exiting
96
- rejectFunc(errorLogs.slice(-3).join("\n"));
97
- }
98
- else {
99
- resolveFunc(options.captureOutput ? { code: code, output: output } : code);
100
- }
101
- });
102
- });
103
- }
104
- async function cmdWithOutput(command, options) {
105
- const result = await cmd(command, { ...options, captureOutput: true });
106
- return result;
107
- }
108
- /**
109
- *
110
- *
111
- * @param {string} [directoryPath=""]
112
- * @return {*} {Promise<string[]>}
113
- */
25
+ const config_1 = require("./config");
114
26
  async function getAllFilePaths(directoryPath = "tests", filters = {}) {
115
27
  let filePaths = [];
116
28
  try {
@@ -172,6 +84,18 @@ async function hasTestBlock({ filePath, scenarioName, suites, }) {
172
84
  });
173
85
  return !!testCaseNode;
174
86
  }
87
+ function getDescribeBlockName(node) {
88
+ if (ts_morph_1.Node.isCallExpression(node)) {
89
+ const expression = node.getExpression();
90
+ if (expression.getText().includes("test.describe")) {
91
+ const [firstArg] = node.getArguments();
92
+ if (firstArg && ts_morph_1.Node.isStringLiteral(firstArg)) {
93
+ return firstArg.getLiteralValue();
94
+ }
95
+ }
96
+ }
97
+ return undefined;
98
+ }
175
99
  function findFirstSerialDescribeBlock(node) {
176
100
  let currentNode = node;
177
101
  // Traverse upwards until we find a 'describe' block with 'serial: true'
@@ -241,39 +165,6 @@ async function markTestAsOnly({ sourceFile, parentDescribeNode, testCaseNode, fi
241
165
  }
242
166
  await promises_1.default.writeFile(filePath, updatedTestFileContent, "utf-8");
243
167
  }
244
- async function getProjectsFromPlaywrightConfig(platform) {
245
- const configName = platform === types_1.Platform.WEB ? "playwright.config.ts" : "appwright.config.ts";
246
- const directoryPath = ".";
247
- const pwFile = path_1.default.resolve(directoryPath, configName);
248
- if (typeof window !== "undefined") {
249
- throw new Error("readPlaywrightConfig cannot be used in browser environments");
250
- }
251
- else {
252
- // Only initialize on server side
253
- // This will only execute on the server
254
- await import("tsx/cjs/api")
255
- .then((module) => {
256
- tsxImport = module;
257
- })
258
- .catch(() => {
259
- console.warn("Failed to import tsx: --->");
260
- });
261
- }
262
- if (!tsxImport) {
263
- console.warn("tsx module not available");
264
- return [];
265
- }
266
- const repoDir = process.cwd();
267
- const [lastDir] = repoDir.split("/").reverse();
268
- try {
269
- const playwrightConfig = (await tsxImport.require(pwFile, `${repoDir}/${lastDir}`)).default;
270
- return playwrightConfig.projects;
271
- }
272
- catch (err) {
273
- console.error("Error getting project list from playwright config", err);
274
- }
275
- return [];
276
- }
277
168
  const filterArrayByGlobMatchersSet = (
278
169
  // array that needs to be filtered
279
170
  input,
@@ -289,7 +180,7 @@ globMatcherSets) => {
289
180
  };
290
181
  exports.filterArrayByGlobMatchersSet = filterArrayByGlobMatchersSet;
291
182
  async function labelTeardownProjects(projectNames, platform) {
292
- const allProjects = await getProjectsFromPlaywrightConfig(platform);
183
+ const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(platform);
293
184
  return projectNames.map((projectName) => {
294
185
  const setupForTeardown = allProjects.find((p) => p.teardown === projectName);
295
186
  if (setupForTeardown) {
@@ -307,7 +198,7 @@ async function labelTeardownProjects(projectNames, platform) {
307
198
  });
308
199
  }
309
200
  const generateProjectFilters = async ({ platform, filteringSets, }) => {
310
- const allProjects = await getProjectsFromPlaywrightConfig(platform);
201
+ const allProjects = await (0, config_1.getProjectsFromPlaywrightConfig)(platform);
311
202
  const allProjectNames = allProjects.map((project) => project.name);
312
203
  const filters = filteringSets.map((matchingString) => matchingString.split(","));
313
204
  const filteredProjects = (0, exports.filterArrayByGlobMatchersSet)(allProjectNames, filters);
@@ -334,7 +225,7 @@ const downloadBuild = async (buildUrl) => {
334
225
  const buildDownloadScript = packageJSONData.scripts["download"];
335
226
  if (buildDownloadScript && buildUrl) {
336
227
  console.log(`Downloading build from ${buildUrl}`);
337
- await cmd(`npm run download ${buildUrl}`.split(" "), {
228
+ await (0, cmd_1.spawnCmd)(`npm`, ["run", "download", buildUrl], {
338
229
  env: { ...Object(process.env) },
339
230
  });
340
231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-run",
3
- "version": "0.8.5",
3
+ "version": "0.9.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -24,7 +24,8 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/async-retry": "^1.4.8",
27
- "@types/node": "^22.5.5"
27
+ "@types/node": "^22.5.5",
28
+ "memfs": "^4.17.1"
28
29
  },
29
30
  "scripts": {
30
31
  "dev": "tsc --build --watch",
@@ -1 +1 @@
1
- {"root":["./src/dashboard.ts","./src/index.ts","./src/bin/index.ts","./src/lib/run-all-tests.ts","./src/lib/run-specific-test.ts","./src/types/index.ts","./src/utils/config-parser.ts","./src/utils/index.ts"],"version":"5.8.3"}
1
+ {"root":["./src/dashboard.ts","./src/index.ts","./src/bin/index.ts","./src/lib/cmd.ts","./src/lib/run-all-tests.ts","./src/lib/run-specific-test.ts","./src/lib/memfs/read-hello-world.ts","./src/parser/index.ts","./src/types/index.ts","./src/utils/config-parser.ts","./src/utils/config.ts","./src/utils/index.ts"],"version":"5.8.3"}