@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 +19 -0
- package/dist/bin/index.js +8 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/run-specific-test.d.ts +1 -1
- package/dist/run-specific-test.d.ts.map +1 -1
- package/dist/run-specific-test.js +19 -17
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/index.d.ts +21 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +107 -11
- package/package.json +3 -1
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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)({
|
|
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,
|
|
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)({
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
process.on("
|
|
57
|
-
|
|
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)({
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/utils/index.js
CHANGED
|
@@ -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
|
-
|
|
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 =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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.
|
|
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"
|