wdio-rerun-service 1.7.6 → 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/.editorconfig +20 -0
- package/.eslintignore +3 -0
- package/.github/workflows/release.yml +68 -0
- package/.github/workflows/{node.js.yml → test.yml} +23 -18
- package/.github/workflows/update.yml +30 -0
- package/.nvmrc +1 -0
- package/README.md +21 -25
- package/build/cjs/index.d.ts +33 -0
- package/build/cjs/index.js +126 -0
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/package.json +1 -0
- package/build/esm/index.d.ts +33 -0
- package/build/esm/index.js +129 -0
- package/build/esm/index.js.map +1 -0
- package/package.json +68 -36
- package/tsconfig.cjs.json +10 -0
- package/tsconfig.esm.json +11 -0
- package/.eslintrc.js +0 -16
- package/babel.config.js +0 -21
- package/build/index.js +0 -115
- package/rerun.sh +0 -1
package/.editorconfig
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# EditorConfig helps developers define and maintain consistent
|
|
2
|
+
# coding styles between different editors and IDEs
|
|
3
|
+
# editorconfig.org
|
|
4
|
+
|
|
5
|
+
root = true
|
|
6
|
+
|
|
7
|
+
[*]
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
end_of_line = lf
|
|
11
|
+
charset = utf-8
|
|
12
|
+
trim_trailing_whitespace = true
|
|
13
|
+
insert_final_newline = true
|
|
14
|
+
|
|
15
|
+
[*.md]
|
|
16
|
+
max_line_length = 0
|
|
17
|
+
trim_trailing_whitespace = false
|
|
18
|
+
|
|
19
|
+
[{*.json,*.yml}]
|
|
20
|
+
indent_size = 2
|
package/.eslintignore
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Manual NPM Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
releaseType:
|
|
7
|
+
description: "Release type - major, minor or patch"
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
default: "patch"
|
|
11
|
+
options:
|
|
12
|
+
- patch
|
|
13
|
+
- minor
|
|
14
|
+
- major
|
|
15
|
+
distTag:
|
|
16
|
+
description: 'NPM tag (e.g. use "next --preRelease=alpha --github.preRelease" to release a test version)'
|
|
17
|
+
required: true
|
|
18
|
+
default: 'latest'
|
|
19
|
+
preRelease:
|
|
20
|
+
description: If latest release was a pre-release (e.g. X.X.X-alpha.0) and you want to push another one, pick "yes"
|
|
21
|
+
required: true
|
|
22
|
+
type: choice
|
|
23
|
+
default: "no"
|
|
24
|
+
options:
|
|
25
|
+
- "yes"
|
|
26
|
+
- "no"
|
|
27
|
+
|
|
28
|
+
env:
|
|
29
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
release:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v3
|
|
36
|
+
with:
|
|
37
|
+
ref: main
|
|
38
|
+
fetch-depth: 0
|
|
39
|
+
- uses: actions/setup-node@v3
|
|
40
|
+
with:
|
|
41
|
+
node-version: 18.x
|
|
42
|
+
- name: NPM Setup
|
|
43
|
+
run: |
|
|
44
|
+
npm set registry "https://registry.npmjs.org/"
|
|
45
|
+
npm set //registry.npmjs.org/:_authToken $NPM_TOKEN
|
|
46
|
+
npm whoami
|
|
47
|
+
- name: Git Setup
|
|
48
|
+
run: |
|
|
49
|
+
git config --global user.email "bot@webdriver.io"
|
|
50
|
+
git config --global user.name "WebdriverIO Release Bot"
|
|
51
|
+
- name: Install Dependencies
|
|
52
|
+
run: npm ci --ignore-scripts
|
|
53
|
+
- name: Build Project
|
|
54
|
+
run: npm run build --if-present
|
|
55
|
+
env:
|
|
56
|
+
NODE_ENV: production
|
|
57
|
+
- name: Release
|
|
58
|
+
run: npx release-it ${{github.event.inputs.releaseType}} --github.release --ci --npm.skipChecks --no-git.requireCleanWorkingDir --npm.tag=${{github.event.inputs.distTag}}
|
|
59
|
+
env:
|
|
60
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
61
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
62
|
+
if: ${{ github.event.inputs.preRelease == 'no' }}
|
|
63
|
+
- name: Pre-Release
|
|
64
|
+
run: npx release-it ${{github.event.inputs.releaseType}} --github.release --ci --npm.skipChecks --no-git.requireCleanWorkingDir --preRelease=alpha --github.preRelease --npm.tag=next
|
|
65
|
+
env:
|
|
66
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
67
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
68
|
+
if: ${{ github.event.inputs.preRelease == 'yes' }}
|
|
@@ -1,45 +1,50 @@
|
|
|
1
1
|
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
2
2
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
3
3
|
|
|
4
|
-
name:
|
|
4
|
+
name: Test
|
|
5
5
|
|
|
6
6
|
on:
|
|
7
7
|
push:
|
|
8
|
-
branches: [
|
|
8
|
+
branches: [main]
|
|
9
9
|
pull_request:
|
|
10
|
-
branches: [
|
|
10
|
+
branches: [main]
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read # to fetch code (actions/checkout)
|
|
11
14
|
|
|
12
15
|
jobs:
|
|
13
16
|
build:
|
|
14
17
|
runs-on: ubuntu-latest
|
|
15
18
|
strategy:
|
|
16
19
|
matrix:
|
|
17
|
-
node-version: [
|
|
18
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
20
|
+
node-version: [16.x, 18.x]
|
|
19
21
|
steps:
|
|
20
|
-
- uses: actions/checkout@
|
|
22
|
+
- uses: actions/checkout@v3
|
|
21
23
|
- name: Use Node.js ${{ matrix.node-version }}
|
|
22
|
-
uses: actions/setup-node@
|
|
24
|
+
uses: actions/setup-node@v3
|
|
23
25
|
with:
|
|
24
26
|
node-version: ${{ matrix.node-version }}
|
|
25
|
-
- run: npm
|
|
26
|
-
- run: npm
|
|
27
|
+
- run: npm i -g npm@latest
|
|
28
|
+
- run: npm ci --ignore-scripts
|
|
27
29
|
- run: npm run build --if-present
|
|
28
|
-
- run: npm
|
|
29
|
-
|
|
30
|
+
- run: npm test
|
|
31
|
+
env:
|
|
32
|
+
CI: true
|
|
33
|
+
|
|
30
34
|
build-windows:
|
|
31
35
|
runs-on: windows-latest
|
|
32
36
|
strategy:
|
|
33
37
|
matrix:
|
|
34
|
-
node-version: [
|
|
35
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
38
|
+
node-version: [16.x]
|
|
36
39
|
steps:
|
|
37
|
-
- uses: actions/checkout@
|
|
40
|
+
- uses: actions/checkout@v3
|
|
38
41
|
- name: Use Node.js ${{ matrix.node-version }}
|
|
39
|
-
uses: actions/setup-node@
|
|
42
|
+
uses: actions/setup-node@v3
|
|
40
43
|
with:
|
|
41
44
|
node-version: ${{ matrix.node-version }}
|
|
42
|
-
- run: npm
|
|
43
|
-
- run: npm
|
|
45
|
+
- run: npm i -g npm@latest
|
|
46
|
+
- run: npm ci --ignore-scripts
|
|
44
47
|
- run: npm run build --if-present
|
|
45
|
-
- run: npm
|
|
48
|
+
- run: npm test
|
|
49
|
+
env:
|
|
50
|
+
CI: true
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# this workflow merges requests from Dependabot if tests are passing
|
|
2
|
+
name: Merge me!
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
workflow_run:
|
|
6
|
+
workflows:
|
|
7
|
+
- Test
|
|
8
|
+
types:
|
|
9
|
+
- completed
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
merge-me:
|
|
13
|
+
name: Merge me!
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Merge me!
|
|
17
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
18
|
+
uses: ridedott/merge-me-action@v2
|
|
19
|
+
with:
|
|
20
|
+
# Depending on branch prodtection rules, a manually populated
|
|
21
|
+
# `GITHUB_TOKEN_WORKAROUND` secret with permissions to push to
|
|
22
|
+
# a protected branch must be used.
|
|
23
|
+
#
|
|
24
|
+
# When using a custom token, it is recommended to leave the following
|
|
25
|
+
# comment for other developers to be aware of the reasoning behind it:
|
|
26
|
+
#
|
|
27
|
+
# This must be used as GitHub Actions token does not support pushing
|
|
28
|
+
# to protected branches.
|
|
29
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
+
PRESET: DEPENDABOT_MINOR
|
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v18.12.1
|
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
WebdriverIO Re-run Service
|
|
2
2
|
==========================
|
|
3
3
|
|
|
4
|
-
[](https://github.com/webdriverio-community/wdio-rerun-service/actions/workflows/test.yml)
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|

|
|
8
8
|
|
|
9
9
|
This service tracks failing Mocha or Jasmine tests and Cucumber scenarios executed within the [WebdriverIO](https://webdriver.io) test framework. It will allow failing or unstable tests or scenarios to be re-run.
|
|
10
10
|
|
|
11
|
-
_NOTE_:
|
|
11
|
+
_NOTE_: Users running WebdriverIO versions `5.x.x` and `6.x.x` should use version `1.6.x`. If you are on `7.x.x`, use version `1.7.x` version of this service. If you are on the latest major version of `8.x.x`, use the latest `2.x.x` version of this service.
|
|
12
12
|
|
|
13
13
|
## Re-run vs. Retry
|
|
14
14
|
|
|
@@ -27,28 +27,24 @@ It is recommended to take some time to evaluate the options available. A hybrid
|
|
|
27
27
|
|
|
28
28
|
## Installation
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Using `npm`:
|
|
31
31
|
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"wdio-rerun-service": "^1.7.6"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
32
|
+
```bash
|
|
33
|
+
npm install wdio-rerun-service
|
|
38
34
|
```
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
or using `yarn`:
|
|
41
37
|
|
|
42
38
|
```bash
|
|
43
|
-
|
|
39
|
+
yarn add wdio-rerun-service
|
|
44
40
|
```
|
|
45
41
|
|
|
46
42
|
After package installation is complete, add it to `services` array in `wdio.conf.js`:
|
|
47
43
|
|
|
48
44
|
```js
|
|
49
45
|
// wdio.conf.js
|
|
50
|
-
|
|
51
|
-
export
|
|
46
|
+
import RerunService from 'wdio-rerun-service';
|
|
47
|
+
export const config = {
|
|
52
48
|
// ...
|
|
53
49
|
services: [RerunService, {
|
|
54
50
|
// ...
|
|
@@ -64,8 +60,8 @@ The following options may be added to the wdio.conf.js file. To define options f
|
|
|
64
60
|
|
|
65
61
|
```js
|
|
66
62
|
// wdio.conf.js
|
|
67
|
-
|
|
68
|
-
export
|
|
63
|
+
import RerunService from 'wdio-rerun-service';
|
|
64
|
+
export const config = {
|
|
69
65
|
// ...
|
|
70
66
|
services: [
|
|
71
67
|
[RerunService, {
|
|
@@ -85,8 +81,8 @@ Default: `./results/rerun`
|
|
|
85
81
|
|
|
86
82
|
Example:
|
|
87
83
|
```js
|
|
88
|
-
|
|
89
|
-
export
|
|
84
|
+
import RerunService from 'wdio-rerun-service';
|
|
85
|
+
export const config = {
|
|
90
86
|
// ...
|
|
91
87
|
services: [
|
|
92
88
|
[RerunService, {
|
|
@@ -106,8 +102,8 @@ Default: `./rerun.sh`
|
|
|
106
102
|
|
|
107
103
|
Example:
|
|
108
104
|
```js
|
|
109
|
-
|
|
110
|
-
export
|
|
105
|
+
import RerunService from 'wdio-rerun-service';
|
|
106
|
+
export const config = {
|
|
111
107
|
// ...
|
|
112
108
|
services: [
|
|
113
109
|
[RerunService, {
|
|
@@ -127,8 +123,8 @@ Default: `[]`
|
|
|
127
123
|
|
|
128
124
|
Example:
|
|
129
125
|
```js
|
|
130
|
-
|
|
131
|
-
export
|
|
126
|
+
import RerunService from 'wdio-rerun-service';
|
|
127
|
+
export const config = {
|
|
132
128
|
// ...
|
|
133
129
|
services: [
|
|
134
130
|
[RerunService, {
|
|
@@ -148,8 +144,8 @@ Default: `''`
|
|
|
148
144
|
|
|
149
145
|
Example:
|
|
150
146
|
```js
|
|
151
|
-
|
|
152
|
-
export
|
|
147
|
+
import RerunService from 'wdio-rerun-service';
|
|
148
|
+
export const config = {
|
|
153
149
|
// ...
|
|
154
150
|
services: [
|
|
155
151
|
[RerunService, {
|
|
@@ -170,8 +166,8 @@ Default: `''`
|
|
|
170
166
|
|
|
171
167
|
Example:
|
|
172
168
|
```js
|
|
173
|
-
|
|
174
|
-
export
|
|
169
|
+
import RerunService from 'wdio-rerun-service';
|
|
170
|
+
export const config = {
|
|
175
171
|
// ...
|
|
176
172
|
services: [
|
|
177
173
|
[RerunService, {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Capabilities, Frameworks, Services } from '@wdio/types';
|
|
2
|
+
type AfterScenario = NonNullable<WebdriverIO.HookFunctionExtension['afterScenario']>;
|
|
3
|
+
type AfterScenarioParameters = Parameters<AfterScenario>;
|
|
4
|
+
type World = AfterScenarioParameters[0];
|
|
5
|
+
interface NonPassingItem {
|
|
6
|
+
location: string;
|
|
7
|
+
failure?: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface RerunServiceOptions {
|
|
10
|
+
ignoredTags?: string[];
|
|
11
|
+
rerunDataDir?: string;
|
|
12
|
+
rerunScriptPath?: string;
|
|
13
|
+
commandPrefix?: string;
|
|
14
|
+
customParameters?: string;
|
|
15
|
+
}
|
|
16
|
+
export default class RerunService implements Services.ServiceInstance {
|
|
17
|
+
nonPassingItems: NonPassingItem[];
|
|
18
|
+
serviceWorkerId: string;
|
|
19
|
+
ignoredTags: string[];
|
|
20
|
+
rerunDataDir: string;
|
|
21
|
+
rerunScriptPath: string;
|
|
22
|
+
commandPrefix: string;
|
|
23
|
+
customParameters: string;
|
|
24
|
+
specFile: string;
|
|
25
|
+
disabled: boolean;
|
|
26
|
+
constructor(options?: RerunServiceOptions);
|
|
27
|
+
before(_capabilities: Capabilities.RemoteCapability, specs: string[]): Promise<void>;
|
|
28
|
+
afterTest(_test: Frameworks.Test, _context: any, results: Frameworks.TestResult): void;
|
|
29
|
+
afterScenario(world: World): void;
|
|
30
|
+
after(): Promise<void>;
|
|
31
|
+
onComplete(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
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
|
+
const minimist_1 = __importDefault(require("minimist"));
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const node_process_1 = require("node:process");
|
|
10
|
+
const uuid_1 = require("uuid");
|
|
11
|
+
class RerunService {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
const { ignoredTags, rerunDataDir, rerunScriptPath, commandPrefix, customParameters, } = options;
|
|
14
|
+
this.nonPassingItems = [];
|
|
15
|
+
this.serviceWorkerId = '';
|
|
16
|
+
this.ignoredTags = ignoredTags ?? [];
|
|
17
|
+
this.rerunDataDir = rerunDataDir ?? './results/rerun';
|
|
18
|
+
this.rerunScriptPath =
|
|
19
|
+
rerunScriptPath ?? (node_process_1.platform === 'win32' ? 'rerun.bat' : 'rerun.sh');
|
|
20
|
+
this.commandPrefix = commandPrefix ?? '';
|
|
21
|
+
this.customParameters = customParameters ?? '';
|
|
22
|
+
this.specFile = '';
|
|
23
|
+
this.disabled = node_process_1.env['DISABLE_RERUN'] === 'true';
|
|
24
|
+
}
|
|
25
|
+
async before(_capabilities, specs) {
|
|
26
|
+
if (this.disabled) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.specFile = specs[0] ?? '';
|
|
30
|
+
// console.log(`Re-run service is activated. Data directory: ${this.rerunDataDir}`);
|
|
31
|
+
await (0, promises_1.mkdir)(this.rerunDataDir, { recursive: true });
|
|
32
|
+
this.serviceWorkerId = (0, uuid_1.v5)(String(Date.now()), uuid_1.v5.DNS);
|
|
33
|
+
}
|
|
34
|
+
afterTest(_test, _context, results) {
|
|
35
|
+
if (this.disabled) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const { passed } = results;
|
|
39
|
+
const config = browser.config;
|
|
40
|
+
if (passed || config.framework === 'cucumber') {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// console.log(`Re-run service is inspecting non-passing test.`);
|
|
44
|
+
// console.log(`Test location: ${this.specFile}`);
|
|
45
|
+
const error = results.error;
|
|
46
|
+
if (error?.message) {
|
|
47
|
+
this.nonPassingItems.push({
|
|
48
|
+
location: this.specFile,
|
|
49
|
+
failure: error.message,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// console.log("The non-passing test did not contain any error message, it could not be added for re-run.")
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Executed after a Cucumber scenario ends.
|
|
57
|
+
afterScenario(world) {
|
|
58
|
+
if (this.disabled) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const config = browser.config;
|
|
62
|
+
const status = world.result?.status;
|
|
63
|
+
if (config.framework !== 'cucumber' ||
|
|
64
|
+
status === 'PASSED' ||
|
|
65
|
+
status === 'SKIPPED') {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const scenarioLineNumber = world.gherkinDocument.feature?.children.filter((child) => child.scenario
|
|
69
|
+
? world.pickle.astNodeIds.includes(child.scenario.id.toString())
|
|
70
|
+
: false)?.[0]?.scenario?.location.line ?? 0;
|
|
71
|
+
const scenarioLocation = `${world.pickle.uri}:${scenarioLineNumber}`;
|
|
72
|
+
const tagsList = world.pickle.tags.map((tag) => tag.name);
|
|
73
|
+
if (!Array.isArray(this.ignoredTags) ||
|
|
74
|
+
!tagsList.some((ignoredTag) => this.ignoredTags.includes(ignoredTag))) {
|
|
75
|
+
this.nonPassingItems.push({
|
|
76
|
+
location: scenarioLocation,
|
|
77
|
+
failure: world.result?.message,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async after() {
|
|
82
|
+
if (this.disabled) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (this.nonPassingItems.length === 0) {
|
|
86
|
+
return; // console.log('Re-run service did not detect any non-passing scenarios or tests.');
|
|
87
|
+
}
|
|
88
|
+
await (0, promises_1.writeFile)((0, node_path_1.join)(this.rerunDataDir, `rerun-${this.serviceWorkerId}.json`), JSON.stringify(this.nonPassingItems));
|
|
89
|
+
}
|
|
90
|
+
async onComplete() {
|
|
91
|
+
if (this.disabled) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const files = await (0, promises_1.readdir)(this.rerunDataDir);
|
|
96
|
+
const rerunFiles = files.filter((file) => file.endsWith('.json'));
|
|
97
|
+
if (rerunFiles.length === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const parsedArgs = (0, minimist_1.default)(node_process_1.argv.slice(2));
|
|
101
|
+
const args = parsedArgs._[0] ? parsedArgs._[0] + ' ' : '';
|
|
102
|
+
const prefix = this.commandPrefix ? this.commandPrefix + ' ' : '';
|
|
103
|
+
const disableRerun = node_process_1.platform === 'win32'
|
|
104
|
+
? 'set DISABLE_RERUN=true &&'
|
|
105
|
+
: 'DISABLE_RERUN=true';
|
|
106
|
+
let rerunCommand = `${prefix}${disableRerun} npx wdio ${args}${this.customParameters}`;
|
|
107
|
+
const failureLocations = new Set();
|
|
108
|
+
for (const file of rerunFiles) {
|
|
109
|
+
const json = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(this.rerunDataDir, file), 'utf8'));
|
|
110
|
+
json.forEach((failure) => {
|
|
111
|
+
failureLocations.add(failure.location.replace(/\\/g, '/'));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
failureLocations.forEach((failureLocation) => {
|
|
115
|
+
rerunCommand += ` --spec=${failureLocation}`;
|
|
116
|
+
});
|
|
117
|
+
await (0, promises_1.writeFile)(this.rerunScriptPath, rerunCommand, { mode: 0o755 });
|
|
118
|
+
// console.log(`Re-run script has been generated @ ${this.rerunScriptPath}`);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
// console.log(`Re-run service failed to generate re-run script: ${err}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.default = RerunService;
|
|
126
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Capabilities, Frameworks, Services } from '@wdio/types';
|
|
2
|
+
type AfterScenario = NonNullable<WebdriverIO.HookFunctionExtension['afterScenario']>;
|
|
3
|
+
type AfterScenarioParameters = Parameters<AfterScenario>;
|
|
4
|
+
type World = AfterScenarioParameters[0];
|
|
5
|
+
interface NonPassingItem {
|
|
6
|
+
location: string;
|
|
7
|
+
failure?: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface RerunServiceOptions {
|
|
10
|
+
ignoredTags?: string[];
|
|
11
|
+
rerunDataDir?: string;
|
|
12
|
+
rerunScriptPath?: string;
|
|
13
|
+
commandPrefix?: string;
|
|
14
|
+
customParameters?: string;
|
|
15
|
+
}
|
|
16
|
+
export default class RerunService implements Services.ServiceInstance {
|
|
17
|
+
nonPassingItems: NonPassingItem[];
|
|
18
|
+
serviceWorkerId: string;
|
|
19
|
+
ignoredTags: string[];
|
|
20
|
+
rerunDataDir: string;
|
|
21
|
+
rerunScriptPath: string;
|
|
22
|
+
commandPrefix: string;
|
|
23
|
+
customParameters: string;
|
|
24
|
+
specFile: string;
|
|
25
|
+
disabled: boolean;
|
|
26
|
+
constructor(options?: RerunServiceOptions);
|
|
27
|
+
before(_capabilities: Capabilities.RemoteCapability, specs: string[]): Promise<void>;
|
|
28
|
+
afterTest(_test: Frameworks.Test, _context: any, results: Frameworks.TestResult): void;
|
|
29
|
+
afterScenario(world: World): void;
|
|
30
|
+
after(): Promise<void>;
|
|
31
|
+
onComplete(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import minimist from 'minimist';
|
|
2
|
+
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { argv, env, platform } from 'node:process';
|
|
5
|
+
import { v5 as uuidv5 } from 'uuid';
|
|
6
|
+
export default class RerunService {
|
|
7
|
+
nonPassingItems;
|
|
8
|
+
serviceWorkerId;
|
|
9
|
+
ignoredTags;
|
|
10
|
+
rerunDataDir;
|
|
11
|
+
rerunScriptPath;
|
|
12
|
+
commandPrefix;
|
|
13
|
+
customParameters;
|
|
14
|
+
specFile;
|
|
15
|
+
disabled;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
const { ignoredTags, rerunDataDir, rerunScriptPath, commandPrefix, customParameters, } = options;
|
|
18
|
+
this.nonPassingItems = [];
|
|
19
|
+
this.serviceWorkerId = '';
|
|
20
|
+
this.ignoredTags = ignoredTags ?? [];
|
|
21
|
+
this.rerunDataDir = rerunDataDir ?? './results/rerun';
|
|
22
|
+
this.rerunScriptPath =
|
|
23
|
+
rerunScriptPath ?? (platform === 'win32' ? 'rerun.bat' : 'rerun.sh');
|
|
24
|
+
this.commandPrefix = commandPrefix ?? '';
|
|
25
|
+
this.customParameters = customParameters ?? '';
|
|
26
|
+
this.specFile = '';
|
|
27
|
+
this.disabled = env['DISABLE_RERUN'] === 'true';
|
|
28
|
+
}
|
|
29
|
+
async before(_capabilities, specs) {
|
|
30
|
+
if (this.disabled) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.specFile = specs[0] ?? '';
|
|
34
|
+
// console.log(`Re-run service is activated. Data directory: ${this.rerunDataDir}`);
|
|
35
|
+
await mkdir(this.rerunDataDir, { recursive: true });
|
|
36
|
+
this.serviceWorkerId = uuidv5(String(Date.now()), uuidv5.DNS);
|
|
37
|
+
}
|
|
38
|
+
afterTest(_test, _context, results) {
|
|
39
|
+
if (this.disabled) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const { passed } = results;
|
|
43
|
+
const config = browser.config;
|
|
44
|
+
if (passed || config.framework === 'cucumber') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// console.log(`Re-run service is inspecting non-passing test.`);
|
|
48
|
+
// console.log(`Test location: ${this.specFile}`);
|
|
49
|
+
const error = results.error;
|
|
50
|
+
if (error?.message) {
|
|
51
|
+
this.nonPassingItems.push({
|
|
52
|
+
location: this.specFile,
|
|
53
|
+
failure: error.message,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// console.log("The non-passing test did not contain any error message, it could not be added for re-run.")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Executed after a Cucumber scenario ends.
|
|
61
|
+
afterScenario(world) {
|
|
62
|
+
if (this.disabled) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const config = browser.config;
|
|
66
|
+
const status = world.result?.status;
|
|
67
|
+
if (config.framework !== 'cucumber' ||
|
|
68
|
+
status === 'PASSED' ||
|
|
69
|
+
status === 'SKIPPED') {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const scenarioLineNumber = world.gherkinDocument.feature?.children.filter((child) => child.scenario
|
|
73
|
+
? world.pickle.astNodeIds.includes(child.scenario.id.toString())
|
|
74
|
+
: false)?.[0]?.scenario?.location.line ?? 0;
|
|
75
|
+
const scenarioLocation = `${world.pickle.uri}:${scenarioLineNumber}`;
|
|
76
|
+
const tagsList = world.pickle.tags.map((tag) => tag.name);
|
|
77
|
+
if (!Array.isArray(this.ignoredTags) ||
|
|
78
|
+
!tagsList.some((ignoredTag) => this.ignoredTags.includes(ignoredTag))) {
|
|
79
|
+
this.nonPassingItems.push({
|
|
80
|
+
location: scenarioLocation,
|
|
81
|
+
failure: world.result?.message,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async after() {
|
|
86
|
+
if (this.disabled) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (this.nonPassingItems.length === 0) {
|
|
90
|
+
return; // console.log('Re-run service did not detect any non-passing scenarios or tests.');
|
|
91
|
+
}
|
|
92
|
+
await writeFile(join(this.rerunDataDir, `rerun-${this.serviceWorkerId}.json`), JSON.stringify(this.nonPassingItems));
|
|
93
|
+
}
|
|
94
|
+
async onComplete() {
|
|
95
|
+
if (this.disabled) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const files = await readdir(this.rerunDataDir);
|
|
100
|
+
const rerunFiles = files.filter((file) => file.endsWith('.json'));
|
|
101
|
+
if (rerunFiles.length === 0) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const parsedArgs = minimist(argv.slice(2));
|
|
105
|
+
const args = parsedArgs._[0] ? parsedArgs._[0] + ' ' : '';
|
|
106
|
+
const prefix = this.commandPrefix ? this.commandPrefix + ' ' : '';
|
|
107
|
+
const disableRerun = platform === 'win32'
|
|
108
|
+
? 'set DISABLE_RERUN=true &&'
|
|
109
|
+
: 'DISABLE_RERUN=true';
|
|
110
|
+
let rerunCommand = `${prefix}${disableRerun} npx wdio ${args}${this.customParameters}`;
|
|
111
|
+
const failureLocations = new Set();
|
|
112
|
+
for (const file of rerunFiles) {
|
|
113
|
+
const json = JSON.parse(await readFile(join(this.rerunDataDir, file), 'utf8'));
|
|
114
|
+
json.forEach((failure) => {
|
|
115
|
+
failureLocations.add(failure.location.replace(/\\/g, '/'));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
failureLocations.forEach((failureLocation) => {
|
|
119
|
+
rerunCommand += ` --spec=${failureLocation}`;
|
|
120
|
+
});
|
|
121
|
+
await writeFile(this.rerunScriptPath, rerunCommand, { mode: 0o755 });
|
|
122
|
+
// console.log(`Re-run script has been generated @ ${this.rerunScriptPath}`);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
// console.log(`Re-run service failed to generate re-run script: ${err}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,26 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wdio-rerun-service",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A WebdriverIO service to track and prepare for re-running failing or flaky Jasmine/Mocha tests or Cucumber Scenarios.",
|
|
5
5
|
"author": "Mike Salvia <msalvia@jwplayer.com>",
|
|
6
6
|
"homepage": "https://github.com/webdriverio-community/wdio-rerun-service",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./build/cjs/index.js",
|
|
13
|
+
"types": "./build/cjs/index.d.ts",
|
|
14
|
+
"module": "./build/esm/index.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./build/esm/index.d.ts",
|
|
19
|
+
"default": "./build/esm/index.js"
|
|
20
|
+
},
|
|
21
|
+
"require": {
|
|
22
|
+
"types": "./build/cjs/index.d.ts",
|
|
23
|
+
"default": "./build/cjs/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
9
27
|
"engines": {
|
|
10
|
-
"node": ">=
|
|
28
|
+
"node": ">=16.0.0"
|
|
11
29
|
},
|
|
12
30
|
"scripts": {
|
|
13
31
|
"build": "run-s clean compile",
|
|
14
32
|
"clean": "rimraf ./build",
|
|
15
|
-
"compile": "
|
|
16
|
-
"
|
|
33
|
+
"compile": "run-s compile:esm compile:cjs generate:cjs:package",
|
|
34
|
+
"compile:cjs": "tsc -p tsconfig.cjs.json",
|
|
35
|
+
"compile:esm": "tsc -p tsconfig.esm.json",
|
|
36
|
+
"generate:cjs:package": "shx echo \"{\\\"type\\\":\\\"commonjs\\\"}\" > ./build/cjs/package.json",
|
|
37
|
+
"prepare": "npm run build",
|
|
17
38
|
"test": "run-s test:*",
|
|
18
|
-
"test:clean": "rimraf ./results ./coverage rerun.sh",
|
|
39
|
+
"test:clean": "rimraf ./results ./coverage rerun.sh rerun.bat",
|
|
19
40
|
"test:eslint": "eslint src tests",
|
|
20
|
-
"test:
|
|
41
|
+
"test:tsc": "tsc -p tsconfig.json --noEmit",
|
|
42
|
+
"test:unit": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
|
|
43
|
+
"watch": "npm-watch"
|
|
21
44
|
},
|
|
22
45
|
"watch": {
|
|
23
|
-
"build": "{src,tests}/*.
|
|
46
|
+
"build": "{src,tests}/*.ts"
|
|
24
47
|
},
|
|
25
48
|
"repository": {
|
|
26
49
|
"type": "git",
|
|
@@ -50,36 +73,45 @@
|
|
|
50
73
|
"url": "https://github.com/webdriverio-community/wdio-rerun-service/issues"
|
|
51
74
|
},
|
|
52
75
|
"dependencies": {
|
|
53
|
-
"@wdio/
|
|
54
|
-
"minimist": "1.2.
|
|
55
|
-
"
|
|
56
|
-
"uuid": "8.3.2"
|
|
57
|
-
},
|
|
58
|
-
"peerDependencies": {},
|
|
59
|
-
"publishConfig": {
|
|
60
|
-
"access": "public"
|
|
76
|
+
"@wdio/types": "^8.0.11",
|
|
77
|
+
"minimist": "^1.2.7",
|
|
78
|
+
"uuid": "^9.0.0"
|
|
61
79
|
},
|
|
62
80
|
"devDependencies": {
|
|
63
|
-
"@
|
|
64
|
-
"@
|
|
65
|
-
"@
|
|
66
|
-
"@
|
|
67
|
-
"@
|
|
68
|
-
"@
|
|
69
|
-
"@
|
|
70
|
-
"@
|
|
71
|
-
"@
|
|
72
|
-
"@
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"babel-plugin-source-map-support": "2.1.3",
|
|
79
|
-
"eslint": "8.13.0",
|
|
80
|
-
"jest": "27.5.1",
|
|
81
|
+
"@jest/globals": "^29.3.1",
|
|
82
|
+
"@tsconfig/node16": "^1.0.3",
|
|
83
|
+
"@tsconfig/node18-strictest-esm": "^1.0.1",
|
|
84
|
+
"@types/minimist": "^1.2.2",
|
|
85
|
+
"@types/node": "^18.11.16",
|
|
86
|
+
"@types/uuid": "^9.0.0",
|
|
87
|
+
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
|
88
|
+
"@typescript-eslint/parser": "^5.46.1",
|
|
89
|
+
"@wdio/cucumber-framework": "^8.0.13",
|
|
90
|
+
"@wdio/globals": "^8.0.13",
|
|
91
|
+
"cross-env": "^7.0.3",
|
|
92
|
+
"eslint": "^8.30.0",
|
|
93
|
+
"eslint-config-prettier": "^8.5.0",
|
|
94
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
95
|
+
"jest": "^29.3.1",
|
|
81
96
|
"npm-run-all": "4.1.5",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
97
|
+
"npm-watch": "0.11.0",
|
|
98
|
+
"prettier": "^2.8.1",
|
|
99
|
+
"prettier-plugin-organize-imports": "^3.2.1",
|
|
100
|
+
"release-it": "^15.5.1",
|
|
101
|
+
"rimraf": "^3.0.2",
|
|
102
|
+
"shx": "^0.3.4",
|
|
103
|
+
"ts-jest": "^29.0.3",
|
|
104
|
+
"ts-node": "^10.9.1",
|
|
105
|
+
"typescript": "^4.9.4"
|
|
106
|
+
},
|
|
107
|
+
"jest": {
|
|
108
|
+
"preset": "ts-jest/presets/default-esm",
|
|
109
|
+
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
|
|
110
|
+
"moduleNameMapper": {
|
|
111
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
112
|
+
},
|
|
113
|
+
"collectCoverageFrom": [
|
|
114
|
+
"src/index.ts"
|
|
115
|
+
]
|
|
84
116
|
}
|
|
85
117
|
}
|
package/.eslintrc.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es2021": true
|
|
5
|
-
},
|
|
6
|
-
"parser": "@typescript-eslint/parser",
|
|
7
|
-
"parserOptions": {
|
|
8
|
-
"ecmaVersion": 12,
|
|
9
|
-
"sourceType": "module"
|
|
10
|
-
},
|
|
11
|
-
"plugins": [
|
|
12
|
-
"@typescript-eslint"
|
|
13
|
-
],
|
|
14
|
-
"rules": {
|
|
15
|
-
}
|
|
16
|
-
};
|
package/babel.config.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
presets: [
|
|
3
|
-
[
|
|
4
|
-
'@babel/preset-env',
|
|
5
|
-
{targets: {node: 'current'}},
|
|
6
|
-
"@babel/preset-typescript"
|
|
7
|
-
]
|
|
8
|
-
],
|
|
9
|
-
plugins: [
|
|
10
|
-
'@babel/plugin-proposal-function-bind',
|
|
11
|
-
'@babel/plugin-proposal-class-properties',
|
|
12
|
-
'@babel/plugin-proposal-optional-catch-binding'
|
|
13
|
-
],
|
|
14
|
-
env: {
|
|
15
|
-
development: {
|
|
16
|
-
sourceMaps: 'inline',
|
|
17
|
-
plugins: ['source-map-support']
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
comments: false
|
|
21
|
-
}
|
package/build/index.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
require("source-map-support/register");
|
|
4
|
-
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
const {
|
|
10
|
-
v5: uuidv5
|
|
11
|
-
} = require('uuid');
|
|
12
|
-
|
|
13
|
-
const argv = require('minimist')(process.argv.slice(2));
|
|
14
|
-
|
|
15
|
-
class RerunService {
|
|
16
|
-
constructor({
|
|
17
|
-
ignoredTags,
|
|
18
|
-
rerunDataDir,
|
|
19
|
-
rerunScriptPath,
|
|
20
|
-
commandPrefix,
|
|
21
|
-
customParameters
|
|
22
|
-
} = {}) {
|
|
23
|
-
this.nonPassingItems = [];
|
|
24
|
-
this.serviceWorkerId;
|
|
25
|
-
this.ignoredTags = ignoredTags || [];
|
|
26
|
-
this.rerunDataDir = rerunDataDir || "./results/rerun";
|
|
27
|
-
this.rerunScriptPath = rerunScriptPath || "./rerun.sh";
|
|
28
|
-
this.commandPrefix = commandPrefix || "";
|
|
29
|
-
this.customParameters = customParameters || "";
|
|
30
|
-
this.specFile = "";
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
before(capabilities, specs) {
|
|
34
|
-
this.specFile = specs[0];
|
|
35
|
-
fs.mkdirSync(this.rerunDataDir, {
|
|
36
|
-
recursive: true
|
|
37
|
-
});
|
|
38
|
-
this.serviceWorkerId = uuidv5(`${Date.now()}`, '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
afterTest(test, context, {
|
|
42
|
-
error,
|
|
43
|
-
result,
|
|
44
|
-
duration,
|
|
45
|
-
passed,
|
|
46
|
-
retries
|
|
47
|
-
}) {
|
|
48
|
-
if (browser.config.framework !== 'cucumber' && !passed) {
|
|
49
|
-
if (error && error.message) {
|
|
50
|
-
this.nonPassingItems.push({
|
|
51
|
-
location: this.specFile,
|
|
52
|
-
failure: error.message
|
|
53
|
-
});
|
|
54
|
-
} else {}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
afterScenario(world, result, context) {
|
|
59
|
-
const CUCUMBER_STATUS_MAP = ['UNKNOWN', 'PASSED', 'SKIPPED', 'PENDING', 'UNDEFINED', 'AMBIGUOUS', 'FAILED'];
|
|
60
|
-
const status = typeof world.result.status === 'number' ? CUCUMBER_STATUS_MAP[world.result.status || 0] : world.result.status;
|
|
61
|
-
const scenarioLineNumber = world.gherkinDocument.feature.children.filter(child => {
|
|
62
|
-
if (child.scenario) {
|
|
63
|
-
return child.scenario && world.pickle.astNodeIds.includes(child.scenario.id.toString());
|
|
64
|
-
}
|
|
65
|
-
})[0].scenario.location.line;
|
|
66
|
-
|
|
67
|
-
if (browser.config.framework === 'cucumber' && status !== 'PASSED' && status !== 'SKIPPED') {
|
|
68
|
-
const scenarioLocation = `${world.pickle.uri}:${scenarioLineNumber}`;
|
|
69
|
-
const tagsList = world.pickle.tags.map(tag => tag.name);
|
|
70
|
-
const service = this;
|
|
71
|
-
|
|
72
|
-
if (this.ignoredTags && !tagsList.some(ignoredTag => service.ignoredTags.includes(ignoredTag))) {
|
|
73
|
-
this.nonPassingItems.push({
|
|
74
|
-
location: scenarioLocation,
|
|
75
|
-
failure: world.result.message
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
after(result, capabilities, specs) {
|
|
82
|
-
if (this.nonPassingItems.length > 0) {
|
|
83
|
-
fs.writeFileSync(`${this.rerunDataDir}/rerun-${this.serviceWorkerId}.json`, JSON.stringify(this.nonPassingItems));
|
|
84
|
-
} else {}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
onComplete(exitCode, config, capabilities, results) {
|
|
88
|
-
const directoryPath = path.join(process.cwd(), `${this.rerunDataDir}`);
|
|
89
|
-
|
|
90
|
-
if (fs.existsSync(directoryPath)) {
|
|
91
|
-
const rerunFiles = fs.readdirSync(directoryPath);
|
|
92
|
-
|
|
93
|
-
if (rerunFiles.length > 0) {
|
|
94
|
-
let rerunCommand = `${this.commandPrefix} DISABLE_RERUN=true node_modules/.bin/wdio ${argv._[0]} ${this.customParameters} `;
|
|
95
|
-
let failureLocations = [];
|
|
96
|
-
rerunFiles.forEach(file => {
|
|
97
|
-
const json = JSON.parse(fs.readFileSync(`${this.rerunDataDir}/${file}`));
|
|
98
|
-
json.forEach(failure => {
|
|
99
|
-
failureLocations.push(failure.location.replace(/\\/g, "/"));
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
const failureLocationsUnique = [...new Set(failureLocations)];
|
|
103
|
-
failureLocationsUnique.forEach(failureLocation => {
|
|
104
|
-
rerunCommand += ` --spec=${failureLocation}`;
|
|
105
|
-
});
|
|
106
|
-
fs.writeFileSync(this.rerunScriptPath, rerunCommand);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
;
|
|
114
|
-
module.exports = RerunService;
|
|
115
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC5qcyJdLCJuYW1lcyI6WyJmcyIsInJlcXVpcmUiLCJwYXRoIiwidjUiLCJ1dWlkdjUiLCJhcmd2IiwicHJvY2VzcyIsInNsaWNlIiwiUmVydW5TZXJ2aWNlIiwiY29uc3RydWN0b3IiLCJpZ25vcmVkVGFncyIsInJlcnVuRGF0YURpciIsInJlcnVuU2NyaXB0UGF0aCIsImNvbW1hbmRQcmVmaXgiLCJjdXN0b21QYXJhbWV0ZXJzIiwibm9uUGFzc2luZ0l0ZW1zIiwic2VydmljZVdvcmtlcklkIiwic3BlY0ZpbGUiLCJiZWZvcmUiLCJjYXBhYmlsaXRpZXMiLCJzcGVjcyIsIm1rZGlyU3luYyIsInJlY3Vyc2l2ZSIsIkRhdGUiLCJub3ciLCJhZnRlclRlc3QiLCJ0ZXN0IiwiY29udGV4dCIsImVycm9yIiwicmVzdWx0IiwiZHVyYXRpb24iLCJwYXNzZWQiLCJyZXRyaWVzIiwiYnJvd3NlciIsImNvbmZpZyIsImZyYW1ld29yayIsIm1lc3NhZ2UiLCJwdXNoIiwibG9jYXRpb24iLCJmYWlsdXJlIiwiYWZ0ZXJTY2VuYXJpbyIsIndvcmxkIiwiQ1VDVU1CRVJfU1RBVFVTX01BUCIsInN0YXR1cyIsInNjZW5hcmlvTGluZU51bWJlciIsImdoZXJraW5Eb2N1bWVudCIsImZlYXR1cmUiLCJjaGlsZHJlbiIsImZpbHRlciIsImNoaWxkIiwic2NlbmFyaW8iLCJwaWNrbGUiLCJhc3ROb2RlSWRzIiwiaW5jbHVkZXMiLCJpZCIsInRvU3RyaW5nIiwibGluZSIsInNjZW5hcmlvTG9jYXRpb24iLCJ1cmkiLCJ0YWdzTGlzdCIsInRhZ3MiLCJtYXAiLCJ0YWciLCJuYW1lIiwic2VydmljZSIsInNvbWUiLCJpZ25vcmVkVGFnIiwiYWZ0ZXIiLCJsZW5ndGgiLCJ3cml0ZUZpbGVTeW5jIiwiSlNPTiIsInN0cmluZ2lmeSIsIm9uQ29tcGxldGUiLCJleGl0Q29kZSIsInJlc3VsdHMiLCJkaXJlY3RvcnlQYXRoIiwiam9pbiIsImN3ZCIsImV4aXN0c1N5bmMiLCJyZXJ1bkZpbGVzIiwicmVhZGRpclN5bmMiLCJyZXJ1bkNvbW1hbmQiLCJfIiwiZmFpbHVyZUxvY2F0aW9ucyIsImZvckVhY2giLCJmaWxlIiwianNvbiIsInBhcnNlIiwicmVhZEZpbGVTeW5jIiwicmVwbGFjZSIsImZhaWx1cmVMb2NhdGlvbnNVbmlxdWUiLCJTZXQiLCJmYWlsdXJlTG9jYXRpb24iLCJtb2R1bGUiLCJleHBvcnRzIl0sIm1hcHBpbmdzIjoiOzs7O0FBQUEsTUFBTUEsRUFBRSxHQUFHQyxPQUFPLENBQUMsSUFBRCxDQUFsQjs7QUFDQSxNQUFNQyxJQUFJLEdBQUdELE9BQU8sQ0FBQyxNQUFELENBQXBCOztBQUNBLE1BQU07QUFBRUUsRUFBQUEsRUFBRSxFQUFFQztBQUFOLElBQWlCSCxPQUFPLENBQUMsTUFBRCxDQUE5Qjs7QUFFQSxNQUFNSSxJQUFJLEdBQUdKLE9BQU8sQ0FBQyxVQUFELENBQVAsQ0FBb0JLLE9BQU8sQ0FBQ0QsSUFBUixDQUFhRSxLQUFiLENBQW1CLENBQW5CLENBQXBCLENBQWI7O0FBRUEsTUFBTUMsWUFBTixDQUFtQjtBQUVmQyxFQUFBQSxXQUFXLENBQUM7QUFBRUMsSUFBQUEsV0FBRjtBQUFlQyxJQUFBQSxZQUFmO0FBQTZCQyxJQUFBQSxlQUE3QjtBQUE4Q0MsSUFBQUEsYUFBOUM7QUFBNkRDLElBQUFBO0FBQTdELE1BQWtGLEVBQW5GLEVBQXVGO0FBQzlGLFNBQUtDLGVBQUwsR0FBdUIsRUFBdkI7QUFDQSxTQUFLQyxlQUFMO0FBQ0EsU0FBS04sV0FBTCxHQUFtQkEsV0FBVyxJQUFJLEVBQWxDO0FBQ0EsU0FBS0MsWUFBTCxHQUFvQkEsWUFBWSxJQUFJLGlCQUFwQztBQUNBLFNBQUtDLGVBQUwsR0FBdUJBLGVBQWUsSUFBSSxZQUExQztBQUNBLFNBQUtDLGFBQUwsR0FBcUJBLGFBQWEsSUFBSSxFQUF0QztBQUNBLFNBQUtDLGdCQUFMLEdBQXdCQSxnQkFBZ0IsSUFBSSxFQUE1QztBQUNBLFNBQUtHLFFBQUwsR0FBZ0IsRUFBaEI7QUFDSDs7QUFF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QyxJQUFJLElBQUk7QUFDdkIsZ0JBQU1DLElBQUksR0FBR2hCLElBQUksQ0FBQ2lCLEtBQUwsQ0FBV3ZGLEVBQUUsQ0FBQ3dGLFlBQUgsQ0FBaUIsR0FBRSxLQUFLN0UsWUFBYSxJQUFHMEUsSUFBSyxFQUE3QyxDQUFYLENBQWI7QUFDQUMsVUFBQUEsSUFBSSxDQUFDRixPQUFMLENBQWE3QyxPQUFPLElBQUk7QUFDcEI0QyxZQUFBQSxnQkFBZ0IsQ0FBQzlDLElBQWpCLENBQXNCRSxPQUFPLENBQUNELFFBQVIsQ0FBaUJtRCxPQUFqQixDQUF5QixLQUF6QixFQUFnQyxHQUFoQyxDQUF0QjtBQUNILFdBRkQ7QUFHSCxTQUxEO0FBTUEsY0FBTUMsc0JBQXNCLEdBQUcsQ0FBQyxHQUFHLElBQUlDLEdBQUosQ0FBUVIsZ0JBQVIsQ0FBSixDQUEvQjtBQUNBTyxRQUFBQSxzQkFBc0IsQ0FBQ04sT0FBdkIsQ0FBK0JRLGVBQWUsSUFBSTtBQUM5Q1gsVUFBQUEsWUFBWSxJQUFLLFdBQVVXLGVBQWdCLEVBQTNDO0FBQ0gsU0FGRDtBQUdBNUYsUUFBQUEsRUFBRSxDQUFDcUUsYUFBSCxDQUFpQixLQUFLekQsZUFBdEIsRUFBdUNxRSxZQUF2QztBQUVIO0FBQ0o7QUFDSjs7QUFwRmM7O0FBcUZsQjtBQUVEWSxNQUFNLENBQUNDLE9BQVAsR0FBaUJ0RixZQUFqQiIsInNvdXJjZXNDb250ZW50IjpbImNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKTtcbmNvbnN0IHBhdGggPSByZXF1aXJlKCdwYXRoJyk7XG5jb25zdCB7IHY1OiB1dWlkdjUgfSA9IHJlcXVpcmUoJ3V1aWQnKTtcblxuY29uc3QgYXJndiA9IHJlcXVpcmUoJ21pbmltaXN0JykocHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTtcblxuY2xhc3MgUmVydW5TZXJ2aWNlIHtcblxuICAgIGNvbnN0cnVjdG9yKHsgaWdub3JlZFRhZ3MsIHJlcnVuRGF0YURpciwgcmVydW5TY3JpcHRQYXRoLCBjb21tYW5kUHJlZml4LCBjdXN0b21QYXJhbWV0ZXJzIH0gPSB7fSkge1xuICAgICAgICB0aGlzLm5vblBhc3NpbmdJdGVtcyA9IFtdO1xuICAgICAgICB0aGlzLnNlcnZpY2VXb3JrZXJJZDtcbiAgICAgICAgdGhpcy5pZ25vcmVkVGFncyA9IGlnbm9yZWRUYWdzIHx8IFtdO1xuICAgICAgICB0aGlzLnJlcnVuRGF0YURpciA9IHJlcnVuRGF0YURpciB8fCBcIi4vcmVzdWx0cy9yZXJ1blwiO1xuICAgICAgICB0aGlzLnJlcnVuU2NyaXB0UGF0aCA9IHJlcnVuU2NyaXB0UGF0aCB8fCBcIi4vcmVydW4uc2hcIjtcbiAgICAgICAgdGhpcy5jb21tYW5kUHJlZml4ID0gY29tbWFuZFByZWZpeCB8fCBcIlwiO1xuICAgICAgICB0aGlzLmN1c3RvbVBhcmFtZXRlcnMgPSBjdXN0b21QYXJhbWV0ZXJzIHx8IFwiXCI7XG4gICAgICAgIHRoaXMuc3BlY0ZpbGUgPSBcIlwiO1xuICAgIH1cblxuICAgIGJlZm9yZShjYXBhYmlsaXRpZXMsIHNwZWNzKSB7XG4gICAgICAgIHRoaXMuc3BlY0ZpbGUgPSBzcGVjc1swXTtcbiAgICAgICAgLy8gY29uc29sZS5sb2coYFJlLXJ1biBzZXJ2aWNlIGlzIGFjdGl2YXRlZC4gRGF0YSBkaXJlY3Rvcnk6ICR7dGhpcy5yZXJ1bkRhdGFEaXJ9YCk7XG4gICAgICAgIGZzLm1rZGlyU3luYyh0aGlzLnJlcnVuRGF0YURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIC8vIElORk86IGBuYW1lc3BhY2VgIGJlbG93IGNvcGllZCBmcm9tOiBodHRwczovL2dpdGh1Yi5jb20va2VsZWt0aXYvbm9kZS11dWlkL2Jsb2IvbWFzdGVyLy9saWIvdjM1LmpzI0w1NDoxNlxuICAgICAgICB0aGlzLnNlcnZpY2VXb3JrZXJJZCA9IHV1aWR2NShgJHtEYXRlLm5vdygpfWAsICc2YmE3YjgxMC05ZGFkLTExZDEtODBiNC0wMGMwNGZkNDMwYzgnKTtcbiAgICB9XG5cbiAgICBhZnRlclRlc3QodGVzdCwgY29udGV4dCwgeyBlcnJvciwgcmVzdWx0LCBkdXJhdGlvbiwgcGFzc2VkLCByZXRyaWVzIH0pIHtcbiAgICAgICAgaWYgKGJyb3dzZXIuY29uZmlnLmZyYW1ld29yayAhPT0gJ2N1Y3VtYmVyJyAmJiAhcGFzc2VkKSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgUmUtcnVuIHNlcnZpY2UgaXMgaW5zcGVjdGluZyBub24tcGFzc2luZyB0ZXN0LmApO1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYFRlc3QgbG9jYXRpb246ICR7dGhpcy5zcGVjRmlsZX1gKTtcbiAgICAgICAgICAgIGlmIChlcnJvciAmJiBlcnJvci5tZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5ub25QYXNzaW5nSXRlbXMucHVzaCh7IGxvY2F0aW9uOiB0aGlzLnNwZWNGaWxlLCBmYWlsdXJlOiBlcnJvci5tZXNzYWdlIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhcIlRoZSBub24tcGFzc2luZyB0ZXN0IGRpZCBub3QgY29udGFpbiBhbnkgZXJyb3IgbWVzc2FnZSwgaXQgY291bGQgbm90IGJlIGFkZGVkIGZvciByZS1ydW4uXCIpXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBFeGVjdXRlZCBhZnRlciBhIEN1Y3VtYmVyIHNjZW5hcmlvIGVuZHMuXG4gICAgYWZ0ZXJTY2VuYXJpbyh3b3JsZCwgcmVzdWx0LCBjb250ZXh0KSB7XG4gICAgICAgIGNvbnN0IENVQ1VNQkVSX1NUQVRVU19NQVAgPSBbJ1VOS05PV04nLCAnUEFTU0VEJywgJ1NLSVBQRUQnLCAnUEVORElORycsICdVTkRFRklORUQnLCAnQU1CSUdVT1VTJywgJ0ZBSUxFRCddXG4gICAgICAgIGNvbnN0IHN0YXR1cyA9IHR5cGVvZiB3b3JsZC5yZXN1bHQuc3RhdHVzID09PSAnbnVtYmVyJyA/IENVQ1VNQkVSX1NUQVRVU19NQVBbd29ybGQucmVzdWx0LnN0YXR1cyB8fCAwXSA6IHdvcmxkLnJlc3VsdC5zdGF0dXM7XG4gICAgICAgIGNvbnN0IHNjZW5hcmlvTGluZU51bWJlciA9IHdvcmxkLmdoZXJraW5Eb2N1bWVudC5mZWF0dXJlLmNoaWxkcmVuLmZpbHRlcihjaGlsZCA9PiB7XG4gICAgICAgICAgICBpZiAoY2hpbGQuc2NlbmFyaW8pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY2hpbGQuc2NlbmFyaW8gJiYgd29ybGQucGlja2xlLmFzdE5vZGVJZHMuaW5jbHVkZXMoY2hpbGQuc2NlbmFyaW8uaWQudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pWzBdLnNjZW5hcmlvLmxvY2F0aW9uLmxpbmU7XG4gICAgICAgIGlmIChicm93c2VyLmNvbmZpZy5mcmFtZXdvcmsgPT09ICdjdWN1bWJlcicgJiYgKHN0YXR1cyAhPT0gJ1BBU1NFRCcgJiYgc3RhdHVzICE9PSAnU0tJUFBFRCcpKSB7XG4gICAgICAgICAgICBjb25zdCBzY2VuYXJpb0xvY2F0aW9uID0gYCR7d29ybGQucGlja2xlLnVyaX06JHtzY2VuYXJpb0xpbmVOdW1iZXJ9YDtcbiAgICAgICAgICAgIGNvbnN0IHRhZ3NMaXN0ID0gd29ybGQucGlja2xlLnRhZ3MubWFwKHRhZyA9PiB0YWcubmFtZSk7XG4gICAgICAgICAgICBjb25zdCBzZXJ2aWNlID0gdGhpcztcbiAgICAgICAgICAgIGlmICh0aGlzLmlnbm9yZWRUYWdzICYmICF0YWdzTGlzdC5zb21lKGlnbm9yZWRUYWcgPT4gc2VydmljZS5pZ25vcmVkVGFncy5pbmNsdWRlcyhpZ25vcmVkVGFnKSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm5vblBhc3NpbmdJdGVtcy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgbG9jYXRpb246IHNjZW5hcmlvTG9jYXRpb24sXG4gICAgICAgICAgICAgICAgICAgIGZhaWx1cmU6IHdvcmxkLnJlc3VsdC5tZXNzYWdlXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhZnRlcihyZXN1bHQsIGNhcGFiaWxpdGllcywgc3BlY3MpIHtcbiAgICAgICAgaWYgKHRoaXMubm9uUGFzc2luZ0l0ZW1zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoYCR7dGhpcy5yZXJ1bkRhdGFEaXJ9L3JlcnVuLSR7dGhpcy5zZXJ2aWNlV29ya2VySWR9Lmpzb25gLCBKU09OLnN0cmluZ2lmeSh0aGlzLm5vblBhc3NpbmdJdGVtcykpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ1JlLXJ1biBzZXJ2aWNlIGRpZCBub3QgZGV0ZWN0IGFueSBub24tcGFzc2luZyBzY2VuYXJpb3Mgb3IgdGVzdHMuJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbkNvbXBsZXRlKGV4aXRDb2RlLCBjb25maWcsIGNhcGFiaWxpdGllcywgcmVzdWx0cykge1xuICAgICAgICBjb25zdCBkaXJlY3RvcnlQYXRoID0gcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksIGAke3RoaXMucmVydW5EYXRhRGlyfWApO1xuICAgICAgICBpZiAoZnMuZXhpc3RzU3luYyhkaXJlY3RvcnlQYXRoKSkge1xuICAgICAgICAgICAgY29uc3QgcmVydW5GaWxlcyA9IGZzLnJlYWRkaXJTeW5jKGRpcmVjdG9yeVBhdGgpO1xuICAgICAgICAgICAgaWYgKHJlcnVuRmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGxldCByZXJ1bkNvbW1hbmQgPSBgJHt0aGlzLmNvbW1hbmRQcmVmaXh9IERJU0FCTEVfUkVSVU49dHJ1ZSBub2RlX21vZHVsZXMvLmJpbi93ZGlvICR7YXJndi5fWzBdfSAke3RoaXMuY3VzdG9tUGFyYW1ldGVyc30gYDtcbiAgICAgICAgICAgICAgICBsZXQgZmFpbHVyZUxvY2F0aW9ucyA9IFtdO1xuICAgICAgICAgICAgICAgIHJlcnVuRmlsZXMuZm9yRWFjaChmaWxlID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QganNvbiA9IEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGAke3RoaXMucmVydW5EYXRhRGlyfS8ke2ZpbGV9YCkpO1xuICAgICAgICAgICAgICAgICAgICBqc29uLmZvckVhY2goZmFpbHVyZSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmYWlsdXJlTG9jYXRpb25zLnB1c2goZmFpbHVyZS5sb2NhdGlvbi5yZXBsYWNlKC9cXFxcL2csIFwiL1wiKSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZhaWx1cmVMb2NhdGlvbnNVbmlxdWUgPSBbLi4ubmV3IFNldChmYWlsdXJlTG9jYXRpb25zKV07XG4gICAgICAgICAgICAgICAgZmFpbHVyZUxvY2F0aW9uc1VuaXF1ZS5mb3JFYWNoKGZhaWx1cmVMb2NhdGlvbiA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJlcnVuQ29tbWFuZCArPSBgIC0tc3BlYz0ke2ZhaWx1cmVMb2NhdGlvbn1gO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmModGhpcy5yZXJ1blNjcmlwdFBhdGgsIHJlcnVuQ29tbWFuZCk7XG4gICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYFJlLXJ1biBzY3JpcHQgaGFzIGJlZW4gZ2VuZXJhdGVkIEAgJHt0aGlzLnJlcnVuU2NyaXB0UGF0aH1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVydW5TZXJ2aWNlO1xuIl19
|
package/rerun.sh
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
CUSTOM_VAR=true DISABLE_RERUN=true node_modules/.bin/wdio undefined --spec=feature/sample.feature:1 --spec=feature/sample.feature:4
|