creevey 0.10.0-beta.42 → 0.10.0-beta.44
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 +282 -0
- package/dist/client/addon/controller.js +1 -1
- package/dist/client/addon/controller.js.map +1 -1
- package/dist/client/addon/decorator.d.ts +1 -1
- package/dist/client/addon/makeDecorator.d.ts +9 -0
- package/dist/client/addon/makeDecorator.js +48 -0
- package/dist/client/addon/makeDecorator.js.map +1 -0
- package/dist/client/addon/preview.d.ts +1 -1
- package/dist/client/addon/withCreevey.d.ts +2 -1
- package/dist/client/addon/withCreevey.js +3 -20
- package/dist/client/addon/withCreevey.js.map +1 -1
- package/dist/client/shared/components/PageHeader/PageHeader.js +13 -4
- package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
- package/dist/client/shared/creeveyClientApi.js +10 -0
- package/dist/client/shared/creeveyClientApi.js.map +1 -1
- package/dist/client/web/CreeveyApp.d.ts +1 -0
- package/dist/client/web/CreeveyApp.js +1 -0
- package/dist/client/web/CreeveyApp.js.map +1 -1
- package/dist/client/web/CreeveyContext.d.ts +1 -0
- package/dist/client/web/CreeveyContext.js +1 -0
- package/dist/client/web/CreeveyContext.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +9 -8
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +13 -3
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +2 -3
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestLink.js +2 -3
- package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.js +1 -0
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.js.map +1 -1
- package/dist/client/web/assets/{index-C47njyZV.js → index-BU4jjKVC.js} +68 -68
- package/dist/client/web/index.html +1 -1
- package/dist/client/web/index.js +8 -3
- package/dist/client/web/index.js.map +1 -1
- package/dist/creevey.d.ts +1 -1
- package/dist/creevey.js +1 -22
- package/dist/creevey.js.map +1 -1
- package/dist/playwright-reporter.d.ts +2 -0
- package/dist/playwright-reporter.js +5 -0
- package/dist/playwright-reporter.js.map +1 -0
- package/dist/playwright.d.ts +1 -1
- package/dist/server/config.js +8 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/index.js +10 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/master/api.d.ts +15 -5
- package/dist/server/master/api.js +89 -27
- package/dist/server/master/api.js.map +1 -1
- package/dist/server/master/handlers/capture-handler.d.ts +2 -0
- package/dist/server/master/handlers/capture-handler.js +35 -0
- package/dist/server/master/handlers/capture-handler.js.map +1 -0
- package/dist/server/master/handlers/index.d.ts +4 -0
- package/dist/server/master/handlers/index.js +21 -0
- package/dist/server/master/handlers/index.js.map +1 -0
- package/dist/server/master/handlers/ping-handler.d.ts +2 -0
- package/dist/server/master/handlers/ping-handler.js +7 -0
- package/dist/server/master/handlers/ping-handler.js.map +1 -0
- package/dist/server/master/handlers/static-handler.d.ts +2 -0
- package/dist/server/master/handlers/static-handler.js +32 -0
- package/dist/server/master/handlers/static-handler.js.map +1 -0
- package/dist/server/master/handlers/stories-handler.d.ts +2 -0
- package/dist/server/master/handlers/stories-handler.js +38 -0
- package/dist/server/master/handlers/stories-handler.js.map +1 -0
- package/dist/server/master/master.js +7 -24
- package/dist/server/master/master.js.map +1 -1
- package/dist/server/master/runner.d.ts +4 -6
- package/dist/server/master/runner.js +30 -127
- package/dist/server/master/runner.js.map +1 -1
- package/dist/server/master/server.js +77 -87
- package/dist/server/master/server.js.map +1 -1
- package/dist/server/master/start.d.ts +1 -2
- package/dist/server/master/start.js +11 -29
- package/dist/server/master/start.js.map +1 -1
- package/dist/server/master/testsManager.d.ts +81 -0
- package/dist/server/master/testsManager.js +281 -0
- package/dist/server/master/testsManager.js.map +1 -0
- package/dist/server/playwright/reporter.d.ts +87 -0
- package/dist/server/playwright/reporter.js +351 -0
- package/dist/server/playwright/reporter.js.map +1 -0
- package/dist/server/selenium/internal.js +20 -2
- package/dist/server/selenium/internal.js.map +1 -1
- package/dist/server/selenium/selenoid.js +4 -0
- package/dist/server/selenium/selenoid.js.map +1 -1
- package/dist/server/shutdown.d.ts +1 -0
- package/dist/server/shutdown.js +23 -0
- package/dist/server/shutdown.js.map +1 -0
- package/dist/server/stories.d.ts +0 -1
- package/dist/server/stories.js +0 -12
- package/dist/server/stories.js.map +1 -1
- package/dist/server/ui-update.d.ts +10 -0
- package/dist/server/ui-update.js +39 -0
- package/dist/server/ui-update.js.map +1 -0
- package/dist/server/utils.d.ts +6 -0
- package/dist/server/utils.js +39 -8
- package/dist/server/utils.js.map +1 -1
- package/dist/server/worker/start.js +1 -1
- package/dist/server/worker/start.js.map +1 -1
- package/dist/types.d.ts +14 -8
- package/dist/types.js.map +1 -1
- package/docs/examples/playwright-reporter-example.ts +202 -0
- package/docs/migration-0.9-to-0.10.md +144 -0
- package/docs/playwright-reporter.md +357 -0
- package/package.json +9 -13
- package/src/client/addon/controller.ts +1 -1
- package/src/client/addon/makeDecorator.ts +69 -0
- package/src/client/addon/withCreevey.ts +4 -17
- package/src/client/shared/components/PageHeader/PageHeader.tsx +18 -4
- package/src/client/shared/creeveyClientApi.ts +10 -0
- package/src/client/web/CreeveyApp.tsx +2 -0
- package/src/client/web/CreeveyContext.tsx +2 -0
- package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +19 -17
- package/src/client/web/CreeveyView/SideBar/SideBarHeader.tsx +18 -3
- package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +9 -7
- package/src/client/web/CreeveyView/SideBar/TestLink.tsx +8 -6
- package/src/client/web/CreeveyView/SideBar/TestsStatus.tsx +1 -0
- package/src/client/web/index.tsx +8 -3
- package/src/creevey.ts +1 -24
- package/src/playwright-reporter.ts +3 -0
- package/src/server/config.ts +9 -1
- package/src/server/index.ts +11 -4
- package/src/server/master/api.ts +95 -26
- package/src/server/master/handlers/capture-handler.ts +39 -0
- package/src/server/master/handlers/index.ts +4 -0
- package/src/server/master/handlers/ping-handler.ts +5 -0
- package/src/server/master/handlers/static-handler.ts +29 -0
- package/src/server/master/handlers/stories-handler.ts +48 -0
- package/src/server/master/master.ts +10 -27
- package/src/server/master/runner.ts +38 -132
- package/src/server/master/server.ts +93 -97
- package/src/server/master/start.ts +17 -41
- package/src/server/master/testsManager.ts +315 -0
- package/src/server/playwright/reporter.ts +386 -0
- package/src/server/selenium/internal.ts +23 -3
- package/src/server/selenium/selenoid.ts +5 -0
- package/src/server/shutdown.ts +19 -0
- package/src/server/stories.ts +1 -12
- package/src/server/ui-update.ts +46 -0
- package/src/server/utils.ts +40 -9
- package/src/server/worker/start.ts +1 -1
- package/src/types.ts +14 -8
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Request, Response } from 'hyper-express';
|
2
|
+
import cluster from 'cluster';
|
3
|
+
import { subscribeOnWorker, sendStoriesMessage } from '../../messages.js';
|
4
|
+
import { CaptureOptions, isDefined } from '../../../types.js';
|
5
|
+
|
6
|
+
export async function captureHandler(request: Request, response: Response): Promise<void> {
|
7
|
+
const { workerId, options } = await request.json<
|
8
|
+
{ workerId: number; options?: CaptureOptions },
|
9
|
+
{
|
10
|
+
workerId: number;
|
11
|
+
options?: CaptureOptions;
|
12
|
+
}
|
13
|
+
>({
|
14
|
+
workerId: 0,
|
15
|
+
options: undefined,
|
16
|
+
});
|
17
|
+
|
18
|
+
const worker = Object.values(cluster.workers ?? {})
|
19
|
+
.filter(isDefined)
|
20
|
+
.find((worker) => worker.process.pid == workerId);
|
21
|
+
|
22
|
+
// NOTE: Hypothetical case when someone send to us capture req and we don't have a worker with browser session for it
|
23
|
+
if (!worker) {
|
24
|
+
response.send();
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
await new Promise<void>((resolve) => {
|
29
|
+
const unsubscribe = subscribeOnWorker(worker, 'stories', (message) => {
|
30
|
+
if (message.type != 'capture') return;
|
31
|
+
unsubscribe();
|
32
|
+
resolve();
|
33
|
+
});
|
34
|
+
sendStoriesMessage(worker, { type: 'capture', payload: options });
|
35
|
+
});
|
36
|
+
|
37
|
+
// TODO Pass screenshot result to show it in inspector
|
38
|
+
response.send('Ok');
|
39
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { Request, Response } from 'hyper-express';
|
2
|
+
import path from 'path';
|
3
|
+
import fs from 'fs';
|
4
|
+
import { logger } from '../../logger.js';
|
5
|
+
|
6
|
+
export function createStaticFileHandler(baseDir: string, pathPrefix?: string) {
|
7
|
+
return (request: Request, response: Response): void => {
|
8
|
+
try {
|
9
|
+
const decodedPath = decodeURIComponent(request.path);
|
10
|
+
const relativePath = pathPrefix ? decodedPath.replace(pathPrefix, '') : decodedPath;
|
11
|
+
let filePath = path.join(baseDir, relativePath || 'index.html');
|
12
|
+
|
13
|
+
// If the path points to a directory, append index.html
|
14
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
|
15
|
+
filePath = path.join(filePath, 'index.html');
|
16
|
+
}
|
17
|
+
|
18
|
+
if (!fs.existsSync(filePath)) {
|
19
|
+
response.status(404).send('File not found');
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
|
23
|
+
response.sendFile(filePath);
|
24
|
+
} catch (error) {
|
25
|
+
logger().error('Error serving file', error);
|
26
|
+
response.status(500).send('Internal server error');
|
27
|
+
}
|
28
|
+
};
|
29
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { Request, Response } from 'hyper-express';
|
2
|
+
import cluster from 'cluster';
|
3
|
+
import { emitStoriesMessage, sendStoriesMessage } from '../../messages.js';
|
4
|
+
import { isDefined, StoryInput } from '../../../types.js';
|
5
|
+
import { deserializeStory } from '../../../shared/index.js';
|
6
|
+
|
7
|
+
export function createStoriesHandler() {
|
8
|
+
let setStoriesCounter = 0;
|
9
|
+
|
10
|
+
// TODO We need this handler for getting stories updates from a browser
|
11
|
+
return async (request: Request, response: Response): Promise<void> => {
|
12
|
+
const { setStoriesCounter: counter, stories } = await request.json<
|
13
|
+
{
|
14
|
+
setStoriesCounter: number;
|
15
|
+
stories: [string, StoryInput[]][];
|
16
|
+
},
|
17
|
+
{
|
18
|
+
setStoriesCounter: number;
|
19
|
+
stories: [string, StoryInput[]][];
|
20
|
+
}
|
21
|
+
>({
|
22
|
+
setStoriesCounter: 0,
|
23
|
+
stories: [],
|
24
|
+
});
|
25
|
+
|
26
|
+
if (setStoriesCounter >= counter) {
|
27
|
+
response.send();
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
|
31
|
+
const deserializedStories = stories.map<[string, StoryInput[]]>(([file, stories]) => [
|
32
|
+
file,
|
33
|
+
stories.map(deserializeStory),
|
34
|
+
]);
|
35
|
+
|
36
|
+
setStoriesCounter = counter;
|
37
|
+
emitStoriesMessage({ type: 'update', payload: deserializedStories });
|
38
|
+
|
39
|
+
Object.values(cluster.workers ?? {})
|
40
|
+
.filter(isDefined)
|
41
|
+
.filter((worker) => worker.isConnected())
|
42
|
+
.forEach((worker) => {
|
43
|
+
sendStoriesMessage(worker, { type: 'update', payload: deserializedStories });
|
44
|
+
});
|
45
|
+
|
46
|
+
response.send();
|
47
|
+
};
|
48
|
+
}
|
@@ -1,44 +1,27 @@
|
|
1
|
-
import
|
2
|
-
import {
|
3
|
-
import { loadTestsFromStories, saveTestsJson } from '../stories.js';
|
1
|
+
import { Config } from '../../types.js';
|
2
|
+
import { loadTestsFromStories } from '../stories.js';
|
4
3
|
import Runner from './runner.js';
|
5
|
-
import {
|
6
|
-
|
7
|
-
function mergeTests(
|
8
|
-
testsWithReports: Partial<Record<string, TestData>>,
|
9
|
-
testsFromStories: Partial<Record<string, ServerTest>>,
|
10
|
-
): Partial<Record<string, ServerTest>> {
|
11
|
-
Object.values(testsFromStories)
|
12
|
-
.filter(isDefined)
|
13
|
-
.forEach((test) => {
|
14
|
-
const testWithReport = testsWithReports[test.id];
|
15
|
-
if (!testWithReport) return;
|
16
|
-
test.retries = testWithReport.retries;
|
17
|
-
if (testWithReport.status == 'success' || testWithReport.status == 'failed') test.status = testWithReport.status;
|
18
|
-
test.results = testWithReport.results;
|
19
|
-
test.approved = testWithReport.approved;
|
20
|
-
});
|
21
|
-
return testsFromStories;
|
22
|
-
}
|
4
|
+
import { TestsManager } from './testsManager.js';
|
23
5
|
|
24
6
|
export default async function master(config: Config, gridUrl?: string): Promise<Runner> {
|
25
|
-
|
26
|
-
const
|
27
|
-
|
7
|
+
// Create TestsManager instance
|
8
|
+
const testsManager = new TestsManager(config.screenDir, config.reportDir);
|
9
|
+
|
10
|
+
// Create Runner with TestsManager
|
11
|
+
const runner = new Runner(config, testsManager, gridUrl);
|
28
12
|
|
29
13
|
await runner.init();
|
30
14
|
|
15
|
+
// Load tests from stories and update TestsManager
|
31
16
|
const tests = await loadTestsFromStories(
|
32
17
|
Object.keys(config.browsers),
|
33
18
|
(listener) => config.storiesProvider(config, listener),
|
34
19
|
(testsDiff) => {
|
35
20
|
runner.updateTests(testsDiff);
|
36
|
-
saveTestsJson(runner.tests, config.reportDir);
|
37
21
|
},
|
38
22
|
);
|
39
23
|
|
40
|
-
|
41
|
-
saveTestsJson(runner.tests, config.reportDir);
|
24
|
+
testsManager.updateTests(testsManager.loadAndMergeTests(tests));
|
42
25
|
|
43
26
|
return runner;
|
44
27
|
}
|
@@ -1,5 +1,3 @@
|
|
1
|
-
import path from 'path';
|
2
|
-
import { copyFile, mkdir } from 'fs/promises';
|
3
1
|
import { EventEmitter } from 'events';
|
4
2
|
import {
|
5
3
|
Config,
|
@@ -10,7 +8,6 @@ import {
|
|
10
8
|
CreeveyUpdate,
|
11
9
|
TestStatus,
|
12
10
|
ServerTest,
|
13
|
-
TestMeta,
|
14
11
|
TEST_EVENTS,
|
15
12
|
FakeSuite,
|
16
13
|
FakeTest,
|
@@ -19,6 +16,7 @@ import Pool from './pool.js';
|
|
19
16
|
import { WorkerQueue } from './queue.js';
|
20
17
|
import { getTestPath } from '../utils.js';
|
21
18
|
import { getReporter } from '../reporters/index.js';
|
19
|
+
import { TestsManager } from './testsManager.js';
|
22
20
|
|
23
21
|
// NOTE: This is workaround to fix parallel tests running with mocha-junit-reporter
|
24
22
|
let isJUnit = false;
|
@@ -33,24 +31,23 @@ class FakeRunner extends EventEmitter {
|
|
33
31
|
|
34
32
|
export default class Runner extends EventEmitter {
|
35
33
|
private failFast: boolean;
|
36
|
-
private screenDir: string;
|
37
|
-
private reportDir: string;
|
38
34
|
private browsers: string[];
|
39
35
|
private scheduler: WorkerQueue;
|
40
36
|
private pools: Record<string, Pool> = {};
|
41
37
|
private fakeRunner: FakeRunner;
|
42
38
|
private config: Config;
|
43
|
-
|
39
|
+
public testsManager: TestsManager;
|
40
|
+
|
44
41
|
public get isRunning(): boolean {
|
45
42
|
return Object.values(this.pools).some((pool) => pool.isRunning);
|
46
43
|
}
|
47
|
-
|
44
|
+
|
45
|
+
constructor(config: Config, testsManager: TestsManager, gridUrl?: string) {
|
48
46
|
super();
|
49
47
|
|
50
48
|
this.config = config;
|
51
49
|
this.failFast = config.failFast;
|
52
|
-
this.
|
53
|
-
this.reportDir = config.reportDir;
|
50
|
+
this.testsManager = testsManager;
|
54
51
|
this.scheduler = new WorkerQueue(config.useWorkerQueue);
|
55
52
|
this.browsers = Object.keys(config.browsers);
|
56
53
|
|
@@ -61,7 +58,7 @@ export default class Runner extends EventEmitter {
|
|
61
58
|
isJUnit = true;
|
62
59
|
}
|
63
60
|
|
64
|
-
new Reporter(runner, { reportDir:
|
61
|
+
new Reporter(runner, { reportDir: config.reportDir, reporterOptions: config.reporterOptions });
|
65
62
|
this.fakeRunner = runner;
|
66
63
|
|
67
64
|
this.browsers
|
@@ -71,10 +68,10 @@ export default class Runner extends EventEmitter {
|
|
71
68
|
|
72
69
|
private handlePoolMessage = (message: { id: string; status: TestStatus; result?: TestResult }): void => {
|
73
70
|
const { id, status, result } = message;
|
74
|
-
const test = this.
|
71
|
+
const test = this.testsManager.getTest(id);
|
75
72
|
|
76
73
|
if (!test) return;
|
77
|
-
const { browser, testName
|
74
|
+
const { browser, testName } = test;
|
78
75
|
|
79
76
|
const fakeSuite: FakeSuite = {
|
80
77
|
title: test.storyPath.slice(0, -1).join('/'),
|
@@ -103,20 +100,14 @@ export default class Runner extends EventEmitter {
|
|
103
100
|
|
104
101
|
fakeSuite.tests.push(fakeTest);
|
105
102
|
|
106
|
-
|
107
|
-
|
103
|
+
const update = this.testsManager.updateTestStatus(id, status, result);
|
104
|
+
if (!update) return;
|
105
|
+
|
108
106
|
if (!result) {
|
109
|
-
// NOTE: Running status
|
110
107
|
this.fakeRunner.emit(TEST_EVENTS.TEST_BEGIN, fakeTest);
|
111
|
-
this.sendUpdate(
|
108
|
+
this.sendUpdate(update);
|
112
109
|
return;
|
113
110
|
}
|
114
|
-
test.results ??= [];
|
115
|
-
test.results.push(result);
|
116
|
-
|
117
|
-
if (status == 'failed') {
|
118
|
-
test.approved = null;
|
119
|
-
}
|
120
111
|
|
121
112
|
const { duration, attachments } = result;
|
122
113
|
|
@@ -146,20 +137,7 @@ export default class Runner extends EventEmitter {
|
|
146
137
|
|
147
138
|
this.fakeRunner.emit(TEST_EVENTS.TEST_END, fakeTest);
|
148
139
|
|
149
|
-
this.sendUpdate(
|
150
|
-
tests: {
|
151
|
-
[id]: {
|
152
|
-
id,
|
153
|
-
browser,
|
154
|
-
testName,
|
155
|
-
storyPath,
|
156
|
-
status: test.status,
|
157
|
-
approved: test.approved,
|
158
|
-
results: [result],
|
159
|
-
storyId,
|
160
|
-
},
|
161
|
-
},
|
162
|
-
});
|
140
|
+
this.sendUpdate(update);
|
163
141
|
|
164
142
|
if (this.failFast && status == 'failed') this.stop();
|
165
143
|
};
|
@@ -177,31 +155,8 @@ export default class Runner extends EventEmitter {
|
|
177
155
|
}
|
178
156
|
|
179
157
|
public updateTests(testsDiff: Partial<Record<string, ServerTest>>): void {
|
180
|
-
const
|
181
|
-
|
182
|
-
Object.entries(testsDiff).forEach(([id, newTest]) => {
|
183
|
-
const oldTest = this.tests[id];
|
184
|
-
if (newTest) {
|
185
|
-
if (oldTest) {
|
186
|
-
this.tests[id] = {
|
187
|
-
...newTest,
|
188
|
-
retries: oldTest.retries,
|
189
|
-
results: oldTest.results,
|
190
|
-
approved: oldTest.approved,
|
191
|
-
};
|
192
|
-
} else this.tests[id] = newTest;
|
193
|
-
|
194
|
-
const { story: _, fn: __, ...restTest } = newTest;
|
195
|
-
tests[id] = { ...restTest, status: 'unknown' };
|
196
|
-
} else if (oldTest) {
|
197
|
-
const { id, browser, testName, storyPath, storyId } = oldTest;
|
198
|
-
removedTests.push({ id, browser, testName, storyPath, storyId });
|
199
|
-
// TODO Use Map instead
|
200
|
-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
201
|
-
delete this.tests[id];
|
202
|
-
}
|
203
|
-
});
|
204
|
-
this.sendUpdate({ tests, removedTests });
|
158
|
+
const update = this.testsManager.updateTests(testsDiff);
|
159
|
+
if (update) this.sendUpdate(update);
|
205
160
|
}
|
206
161
|
|
207
162
|
public start(ids: string[]): void {
|
@@ -209,27 +164,32 @@ export default class Runner extends EventEmitter {
|
|
209
164
|
if (this.isRunning) return;
|
210
165
|
|
211
166
|
const testsToStart = ids
|
212
|
-
.map((id) => this.
|
167
|
+
.map((id) => this.testsManager.getTest(id))
|
213
168
|
.filter(isDefined)
|
214
169
|
.filter((test) => !test.skip);
|
215
170
|
|
216
171
|
if (testsToStart.length == 0) return;
|
217
172
|
|
173
|
+
const pendingTests: CreeveyUpdate['tests'] = testsToStart.reduce(
|
174
|
+
(update: CreeveyUpdate['tests'], { id, storyId, browser, testName, storyPath }) => ({
|
175
|
+
...update,
|
176
|
+
[id]: { id, browser, testName, storyPath, status: 'pending', storyId },
|
177
|
+
}),
|
178
|
+
{},
|
179
|
+
);
|
180
|
+
|
218
181
|
this.sendUpdate({
|
219
182
|
isRunning: true,
|
220
|
-
tests:
|
221
|
-
(update: CreeveyUpdate['tests'], { id, storyId, browser, testName, storyPath }) => ({
|
222
|
-
...update,
|
223
|
-
[id]: { id, browser, testName, storyPath, status: 'pending', storyId },
|
224
|
-
}),
|
225
|
-
{},
|
226
|
-
),
|
183
|
+
tests: pendingTests,
|
227
184
|
});
|
228
185
|
|
229
186
|
const testsByBrowser: Partial<TestsByBrowser> = testsToStart.reduce((tests: Partial<TestsByBrowser>, test) => {
|
230
187
|
const { id, browser, testName, storyPath } = test;
|
231
188
|
const restPath = [...storyPath, testName].filter(isDefined);
|
232
|
-
|
189
|
+
|
190
|
+
// Update status to pending in TestsManager
|
191
|
+
this.testsManager.updateTestStatus(id, 'pending');
|
192
|
+
|
233
193
|
return {
|
234
194
|
...tests,
|
235
195
|
[browser]: [...(tests[browser] ?? []), { id, path: restPath }],
|
@@ -255,78 +215,24 @@ export default class Runner extends EventEmitter {
|
|
255
215
|
}
|
256
216
|
|
257
217
|
public get status(): CreeveyStatus {
|
258
|
-
const tests: CreeveyStatus['tests'] = {};
|
259
|
-
Object.values(this.tests)
|
260
|
-
.filter(isDefined)
|
261
|
-
|
262
|
-
.forEach(({ story: _, fn: __, ...test }) => (tests[test.id] = test));
|
263
218
|
return {
|
264
219
|
isRunning: this.isRunning,
|
265
|
-
tests,
|
220
|
+
tests: this.testsManager.getTestsData(),
|
266
221
|
browsers: this.browsers,
|
222
|
+
isUpdateMode: false,
|
267
223
|
};
|
268
224
|
}
|
269
225
|
|
270
|
-
private async copyImage(test: ServerTest, image: string, actual: string): Promise<void> {
|
271
|
-
const { browser, testName, storyPath } = test;
|
272
|
-
const restPath = [...storyPath, testName].filter(isDefined);
|
273
|
-
const testPath = path.join(...restPath, image == browser ? '' : browser);
|
274
|
-
const srcImagePath = path.join(this.reportDir, testPath, actual);
|
275
|
-
const dstImagePath = path.join(this.screenDir, testPath, `${image}.png`);
|
276
|
-
await mkdir(path.join(this.screenDir, testPath), { recursive: true });
|
277
|
-
await copyFile(srcImagePath, dstImagePath);
|
278
|
-
}
|
279
|
-
|
280
226
|
public async approveAll(): Promise<void> {
|
281
|
-
const
|
282
|
-
|
283
|
-
if (!test?.results) continue;
|
284
|
-
const retry = test.results.length - 1;
|
285
|
-
const { images, status } = test.results.at(retry) ?? {};
|
286
|
-
if (!images || status != 'failed') continue;
|
287
|
-
for (const [name, image] of Object.entries(images)) {
|
288
|
-
if (!image) continue;
|
289
|
-
await this.copyImage(test, name, image.actual);
|
290
|
-
|
291
|
-
test.approved ??= {};
|
292
|
-
test.approved[name] = retry;
|
293
|
-
test.status = 'approved';
|
294
|
-
|
295
|
-
updatedTests[test.id] = {
|
296
|
-
id: test.id,
|
297
|
-
browser: test.browser,
|
298
|
-
storyPath: test.storyPath,
|
299
|
-
storyId: test.storyId,
|
300
|
-
status: test.status,
|
301
|
-
approved: { [name]: retry },
|
302
|
-
};
|
303
|
-
}
|
304
|
-
}
|
305
|
-
this.sendUpdate({ tests: updatedTests });
|
227
|
+
const update = await this.testsManager.approveAll();
|
228
|
+
this.sendUpdate(update);
|
306
229
|
}
|
307
230
|
|
308
|
-
public async approve(
|
309
|
-
const
|
310
|
-
if (
|
311
|
-
const result = test.results[retry];
|
312
|
-
if (!result.images) return;
|
313
|
-
const images = result.images[image];
|
314
|
-
if (!images) return;
|
315
|
-
test.approved ??= {};
|
316
|
-
const { browser, testName, storyPath, storyId } = test;
|
317
|
-
|
318
|
-
await this.copyImage(test, image, images.actual);
|
319
|
-
|
320
|
-
test.approved[image] = retry;
|
321
|
-
|
322
|
-
if (Object.keys(result.images).every((name) => typeof test.approved?.[name] == 'number')) {
|
323
|
-
test.status = 'approved';
|
324
|
-
}
|
325
|
-
|
326
|
-
this.sendUpdate({
|
327
|
-
tests: { [id]: { id, browser, testName, storyPath, status: test.status, approved: { [image]: retry }, storyId } },
|
328
|
-
});
|
231
|
+
public async approve(payload: ApprovePayload): Promise<void> {
|
232
|
+
const update = await this.testsManager.approve(payload);
|
233
|
+
if (update) this.sendUpdate(update);
|
329
234
|
}
|
235
|
+
|
330
236
|
private sendUpdate(data: CreeveyUpdate): void {
|
331
237
|
this.emit('update', data);
|
332
238
|
}
|