creevey 0.10.0-beta.4 → 0.10.0-beta.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -41
- package/dist/client/addon/components/Addon.js +17 -7
- package/dist/client/addon/components/Addon.js.map +1 -1
- package/dist/client/addon/components/Panel.js +2 -2
- package/dist/client/addon/components/Panel.js.map +1 -1
- package/dist/client/addon/components/Tools.js +17 -7
- package/dist/client/addon/components/Tools.js.map +1 -1
- package/dist/client/addon/withCreevey.d.ts +2 -1
- package/dist/client/addon/withCreevey.js +11 -1
- package/dist/client/addon/withCreevey.js.map +1 -1
- package/dist/client/shared/components/ImagesView/BlendView.d.ts +1 -1
- package/dist/client/shared/components/ImagesView/BlendView.js +17 -7
- package/dist/client/shared/components/ImagesView/BlendView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SideBySideView.d.ts +1 -1
- package/dist/client/shared/components/ImagesView/SideBySideView.js +17 -7
- package/dist/client/shared/components/ImagesView/SideBySideView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SlideView.d.ts +1 -1
- package/dist/client/shared/components/ImagesView/SlideView.js +17 -7
- package/dist/client/shared/components/ImagesView/SlideView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SwapView.d.ts +1 -1
- package/dist/client/shared/components/ImagesView/SwapView.js +29 -7
- package/dist/client/shared/components/ImagesView/SwapView.js.map +1 -1
- package/dist/client/shared/components/PageHeader/ImagePreview.d.ts +1 -1
- package/dist/client/shared/components/PageHeader/ImagePreview.js +1 -0
- package/dist/client/shared/components/PageHeader/ImagePreview.js.map +1 -1
- package/dist/client/shared/components/PageHeader/PageHeader.js +20 -8
- package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
- package/dist/client/shared/components/ResultsPage.d.ts +1 -1
- package/dist/client/shared/components/ResultsPage.js +43 -13
- package/dist/client/shared/components/ResultsPage.js.map +1 -1
- package/dist/client/shared/creeveyClientApi.js +8 -1
- package/dist/client/shared/creeveyClientApi.js.map +1 -1
- package/dist/client/shared/helpers.d.ts +1 -3
- package/dist/client/shared/helpers.js +4 -19
- package/dist/client/shared/helpers.js.map +1 -1
- package/dist/client/web/CreeveyApp.js +42 -14
- package/dist/client/web/CreeveyApp.js.map +1 -1
- package/dist/client/web/CreeveyContext.d.ts +5 -0
- package/dist/client/web/CreeveyContext.js +20 -7
- package/dist/client/web/CreeveyContext.js.map +1 -1
- package/dist/client/web/CreeveyLoader.js +2 -2
- package/dist/client/web/CreeveyLoader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Search.js +19 -9
- package/dist/client/web/CreeveyView/SideBar/Search.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBar.js +18 -7
- package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +60 -7
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +17 -7
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.d.ts +2 -2
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +18 -10
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestLink.js +18 -10
- package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.d.ts +1 -1
- package/dist/client/web/KeyboardEventsContext.d.ts +1 -8
- package/dist/client/web/KeyboardEventsContext.js +79 -64
- package/dist/client/web/KeyboardEventsContext.js.map +1 -1
- package/dist/client/web/assets/index-B0Xv0lOY.js +802 -0
- package/dist/client/web/index.html +1 -1
- package/dist/client/web/index.js +17 -7
- package/dist/client/web/index.js.map +1 -1
- package/dist/client/web/themes.d.ts +2 -0
- package/dist/client/web/themes.js +22 -0
- package/dist/client/web/themes.js.map +1 -0
- package/dist/creevey.js +16 -9
- package/dist/creevey.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/server/config.d.ts +1 -1
- package/dist/server/config.js +27 -5
- package/dist/server/config.js.map +1 -1
- package/dist/server/connection.d.ts +3 -0
- package/dist/server/connection.js +28 -0
- package/dist/server/connection.js.map +1 -0
- package/dist/server/docker.d.ts +1 -1
- package/dist/server/docker.js +56 -32
- package/dist/server/docker.js.map +1 -1
- package/dist/server/index.js +64 -11
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.d.ts +2 -1
- package/dist/server/logger.js +7 -3
- package/dist/server/logger.js.map +1 -1
- package/dist/server/master/api.js +1 -1
- package/dist/server/master/api.js.map +1 -1
- package/dist/server/master/pool.d.ts +4 -3
- package/dist/server/master/pool.js +13 -66
- package/dist/server/master/pool.js.map +1 -1
- package/dist/server/master/queue.d.ts +13 -0
- package/dist/server/master/queue.js +71 -0
- package/dist/server/master/queue.js.map +1 -0
- package/dist/server/master/runner.d.ts +3 -0
- package/dist/server/master/runner.js +76 -10
- package/dist/server/master/runner.js.map +1 -1
- package/dist/server/master/server.js +1 -1
- package/dist/server/master/server.js.map +1 -1
- package/dist/server/master/start.js +13 -11
- package/dist/server/master/start.js.map +1 -1
- package/dist/server/playwright/docker-file.d.ts +1 -1
- package/dist/server/playwright/docker-file.js +15 -6
- package/dist/server/playwright/docker-file.js.map +1 -1
- package/dist/server/playwright/docker.d.ts +2 -1
- package/dist/server/playwright/docker.js +10 -2
- package/dist/server/playwright/docker.js.map +1 -1
- package/dist/server/playwright/index-source.mjs +16 -0
- package/dist/server/playwright/internal.d.ts +6 -6
- package/dist/server/playwright/internal.js +143 -91
- package/dist/server/playwright/internal.js.map +1 -1
- package/dist/server/playwright/webdriver.d.ts +1 -1
- package/dist/server/playwright/webdriver.js +5 -8
- package/dist/server/playwright/webdriver.js.map +1 -1
- package/dist/server/providers/browser.js +6 -4
- package/dist/server/providers/browser.js.map +1 -1
- package/dist/server/providers/hybrid.js +1 -1
- package/dist/server/providers/hybrid.js.map +1 -1
- package/dist/server/reporter.d.ts +4 -19
- package/dist/server/reporter.js +30 -21
- package/dist/server/reporter.js.map +1 -1
- package/dist/server/selenium/internal.d.ts +3 -4
- package/dist/server/selenium/internal.js +127 -108
- package/dist/server/selenium/internal.js.map +1 -1
- package/dist/server/selenium/selenoid.js +8 -6
- package/dist/server/selenium/selenoid.js.map +1 -1
- package/dist/server/selenium/webdriver.d.ts +1 -1
- package/dist/server/selenium/webdriver.js +5 -9
- package/dist/server/selenium/webdriver.js.map +1 -1
- package/dist/server/telemetry.js +2 -2
- package/dist/server/testsFiles/parser.js +45 -5
- package/dist/server/testsFiles/parser.js.map +1 -1
- package/dist/server/utils.d.ts +19 -1
- package/dist/server/utils.js +87 -8
- package/dist/server/utils.js.map +1 -1
- package/dist/server/webdriver.d.ts +5 -4
- package/dist/server/webdriver.js +23 -10
- package/dist/server/webdriver.js.map +1 -1
- package/dist/server/worker/chai-image.d.ts +1 -2
- package/dist/server/worker/chai-image.js +4 -3
- package/dist/server/worker/chai-image.js.map +1 -1
- package/dist/server/worker/context.d.ts +3 -0
- package/dist/server/worker/context.js +15 -0
- package/dist/server/worker/context.js.map +1 -0
- package/dist/server/worker/match-image.d.ts +4 -4
- package/dist/server/worker/match-image.js +7 -4
- package/dist/server/worker/match-image.js.map +1 -1
- package/dist/server/worker/start.js +45 -73
- package/dist/server/worker/start.js.map +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/types.d.ts +40 -8
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/docs/cli.md +12 -0
- package/docs/config.md +179 -165
- package/docs/storybook.md +60 -0
- package/docs/tests.md +50 -45
- package/package.json +64 -63
- package/src/client/addon/components/Panel.tsx +2 -2
- package/src/client/addon/withCreevey.ts +10 -2
- package/src/client/shared/components/ImagesView/SwapView.tsx +18 -0
- package/src/client/shared/components/PageHeader/ImagePreview.tsx +1 -0
- package/src/client/shared/components/PageHeader/PageHeader.tsx +4 -2
- package/src/client/shared/components/ResultsPage.tsx +31 -8
- package/src/client/shared/creeveyClientApi.ts +9 -1
- package/src/client/shared/helpers.ts +4 -24
- package/src/client/web/CreeveyApp.tsx +27 -8
- package/src/client/web/CreeveyContext.tsx +9 -0
- package/src/client/web/CreeveyLoader.tsx +1 -1
- package/src/client/web/CreeveyView/SideBar/Search.tsx +3 -3
- package/src/client/web/CreeveyView/SideBar/SideBar.tsx +1 -0
- package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +37 -6
- package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +3 -5
- package/src/client/web/CreeveyView/SideBar/TestLink.tsx +2 -4
- package/src/client/web/KeyboardEventsContext.tsx +61 -73
- package/src/client/web/themes.ts +24 -0
- package/src/creevey.ts +16 -10
- package/src/server/config.ts +28 -6
- package/src/server/connection.ts +26 -0
- package/src/server/docker.ts +63 -34
- package/src/server/index.ts +72 -14
- package/src/server/logger.ts +6 -2
- package/src/server/master/api.ts +1 -1
- package/src/server/master/pool.ts +23 -59
- package/src/server/master/queue.ts +77 -0
- package/src/server/master/runner.ts +94 -10
- package/src/server/master/server.ts +1 -1
- package/src/server/master/start.ts +16 -11
- package/src/server/playwright/docker-file.ts +18 -6
- package/src/server/playwright/docker.ts +16 -3
- package/src/server/playwright/index-source.mjs +16 -0
- package/src/server/playwright/internal.ts +182 -111
- package/src/server/playwright/webdriver.ts +6 -9
- package/src/server/providers/browser.ts +6 -4
- package/src/server/providers/hybrid.ts +1 -1
- package/src/server/reporter.ts +37 -34
- package/src/server/selenium/internal.ts +131 -116
- package/src/server/selenium/selenoid.ts +8 -6
- package/src/server/selenium/webdriver.ts +6 -10
- package/src/server/telemetry.ts +2 -2
- package/src/server/testsFiles/parser.ts +52 -4
- package/src/server/utils.ts +97 -9
- package/src/server/webdriver.ts +24 -16
- package/src/server/worker/chai-image.ts +4 -4
- package/src/server/worker/context.ts +14 -0
- package/src/server/worker/match-image.ts +12 -8
- package/src/server/worker/start.ts +49 -86
- package/src/shared/index.ts +1 -1
- package/src/types.ts +44 -8
- package/types/global.d.ts +1 -0
- package/.yarnrc.yml +0 -1
- package/chromatic.config.json +0 -5
- package/dist/client/web/assets/index-DkmZfG9C.js +0 -591
@@ -11,15 +11,34 @@ import {
|
|
11
11
|
TestStatus,
|
12
12
|
ServerTest,
|
13
13
|
TestMeta,
|
14
|
+
TEST_EVENTS,
|
15
|
+
FakeSuite,
|
16
|
+
FakeTest,
|
14
17
|
} from '../../types.js';
|
15
18
|
import Pool from './pool.js';
|
19
|
+
import { WorkerQueue } from './queue.js';
|
20
|
+
import { getTestPath } from '../utils.js';
|
21
|
+
|
22
|
+
// NOTE: This is workaround to fix parallel tests running with mocha-junit-reporter
|
23
|
+
let isJUnit = false;
|
24
|
+
|
25
|
+
class FakeRunner extends EventEmitter {
|
26
|
+
public stats = {
|
27
|
+
duration: 0,
|
28
|
+
failures: 0,
|
29
|
+
pending: 0,
|
30
|
+
};
|
31
|
+
}
|
16
32
|
|
17
33
|
export default class Runner extends EventEmitter {
|
18
34
|
private failFast: boolean;
|
19
35
|
private screenDir: string;
|
20
36
|
private reportDir: string;
|
21
37
|
private browsers: string[];
|
38
|
+
private scheduler: WorkerQueue;
|
22
39
|
private pools: Record<string, Pool> = {};
|
40
|
+
private fakeRunner: FakeRunner;
|
41
|
+
private config: Config;
|
23
42
|
tests: Partial<Record<string, ServerTest>> = {};
|
24
43
|
public get isRunning(): boolean {
|
25
44
|
return Object.values(this.pools).some((pool) => pool.isRunning);
|
@@ -27,12 +46,25 @@ export default class Runner extends EventEmitter {
|
|
27
46
|
constructor(config: Config, gridUrl?: string) {
|
28
47
|
super();
|
29
48
|
|
49
|
+
this.config = config;
|
30
50
|
this.failFast = config.failFast;
|
31
51
|
this.screenDir = config.screenDir;
|
32
52
|
this.reportDir = config.reportDir;
|
53
|
+
this.scheduler = new WorkerQueue(config.useWorkerQueue);
|
33
54
|
this.browsers = Object.keys(config.browsers);
|
55
|
+
|
56
|
+
const runner = new FakeRunner();
|
57
|
+
const Reporter = config.reporter;
|
58
|
+
|
59
|
+
if (Reporter.name == 'MochaJUnitReporter') {
|
60
|
+
isJUnit = true;
|
61
|
+
}
|
62
|
+
|
63
|
+
new Reporter(runner, { reporterOptions: config.reporterOptions });
|
64
|
+
this.fakeRunner = runner;
|
65
|
+
|
34
66
|
this.browsers
|
35
|
-
.map((browser) => (this.pools[browser] = new Pool(config, browser, gridUrl)))
|
67
|
+
.map((browser) => (this.pools[browser] = new Pool(this.scheduler, config, browser, gridUrl)))
|
36
68
|
.map((pool) => pool.on('test', this.handlePoolMessage));
|
37
69
|
}
|
38
70
|
|
@@ -42,22 +74,76 @@ export default class Runner extends EventEmitter {
|
|
42
74
|
|
43
75
|
if (!test) return;
|
44
76
|
const { browser, testName, storyPath, storyId } = test;
|
77
|
+
|
78
|
+
const fakeSuite: FakeSuite = {
|
79
|
+
title: test.storyPath.slice(0, -1).join('/'),
|
80
|
+
fullTitle: () => fakeSuite.title,
|
81
|
+
titlePath: () => [fakeSuite.title],
|
82
|
+
tests: [],
|
83
|
+
};
|
84
|
+
|
85
|
+
const fakeTest: FakeTest = {
|
86
|
+
parent: fakeSuite,
|
87
|
+
title: [test.story.name, testName, browser].filter(isDefined).join('/'),
|
88
|
+
fullTitle: () => getTestPath(test).join('/'),
|
89
|
+
titlePath: () => getTestPath(test),
|
90
|
+
currentRetry: () => result?.retries,
|
91
|
+
retires: () => this.config.maxRetries,
|
92
|
+
slow: () => 1000,
|
93
|
+
creevey: {
|
94
|
+
reportDir: this.reportDir,
|
95
|
+
sessionId: result?.sessionId ?? id,
|
96
|
+
browserName: browser,
|
97
|
+
willRetry: (result?.retries ?? 0) < this.config.maxRetries,
|
98
|
+
images: result?.images ?? {},
|
99
|
+
},
|
100
|
+
};
|
101
|
+
|
102
|
+
fakeSuite.tests.push(fakeTest);
|
103
|
+
|
45
104
|
// TODO Handle 'retrying' status
|
46
105
|
test.status = status == 'retrying' ? 'failed' : status;
|
47
106
|
if (!result) {
|
48
107
|
// NOTE: Running status
|
108
|
+
this.fakeRunner.emit(TEST_EVENTS.TEST_BEGIN, fakeTest);
|
49
109
|
this.sendUpdate({ tests: { [id]: { id, browser, testName, storyPath, status: test.status, storyId } } });
|
50
110
|
return;
|
51
111
|
}
|
52
|
-
|
53
|
-
test.results = [];
|
54
|
-
}
|
112
|
+
test.results ??= [];
|
55
113
|
test.results.push(result);
|
56
114
|
|
57
115
|
if (status == 'failed') {
|
58
116
|
test.approved = null;
|
59
117
|
}
|
60
118
|
|
119
|
+
const { duration, attachments } = result;
|
120
|
+
|
121
|
+
fakeTest.duration = duration;
|
122
|
+
fakeTest.attachments = attachments;
|
123
|
+
fakeTest.state = result.status === 'failed' ? 'failed' : 'passed';
|
124
|
+
if (duration !== undefined) {
|
125
|
+
fakeTest.speed = duration > fakeTest.slow() ? 'slow' : duration / 2 > fakeTest.slow() ? 'medium' : 'fast';
|
126
|
+
}
|
127
|
+
|
128
|
+
if (isJUnit) {
|
129
|
+
this.fakeRunner.emit(TEST_EVENTS.SUITE_BEGIN, fakeSuite);
|
130
|
+
}
|
131
|
+
|
132
|
+
if (result.status === 'failed') {
|
133
|
+
fakeTest.err = result.error;
|
134
|
+
this.fakeRunner.emit(TEST_EVENTS.TEST_FAIL, fakeTest, result.error);
|
135
|
+
this.fakeRunner.stats.failures++;
|
136
|
+
} else {
|
137
|
+
this.fakeRunner.emit(TEST_EVENTS.TEST_PASS, fakeTest);
|
138
|
+
this.fakeRunner.stats.duration += duration ?? 0;
|
139
|
+
}
|
140
|
+
|
141
|
+
if (isJUnit) {
|
142
|
+
this.fakeRunner.emit(TEST_EVENTS.SUITE_END, fakeSuite);
|
143
|
+
}
|
144
|
+
|
145
|
+
this.fakeRunner.emit(TEST_EVENTS.TEST_END, fakeTest);
|
146
|
+
|
61
147
|
this.sendUpdate({
|
62
148
|
tests: {
|
63
149
|
[id]: {
|
@@ -78,6 +164,7 @@ export default class Runner extends EventEmitter {
|
|
78
164
|
|
79
165
|
private handlePoolStop = (): void => {
|
80
166
|
if (!this.isRunning) {
|
167
|
+
this.fakeRunner.emit(TEST_EVENTS.RUN_END);
|
81
168
|
this.sendUpdate({ isRunning: false });
|
82
169
|
this.emit('stop');
|
83
170
|
}
|
@@ -147,6 +234,7 @@ export default class Runner extends EventEmitter {
|
|
147
234
|
};
|
148
235
|
}, {});
|
149
236
|
|
237
|
+
this.fakeRunner.emit(TEST_EVENTS.RUN_BEGIN);
|
150
238
|
this.browsers.forEach((browser) => {
|
151
239
|
const pool = this.pools[browser];
|
152
240
|
const tests = testsByBrowser[browser];
|
@@ -198,9 +286,7 @@ export default class Runner extends EventEmitter {
|
|
198
286
|
if (!image) continue;
|
199
287
|
await this.copyImage(test, name, image.actual);
|
200
288
|
|
201
|
-
|
202
|
-
test.approved = {};
|
203
|
-
}
|
289
|
+
test.approved ??= {};
|
204
290
|
test.approved[name] = retry;
|
205
291
|
test.status = 'approved';
|
206
292
|
|
@@ -224,9 +310,7 @@ export default class Runner extends EventEmitter {
|
|
224
310
|
if (!result.images) return;
|
225
311
|
const images = result.images[image];
|
226
312
|
if (!images) return;
|
227
|
-
|
228
|
-
test.approved = {};
|
229
|
-
}
|
313
|
+
test.approved ??= {};
|
230
314
|
const { browser, testName, storyPath, storyId } = test;
|
231
315
|
|
232
316
|
await this.copyImage(test, image, images.actual);
|
@@ -14,13 +14,14 @@ import { sendScreenshotsCount } from '../telemetry.js';
|
|
14
14
|
const importMetaUrl = pathToFileURL(__filename).href;
|
15
15
|
|
16
16
|
async function copyStatics(reportDir: string): Promise<void> {
|
17
|
-
const clientDir = path.join(path.dirname(fileURLToPath(importMetaUrl)), '
|
18
|
-
const
|
19
|
-
.filter((dirent) => dirent.isFile()
|
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
20
|
.map((dirent) => dirent.name);
|
21
|
-
await mkdir(reportDir, { recursive: true });
|
22
|
-
|
23
|
-
|
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));
|
24
25
|
}
|
25
26
|
}
|
26
27
|
|
@@ -42,7 +43,10 @@ function outputUnnecessaryImages(imagesDir: string, images: Set<string>): void {
|
|
42
43
|
.map((imagePath) => path.posix.relative(imagesDir, imagePath))
|
43
44
|
.filter((imagePath) => !images.has(imagePath));
|
44
45
|
if (unnecessaryImages.length > 0) {
|
45
|
-
logger.warn(
|
46
|
+
logger().warn(
|
47
|
+
'We found unnecessary screenshot images, those can be safely removed:\n',
|
48
|
+
unnecessaryImages.join('\n'),
|
49
|
+
);
|
46
50
|
}
|
47
51
|
}
|
48
52
|
|
@@ -81,10 +85,10 @@ export async function start(
|
|
81
85
|
|
82
86
|
if (options.ui) {
|
83
87
|
resolveApi(creeveyApi(runner));
|
84
|
-
logger.info(`Started on http://localhost:${options.port}`);
|
88
|
+
logger().info(`Started on http://localhost:${options.port}`);
|
85
89
|
} else {
|
86
90
|
if (Object.values(runner.status.tests).filter((test) => test && !test.skip).length == 0) {
|
87
|
-
logger.warn("Don't have any tests to run");
|
91
|
+
logger().warn("Don't have any tests to run");
|
88
92
|
|
89
93
|
void shutdownWorkers().then(() => process.exit());
|
90
94
|
return;
|
@@ -101,10 +105,11 @@ export async function start(
|
|
101
105
|
void sendScreenshotsCount(config, options, runner.status)
|
102
106
|
.catch((reason: unknown) => {
|
103
107
|
const error = reason instanceof Error ? (reason.stack ?? reason.message) : (reason as string);
|
104
|
-
logger.warn(`Can't send telemetry: ${error}`);
|
108
|
+
logger().warn(`Can't send telemetry: ${error}`);
|
105
109
|
})
|
106
110
|
.finally(() => {
|
107
|
-
|
111
|
+
// NOTE: Take some time to kill processes
|
112
|
+
void shutdownWorkers().then(() => setTimeout(() => process.exit(), 500));
|
108
113
|
});
|
109
114
|
});
|
110
115
|
// TODO grep
|
@@ -1,8 +1,12 @@
|
|
1
|
+
import { readFile } from 'fs/promises';
|
2
|
+
import { pathToFileURL } from 'url';
|
1
3
|
import semver from 'semver';
|
2
4
|
import { exec } from 'shelljs';
|
3
5
|
|
6
|
+
const importMetaUrl = pathToFileURL(__filename).href;
|
7
|
+
|
4
8
|
// TODO Support custom docker images
|
5
|
-
export function playwrightDockerFile(browser: string, version: string): string {
|
9
|
+
export async function playwrightDockerFile(browser: string, version: string): Promise<string> {
|
6
10
|
const sv = semver.coerce(version);
|
7
11
|
|
8
12
|
let npmRegistry;
|
@@ -12,23 +16,31 @@ export function playwrightDockerFile(browser: string, version: string): string {
|
|
12
16
|
/* noop */
|
13
17
|
}
|
14
18
|
|
15
|
-
|
16
|
-
|
19
|
+
const indexJs = await readFile(new URL('./index-source.mjs', importMetaUrl), 'utf-8');
|
20
|
+
|
21
|
+
const dockerfile = `
|
22
|
+
FROM node:lts
|
17
23
|
|
18
24
|
WORKDIR /creevey
|
19
25
|
|
20
26
|
RUN echo "{ \\"type\\": \\"module\\" }" > package.json && \\
|
21
|
-
|
22
|
-
|
27
|
+
${indexJs
|
28
|
+
.split('\n')
|
29
|
+
.map((line) => ` echo "${line.replace(/"/g, '\\"')}" >> index.js && \\`)
|
30
|
+
.join('\n')}
|
31
|
+
${
|
23
32
|
npmRegistry
|
24
33
|
? `
|
25
34
|
echo "registry=${npmRegistry}" > .npmrc && \\`
|
26
35
|
: ''
|
27
36
|
}
|
28
|
-
npm i playwright-core${sv ? `@${sv.format()}` : ''}
|
37
|
+
npm i playwright-core${sv ? `@${sv.format()}` : ''} && \\
|
38
|
+
npx -y playwright${sv ? `@${sv.format()}` : ''} install --with-deps ${browser}
|
29
39
|
|
30
40
|
EXPOSE 4444
|
31
41
|
|
32
42
|
ENTRYPOINT [ "node", "./index.js" ]
|
33
43
|
`;
|
44
|
+
|
45
|
+
return dockerfile.replace(/\\\n\s*\\?\n/g, '\\\n');
|
34
46
|
}
|
@@ -1,9 +1,17 @@
|
|
1
|
+
import assert from 'assert';
|
1
2
|
import { runImage } from '../docker';
|
2
3
|
import { emitWorkerMessage, subscribeOn } from '../messages';
|
3
|
-
import { isInsideDocker } from '../utils';
|
4
|
+
import { getCreeveyCache, isInsideDocker, resolvePlaywrightBrowserType } from '../utils';
|
4
5
|
import { LOCALHOST_REGEXP } from '../webdriver';
|
6
|
+
import type { BrowserConfigObject, Config } from '../../types';
|
5
7
|
|
6
|
-
export async function startPlaywrightContainer(
|
8
|
+
export async function startPlaywrightContainer(
|
9
|
+
imageName: string,
|
10
|
+
browser: string,
|
11
|
+
config: Config,
|
12
|
+
debug: boolean,
|
13
|
+
): Promise<string> {
|
14
|
+
const { browserName, playwrightOptions } = config.browsers[browser] as BrowserConfigObject;
|
7
15
|
const port = await new Promise<number>((resolve) => {
|
8
16
|
subscribeOn('worker', (message) => {
|
9
17
|
if (message.type == 'port') {
|
@@ -13,13 +21,18 @@ export async function startPlaywrightContainer(imageName: string, debug: boolean
|
|
13
21
|
emitWorkerMessage({ type: 'port', payload: { port: -1 } });
|
14
22
|
});
|
15
23
|
|
24
|
+
const cacheDir = await getCreeveyCache();
|
25
|
+
|
26
|
+
assert(cacheDir, "Couldn't get cache directory");
|
27
|
+
|
16
28
|
const host = await runImage(
|
17
29
|
imageName,
|
18
|
-
[],
|
30
|
+
[JSON.stringify({ ...playwrightOptions, browser: resolvePlaywrightBrowserType(browserName) })],
|
19
31
|
{
|
20
32
|
ExposedPorts: { [`${port}/tcp`]: {} },
|
21
33
|
HostConfig: {
|
22
34
|
PortBindings: { ['4444/tcp']: [{ HostPort: `${port}` }] },
|
35
|
+
Binds: [`${cacheDir}/${process.pid}:/creevey/traces`],
|
23
36
|
},
|
24
37
|
},
|
25
38
|
debug,
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { chromium, firefox, webkit } from 'playwright-core';
|
2
|
+
|
3
|
+
/** @type import("playwright-core").LaunchOptions & { browser: 'chromium' | 'firefox' | 'webkit' } */
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
5
|
+
const config = JSON.parse(process.argv.slice(2)[0]);
|
6
|
+
|
7
|
+
const browsers = { chromium, firefox, webkit };
|
8
|
+
|
9
|
+
const ws = await browsers[config.browser].launchServer({
|
10
|
+
...config,
|
11
|
+
port: 4444,
|
12
|
+
wsPath: 'creevey',
|
13
|
+
tracesDir: 'traces',
|
14
|
+
});
|
15
|
+
|
16
|
+
console.log(config.browser, 'browser server launched on:', ws.wsEndpoint());
|