@empiricalrun/test-run 0.5.0 → 0.5.2

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,18 @@
1
1
  # @empiricalrun/test-run
2
2
 
3
+ ## 0.5.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 7332043: feat: pass signals to test-run child process for graceful exit
8
+
9
+ ## 0.5.1
10
+
11
+ ### Patch Changes
12
+
13
+ - bce3667: fix: use name and suites to find test block
14
+ - bce3667: fix: test-run package to support suites
15
+
3
16
  ## 0.5.0
4
17
 
5
18
  ### 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;AAuBlB,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,43 @@ 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
+ }
14
33
  function cmd(command, options) {
15
34
  let errorLogs = [];
16
35
  return new Promise((resolveFunc, rejectFunc) => {
17
- let p = (0, child_process_1.spawn)(command[0], command.slice(1), {
36
+ const p = (0, child_process_1.spawn)(command[0], command.slice(1), {
18
37
  env: { ...process.env, ...options.env },
38
+ // Ensure child process receives signals
39
+ detached: false,
19
40
  });
41
+ // Setup signal handlers
42
+ setupProcessSignalHandlers(p);
20
43
  p.stdout.on("data", (x) => {
21
44
  const log = x.toString();
22
45
  if (log.includes("Error")) {
@@ -92,21 +115,21 @@ const getTestModuleAliasFromSourceFile = (sourceFile) => {
92
115
  ?.getText() || "test");
93
116
  };
94
117
  exports.getTestModuleAliasFromSourceFile = getTestModuleAliasFromSourceFile;
95
- async function getTestCaseNode({ filePath, scenarioName, }) {
96
- const project = new ts_morph_1.Project();
118
+ async function getTestCaseNode({ filePath, scenarioName, suites, }) {
97
119
  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 };
120
+ const { testNode, sourceFile } = getTypescriptTestBlock({
121
+ scenarioName,
122
+ content,
123
+ suites, // since this method is called on the generated content, not the whole file
124
+ });
125
+ return { testCaseNode: testNode, sourceFile };
104
126
  }
105
127
  exports.getTestCaseNode = getTestCaseNode;
106
- async function hasTestBlock({ filePath, scenarioName, }) {
128
+ async function hasTestBlock({ filePath, scenarioName, suites, }) {
107
129
  const { testCaseNode } = await getTestCaseNode({
108
130
  filePath,
109
131
  scenarioName,
132
+ suites,
110
133
  });
111
134
  return !!testCaseNode;
112
135
  }
@@ -314,3 +337,72 @@ const handleTeardownSkipFlag = async (directory) => {
314
337
  });
315
338
  };
316
339
  exports.handleTeardownSkipFlag = handleTeardownSkipFlag;
340
+ const getParentDescribeNames = (node) => {
341
+ const names = [];
342
+ let current = node.getParent();
343
+ while (current) {
344
+ if (ts_morph_1.Node.isCallExpression(current)) {
345
+ const expr = current.getExpression();
346
+ if (expr.getText() === "test.describe") {
347
+ const describeBlockArguments = current.getArguments();
348
+ if (describeBlockArguments.length > 0) {
349
+ const describeBlockName = describeBlockArguments[0];
350
+ if (ts_morph_1.Node.isStringLiteral(describeBlockName)) {
351
+ names.push(describeBlockName.getLiteralText());
352
+ }
353
+ }
354
+ }
355
+ }
356
+ current = current.getParent();
357
+ }
358
+ return names.reverse(); // Reverse to get from outermost to innermost
359
+ };
360
+ /**
361
+ * function to get the test block and test node for the scenario
362
+ * @export
363
+ * @param {string} scenarioName
364
+ * @param {string} content
365
+ * @return { testBlock: string; parentDescribe: string; } testBlock - the test block content, testNode - the test function node
366
+ */
367
+ function getTypescriptTestBlock({ scenarioName, suites, content, }) {
368
+ const project = new ts_morph_1.Project();
369
+ const sourceFile = project.createSourceFile("test.ts", content);
370
+ const testAlias = (0, exports.getTestModuleAliasFromSourceFile)(sourceFile);
371
+ // Get all test function nodes that match the scenario name
372
+ const matchingTestFunctionNodes = sourceFile
373
+ .getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)
374
+ .filter((node) => {
375
+ return Boolean(node.getExpression().getText() === testAlias &&
376
+ node.getArguments()[0]?.getText().includes(scenarioName));
377
+ });
378
+ if (!suites?.length) {
379
+ const firstNode = matchingTestFunctionNodes?.[0];
380
+ return {
381
+ testBlock: firstNode?.getText(),
382
+ testNode: firstNode,
383
+ testAlias,
384
+ sourceFile,
385
+ };
386
+ }
387
+ // Iterate over each test function node and check if the suites match
388
+ for (const testNode of matchingTestFunctionNodes) {
389
+ const parentDescribes = getParentDescribeNames(testNode);
390
+ if ((0, lodash_isequal_1.default)(parentDescribes, suites)) {
391
+ // Found the matching test block
392
+ return {
393
+ testBlock: testNode.getText(),
394
+ testNode,
395
+ testAlias,
396
+ sourceFile,
397
+ };
398
+ }
399
+ }
400
+ // No matching test block found
401
+ return {
402
+ testBlock: undefined,
403
+ testNode: undefined,
404
+ testAlias,
405
+ sourceFile,
406
+ };
407
+ }
408
+ 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.2",
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"