@empiricalrun/test-run 0.5.0 → 0.5.3

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,24 @@
1
1
  # @empiricalrun/test-run
2
2
 
3
+ ## 0.5.3
4
+
5
+ ### Patch Changes
6
+
7
+ - b9f53be: fix: logs for other signals to catch github actions behavior
8
+
9
+ ## 0.5.2
10
+
11
+ ### Patch Changes
12
+
13
+ - 7332043: feat: pass signals to test-run child process for graceful exit
14
+
15
+ ## 0.5.1
16
+
17
+ ### Patch Changes
18
+
19
+ - bce3667: fix: use name and suites to find test block
20
+ - bce3667: fix: test-run package to support suites
21
+
3
22
  ## 0.5.0
4
23
 
5
24
  ### Minor Changes
package/dist/bin/index.js CHANGED
@@ -13,6 +13,7 @@ const utils_1 = require("../utils");
13
13
  .option("-d, --dir <test-dir>", "Path to the test directory")
14
14
  .option("-f, --file <test-file-path>", "Path to the test file")
15
15
  .option("-p, --project <project-name...>", "Test projects to run")
16
+ .option("-s, --suites <suites>", "suites under which the test is defined")
16
17
  .option("--skip-teardown", "This options skips running teardown tests")
17
18
  .option("--forbid-only", `This options forbids the use of ".only" in the test files`)
18
19
  .allowUnknownOption();
@@ -34,10 +35,13 @@ const utils_1 = require("../utils");
34
35
  "--dir",
35
36
  "-p",
36
37
  "--project",
38
+ "-s",
39
+ "--suites",
37
40
  options.skipTeardown,
38
41
  options.name,
39
42
  options.dir,
40
43
  options.file,
44
+ options.suites,
41
45
  ...options.project, // an array of comma separated project names/pattern matching globs *,premium-*,super-premium-*,safari
42
46
  ];
43
47
  const pwOptions = process.argv
@@ -69,12 +73,16 @@ const utils_1 = require("../utils");
69
73
  if (options.skipTeardown) {
70
74
  await (0, utils_1.handleTeardownSkipFlag)(directory);
71
75
  }
76
+ const suites = options.suites && options.suites.trim() !== ""
77
+ ? options.suites?.split(",")
78
+ : undefined;
72
79
  const { hasTestPassed } = await (0, __1.runTest)({
73
80
  name: options.name,
74
81
  filePath: options.file,
75
82
  dir: directory,
76
83
  pwOptions: pwOptions.join(" "),
77
84
  platform,
85
+ suites,
78
86
  });
79
87
  if (!hasTestPassed) {
80
88
  process.exit(1);
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { TestRunParameters } from "./types";
4
4
  * @export
5
5
  * @param {TestRunParameters} { name, dir, pwOptions }
6
6
  */
7
- export declare function runTest({ name, filePath, dir, pwOptions, platform, }: TestRunParameters): Promise<{
7
+ export declare function runTest({ name, filePath, dir, pwOptions, platform, suites, }: TestRunParameters): Promise<{
8
8
  hasTestPassed: boolean;
9
9
  }>;
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,SAAS,EACT,QAAQ,GACT,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CAMD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,SAAS,EACT,QAAQ,EACR,MAAM,GACP,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CAaD"}
package/dist/index.js CHANGED
@@ -8,9 +8,16 @@ const run_specific_test_1 = require("./run-specific-test");
8
8
  * @export
9
9
  * @param {TestRunParameters} { name, dir, pwOptions }
10
10
  */
11
- async function runTest({ name, filePath, dir, pwOptions, platform, }) {
11
+ async function runTest({ name, filePath, dir, pwOptions, platform, suites, }) {
12
12
  if (name) {
13
- return await (0, run_specific_test_1.runSpecificTest)({ name, dir, filePath, pwOptions, platform });
13
+ return await (0, run_specific_test_1.runSpecificTest)({
14
+ name,
15
+ dir,
16
+ filePath,
17
+ pwOptions,
18
+ platform,
19
+ suites,
20
+ });
14
21
  }
15
22
  return await (0, run_all_tests_1.runAllTests)({ pwOptions, platform });
16
23
  }
@@ -4,7 +4,7 @@ import { TestRunParameters } from "./types";
4
4
  * @export
5
5
  * @param {TestRunParameters} { name, dir, pwOptions }
6
6
  */
7
- export declare function runSpecificTest({ name, filePath, dir, pwOptions, platform, }: TestRunParameters): Promise<{
7
+ export declare function runSpecificTest({ name, filePath, dir, pwOptions, platform, suites, }: TestRunParameters): Promise<{
8
8
  hasTestPassed: boolean;
9
9
  }>;
10
10
  //# sourceMappingURL=run-specific-test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-specific-test.d.ts","sourceRoot":"","sources":["../src/run-specific-test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAY5C;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,EACpC,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,SAAS,EACT,QAAQ,GACT,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CA0ED"}
1
+ {"version":3,"file":"run-specific-test.d.ts","sourceRoot":"","sources":["../src/run-specific-test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAY5C;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,EACpC,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,SAAS,EACT,QAAQ,EACR,MAAM,GACP,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CA2ED"}
@@ -11,7 +11,7 @@ const utils_1 = require("./utils");
11
11
  * @export
12
12
  * @param {TestRunParameters} { name, dir, pwOptions }
13
13
  */
14
- async function runSpecificTest({ name, filePath, dir, pwOptions, platform, }) {
14
+ async function runSpecificTest({ name, filePath, dir, pwOptions, platform, suites, }) {
15
15
  const files = await (0, utils_1.getAllFilePaths)(dir, {
16
16
  filePath,
17
17
  });
@@ -19,7 +19,11 @@ async function runSpecificTest({ name, filePath, dir, pwOptions, platform, }) {
19
19
  // find the first file that contains the test block
20
20
  // TODO: add suites support
21
21
  for (const file of files) {
22
- const match = await (0, utils_1.hasTestBlock)({ filePath: file, scenarioName: name });
22
+ const match = await (0, utils_1.hasTestBlock)({
23
+ filePath: file,
24
+ scenarioName: name,
25
+ suites,
26
+ });
23
27
  if (match) {
24
28
  matchingFilePath = file;
25
29
  break;
@@ -32,6 +36,7 @@ async function runSpecificTest({ name, filePath, dir, pwOptions, platform, }) {
32
36
  const { testCaseNode, sourceFile } = await (0, utils_1.getTestCaseNode)({
33
37
  filePath: matchingFilePath,
34
38
  scenarioName: name,
39
+ suites,
35
40
  });
36
41
  const parentDescribe = (0, utils_1.findFirstSerialDescribeBlock)(testCaseNode);
37
42
  const isFileMarkedSerial = await (0, utils_1.hasTopLevelDescribeConfigureWithSerialMode)(matchingFilePath);
@@ -39,23 +44,20 @@ async function runSpecificTest({ name, filePath, dir, pwOptions, platform, }) {
39
44
  console.log("Is parent describe block marked serial:", !!parentDescribe);
40
45
  console.log("Is file marked serial:", isFileMarkedSerial);
41
46
  const currentFileContent = await fs_extra_1.default.readFile(matchingFilePath, "utf-8");
42
- const revertFileContent = () => {
43
- fs_extra_1.default.writeFileSync(matchingFilePath, currentFileContent);
44
- };
45
47
  // revert the changes made to the file to mark tests as only
46
48
  // these needs to handle by listening to process exit/kill events
47
- process.on("beforeExit", () => {
48
- revertFileContent();
49
- });
50
- process.on("exit", () => {
51
- revertFileContent();
52
- });
53
- process.on("SIGINT", () => {
54
- revertFileContent();
55
- });
56
- process.on("SIGTERM", () => {
57
- revertFileContent();
58
- });
49
+ const revertFileContent = () => {
50
+ try {
51
+ fs_extra_1.default.writeFileSync(matchingFilePath, currentFileContent);
52
+ }
53
+ catch (error) {
54
+ console.error("Error while cleaning up test file:", error);
55
+ }
56
+ };
57
+ process.on("beforeExit", revertFileContent);
58
+ process.on("exit", revertFileContent);
59
+ process.on("SIGINT", revertFileContent);
60
+ process.on("SIGTERM", revertFileContent);
59
61
  // if the file is not marked serial, we need to mark the test or describe block as only
60
62
  if (!isFileMarkedSerial && testCaseNode) {
61
63
  await (0, utils_1.markTestAsOnly)({
@@ -4,6 +4,7 @@ export type TestRunParameters = {
4
4
  dir?: string;
5
5
  pwOptions?: string;
6
6
  platform: Platform;
7
+ suites?: string[];
7
8
  };
8
9
  export type Environment = {
9
10
  id: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACpB,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,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,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"}
@@ -13,16 +13,18 @@ export declare function getAllFilePaths(directoryPath?: string, filters?: {
13
13
  filePath?: string;
14
14
  }): Promise<string[]>;
15
15
  export declare const getTestModuleAliasFromSourceFile: (sourceFile: SourceFile) => string;
16
- export declare function getTestCaseNode({ filePath, scenarioName, }: {
16
+ export declare function getTestCaseNode({ filePath, scenarioName, suites, }: {
17
17
  filePath: string;
18
18
  scenarioName: string;
19
+ suites?: string[];
19
20
  }): Promise<{
20
21
  testCaseNode: Node | undefined;
21
22
  sourceFile: SourceFile;
22
23
  }>;
23
- export declare function hasTestBlock({ filePath, scenarioName, }: {
24
+ export declare function hasTestBlock({ filePath, scenarioName, suites, }: {
24
25
  filePath: string;
25
26
  scenarioName: string;
27
+ suites?: string[];
26
28
  }): Promise<boolean>;
27
29
  export declare function findFirstSerialDescribeBlock(node: Node | undefined): Node | undefined;
28
30
  export declare function hasTopLevelDescribeConfigureWithSerialMode(filePath: string): Promise<boolean>;
@@ -43,4 +45,21 @@ export declare const pickNameFromPackageJson: () => Promise<string | undefined>;
43
45
  export declare const downloadBuild: (buildUrl: string) => Promise<void>;
44
46
  export declare const getTestRunner: (platform: Platform) => TestFramework;
45
47
  export declare const handleTeardownSkipFlag: (directory: string) => Promise<void>;
48
+ /**
49
+ * function to get the test block and test node for the scenario
50
+ * @export
51
+ * @param {string} scenarioName
52
+ * @param {string} content
53
+ * @return { testBlock: string; parentDescribe: string; } testBlock - the test block content, testNode - the test function node
54
+ */
55
+ export declare function getTypescriptTestBlock({ scenarioName, suites, content, }: {
56
+ scenarioName: string;
57
+ suites?: string[];
58
+ content: string;
59
+ }): {
60
+ testBlock: string | undefined;
61
+ testNode: Node | undefined;
62
+ testAlias: string;
63
+ sourceFile: SourceFile;
64
+ };
46
65
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAW,UAAU,EAAc,MAAM,UAAU,CAAC;AAGjE,OAAO,EAEL,QAAQ,EAER,aAAa,EACd,MAAM,UAAU,CAAC;AAElB,wBAAgB,GAAG,CACjB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,aAAa,GAAE,MAAW,EAC1B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BnB;AAED,eAAO,MAAM,gCAAgC,eAC/B,UAAU,KACrB,MAgBF,CAAC;AAEF,wBAAsB,eAAe,CAAC,EACpC,QAAQ,EACR,YAAY,GACb,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC,CAetE;AAED,wBAAsB,YAAY,CAAC,EACjC,QAAQ,EACR,YAAY,GACb,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,IAAI,GAAG,SAAS,GACrB,IAAI,GAAG,SAAS,CA2BlB;AAED,wBAAsB,0CAA0C,CAC9D,QAAQ,EAAE,MAAM,oBA+BjB;AAED,wBAAsB,cAAc,CAAC,EACnC,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACtC,YAAY,EAAE,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAgBA;AAED,wBAAsB,+BAA+B,CAAC,QAAQ,EAAE,QAAQ,gBAevE;AAED,eAAO,MAAM,4BAA4B,UAEhC,MAAM,EAAE,mBAGE,MAAM,EAAE,EAAE,KAC1B,MAAM,EAUR,CAAC;AAEF,eAAO,MAAM,sBAAsB;cAIvB,QAAQ;mBACH,MAAM,EAAE;MACrB,QAAQ,MAAM,EAAE,CAmBnB,CAAC;AAEF,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,eAAO,MAAM,uBAAuB,QAAa,QAC/C,MAAM,GAAG,SAAS,CAMnB,CAAC;AAEF,eAAO,MAAM,aAAa,aAAoB,MAAM,KAAG,QAAQ,IAAI,CAWlE,CAAC;AAEF,eAAO,MAAM,aAAa,aAAc,QAAQ,KAAG,aAIlD,CAAC;AA4DF,eAAO,MAAM,sBAAsB,cAAqB,MAAM,kBAkB7D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAW,UAAU,EAAc,MAAM,UAAU,CAAC;AAGjE,OAAO,EAEL,QAAQ,EAER,aAAa,EACd,MAAM,UAAU,CAAC;AA6BlB,wBAAgB,GAAG,CACjB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,CAiCjB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,aAAa,GAAE,MAAW,EAC1B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BnB;AAED,eAAO,MAAM,gCAAgC,eAC/B,UAAU,KACrB,MAgBF,CAAC;AAEF,wBAAsB,eAAe,CAAC,EACpC,QAAQ,EACR,YAAY,EACZ,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC,CAQtE;AAED,wBAAsB,YAAY,CAAC,EACjC,QAAQ,EACR,YAAY,EACZ,MAAM,GACP,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,IAAI,GAAG,SAAS,GACrB,IAAI,GAAG,SAAS,CA2BlB;AAED,wBAAsB,0CAA0C,CAC9D,QAAQ,EAAE,MAAM,oBA+BjB;AAED,wBAAsB,cAAc,CAAC,EACnC,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACtC,YAAY,EAAE,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAgBA;AAED,wBAAsB,+BAA+B,CAAC,QAAQ,EAAE,QAAQ,gBAevE;AAED,eAAO,MAAM,4BAA4B,UAEhC,MAAM,EAAE,mBAGE,MAAM,EAAE,EAAE,KAC1B,MAAM,EAUR,CAAC;AAEF,eAAO,MAAM,sBAAsB;cAIvB,QAAQ;mBACH,MAAM,EAAE;MACrB,QAAQ,MAAM,EAAE,CAmBnB,CAAC;AAEF,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,eAAO,MAAM,uBAAuB,QAAa,QAC/C,MAAM,GAAG,SAAS,CAMnB,CAAC;AAEF,eAAO,MAAM,aAAa,aAAoB,MAAM,KAAG,QAAQ,IAAI,CAWlE,CAAC;AAEF,eAAO,MAAM,aAAa,aAAc,QAAQ,KAAG,aAIlD,CAAC;AA4DF,eAAO,MAAM,sBAAsB,cAAqB,MAAM,kBAkB7D,CAAC;AAuBF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,YAAY,EACZ,MAAM,EACN,OAAO,GACR,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG;IACF,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,IAAI,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;CACxB,CA8CA"}
@@ -3,20 +3,47 @@ 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.handleTeardownSkipFlag = exports.getTestRunner = exports.downloadBuild = exports.pickNameFromPackageJson = exports.buildRepoName = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.getProjectsFromPlaywrightConfig = exports.markTestAsOnly = exports.hasTopLevelDescribeConfigureWithSerialMode = exports.findFirstSerialDescribeBlock = exports.hasTestBlock = exports.getTestCaseNode = exports.getTestModuleAliasFromSourceFile = exports.getAllFilePaths = exports.cmd = void 0;
6
+ exports.getTypescriptTestBlock = exports.handleTeardownSkipFlag = exports.getTestRunner = exports.downloadBuild = exports.pickNameFromPackageJson = exports.buildRepoName = exports.generateProjectFilters = exports.filterArrayByGlobMatchersSet = exports.getProjectsFromPlaywrightConfig = exports.markTestAsOnly = exports.hasTopLevelDescribeConfigureWithSerialMode = exports.findFirstSerialDescribeBlock = exports.hasTestBlock = exports.getTestCaseNode = exports.getTestModuleAliasFromSourceFile = exports.getAllFilePaths = exports.cmd = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
9
10
  const minimatch_1 = require("minimatch");
10
11
  const path_1 = __importDefault(require("path"));
11
12
  const ts_morph_1 = require("ts-morph");
12
13
  const api_1 = require("tsx/esm/api");
13
14
  const types_1 = require("../types");
15
+ function setupProcessSignalHandlers(proc) {
16
+ const handleSignal = async (signal) => {
17
+ console.log(`\nReceived ${signal}, gracefully shutting down...`);
18
+ if (proc && !proc.killed) {
19
+ // Forward the signal to the child process
20
+ proc.kill(signal);
21
+ // Wait for the child process to exit
22
+ await new Promise((resolve) => {
23
+ proc.once("exit", () => {
24
+ resolve();
25
+ });
26
+ });
27
+ }
28
+ process.exit(0);
29
+ };
30
+ process.once("SIGINT", async () => await handleSignal("SIGINT"));
31
+ process.once("SIGTERM", async () => await handleSignal("SIGTERM"));
32
+ // Handler for other signals to catch GitHub Actions behaviors
33
+ ["SIGABRT", "SIGHUP", "SIGQUIT"].forEach((signal) => {
34
+ process.once(signal, () => console.log(`Received ${signal}, which is a no-op`));
35
+ });
36
+ }
14
37
  function cmd(command, options) {
15
38
  let errorLogs = [];
16
39
  return new Promise((resolveFunc, rejectFunc) => {
17
- let p = (0, child_process_1.spawn)(command[0], command.slice(1), {
40
+ const p = (0, child_process_1.spawn)(command[0], command.slice(1), {
18
41
  env: { ...process.env, ...options.env },
42
+ // Ensure child process receives signals
43
+ detached: false,
19
44
  });
45
+ // Setup signal handlers
46
+ setupProcessSignalHandlers(p);
20
47
  p.stdout.on("data", (x) => {
21
48
  const log = x.toString();
22
49
  if (log.includes("Error")) {
@@ -92,21 +119,21 @@ const getTestModuleAliasFromSourceFile = (sourceFile) => {
92
119
  ?.getText() || "test");
93
120
  };
94
121
  exports.getTestModuleAliasFromSourceFile = getTestModuleAliasFromSourceFile;
95
- async function getTestCaseNode({ filePath, scenarioName, }) {
96
- const project = new ts_morph_1.Project();
122
+ async function getTestCaseNode({ filePath, scenarioName, suites, }) {
97
123
  const content = await fs_extra_1.default.readFile(filePath, "utf-8");
98
- const sourceFile = project.createSourceFile("test.ts", content);
99
- const testAlias = (0, exports.getTestModuleAliasFromSourceFile)(sourceFile);
100
- const testCaseNode = sourceFile.getFirstDescendant((node) => !!(node.isKind(ts_morph_1.SyntaxKind.CallExpression) &&
101
- node.getExpression().getText() === testAlias &&
102
- node.getArguments()[0]?.getText().includes(scenarioName)));
103
- return { testCaseNode, sourceFile };
124
+ const { testNode, sourceFile } = getTypescriptTestBlock({
125
+ scenarioName,
126
+ content,
127
+ suites, // since this method is called on the generated content, not the whole file
128
+ });
129
+ return { testCaseNode: testNode, sourceFile };
104
130
  }
105
131
  exports.getTestCaseNode = getTestCaseNode;
106
- async function hasTestBlock({ filePath, scenarioName, }) {
132
+ async function hasTestBlock({ filePath, scenarioName, suites, }) {
107
133
  const { testCaseNode } = await getTestCaseNode({
108
134
  filePath,
109
135
  scenarioName,
136
+ suites,
110
137
  });
111
138
  return !!testCaseNode;
112
139
  }
@@ -314,3 +341,72 @@ const handleTeardownSkipFlag = async (directory) => {
314
341
  });
315
342
  };
316
343
  exports.handleTeardownSkipFlag = handleTeardownSkipFlag;
344
+ const getParentDescribeNames = (node) => {
345
+ const names = [];
346
+ let current = node.getParent();
347
+ while (current) {
348
+ if (ts_morph_1.Node.isCallExpression(current)) {
349
+ const expr = current.getExpression();
350
+ if (expr.getText() === "test.describe") {
351
+ const describeBlockArguments = current.getArguments();
352
+ if (describeBlockArguments.length > 0) {
353
+ const describeBlockName = describeBlockArguments[0];
354
+ if (ts_morph_1.Node.isStringLiteral(describeBlockName)) {
355
+ names.push(describeBlockName.getLiteralText());
356
+ }
357
+ }
358
+ }
359
+ }
360
+ current = current.getParent();
361
+ }
362
+ return names.reverse(); // Reverse to get from outermost to innermost
363
+ };
364
+ /**
365
+ * function to get the test block and test node for the scenario
366
+ * @export
367
+ * @param {string} scenarioName
368
+ * @param {string} content
369
+ * @return { testBlock: string; parentDescribe: string; } testBlock - the test block content, testNode - the test function node
370
+ */
371
+ function getTypescriptTestBlock({ scenarioName, suites, content, }) {
372
+ const project = new ts_morph_1.Project();
373
+ const sourceFile = project.createSourceFile("test.ts", content);
374
+ const testAlias = (0, exports.getTestModuleAliasFromSourceFile)(sourceFile);
375
+ // Get all test function nodes that match the scenario name
376
+ const matchingTestFunctionNodes = sourceFile
377
+ .getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)
378
+ .filter((node) => {
379
+ return Boolean(node.getExpression().getText() === testAlias &&
380
+ node.getArguments()[0]?.getText().includes(scenarioName));
381
+ });
382
+ if (!suites?.length) {
383
+ const firstNode = matchingTestFunctionNodes?.[0];
384
+ return {
385
+ testBlock: firstNode?.getText(),
386
+ testNode: firstNode,
387
+ testAlias,
388
+ sourceFile,
389
+ };
390
+ }
391
+ // Iterate over each test function node and check if the suites match
392
+ for (const testNode of matchingTestFunctionNodes) {
393
+ const parentDescribes = getParentDescribeNames(testNode);
394
+ if ((0, lodash_isequal_1.default)(parentDescribes, suites)) {
395
+ // Found the matching test block
396
+ return {
397
+ testBlock: testNode.getText(),
398
+ testNode,
399
+ testAlias,
400
+ sourceFile,
401
+ };
402
+ }
403
+ }
404
+ // No matching test block found
405
+ return {
406
+ testBlock: undefined,
407
+ testNode: undefined,
408
+ testAlias,
409
+ sourceFile,
410
+ };
411
+ }
412
+ exports.getTypescriptTestBlock = getTypescriptTestBlock;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-run",
3
- "version": "0.5.0",
3
+ "version": "0.5.3",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -15,9 +15,11 @@
15
15
  },
16
16
  "author": "Empirical Team <hey@empirical.run>",
17
17
  "dependencies": {
18
+ "@types/lodash.isequal": "^4.5.8",
18
19
  "async-retry": "^1.3.3",
19
20
  "commander": "^12.1.0",
20
21
  "fs-extra": "^11.2.0",
22
+ "lodash.isequal": "^4.5.0",
21
23
  "minimatch": "^10.0.1",
22
24
  "ts-morph": "^23.0.0",
23
25
  "tsx": "^4.16.2"