cypress-plugin-last-failed 1.2.0 → 2.0.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/README.md +23 -14
- package/cypress/config/cypress.config.js +26 -0
- package/package.json +2 -1
- package/runFailed.js +15 -8
- package/src/index.d.ts +23 -0
- package/src/index.js +43 -35
package/README.md
CHANGED
|
@@ -18,14 +18,16 @@ A companion Cypress plugin for <code>cy-grep</code> that re-runs the last failed
|
|
|
18
18
|
|
|
19
19
|
#### Table of Contents
|
|
20
20
|
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
21
|
+
- [Features](#features)
|
|
22
|
+
- [Table of Contents](#table-of-contents)
|
|
23
|
+
- [📦 Installation](#-installation)
|
|
24
|
+
- [👟 Run mode](#-run-mode)
|
|
23
25
|
- [Add rule to gitignore](#add-rule-to-gitignore)
|
|
24
|
-
- [Setting up a `npm` script](#-setting-up-a-npm-script)
|
|
25
|
-
- [Open mode](#-open-mode)
|
|
26
|
+
- [📃 Setting up a `npm` script](#-setting-up-a-npm-script)
|
|
27
|
+
- [⌛ Open mode](#-open-mode)
|
|
26
28
|
- [Recommended open mode env variables](#recommended-open-mode-env-variables)
|
|
27
29
|
- [Use Required Test Tags Instead Of Skipping Tests](#use-required-test-tags-instead-of-skipping-tests)
|
|
28
|
-
- [
|
|
30
|
+
- [Continuous integration support](#continuous-integration-support)
|
|
29
31
|
- [Typescript support](#typescript-support)
|
|
30
32
|
- [Contributions](#contributions)
|
|
31
33
|
|
|
@@ -43,9 +45,9 @@ npm install --save-dev cypress-plugin-last-failed
|
|
|
43
45
|
2. In `cypress/support/e2e.js` (For E2E tests) and/or `cypress/support/component.js` (For Component tests),
|
|
44
46
|
|
|
45
47
|
```js
|
|
46
|
-
import { failedTestToggle } from
|
|
48
|
+
import { failedTestToggle } from "cypress-plugin-last-failed";
|
|
47
49
|
|
|
48
|
-
const registerCypressGrep = require(
|
|
50
|
+
const registerCypressGrep = require("@bahmutov/cy-grep");
|
|
49
51
|
registerCypressGrep();
|
|
50
52
|
|
|
51
53
|
failedTestToggle();
|
|
@@ -54,8 +56,8 @@ failedTestToggle();
|
|
|
54
56
|
3. In `cypress.config`, include the following within `setupNodeEvents` for `e2e` and/or `component` testing:
|
|
55
57
|
|
|
56
58
|
```js
|
|
57
|
-
const { defineConfig } = require(
|
|
58
|
-
const { collectFailingTests } = require(
|
|
59
|
+
const { defineConfig } = require("cypress");
|
|
60
|
+
const { collectFailingTests } = require("cypress-plugin-last-failed");
|
|
59
61
|
|
|
60
62
|
module.exports = defineConfig({
|
|
61
63
|
screenshotOnRunFailure: false,
|
|
@@ -67,7 +69,7 @@ module.exports = defineConfig({
|
|
|
67
69
|
setupNodeEvents(on, config) {
|
|
68
70
|
collectFailingTests(on, config);
|
|
69
71
|
|
|
70
|
-
require(
|
|
72
|
+
require("@bahmutov/cy-grep/src/plugin")(config);
|
|
71
73
|
return config;
|
|
72
74
|
},
|
|
73
75
|
},
|
|
@@ -75,7 +77,7 @@ module.exports = defineConfig({
|
|
|
75
77
|
setupNodeEvents(on, config) {
|
|
76
78
|
collectFailingTests(on, config);
|
|
77
79
|
|
|
78
|
-
require(
|
|
80
|
+
require("@bahmutov/cy-grep/src/plugin")(config);
|
|
79
81
|
return config;
|
|
80
82
|
},
|
|
81
83
|
},
|
|
@@ -106,7 +108,14 @@ You can also include more cli arguments similar to `cypress run`, as the command
|
|
|
106
108
|
npx cypress-plugin-last-failed run --e2e --browser chrome
|
|
107
109
|
```
|
|
108
110
|
|
|
109
|
-
There will be a folder called
|
|
111
|
+
There will be a folder called test-results created in the directory of the cypress.config. If you would like to specify a different folder for test results, use the LAST_FAILED_RESULTS_PATH environment variable:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Example
|
|
115
|
+
LAST_FAILED_RESULTS_PATH=cypress/custom-test-results npx cypress-plugin-last-failed run
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This environment variable will direct the plugin to store or retrieve the last run's failed test results from the specified folder.
|
|
110
119
|
|
|
111
120
|
### Add rule to gitignore
|
|
112
121
|
|
|
@@ -162,7 +171,7 @@ Normally, any Cypress test or suite of tests marked with a `.skip` will be shown
|
|
|
162
171
|
Since this plugin uses `@bahmutov/cy-grep` plugin, we can instead designate skipped tests using a **required tag**:
|
|
163
172
|
|
|
164
173
|
```js
|
|
165
|
-
it(
|
|
174
|
+
it("deletes an item", { requiredTags: "@skip" }, () => {
|
|
166
175
|
expect(1).to.equal(2);
|
|
167
176
|
});
|
|
168
177
|
```
|
|
@@ -186,7 +195,7 @@ name: test-last-failed-node-script
|
|
|
186
195
|
on:
|
|
187
196
|
push:
|
|
188
197
|
branches:
|
|
189
|
-
-
|
|
198
|
+
- "main"
|
|
190
199
|
pull_request:
|
|
191
200
|
workflow_dispatch:
|
|
192
201
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const { defineConfig } = require("cypress");
|
|
2
|
+
const { collectFailingTests } = require("../../src/index");
|
|
3
|
+
|
|
4
|
+
module.exports = defineConfig({
|
|
5
|
+
env: {
|
|
6
|
+
grepOmitFiltered: true,
|
|
7
|
+
grepFilterSpecs: true,
|
|
8
|
+
},
|
|
9
|
+
screenshotOnRunFailure: false,
|
|
10
|
+
e2e: {
|
|
11
|
+
setupNodeEvents(on, config) {
|
|
12
|
+
require("@bahmutov/cy-grep/src/plugin")(config);
|
|
13
|
+
collectFailingTests(on, config);
|
|
14
|
+
|
|
15
|
+
return config;
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
component: {
|
|
19
|
+
setupNodeEvents(on, config) {
|
|
20
|
+
require("@bahmutov/cy-grep/src/plugin")(config);
|
|
21
|
+
collectFailingTests(on, config);
|
|
22
|
+
|
|
23
|
+
return config;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cypress-plugin-last-failed",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Cypress plugin to rerun last failed tests in cypress run and open mode",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"last-failed": "npx cypress-plugin-last-failed run --e2e --browser electron"
|
|
8
9
|
},
|
package/runFailed.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const cypress = require(
|
|
4
|
-
const fs = require(
|
|
5
|
-
const path = require(
|
|
6
|
-
const appDir = process.env.INIT_CWD ? process.env.INIT_CWD : path.resolve(
|
|
3
|
+
const cypress = require("cypress");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const appDir = process.env.INIT_CWD ? process.env.INIT_CWD : path.resolve(".");
|
|
7
7
|
|
|
8
8
|
async function runLastFailed() {
|
|
9
9
|
const noFailedTestsMessage = `No previous failed tests detected
|
|
10
10
|
Ensure you are in the directory of your cypress config
|
|
11
11
|
Try running tests again with cypress run`;
|
|
12
12
|
|
|
13
|
-
const failedTestFilePath =
|
|
13
|
+
const failedTestFilePath = process.env.LAST_FAILED_RESULTS_PATH
|
|
14
|
+
? path.join(
|
|
15
|
+
appDir,
|
|
16
|
+
process.env.LAST_FAILED_RESULTS_PATH,
|
|
17
|
+
"test-results",
|
|
18
|
+
"last-run.json"
|
|
19
|
+
)
|
|
20
|
+
: path.join(appDir, "test-results", "last-run.json");
|
|
14
21
|
|
|
15
22
|
if (fs.existsSync(failedTestFilePath)) {
|
|
16
23
|
// Retrieve the failedTests from the file
|
|
17
|
-
const failedTests = await fs.promises.readFile(failedTestFilePath,
|
|
24
|
+
const failedTests = await fs.promises.readFile(failedTestFilePath, "utf8");
|
|
18
25
|
|
|
19
26
|
// Retrieve the parent suite and tests in the results from test-results/last-run
|
|
20
27
|
const parentAndTest = JSON.parse(failedTests).map(({ parent, test }) => ({
|
|
@@ -24,13 +31,13 @@ Try running tests again with cypress run`;
|
|
|
24
31
|
// Combine parent suite and test together
|
|
25
32
|
const resultSet = new Set(
|
|
26
33
|
Object.values(parentAndTest).flatMap(
|
|
27
|
-
(parent) => parent.parent +
|
|
34
|
+
(parent) => parent.parent + "," + parent.test + ";"
|
|
28
35
|
)
|
|
29
36
|
);
|
|
30
37
|
// Format string for use in grep functionality
|
|
31
38
|
const stringedTests = Array.from(resultSet)
|
|
32
39
|
.toString()
|
|
33
|
-
.replaceAll(
|
|
40
|
+
.replaceAll(",", " ")
|
|
34
41
|
.slice(0, -1);
|
|
35
42
|
|
|
36
43
|
if (stringedTests.length > 0) {
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// index.d.ts
|
|
2
|
+
declare module "cypress-plugin-last-failed" {
|
|
3
|
+
/**
|
|
4
|
+
* Collects failed tests from the most recent Cypress test run.
|
|
5
|
+
*
|
|
6
|
+
* After each run, a file will store failed test titles within a test-results directory.
|
|
7
|
+
*
|
|
8
|
+
* @param {Function} on - Cypress event registration function.
|
|
9
|
+
* @param {object} config - Cypress config object.
|
|
10
|
+
* @returns {void}
|
|
11
|
+
*/
|
|
12
|
+
export function collectFailingTests(
|
|
13
|
+
on: (event: string, callback: Function) => void,
|
|
14
|
+
config: { env: { TEST_RESULTS_PATH?: string }; configFile: string }
|
|
15
|
+
): void;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Toggles the display of failed tests in the Cypress UI.
|
|
19
|
+
*
|
|
20
|
+
* @returns {void}
|
|
21
|
+
*/
|
|
22
|
+
export function failedTestToggle(): void;
|
|
23
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,60 +1,68 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const failedTestToggle = require(
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const failedTestToggle = require("./toggle");
|
|
4
|
+
|
|
4
5
|
/**
|
|
5
6
|
* Collects failed tests from the most recent Cypress test run
|
|
6
7
|
*
|
|
7
8
|
* After each run, a file will store failed test titles within a test-results directory
|
|
8
9
|
*
|
|
9
|
-
* The test-results directory will be stored in cypress.config directory
|
|
10
|
+
* The test-results directory will be stored in the cypress.config directory
|
|
10
11
|
*
|
|
11
12
|
* Subsequent test runs containing failed tests will overwrite this file
|
|
12
13
|
* @param {*} on
|
|
13
14
|
* @param {*} config
|
|
14
15
|
* @returns
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
17
|
const collectFailingTests = (on, config) => {
|
|
18
|
-
on(
|
|
18
|
+
on("after:run", async (results) => {
|
|
19
19
|
let failedTests = [];
|
|
20
|
-
|
|
21
|
-
for (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
spec: spec,
|
|
31
|
-
parent: [...tests[i].slice(0, -1)],
|
|
32
|
-
test: tests[i].pop(),
|
|
33
|
-
};
|
|
34
|
-
// Only store non empty test titles
|
|
35
|
-
if (tests != '') {
|
|
36
|
-
failedTests.push(report);
|
|
37
|
-
}
|
|
20
|
+
|
|
21
|
+
for (const run of results.runs) {
|
|
22
|
+
if (run.tests && run.spec) {
|
|
23
|
+
const tests = run.tests
|
|
24
|
+
.filter((test) => test.state === "failed")
|
|
25
|
+
.map((test) => test.title);
|
|
26
|
+
|
|
27
|
+
const spec = run.spec.relative;
|
|
28
|
+
|
|
29
|
+
failedTests = failedTests.concat(generateReports(tests, spec));
|
|
38
30
|
}
|
|
39
31
|
}
|
|
40
32
|
|
|
41
|
-
// Use
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
// Use process.env.LAST_FAILED_RESULTS_PATH or fallback to the default path
|
|
34
|
+
const failedTestFilePath = process.env.LAST_FAILED_RESULTS_PATH
|
|
35
|
+
? path.join(
|
|
36
|
+
process.env.INIT_CWD,
|
|
37
|
+
process.env.LAST_FAILED_RESULTS_PATH,
|
|
38
|
+
"test-results"
|
|
39
|
+
)
|
|
40
|
+
: `${path.dirname(config.configFile)}/test-results/`;
|
|
45
41
|
|
|
46
42
|
// Create the directory and last-run file where failed tests will be written to
|
|
47
|
-
await fs.promises.mkdir(
|
|
48
|
-
|
|
49
|
-
});
|
|
50
|
-
const lastRunReportFile = path.join(
|
|
51
|
-
`${failedTestFileDirectory}`,
|
|
52
|
-
'last-run.json'
|
|
53
|
-
);
|
|
43
|
+
await fs.promises.mkdir(failedTestFilePath, { recursive: true });
|
|
44
|
+
const lastRunReportFile = path.join(failedTestFilePath, "last-run.json");
|
|
54
45
|
await fs.promises.writeFile(lastRunReportFile, JSON.stringify(failedTests));
|
|
55
46
|
});
|
|
56
47
|
|
|
57
48
|
return collectFailingTests;
|
|
58
49
|
};
|
|
59
50
|
|
|
51
|
+
const generateReports = (tests, spec) => {
|
|
52
|
+
const reports = [];
|
|
53
|
+
for (const test of tests) {
|
|
54
|
+
const testCopy = [...test]; // Create a copy of the array to avoid mutation
|
|
55
|
+
const testTitle = testCopy.pop(); // Extract the test title
|
|
56
|
+
if (testTitle) {
|
|
57
|
+
const report = {
|
|
58
|
+
spec: spec,
|
|
59
|
+
parent: testCopy, // Parent titles
|
|
60
|
+
test: testTitle, // The actual test title
|
|
61
|
+
};
|
|
62
|
+
reports.push(report);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return reports;
|
|
66
|
+
};
|
|
67
|
+
|
|
60
68
|
module.exports = { collectFailingTests, failedTestToggle };
|