creevey 0.10.0-beta.43 → 0.10.0-beta.45
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/withCreevey.js +1 -18
- 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 +12 -5
- package/dist/server/index.js.map +1 -1
- package/dist/server/master/api.d.ts +11 -6
- package/dist/server/master/api.js +88 -25
- package/dist/server/master/api.js.map +1 -1
- package/dist/server/master/handlers/capture-handler.d.ts +5 -0
- package/dist/server/master/handlers/capture-handler.js +25 -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 +8 -0
- package/dist/server/master/handlers/ping-handler.js.map +1 -0
- package/dist/server/master/handlers/static-handler.d.ts +1 -0
- package/dist/server/master/handlers/static-handler.js +22 -0
- package/dist/server/master/handlers/static-handler.js.map +1 -0
- package/dist/server/master/handlers/stories-handler.d.ts +4 -0
- package/dist/server/master/handlers/stories-handler.js +24 -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 +191 -89
- 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/docker-file.js +2 -2
- package/dist/server/playwright/docker-file.js.map +1 -1
- 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 +10 -14
- package/src/client/addon/controller.ts +1 -1
- package/src/client/addon/withCreevey.ts +2 -16
- 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 +13 -6
- package/src/server/master/api.ts +94 -28
- package/src/server/master/handlers/capture-handler.ts +20 -0
- package/src/server/master/handlers/index.ts +4 -0
- package/src/server/master/handlers/ping-handler.ts +6 -0
- package/src/server/master/handlers/static-handler.ts +18 -0
- package/src/server/master/handlers/stories-handler.ts +20 -0
- package/src/server/master/master.ts +10 -27
- package/src/server/master/runner.ts +38 -132
- package/src/server/master/server.ts +210 -98
- package/src/server/master/start.ts +17 -41
- package/src/server/master/testsManager.ts +315 -0
- package/src/server/playwright/docker-file.ts +2 -2
- 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
@@ -1,41 +1,14 @@
|
|
1
1
|
import path from 'path';
|
2
2
|
import { existsSync } from 'fs';
|
3
|
-
import { fileURLToPath, pathToFileURL } from 'url';
|
4
|
-
import { copyFile, readdir, mkdir, writeFile } from 'fs/promises';
|
5
3
|
import master from './master.js';
|
6
|
-
import
|
7
|
-
import { Config, Options,
|
8
|
-
import { shutdownWorkers, testsToImages, readDirRecursive } from '../utils.js';
|
4
|
+
import { CreeveyApi } from './api.js';
|
5
|
+
import { Config, Options, isDefined } from '../../types.js';
|
6
|
+
import { shutdownWorkers, testsToImages, readDirRecursive, copyStatics } from '../utils.js';
|
9
7
|
import { subscribeOn } from '../messages.js';
|
10
8
|
import Runner from './runner.js';
|
11
9
|
import { logger } from '../logger.js';
|
12
10
|
import { sendScreenshotsCount } from '../telemetry.js';
|
13
|
-
|
14
|
-
const importMetaUrl = pathToFileURL(__filename).href;
|
15
|
-
|
16
|
-
async function copyStatics(reportDir: string): Promise<void> {
|
17
|
-
const clientDir = path.join(path.dirname(fileURLToPath(importMetaUrl)), '../../../dist/client/web');
|
18
|
-
const assets = (await readdir(path.join(clientDir, 'assets'), { withFileTypes: true }))
|
19
|
-
.filter((dirent) => dirent.isFile())
|
20
|
-
.map((dirent) => dirent.name);
|
21
|
-
await mkdir(path.join(reportDir, 'assets'), { recursive: true });
|
22
|
-
await copyFile(path.join(clientDir, 'index.html'), path.join(reportDir, 'index.html'));
|
23
|
-
for (const asset of assets) {
|
24
|
-
await copyFile(path.join(clientDir, 'assets', asset), path.join(reportDir, 'assets', asset));
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
function reportDataModule(data: Partial<Record<string, TestData>>): string {
|
29
|
-
return `
|
30
|
-
(function (root, factory) {
|
31
|
-
if (typeof module === 'object' && module.exports) {
|
32
|
-
module.exports = factory();
|
33
|
-
} else {
|
34
|
-
root.__CREEVEY_DATA__ = factory();
|
35
|
-
}
|
36
|
-
}(this, function () { return ${JSON.stringify(data)} }));
|
37
|
-
`;
|
38
|
-
}
|
11
|
+
import { start as startServer } from './server.js';
|
39
12
|
|
40
13
|
function outputUnnecessaryImages(imagesDir: string, images: Set<string>): void {
|
41
14
|
if (!existsSync(imagesDir)) return;
|
@@ -50,12 +23,9 @@ function outputUnnecessaryImages(imagesDir: string, images: Set<string>): void {
|
|
50
23
|
}
|
51
24
|
}
|
52
25
|
|
53
|
-
export async function start(
|
54
|
-
|
55
|
-
|
56
|
-
options: Options,
|
57
|
-
resolveApi: (api: CreeveyApi) => void,
|
58
|
-
): Promise<void> {
|
26
|
+
export async function start(gridUrl: string | undefined, config: Config, options: Options): Promise<void> {
|
27
|
+
const resolveApi = startServer(config.reportDir, options.port, options.ui);
|
28
|
+
|
59
29
|
let runner: Runner | null = null;
|
60
30
|
if (config.hooks.before) {
|
61
31
|
await config.hooks.before();
|
@@ -78,13 +48,19 @@ export async function start(
|
|
78
48
|
runner = await master(config, gridUrl);
|
79
49
|
|
80
50
|
runner.on('stop', () => {
|
81
|
-
void copyStatics(config.reportDir).then(() =>
|
82
|
-
writeFile(path.join(config.reportDir, 'data.js'), reportDataModule(runner.status.tests)),
|
83
|
-
);
|
51
|
+
void copyStatics(config.reportDir).then(() => runner.testsManager.saveTestData());
|
84
52
|
});
|
85
53
|
|
86
54
|
if (options.ui) {
|
87
|
-
|
55
|
+
// Initialize TestsManager
|
56
|
+
const testsManager = runner.testsManager;
|
57
|
+
|
58
|
+
// Create the CreeveyApi instance using the existing runner
|
59
|
+
const api = new CreeveyApi(testsManager, runner);
|
60
|
+
|
61
|
+
// Resolve the API for the server
|
62
|
+
resolveApi(api);
|
63
|
+
|
88
64
|
logger().info(`Started on http://localhost:${options.port}`);
|
89
65
|
} else {
|
90
66
|
if (Object.values(runner.status.tests).filter((test) => test && !test.skip).length == 0) {
|
@@ -0,0 +1,315 @@
|
|
1
|
+
import path from 'path';
|
2
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
3
|
+
import EventEmitter from 'events';
|
4
|
+
import {
|
5
|
+
ServerTest,
|
6
|
+
TestMeta,
|
7
|
+
TestResult,
|
8
|
+
TestStatus,
|
9
|
+
CreeveyUpdate,
|
10
|
+
ApprovePayload,
|
11
|
+
isDefined,
|
12
|
+
isFunction,
|
13
|
+
CreeveyStatus,
|
14
|
+
} from '../../types.js';
|
15
|
+
import { tryToLoadTestsData } from '../utils.js';
|
16
|
+
import { copyFile, mkdir, writeFile } from 'fs/promises';
|
17
|
+
|
18
|
+
/**
|
19
|
+
* TestsManager is responsible for all operations related to test data management
|
20
|
+
* including loading, saving, merging, and updating test data.
|
21
|
+
* It extends EventEmitter to emit update events that can be subscribed to.
|
22
|
+
*/
|
23
|
+
export class TestsManager extends EventEmitter {
|
24
|
+
private tests: Partial<Record<string, ServerTest>> = {};
|
25
|
+
private screenDir: string;
|
26
|
+
private reportDir: string;
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Creates a new TestsManager instance
|
30
|
+
* @param screenDir Directory for storing reference images
|
31
|
+
* @param reportDir Directory for storing reports and screenshots
|
32
|
+
*/
|
33
|
+
constructor(screenDir: string, reportDir: string) {
|
34
|
+
super();
|
35
|
+
this.screenDir = screenDir;
|
36
|
+
this.reportDir = reportDir;
|
37
|
+
}
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Get a copy of all tests
|
41
|
+
* @returns all tests
|
42
|
+
*/
|
43
|
+
public getTests(): Partial<Record<string, ServerTest>> {
|
44
|
+
return this.tests;
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Get a test by ID
|
49
|
+
* @param id Test ID
|
50
|
+
* @returns Test data
|
51
|
+
*/
|
52
|
+
public getTest(id: string): ServerTest | undefined {
|
53
|
+
return this.tests[id];
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Get test data in a format suitable for status reporting
|
58
|
+
* @returns Test data in the format needed for status
|
59
|
+
*/
|
60
|
+
public getTestsData(): CreeveyStatus['tests'] {
|
61
|
+
const testsData: CreeveyStatus['tests'] = {};
|
62
|
+
|
63
|
+
Object.entries(this.tests).forEach(([id, test]) => {
|
64
|
+
if (!test) return;
|
65
|
+
|
66
|
+
const { story: _, fn: __, ...testData } = test;
|
67
|
+
testsData[id] = testData;
|
68
|
+
});
|
69
|
+
|
70
|
+
return testsData;
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Load tests from a report file
|
75
|
+
*/
|
76
|
+
public loadTestsFromReport(): Partial<Record<string, ServerTest>> {
|
77
|
+
const reportDataPath = path.join(this.reportDir, 'data.js');
|
78
|
+
const testsFromReport = tryToLoadTestsData(reportDataPath) ?? {};
|
79
|
+
return testsFromReport;
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Merge tests from report with tests from stories
|
84
|
+
*/
|
85
|
+
private mergeTests(
|
86
|
+
testsWithReports: CreeveyStatus['tests'],
|
87
|
+
testsFromStories: Partial<Record<string, ServerTest>>,
|
88
|
+
): Partial<Record<string, ServerTest>> {
|
89
|
+
Object.values(testsFromStories)
|
90
|
+
.filter(isDefined)
|
91
|
+
.forEach((test) => {
|
92
|
+
const testWithReport = testsWithReports[test.id];
|
93
|
+
if (!testWithReport) return;
|
94
|
+
test.retries = testWithReport.retries;
|
95
|
+
if (testWithReport.status === 'success' || testWithReport.status === 'failed') {
|
96
|
+
test.status = testWithReport.status;
|
97
|
+
}
|
98
|
+
test.results = testWithReport.results;
|
99
|
+
test.approved = testWithReport.approved;
|
100
|
+
});
|
101
|
+
|
102
|
+
return testsFromStories;
|
103
|
+
}
|
104
|
+
|
105
|
+
public loadAndMergeTests(testsFromStories: Partial<Record<string, ServerTest>>): Partial<Record<string, ServerTest>> {
|
106
|
+
const testsFromReport = this.loadTestsFromReport();
|
107
|
+
|
108
|
+
return this.mergeTests(testsFromReport, testsFromStories);
|
109
|
+
}
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Update tests with incremental changes
|
113
|
+
* @param testsDiff Tests to update or remove
|
114
|
+
*/
|
115
|
+
public updateTests(testsDiff: Partial<Record<string, ServerTest>>): CreeveyUpdate | null {
|
116
|
+
const tests: CreeveyUpdate['tests'] = {};
|
117
|
+
const removedTests: TestMeta[] = [];
|
118
|
+
|
119
|
+
Object.entries(testsDiff).forEach(([id, newTest]) => {
|
120
|
+
if (newTest) {
|
121
|
+
if (this.tests[id]) {
|
122
|
+
this.tests[id] = {
|
123
|
+
...newTest,
|
124
|
+
retries: this.tests[id].retries,
|
125
|
+
results: this.tests[id].results,
|
126
|
+
approved: this.tests[id].approved,
|
127
|
+
};
|
128
|
+
} else {
|
129
|
+
this.tests[id] = newTest;
|
130
|
+
}
|
131
|
+
|
132
|
+
const { story: _, fn: __, ...restTest } = newTest;
|
133
|
+
tests[id] = { ...restTest, status: 'unknown' };
|
134
|
+
} else if (this.tests[id]) {
|
135
|
+
const { id: testId, browser, testName, storyPath, storyId } = this.tests[id];
|
136
|
+
removedTests.push({ id: testId, browser, testName, storyPath, storyId });
|
137
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
138
|
+
delete this.tests[id];
|
139
|
+
}
|
140
|
+
});
|
141
|
+
|
142
|
+
this.saveTestsToJson();
|
143
|
+
|
144
|
+
const update = { tests, removedTests };
|
145
|
+
this.emit('update', update);
|
146
|
+
return update;
|
147
|
+
}
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Update test result
|
151
|
+
* @param id Test ID
|
152
|
+
* @param status New test status
|
153
|
+
* @param result Optional test result
|
154
|
+
*/
|
155
|
+
public updateTestStatus(id: string, status: TestStatus, result?: TestResult): CreeveyUpdate | null {
|
156
|
+
// TODO Handle 'retrying' status
|
157
|
+
const test = this.tests[id];
|
158
|
+
if (!test) return null;
|
159
|
+
|
160
|
+
const { browser, testName, storyPath, storyId } = test;
|
161
|
+
test.status = status === 'retrying' ? 'failed' : status;
|
162
|
+
|
163
|
+
if (!result) {
|
164
|
+
// NOTE: Running status
|
165
|
+
const update = { tests: { [id]: { id, browser, testName, storyPath, status, storyId } } };
|
166
|
+
this.emit('update', update);
|
167
|
+
return update;
|
168
|
+
}
|
169
|
+
|
170
|
+
test.results ??= [];
|
171
|
+
test.results.push(result);
|
172
|
+
|
173
|
+
if (status === 'failed') {
|
174
|
+
test.approved = null;
|
175
|
+
}
|
176
|
+
|
177
|
+
const update = {
|
178
|
+
tests: {
|
179
|
+
[id]: {
|
180
|
+
id,
|
181
|
+
browser,
|
182
|
+
testName,
|
183
|
+
storyPath,
|
184
|
+
status,
|
185
|
+
approved: test.approved,
|
186
|
+
results: [result],
|
187
|
+
storyId,
|
188
|
+
},
|
189
|
+
},
|
190
|
+
};
|
191
|
+
|
192
|
+
this.emit('update', update);
|
193
|
+
return update;
|
194
|
+
}
|
195
|
+
|
196
|
+
/**
|
197
|
+
* Save tests to JSON file
|
198
|
+
* @param reportDir Directory to save the JSON file
|
199
|
+
*/
|
200
|
+
public saveTestsToJson(): void {
|
201
|
+
mkdirSync(this.reportDir, { recursive: true });
|
202
|
+
writeFileSync(
|
203
|
+
path.join(this.reportDir, 'tests.json'),
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
205
|
+
JSON.stringify(this.tests, (_, value) => (isFunction(value) ? value.toString() : value), 2),
|
206
|
+
);
|
207
|
+
}
|
208
|
+
|
209
|
+
/**
|
210
|
+
* Save test data to a module
|
211
|
+
* @param data Test data to include in the module
|
212
|
+
*/
|
213
|
+
public async saveTestData(data: CreeveyStatus['tests'] = this.getTestsData()): Promise<void> {
|
214
|
+
const dataModule = `
|
215
|
+
(function (root, factory) {
|
216
|
+
if (typeof module === 'object' && module.exports) {
|
217
|
+
module.exports = factory();
|
218
|
+
} else {
|
219
|
+
root.__CREEVEY_DATA__ = factory();
|
220
|
+
}
|
221
|
+
}(this, function () { return ${JSON.stringify(data)} }));
|
222
|
+
`;
|
223
|
+
await writeFile(path.join(this.reportDir, 'data.js'), dataModule);
|
224
|
+
}
|
225
|
+
|
226
|
+
/**
|
227
|
+
* Copy image for approval
|
228
|
+
* @param test Test data
|
229
|
+
* @param image Image name
|
230
|
+
* @param actual Actual image path
|
231
|
+
*/
|
232
|
+
private async copyImage(test: ServerTest, image: string, actual: string): Promise<void> {
|
233
|
+
const { browser, testName, storyPath } = test;
|
234
|
+
const restPath = [...storyPath, testName].filter(isDefined);
|
235
|
+
const testPath = path.join(...restPath, image == browser ? '' : browser);
|
236
|
+
const srcImagePath = path.join(this.reportDir, testPath, actual);
|
237
|
+
const dstImagePath = path.join(this.screenDir, testPath, `${image}.png`);
|
238
|
+
await mkdir(path.join(this.screenDir, testPath), { recursive: true });
|
239
|
+
await copyFile(srcImagePath, dstImagePath);
|
240
|
+
}
|
241
|
+
|
242
|
+
/**
|
243
|
+
* Approve a specific test
|
244
|
+
* @param payload Approval payload with test ID, retry index, and image name
|
245
|
+
*/
|
246
|
+
public async approve({ id, retry, image }: ApprovePayload): Promise<CreeveyUpdate | null> {
|
247
|
+
const test = this.tests[id];
|
248
|
+
if (!test?.results) return null;
|
249
|
+
const result = test.results[retry];
|
250
|
+
if (!result.images) return null;
|
251
|
+
const images = result.images[image];
|
252
|
+
if (!images) return null;
|
253
|
+
test.approved ??= {};
|
254
|
+
const { browser, testName, storyPath, storyId } = test;
|
255
|
+
|
256
|
+
await this.copyImage(test, image, images.actual);
|
257
|
+
|
258
|
+
test.approved[image] = retry;
|
259
|
+
|
260
|
+
if (Object.keys(result.images).every((name) => typeof test.approved?.[name] == 'number')) {
|
261
|
+
test.status = 'approved';
|
262
|
+
}
|
263
|
+
|
264
|
+
const update = {
|
265
|
+
tests: {
|
266
|
+
[id]: {
|
267
|
+
id,
|
268
|
+
browser,
|
269
|
+
testName,
|
270
|
+
storyPath,
|
271
|
+
status: test.status,
|
272
|
+
approved: test.approved,
|
273
|
+
storyId,
|
274
|
+
},
|
275
|
+
},
|
276
|
+
};
|
277
|
+
|
278
|
+
this.emit('update', update);
|
279
|
+
return update;
|
280
|
+
}
|
281
|
+
|
282
|
+
/**
|
283
|
+
* Approve all failed tests
|
284
|
+
*/
|
285
|
+
public async approveAll(): Promise<CreeveyUpdate> {
|
286
|
+
const updatedTests: NonNullable<CreeveyUpdate['tests']> = {};
|
287
|
+
for (const test of Object.values(this.tests)) {
|
288
|
+
if (!test?.results) continue;
|
289
|
+
const retry = test.results.length - 1;
|
290
|
+
const { images, status } = test.results.at(retry) ?? {};
|
291
|
+
if (!images || status != 'failed') continue;
|
292
|
+
for (const [name, image] of Object.entries(images)) {
|
293
|
+
if (!image) continue;
|
294
|
+
await this.copyImage(test, name, image.actual);
|
295
|
+
|
296
|
+
test.approved ??= {};
|
297
|
+
test.approved[name] = retry;
|
298
|
+
test.status = 'approved';
|
299
|
+
|
300
|
+
updatedTests[test.id] = {
|
301
|
+
id: test.id,
|
302
|
+
browser: test.browser,
|
303
|
+
storyPath: test.storyPath,
|
304
|
+
storyId: test.storyId,
|
305
|
+
status: test.status,
|
306
|
+
approved: { [name]: retry },
|
307
|
+
};
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
const result = { tests: updatedTests };
|
312
|
+
this.emit('update', result);
|
313
|
+
return result;
|
314
|
+
}
|
315
|
+
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { readFile } from 'fs/promises';
|
2
2
|
import { pathToFileURL } from 'url';
|
3
3
|
import semver from 'semver';
|
4
|
-
import
|
4
|
+
import sh from 'shelljs';
|
5
5
|
|
6
6
|
const importMetaUrl = pathToFileURL(__filename).href;
|
7
7
|
|
@@ -11,7 +11,7 @@ export async function playwrightDockerFile(browser: string, version: string): Pr
|
|
11
11
|
|
12
12
|
let npmRegistry;
|
13
13
|
try {
|
14
|
-
npmRegistry = exec('npm config get registry', { silent: true }).stdout.trim();
|
14
|
+
npmRegistry = sh.exec('npm config get registry', { silent: true }).stdout.trim();
|
15
15
|
} catch {
|
16
16
|
/* noop */
|
17
17
|
}
|