creevey 0.9.0-beta.2 → 0.9.0-beta.20
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/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +1 -0
- package/CHANGELOG.md +51 -0
- package/README.md +9 -1
- package/addon/README.md +3 -0
- package/addon/package.json +5 -0
- package/docs/config.md +29 -26
- package/jest.config.js +6 -0
- package/lib/cjs/cli.js +1 -0
- package/lib/cjs/client/addon/Manager.js +170 -390
- package/lib/cjs/client/addon/components/Addon.js +17 -45
- package/lib/cjs/client/addon/components/Icons.js +12 -14
- package/lib/cjs/client/addon/components/Panel.js +21 -30
- package/lib/cjs/client/addon/components/TestSelect.js +20 -31
- package/lib/cjs/client/addon/components/Tools.js +35 -65
- package/lib/cjs/client/addon/decorator.js +1 -4
- package/lib/cjs/client/addon/index.js +27 -0
- package/lib/cjs/client/addon/preset.js +3 -76
- package/lib/cjs/client/addon/preview.js +11 -0
- package/lib/cjs/client/addon/readyForCapture.js +1 -4
- package/lib/cjs/client/addon/register.js +43 -82
- package/lib/cjs/client/addon/utils.js +4 -8
- package/lib/cjs/client/addon/withCreevey.js +145 -404
- package/lib/cjs/client/shared/components/ImagesView/BlendView.js +25 -35
- package/lib/cjs/client/shared/components/ImagesView/ImagesView.js +29 -41
- package/lib/cjs/client/shared/components/ImagesView/SideBySideView.js +46 -83
- package/lib/cjs/client/shared/components/ImagesView/SlideView.js +39 -67
- package/lib/cjs/client/shared/components/ImagesView/SwapView.js +26 -57
- package/lib/cjs/client/shared/components/ImagesView/index.js +9 -14
- package/lib/cjs/client/shared/components/PageFooter/PageFooter.js +13 -16
- package/lib/cjs/client/shared/components/PageFooter/Paging.js +16 -37
- package/lib/cjs/client/shared/components/PageHeader/ImagePreview.js +42 -34
- package/lib/cjs/client/shared/components/PageHeader/PageHeader.js +40 -84
- package/lib/cjs/client/shared/components/ResultsPage.js +42 -99
- package/lib/cjs/client/shared/creeveyClientApi.js +56 -93
- package/lib/cjs/client/shared/helpers.js +149 -274
- package/lib/cjs/client/shared/viewMode.js +5 -9
- package/lib/cjs/client/web/192.js +1 -0
- package/lib/cjs/client/web/632.js +43 -0
- package/lib/cjs/client/web/794.js +1 -0
- package/lib/cjs/client/web/main.js +79 -38
- package/lib/cjs/client/web/main.js.LICENSE.txt +34 -0
- package/lib/cjs/creevey.js +15 -30
- package/lib/cjs/index.js +0 -15
- package/lib/cjs/server/config.js +16 -36
- package/lib/cjs/server/docker.js +8 -34
- package/lib/cjs/server/index.js +9 -34
- package/lib/cjs/server/logger.js +7 -20
- package/lib/cjs/server/master/api.js +1 -14
- package/lib/cjs/server/master/index.js +25 -49
- package/lib/cjs/server/master/master.js +6 -21
- package/lib/cjs/server/master/pool.js +10 -53
- package/lib/cjs/server/master/runner.js +65 -105
- package/lib/cjs/server/master/server.js +10 -29
- package/lib/cjs/server/messages.js +14 -62
- package/lib/cjs/server/selenium/browser.js +149 -185
- package/lib/cjs/server/selenium/index.js +0 -4
- package/lib/cjs/server/selenium/selenoid.js +18 -44
- package/lib/cjs/server/stories.js +35 -57
- package/lib/cjs/server/storybook/providers/browser.js +15 -29
- package/lib/cjs/server/storybook/providers/hybrid.js +16 -37
- package/lib/cjs/server/telemetry.js +167 -0
- package/lib/cjs/server/testsFiles/parser.js +3 -19
- package/lib/cjs/server/testsFiles/register.js +8 -14
- package/lib/cjs/server/update.js +4 -25
- package/lib/cjs/server/utils.js +35 -76
- package/lib/cjs/server/worker/chai-image.js +1 -27
- package/lib/cjs/server/worker/helpers.js +2 -12
- package/lib/cjs/server/worker/index.js +1 -3
- package/lib/cjs/server/worker/reporter.js +16 -43
- package/lib/cjs/server/worker/worker.js +32 -72
- package/lib/cjs/shared/index.js +87 -0
- package/lib/cjs/shared/serializeRegExp.js +34 -0
- package/lib/cjs/types.js +11 -20
- package/lib/esm/cli.js +1 -1
- package/lib/esm/client/addon/Manager.js +170 -381
- package/lib/esm/client/addon/components/Addon.js +15 -34
- package/lib/esm/client/addon/components/Icons.js +10 -6
- package/lib/esm/client/addon/components/Panel.js +20 -18
- package/lib/esm/client/addon/components/TestSelect.js +19 -23
- package/lib/esm/client/addon/components/Tools.js +33 -49
- package/lib/esm/client/addon/decorator.js +1 -1
- package/lib/esm/client/addon/index.js +2 -0
- package/lib/esm/client/addon/preset.js +2 -56
- package/lib/esm/client/addon/preview.js +5 -0
- package/lib/esm/client/addon/readyForCapture.js +1 -3
- package/lib/esm/client/addon/register.js +41 -67
- package/lib/esm/client/addon/utils.js +3 -7
- package/lib/esm/client/addon/withCreevey.js +142 -388
- package/lib/esm/client/shared/components/ImagesView/BlendView.js +22 -18
- package/lib/esm/client/shared/components/ImagesView/ImagesView.js +27 -25
- package/lib/esm/client/shared/components/ImagesView/SideBySideView.js +43 -63
- package/lib/esm/client/shared/components/ImagesView/SlideView.js +36 -47
- package/lib/esm/client/shared/components/ImagesView/SwapView.js +23 -40
- package/lib/esm/client/shared/components/PageFooter/PageFooter.js +12 -8
- package/lib/esm/client/shared/components/PageFooter/Paging.js +15 -29
- package/lib/esm/client/shared/components/PageHeader/ImagePreview.js +40 -25
- package/lib/esm/client/shared/components/PageHeader/PageHeader.js +38 -66
- package/lib/esm/client/shared/components/ResultsPage.js +39 -75
- package/lib/esm/client/shared/creeveyClientApi.js +56 -90
- package/lib/esm/client/shared/helpers.js +133 -230
- package/lib/esm/client/shared/viewMode.js +4 -4
- package/lib/esm/client/web/192.js +1 -0
- package/lib/esm/client/web/632.js +43 -0
- package/lib/esm/client/web/794.js +1 -0
- package/lib/esm/client/web/index.html +19 -0
- package/lib/esm/client/web/main.js +79 -0
- package/lib/esm/client/web/main.js.LICENSE.txt +34 -0
- package/lib/esm/creevey.js +13 -16
- package/lib/esm/index.js +1 -4
- package/lib/esm/server/config.js +9 -16
- package/lib/esm/server/docker.js +6 -14
- package/lib/esm/server/index.js +8 -22
- package/lib/esm/server/logger.js +0 -1
- package/lib/esm/server/master/api.js +0 -9
- package/lib/esm/server/master/index.js +25 -35
- package/lib/esm/server/master/master.js +2 -7
- package/lib/esm/server/master/pool.js +8 -41
- package/lib/esm/server/master/runner.js +64 -90
- package/lib/esm/server/master/server.js +9 -11
- package/lib/esm/server/messages.js +8 -42
- package/lib/esm/server/selenium/browser.js +147 -163
- package/lib/esm/server/selenium/selenoid.js +16 -27
- package/lib/esm/server/stories.js +34 -46
- package/lib/esm/server/storybook/providers/browser.js +12 -17
- package/lib/esm/server/storybook/providers/hybrid.js +11 -22
- package/lib/esm/server/telemetry.js +160 -0
- package/lib/esm/server/testsFiles/parser.js +0 -6
- package/lib/esm/server/testsFiles/register.js +6 -7
- package/lib/esm/server/update.js +1 -13
- package/lib/esm/server/utils.js +20 -41
- package/lib/esm/server/worker/chai-image.js +0 -21
- package/lib/esm/server/worker/helpers.js +2 -9
- package/lib/esm/server/worker/reporter.js +15 -29
- package/lib/esm/server/worker/worker.js +31 -48
- package/lib/esm/shared/index.js +77 -0
- package/lib/esm/shared/serializeRegExp.js +24 -0
- package/lib/esm/types.js +5 -1
- package/lib/types/client/addon/Manager.d.ts +3 -3
- package/lib/types/client/addon/components/Addon.d.ts +1 -0
- package/lib/types/client/addon/components/Icons.d.ts +1 -0
- package/lib/types/client/addon/components/Panel.d.ts +1 -0
- package/lib/types/client/addon/components/Tools.d.ts +1 -0
- package/lib/types/client/addon/decorator.d.ts +1 -1
- package/lib/types/client/addon/index.d.ts +2 -0
- package/lib/types/client/addon/preset.d.ts +2 -24
- package/lib/types/client/addon/preview.d.ts +4 -0
- package/lib/types/client/addon/utils.d.ts +1 -0
- package/lib/types/client/addon/withCreevey.d.ts +4 -3
- package/lib/types/client/shared/components/ImagesView/BlendView.d.ts +3 -1
- package/lib/types/client/shared/components/ImagesView/SideBySideView.d.ts +3 -1
- package/lib/types/client/shared/components/ImagesView/SlideView.d.ts +3 -1
- package/lib/types/client/shared/components/ImagesView/SwapView.d.ts +3 -1
- package/lib/types/client/shared/components/PageHeader/ImagePreview.d.ts +3 -1
- package/lib/types/client/shared/components/ResultsPage.d.ts +3 -1
- package/lib/types/client/web/CreeveyLoader.d.ts +1 -1
- package/lib/types/client/web/CreeveyView/SideBar/Checkbox.d.ts +6 -3
- package/lib/types/client/web/CreeveyView/SideBar/Search.d.ts +1 -0
- package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +19 -14
- package/lib/types/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +3 -1
- package/lib/types/client/web/CreeveyView/SideBar/TestsStatus.d.ts +3 -1
- package/lib/types/client/web/CreeveyView/SideBar/Toggle.d.ts +1 -0
- package/lib/types/client/web/KeyboardEventsContext.d.ts +4 -2
- package/lib/types/index.d.ts +4 -1
- package/lib/types/server/logger.d.ts +6 -2
- package/lib/types/server/messages.d.ts +14 -12
- package/lib/types/server/selenium/browser.d.ts +5 -3
- package/lib/types/server/storybook/providers/browser.d.ts +2 -4
- package/lib/types/server/storybook/providers/hybrid.d.ts +2 -4
- package/lib/types/server/telemetry.d.ts +2 -0
- package/lib/types/server/utils.d.ts +5 -1
- package/lib/types/shared/index.d.ts +7 -0
- package/lib/types/shared/serializeRegExp.d.ts +9 -0
- package/lib/types/types.d.ts +29 -36
- package/package.json +132 -133
- package/types/global.d.ts +5 -0
- package/lib/cjs/client/web/1.js +0 -13
- package/lib/cjs/client/web/2.js +0 -1
- package/lib/cjs/server/extract.js +0 -50
- package/lib/cjs/server/loaders/babel/creevey-plugin.js +0 -88
- package/lib/cjs/server/loaders/babel/helpers.js +0 -479
- package/lib/cjs/server/loaders/babel/register.js +0 -126
- package/lib/cjs/server/loaders/hooks/mdx.js +0 -30
- package/lib/cjs/server/loaders/hooks/svelte.js +0 -65
- package/lib/cjs/server/loaders/webpack/compile.js +0 -286
- package/lib/cjs/server/loaders/webpack/creevey-loader.js +0 -174
- package/lib/cjs/server/loaders/webpack/dummy-hmr.js +0 -44
- package/lib/cjs/server/loaders/webpack/mdx-loader.js +0 -72
- package/lib/cjs/server/loaders/webpack/start.js +0 -41
- package/lib/cjs/server/storybook/entry.js +0 -68
- package/lib/cjs/server/storybook/helpers.js +0 -165
- package/lib/cjs/server/storybook/providers/nodejs.js +0 -239
- package/lib/cjs/shared.js +0 -124
- package/lib/esm/server/extract.js +0 -34
- package/lib/esm/server/loaders/babel/creevey-plugin.js +0 -74
- package/lib/esm/server/loaders/babel/helpers.js +0 -462
- package/lib/esm/server/loaders/babel/register.js +0 -105
- package/lib/esm/server/loaders/hooks/mdx.js +0 -15
- package/lib/esm/server/loaders/hooks/svelte.js +0 -49
- package/lib/esm/server/loaders/webpack/compile.js +0 -263
- package/lib/esm/server/loaders/webpack/creevey-loader.js +0 -153
- package/lib/esm/server/loaders/webpack/dummy-hmr.js +0 -36
- package/lib/esm/server/loaders/webpack/mdx-loader.js +0 -58
- package/lib/esm/server/loaders/webpack/start.js +0 -27
- package/lib/esm/server/storybook/entry.js +0 -44
- package/lib/esm/server/storybook/helpers.js +0 -106
- package/lib/esm/server/storybook/providers/nodejs.js +0 -217
- package/lib/esm/shared.js +0 -93
- package/lib/types/server/extract.d.ts +0 -2
- package/lib/types/server/loaders/babel/creevey-plugin.d.ts +0 -1
- package/lib/types/server/loaders/babel/helpers.d.ts +0 -19
- package/lib/types/server/loaders/babel/register.d.ts +0 -5
- package/lib/types/server/loaders/hooks/mdx.d.ts +0 -1
- package/lib/types/server/loaders/hooks/svelte.d.ts +0 -1
- package/lib/types/server/loaders/webpack/compile.d.ts +0 -2
- package/lib/types/server/loaders/webpack/creevey-loader.d.ts +0 -2
- package/lib/types/server/loaders/webpack/dummy-hmr.d.ts +0 -10
- package/lib/types/server/loaders/webpack/mdx-loader.d.ts +0 -6
- package/lib/types/server/loaders/webpack/start.d.ts +0 -1
- package/lib/types/server/storybook/entry.d.ts +0 -18
- package/lib/types/server/storybook/helpers.d.ts +0 -24
- package/lib/types/server/storybook/providers/nodejs.d.ts +0 -9
- package/lib/types/shared.d.ts +0 -16
- package/preset.js +0 -9
- package/storybook-static/stories.json +0 -21
- package/types/mdx.d.ts +0 -6
@@ -1,46 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
import cluster from 'cluster';
|
1
|
+
import cluster, { Worker as ClusterWorker } from 'cluster';
|
4
2
|
import { EventEmitter } from 'events';
|
5
3
|
import { isWorkerMessage } from '../../types';
|
6
4
|
import { sendTestMessage, sendShutdownMessage, subscribeOnWorker } from '../messages';
|
7
5
|
import { isShuttingDown } from '../utils';
|
8
6
|
const FORK_RETRIES = 5;
|
9
7
|
export default class Pool extends EventEmitter {
|
8
|
+
workers = [];
|
9
|
+
queue = [];
|
10
|
+
forcedStop = false;
|
10
11
|
get isRunning() {
|
11
12
|
return this.workers.length !== this.freeWorkers.length;
|
12
13
|
}
|
13
|
-
|
14
14
|
constructor(config, browser) {
|
15
15
|
super();
|
16
16
|
this.browser = browser;
|
17
|
-
|
18
|
-
_defineProperty(this, "maxRetries", void 0);
|
19
|
-
|
20
|
-
_defineProperty(this, "config", void 0);
|
21
|
-
|
22
|
-
_defineProperty(this, "workers", []);
|
23
|
-
|
24
|
-
_defineProperty(this, "queue", []);
|
25
|
-
|
26
|
-
_defineProperty(this, "forcedStop", false);
|
27
|
-
|
28
|
-
_defineProperty(this, "failFast", void 0);
|
29
|
-
|
30
17
|
this.failFast = config.failFast;
|
31
18
|
this.maxRetries = config.maxRetries;
|
32
19
|
this.config = config.browsers[browser];
|
33
20
|
}
|
34
|
-
|
35
21
|
async init() {
|
36
22
|
const poolSize = this.config.limit || 1;
|
23
|
+
// TODO Init queue for workers to smooth browser starting load
|
37
24
|
this.workers = (await Promise.all(Array.from({
|
38
25
|
length: poolSize
|
39
|
-
}).map(() => this.forkWorker()))).filter(workerOrError => workerOrError instanceof
|
26
|
+
}).map(() => this.forkWorker()))).filter(workerOrError => workerOrError instanceof ClusterWorker);
|
40
27
|
if (this.workers.length != poolSize) throw new Error(`Can't instantiate workers for ${this.browser} due many errors`);
|
41
28
|
this.workers.forEach(worker => this.exitHandler(worker));
|
42
29
|
}
|
43
|
-
|
44
30
|
start(tests) {
|
45
31
|
if (this.isRunning) return false;
|
46
32
|
this.queue = tests.map(({
|
@@ -54,27 +40,22 @@ export default class Pool extends EventEmitter {
|
|
54
40
|
this.process();
|
55
41
|
return true;
|
56
42
|
}
|
57
|
-
|
58
43
|
stop() {
|
59
44
|
if (!this.isRunning) {
|
60
45
|
this.emit('stop');
|
61
46
|
return;
|
62
47
|
}
|
63
|
-
|
64
48
|
this.forcedStop = true;
|
65
49
|
this.queue = [];
|
66
50
|
}
|
67
|
-
|
68
51
|
process() {
|
69
52
|
const worker = this.getFreeWorker();
|
70
53
|
const [test] = this.queue;
|
71
|
-
|
72
54
|
if (this.queue.length == 0 && this.workers.length === this.freeWorkers.length) {
|
73
55
|
this.forcedStop = false;
|
74
56
|
this.emit('stop');
|
75
57
|
return;
|
76
58
|
}
|
77
|
-
|
78
59
|
if (!worker || !test) return;
|
79
60
|
worker.isRunning = true;
|
80
61
|
const {
|
@@ -92,25 +73,20 @@ export default class Pool extends EventEmitter {
|
|
92
73
|
});
|
93
74
|
this.process();
|
94
75
|
}
|
95
|
-
|
96
76
|
sendStatus(message) {
|
97
77
|
this.emit('test', message);
|
98
78
|
}
|
99
|
-
|
100
79
|
getFreeWorker() {
|
101
80
|
return this.freeWorkers[Math.floor(Math.random() * this.freeWorkers.length)];
|
102
81
|
}
|
103
|
-
|
104
82
|
get aliveWorkers() {
|
105
83
|
return this.workers.filter(worker => !worker.exitedAfterDisconnect);
|
106
84
|
}
|
107
|
-
|
108
85
|
get freeWorkers() {
|
109
86
|
return this.aliveWorkers.filter(worker => !worker.isRunning);
|
110
87
|
}
|
111
|
-
|
112
88
|
async forkWorker(retry = 0) {
|
113
|
-
cluster.
|
89
|
+
cluster.setupPrimary({
|
114
90
|
args: ['--browser', this.browser, ...process.argv.slice(2)]
|
115
91
|
});
|
116
92
|
const worker = cluster.fork();
|
@@ -120,7 +96,6 @@ export default class Pool extends EventEmitter {
|
|
120
96
|
worker.off('message', readyHandler);
|
121
97
|
resolve(message);
|
122
98
|
};
|
123
|
-
|
124
99
|
worker.on('message', readyHandler);
|
125
100
|
});
|
126
101
|
if (message.type != 'error') return worker;
|
@@ -128,37 +103,31 @@ export default class Pool extends EventEmitter {
|
|
128
103
|
if (retry == FORK_RETRIES) return message.payload;
|
129
104
|
return this.forkWorker(retry + 1);
|
130
105
|
}
|
131
|
-
|
132
106
|
exitHandler(worker) {
|
133
107
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
134
108
|
worker.once('exit', async () => {
|
135
109
|
if (isShuttingDown.current) return;
|
136
110
|
const workerOrError = await this.forkWorker();
|
137
|
-
if (!(workerOrError instanceof
|
111
|
+
if (!(workerOrError instanceof ClusterWorker)) throw new Error(`Can't instantiate worker for ${this.browser} due many errors`);
|
138
112
|
this.exitHandler(workerOrError);
|
139
113
|
this.workers[this.workers.indexOf(worker)] = workerOrError;
|
140
114
|
this.process();
|
141
115
|
});
|
142
116
|
}
|
143
|
-
|
144
117
|
gracefullyKill(worker) {
|
145
118
|
const timeout = setTimeout(() => worker.kill(), 10000);
|
146
119
|
worker.on('exit', () => clearTimeout(timeout));
|
147
120
|
sendShutdownMessage(worker);
|
148
121
|
}
|
149
|
-
|
150
122
|
shouldRetry(test) {
|
151
123
|
return test.retries < this.maxRetries && !this.forcedStop;
|
152
124
|
}
|
153
|
-
|
154
125
|
handleTestResult(worker, test, result) {
|
155
126
|
const shouldRetry = result.status == 'failed' && this.shouldRetry(test);
|
156
|
-
|
157
127
|
if (shouldRetry) {
|
158
128
|
test.retries += 1;
|
159
129
|
this.queue[this.failFast ? 'unshift' : 'push'](test);
|
160
130
|
}
|
161
|
-
|
162
131
|
this.sendStatus({
|
163
132
|
id: test.id,
|
164
133
|
status: shouldRetry ? 'retrying' : result.status,
|
@@ -167,7 +136,6 @@ export default class Pool extends EventEmitter {
|
|
167
136
|
worker.isRunning = false;
|
168
137
|
setImmediate(() => this.process());
|
169
138
|
}
|
170
|
-
|
171
139
|
subscribe(worker, test) {
|
172
140
|
const subscriptions = [subscribeOnWorker(worker, 'worker', message => {
|
173
141
|
if (message.type != 'error') return;
|
@@ -183,5 +151,4 @@ export default class Pool extends EventEmitter {
|
|
183
151
|
this.handleTestResult(worker, test, message.payload);
|
184
152
|
})];
|
185
153
|
}
|
186
|
-
|
187
154
|
}
|
@@ -1,5 +1,3 @@
|
|
1
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
2
|
-
|
3
1
|
import path from 'path';
|
4
2
|
import { copyFile, mkdir } from 'fs';
|
5
3
|
import { promisify } from 'util';
|
@@ -9,63 +7,36 @@ import Pool from './pool';
|
|
9
7
|
const copyFileAsync = promisify(copyFile);
|
10
8
|
const mkdirAsync = promisify(mkdir);
|
11
9
|
export default class Runner extends EventEmitter {
|
10
|
+
pools = {};
|
11
|
+
tests = {};
|
12
12
|
get isRunning() {
|
13
13
|
return Object.values(this.pools).some(pool => pool.isRunning);
|
14
14
|
}
|
15
|
-
|
16
15
|
constructor(config) {
|
17
16
|
super();
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
testName,
|
42
|
-
storyPath,
|
43
|
-
storyId
|
44
|
-
} = test; // TODO Handle 'retrying' status
|
45
|
-
|
46
|
-
test.status = status == 'retrying' ? 'failed' : status;
|
47
|
-
|
48
|
-
if (!result) {
|
49
|
-
this.sendUpdate({
|
50
|
-
tests: {
|
51
|
-
[id]: {
|
52
|
-
id,
|
53
|
-
browser,
|
54
|
-
testName,
|
55
|
-
storyPath,
|
56
|
-
status: test.status,
|
57
|
-
storyId
|
58
|
-
}
|
59
|
-
}
|
60
|
-
});
|
61
|
-
return;
|
62
|
-
}
|
63
|
-
|
64
|
-
if (!test.results) {
|
65
|
-
test.results = [];
|
66
|
-
}
|
67
|
-
|
68
|
-
test.results.push(result);
|
17
|
+
this.failFast = config.failFast;
|
18
|
+
this.screenDir = config.screenDir;
|
19
|
+
this.reportDir = config.reportDir;
|
20
|
+
this.browsers = Object.keys(config.browsers);
|
21
|
+
this.browsers.map(browser => this.pools[browser] = new Pool(config, browser)).map(pool => pool.on('test', this.handlePoolMessage));
|
22
|
+
}
|
23
|
+
handlePoolMessage = message => {
|
24
|
+
const {
|
25
|
+
id,
|
26
|
+
status,
|
27
|
+
result
|
28
|
+
} = message;
|
29
|
+
const test = this.tests[id];
|
30
|
+
if (!test) return;
|
31
|
+
const {
|
32
|
+
browser,
|
33
|
+
testName,
|
34
|
+
storyPath,
|
35
|
+
storyId
|
36
|
+
} = test;
|
37
|
+
// TODO Handle 'retrying' status
|
38
|
+
test.status = status == 'retrying' ? 'failed' : status;
|
39
|
+
if (!result) {
|
69
40
|
this.sendUpdate({
|
70
41
|
tests: {
|
71
42
|
[id]: {
|
@@ -74,56 +45,65 @@ export default class Runner extends EventEmitter {
|
|
74
45
|
testName,
|
75
46
|
storyPath,
|
76
47
|
status: test.status,
|
77
|
-
results: [result],
|
78
48
|
storyId
|
79
49
|
}
|
80
50
|
}
|
81
51
|
});
|
82
|
-
|
83
|
-
}
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
if (!test.results) {
|
55
|
+
test.results = [];
|
56
|
+
}
|
57
|
+
test.results.push(result);
|
58
|
+
this.sendUpdate({
|
59
|
+
tests: {
|
60
|
+
[id]: {
|
61
|
+
id,
|
62
|
+
browser,
|
63
|
+
testName,
|
64
|
+
storyPath,
|
65
|
+
status: test.status,
|
66
|
+
results: [result],
|
67
|
+
storyId
|
68
|
+
}
|
91
69
|
}
|
92
70
|
});
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
this.
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
71
|
+
if (this.failFast && status == 'failed') this.stop();
|
72
|
+
};
|
73
|
+
handlePoolStop = () => {
|
74
|
+
if (!this.isRunning) {
|
75
|
+
this.sendUpdate({
|
76
|
+
isRunning: false
|
77
|
+
});
|
78
|
+
this.emit('stop');
|
79
|
+
}
|
80
|
+
};
|
101
81
|
async init() {
|
102
82
|
await Promise.all(Object.values(this.pools).map(pool => pool.init()));
|
103
83
|
}
|
104
|
-
|
105
84
|
updateTests(testsDiff) {
|
106
85
|
const tests = {};
|
107
86
|
const removedTests = [];
|
108
87
|
Object.entries(testsDiff).forEach(([id, newTest]) => {
|
109
88
|
const oldTest = this.tests[id];
|
110
|
-
|
111
89
|
if (newTest) {
|
112
90
|
if (oldTest) {
|
113
|
-
this.tests[id] = {
|
91
|
+
this.tests[id] = {
|
92
|
+
...newTest,
|
114
93
|
retries: oldTest.retries,
|
115
94
|
results: oldTest.results,
|
116
95
|
approved: oldTest.approved
|
117
96
|
};
|
118
|
-
} else this.tests[id] = newTest;
|
119
|
-
|
97
|
+
} else this.tests[id] = newTest;
|
120
98
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
121
100
|
const {
|
122
101
|
story,
|
123
102
|
fn,
|
124
103
|
...restTest
|
125
104
|
} = newTest;
|
126
|
-
tests[id] = {
|
105
|
+
tests[id] = {
|
106
|
+
...restTest,
|
127
107
|
status: 'unknown'
|
128
108
|
};
|
129
109
|
} else if (oldTest) {
|
@@ -149,7 +129,6 @@ export default class Runner extends EventEmitter {
|
|
149
129
|
removedTests
|
150
130
|
});
|
151
131
|
}
|
152
|
-
|
153
132
|
start(ids) {
|
154
133
|
if (this.isRunning) return;
|
155
134
|
const testsToStart = ids.map(id => this.tests[id]).filter(isDefined).filter(test => !test.skip);
|
@@ -162,7 +141,8 @@ export default class Runner extends EventEmitter {
|
|
162
141
|
browser,
|
163
142
|
testName,
|
164
143
|
storyPath
|
165
|
-
}) => ({
|
144
|
+
}) => ({
|
145
|
+
...update,
|
166
146
|
[id]: {
|
167
147
|
id,
|
168
148
|
browser,
|
@@ -182,7 +162,8 @@ export default class Runner extends EventEmitter {
|
|
182
162
|
} = test;
|
183
163
|
const restPath = [...storyPath, testName].filter(isDefined);
|
184
164
|
test.status = 'pending';
|
185
|
-
return {
|
165
|
+
return {
|
166
|
+
...tests,
|
186
167
|
[browser]: [...(tests[browser] || []), {
|
187
168
|
id,
|
188
169
|
path: restPath
|
@@ -192,21 +173,19 @@ export default class Runner extends EventEmitter {
|
|
192
173
|
this.browsers.forEach(browser => {
|
193
174
|
const pool = this.pools[browser];
|
194
175
|
const tests = testsByBrowser[browser];
|
195
|
-
|
196
176
|
if (tests && tests.length > 0 && pool.start(tests)) {
|
197
177
|
pool.once('stop', this.handlePoolStop);
|
198
178
|
}
|
199
179
|
});
|
200
180
|
}
|
201
|
-
|
202
181
|
stop() {
|
203
182
|
if (!this.isRunning) return;
|
204
183
|
this.browsers.forEach(browser => this.pools[browser].stop());
|
205
184
|
}
|
206
|
-
|
207
185
|
get status() {
|
208
186
|
const tests = {};
|
209
|
-
Object.values(this.tests).filter(isDefined)
|
187
|
+
Object.values(this.tests).filter(isDefined)
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
210
189
|
.forEach(({
|
211
190
|
story,
|
212
191
|
fn,
|
@@ -218,7 +197,6 @@ export default class Runner extends EventEmitter {
|
|
218
197
|
browsers: this.browsers
|
219
198
|
};
|
220
199
|
}
|
221
|
-
|
222
200
|
async approve({
|
223
201
|
id,
|
224
202
|
retry,
|
@@ -230,11 +208,9 @@ export default class Runner extends EventEmitter {
|
|
230
208
|
if (!result || !result.images) return;
|
231
209
|
const images = result.images[image];
|
232
210
|
if (!images) return;
|
233
|
-
|
234
211
|
if (!test.approved) {
|
235
212
|
test.approved = {};
|
236
213
|
}
|
237
|
-
|
238
214
|
const {
|
239
215
|
browser,
|
240
216
|
testName,
|
@@ -264,9 +240,7 @@ export default class Runner extends EventEmitter {
|
|
264
240
|
}
|
265
241
|
});
|
266
242
|
}
|
267
|
-
|
268
243
|
sendUpdate(data) {
|
269
244
|
this.emit('update', data);
|
270
245
|
}
|
271
|
-
|
272
246
|
}
|
@@ -27,17 +27,14 @@ export default function server(reportDir, port, ui) {
|
|
27
27
|
ctx.body = 'pong';
|
28
28
|
return;
|
29
29
|
}
|
30
|
-
|
31
30
|
await next();
|
32
31
|
});
|
33
|
-
|
34
32
|
if (ui) {
|
35
33
|
app.use(async (_, next) => {
|
36
34
|
await creeveyApi;
|
37
35
|
await next();
|
38
36
|
});
|
39
37
|
}
|
40
|
-
|
41
38
|
app.use(async (ctx, next) => {
|
42
39
|
if (ctx.method == 'POST' && ctx.path == '/stories') {
|
43
40
|
const {
|
@@ -51,13 +48,12 @@ export default function server(reportDir, port, ui) {
|
|
51
48
|
type: 'update',
|
52
49
|
payload: deserializedStories
|
53
50
|
});
|
54
|
-
Object.values(cluster.workers).filter(isDefined).filter(worker => worker.isConnected()).forEach(worker => sendStoriesMessage(worker, {
|
51
|
+
Object.values(cluster.workers ?? {}).filter(isDefined).filter(worker => worker.isConnected()).forEach(worker => sendStoriesMessage(worker, {
|
55
52
|
type: 'update',
|
56
53
|
payload: deserializedStories
|
57
54
|
}));
|
58
55
|
return;
|
59
56
|
}
|
60
|
-
|
61
57
|
await next();
|
62
58
|
});
|
63
59
|
app.use(async (ctx, next) => {
|
@@ -66,8 +62,8 @@ export default function server(reportDir, port, ui) {
|
|
66
62
|
workerId,
|
67
63
|
options
|
68
64
|
} = ctx.request.body;
|
69
|
-
const worker = Object.values(cluster.workers).filter(isDefined).find(worker => worker.process.pid == workerId);
|
70
|
-
|
65
|
+
const worker = Object.values(cluster.workers ?? {}).filter(isDefined).find(worker => worker.process.pid == workerId);
|
66
|
+
// NOTE: Hypothetical case when someone send to us capture req and we don't have a worker with browser session for it
|
71
67
|
if (!worker) return;
|
72
68
|
await new Promise(resolve => {
|
73
69
|
const unsubscribe = subscribeOnWorker(worker, 'stories', message => {
|
@@ -79,12 +75,11 @@ export default function server(reportDir, port, ui) {
|
|
79
75
|
type: 'capture',
|
80
76
|
payload: options
|
81
77
|
});
|
82
|
-
});
|
83
|
-
|
78
|
+
});
|
79
|
+
// TODO Pass screenshot result to show it in inspector
|
84
80
|
ctx.body = 'Ok';
|
85
81
|
return;
|
86
82
|
}
|
87
|
-
|
88
83
|
await next();
|
89
84
|
});
|
90
85
|
app.use(serve(path.join(__dirname, '../../client/web')));
|
@@ -94,11 +89,14 @@ export default function server(reportDir, port, ui) {
|
|
94
89
|
subscribeOn('shutdown', () => {
|
95
90
|
server.close();
|
96
91
|
wss.close();
|
92
|
+
wss.clients.forEach(ws => ws.close());
|
97
93
|
});
|
98
94
|
void creeveyApi.then(api => {
|
99
95
|
api.subscribe(wss);
|
100
96
|
wss.on('connection', ws => {
|
101
|
-
ws.on('message', message =>
|
97
|
+
ws.on('message', (message, isBinary) => {
|
98
|
+
api.handleMessage(ws, isBinary ? message : message.toString());
|
99
|
+
});
|
102
100
|
});
|
103
101
|
});
|
104
102
|
return resolveApi;
|