creevey 0.9.2 → 0.10.0-beta.0
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/chromatic.config.json +5 -0
- package/dist/client/addon/components/Addon.d.ts +1 -0
- package/dist/client/addon/components/Addon.js.map +1 -1
- package/dist/client/addon/components/Icons.d.ts +1 -0
- package/dist/client/addon/components/Icons.js.map +1 -1
- package/dist/client/addon/components/Panel.d.ts +1 -0
- package/dist/client/addon/components/Panel.js.map +1 -1
- package/dist/client/addon/components/TestSelect.d.ts +1 -0
- package/dist/client/addon/components/TestSelect.js +4 -3
- package/dist/client/addon/components/TestSelect.js.map +1 -1
- package/dist/client/addon/components/Tools.d.ts +1 -0
- package/dist/client/addon/components/Tools.js +7 -8
- package/dist/client/addon/components/Tools.js.map +1 -1
- package/dist/client/addon/controller.d.ts +1 -1
- package/dist/client/addon/controller.js.map +1 -1
- package/dist/client/addon/decorator.d.ts +1 -1
- package/dist/client/addon/manager.js +3 -2
- package/dist/client/addon/manager.js.map +1 -1
- package/dist/client/addon/preview.d.ts +1 -1
- package/dist/client/addon/withCreevey.d.ts +6 -8
- package/dist/client/addon/withCreevey.js +21 -19
- 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.map +1 -1
- package/dist/client/shared/components/ImagesView/ImagesView.d.ts +1 -0
- package/dist/client/shared/components/ImagesView/ImagesView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SideBySideView.d.ts +1 -1
- 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.map +1 -1
- package/dist/client/shared/components/ImagesView/SwapView.d.ts +1 -1
- package/dist/client/shared/components/ImagesView/SwapView.js.map +1 -1
- package/dist/client/shared/components/PageFooter/PageFooter.d.ts +1 -0
- package/dist/client/shared/components/PageFooter/PageFooter.js +1 -1
- package/dist/client/shared/components/PageFooter/PageFooter.js.map +1 -1
- package/dist/client/shared/components/PageFooter/Paging.d.ts +2 -2
- package/dist/client/shared/components/PageFooter/Paging.js +8 -6
- package/dist/client/shared/components/PageFooter/Paging.js.map +1 -1
- package/dist/client/shared/components/PageHeader/ImagePreview.js.map +1 -1
- package/dist/client/shared/components/PageHeader/PageHeader.d.ts +1 -0
- package/dist/client/shared/components/PageHeader/PageHeader.js +2 -1
- package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
- package/dist/client/shared/components/ResultsPage.d.ts +2 -2
- package/dist/client/shared/components/ResultsPage.js.map +1 -1
- package/dist/client/web/CreeveyApp.d.ts +1 -0
- package/dist/client/web/CreeveyApp.js.map +1 -1
- package/dist/client/web/CreeveyLoader.d.ts +1 -0
- package/dist/client/web/CreeveyLoader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Checkbox.d.ts +1 -1
- package/dist/client/web/CreeveyView/SideBar/Checkbox.js +4 -4
- package/dist/client/web/CreeveyView/SideBar/Checkbox.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Search.d.ts +1 -0
- package/dist/client/web/CreeveyView/SideBar/Search.js +4 -4
- package/dist/client/web/CreeveyView/SideBar/Search.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBar.d.ts +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBar.js +1 -7
- package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.d.ts +1 -0
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +5 -4
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.d.ts +1 -0
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +4 -3
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.d.ts +3 -7
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +6 -5
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestLink.d.ts +1 -0
- package/dist/client/web/CreeveyView/SideBar/TestLink.js +5 -1
- package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js +15 -8
- package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.js +5 -4
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Toggle.d.ts +1 -0
- package/dist/client/web/CreeveyView/SideBar/Toggle.js.map +1 -1
- package/dist/client/web/KeyboardEventsContext.d.ts +3 -4
- package/dist/client/web/KeyboardEventsContext.js.map +1 -1
- package/dist/client/web/assets/index-DkmZfG9C.js +591 -0
- package/dist/client/web/index.html +1 -1
- package/dist/client/web/index.js +5 -6
- package/dist/client/web/index.js.map +1 -1
- package/dist/creevey.js +21 -9
- package/dist/creevey.js.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/server/config.d.ts +1 -1
- package/dist/server/config.js +9 -5
- package/dist/server/config.js.map +1 -1
- package/dist/server/docker.d.ts +2 -2
- package/dist/server/docker.js +46 -40
- package/dist/server/docker.js.map +1 -1
- package/dist/server/index.js +54 -15
- package/dist/server/index.js.map +1 -1
- package/dist/server/master/master.d.ts +1 -5
- package/dist/server/master/master.js +3 -3
- package/dist/server/master/master.js.map +1 -1
- package/dist/server/master/pool.d.ts +2 -1
- package/dist/server/master/pool.js +9 -5
- package/dist/server/master/pool.js.map +1 -1
- package/dist/server/master/runner.d.ts +1 -1
- package/dist/server/master/runner.js +2 -2
- package/dist/server/master/runner.js.map +1 -1
- package/dist/server/master/server.js +1 -0
- package/dist/server/master/server.js.map +1 -1
- package/dist/server/master/start.d.ts +3 -0
- package/dist/server/master/{index.js → start.js} +6 -9
- package/dist/server/master/start.js.map +1 -0
- package/dist/server/messages.d.ts +4 -10
- package/dist/server/messages.js +4 -58
- package/dist/server/messages.js.map +1 -1
- package/dist/server/playwright/docker-file.d.ts +1 -0
- package/dist/server/playwright/docker-file.js +26 -0
- package/dist/server/playwright/docker-file.js.map +1 -0
- package/dist/server/playwright/docker.d.ts +1 -0
- package/dist/server/playwright/docker.js +31 -0
- package/dist/server/playwright/docker.js.map +1 -0
- package/dist/server/playwright/internal.d.ts +25 -0
- package/dist/server/playwright/internal.js +319 -0
- package/dist/server/playwright/internal.js.map +1 -0
- package/dist/server/playwright/webdriver.d.ts +16 -0
- package/dist/server/playwright/webdriver.js +105 -0
- package/dist/server/playwright/webdriver.js.map +1 -0
- package/dist/server/providers/browser.d.ts +2 -0
- package/dist/server/{storybook/providers → providers}/browser.js +6 -7
- package/dist/server/providers/browser.js.map +1 -0
- package/dist/server/providers/hybrid.d.ts +2 -0
- package/dist/server/{storybook/providers → providers}/hybrid.js +8 -8
- package/dist/server/providers/hybrid.js.map +1 -0
- package/dist/server/reporter.d.ts +26 -0
- package/dist/server/{worker/reporter.js → reporter.js} +34 -56
- package/dist/server/reporter.js.map +1 -0
- package/dist/server/selenium/internal.d.ts +31 -0
- package/dist/server/selenium/internal.js +606 -0
- package/dist/server/selenium/internal.js.map +1 -0
- package/dist/server/selenium/selenoid.js +6 -13
- package/dist/server/selenium/selenoid.js.map +1 -1
- package/dist/server/selenium/webdriver.d.ts +24 -0
- package/dist/server/selenium/webdriver.js +106 -0
- package/dist/server/selenium/webdriver.js.map +1 -0
- package/dist/server/stories.js +16 -9
- package/dist/server/stories.js.map +1 -1
- package/dist/server/telemetry.d.ts +1 -1
- package/dist/server/telemetry.js +4 -4
- package/dist/server/telemetry.js.map +1 -1
- package/dist/server/utils.d.ts +3 -4
- package/dist/server/utils.js +10 -9
- package/dist/server/utils.js.map +1 -1
- package/dist/server/webdriver.d.ts +19 -0
- package/dist/server/webdriver.js +79 -0
- package/dist/server/webdriver.js.map +1 -0
- package/dist/server/worker/chai-image.d.ts +2 -5
- package/dist/server/worker/chai-image.js +14 -102
- package/dist/server/worker/chai-image.js.map +1 -1
- package/dist/server/worker/match-image.d.ts +14 -0
- package/dist/server/worker/match-image.js +231 -0
- package/dist/server/worker/match-image.js.map +1 -0
- package/dist/server/worker/start.d.ts +2 -0
- package/dist/server/worker/start.js +258 -0
- package/dist/server/worker/start.js.map +1 -0
- package/dist/types.d.ts +126 -64
- package/dist/types.js +15 -9
- package/dist/types.js.map +1 -1
- package/package.json +108 -110
- package/src/client/addon/components/Addon.tsx +1 -1
- package/src/client/addon/components/Icons.tsx +1 -1
- package/src/client/addon/components/Panel.tsx +1 -1
- package/src/client/addon/components/TestSelect.tsx +5 -5
- package/src/client/addon/components/Tools.tsx +9 -9
- package/src/client/addon/controller.ts +1 -1
- package/src/client/addon/manager.ts +4 -4
- package/src/client/addon/withCreevey.ts +26 -28
- package/src/client/shared/components/ImagesView/BlendView.tsx +1 -1
- package/src/client/shared/components/ImagesView/ImagesView.tsx +2 -2
- package/src/client/shared/components/ImagesView/SideBySideView.tsx +1 -1
- package/src/client/shared/components/ImagesView/SlideView.tsx +1 -1
- package/src/client/shared/components/ImagesView/SwapView.tsx +1 -1
- package/src/client/shared/components/PageFooter/PageFooter.tsx +2 -2
- package/src/client/shared/components/PageFooter/Paging.tsx +13 -13
- package/src/client/shared/components/PageHeader/ImagePreview.tsx +1 -1
- package/src/client/shared/components/PageHeader/PageHeader.tsx +4 -3
- package/src/client/shared/components/ResultsPage.tsx +1 -1
- package/src/client/web/CreeveyApp.tsx +1 -1
- package/src/client/web/CreeveyLoader.tsx +1 -1
- package/src/client/web/CreeveyView/SideBar/Checkbox.tsx +6 -7
- package/src/client/web/CreeveyView/SideBar/Search.tsx +4 -4
- package/src/client/web/CreeveyView/SideBar/SideBar.tsx +3 -10
- package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +7 -6
- package/src/client/web/CreeveyView/SideBar/SideBarHeader.tsx +7 -6
- package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +8 -6
- package/src/client/web/CreeveyView/SideBar/TestLink.tsx +8 -3
- package/src/client/web/CreeveyView/SideBar/TestStatusIcon.tsx +18 -10
- package/src/client/web/CreeveyView/SideBar/TestsStatus.tsx +7 -10
- package/src/client/web/CreeveyView/SideBar/Toggle.tsx +1 -2
- package/src/client/web/KeyboardEventsContext.tsx +3 -4
- package/src/client/web/index.html +1 -1
- package/src/client/web/index.tsx +4 -3
- package/src/creevey.ts +25 -8
- package/src/index.ts +4 -2
- package/src/server/config.ts +12 -8
- package/src/server/docker.ts +58 -44
- package/src/server/index.ts +57 -18
- package/src/server/master/master.ts +3 -6
- package/src/server/master/pool.ts +20 -7
- package/src/server/master/runner.ts +2 -2
- package/src/server/master/server.ts +1 -0
- package/src/server/master/{index.ts → start.ts} +13 -11
- package/src/server/messages.ts +11 -75
- package/src/server/playwright/docker-file.ts +21 -0
- package/src/server/playwright/docker.ts +41 -0
- package/src/server/playwright/internal.ts +387 -0
- package/src/server/playwright/webdriver.ts +126 -0
- package/src/server/{storybook/providers → providers}/browser.ts +7 -8
- package/src/server/{storybook/providers → providers}/hybrid.ts +19 -19
- package/src/server/{worker/reporter.ts → reporter.ts} +40 -72
- package/src/server/selenium/internal.ts +785 -0
- package/src/server/selenium/selenoid.ts +12 -17
- package/src/server/selenium/webdriver.ts +136 -0
- package/src/server/stories.ts +18 -11
- package/src/server/telemetry.ts +2 -2
- package/src/server/utils.ts +9 -9
- package/src/server/webdriver.ts +127 -0
- package/src/server/worker/chai-image.ts +21 -133
- package/src/server/worker/match-image.ts +303 -0
- package/src/server/worker/start.ts +303 -0
- package/src/types.ts +161 -60
- package/dist/client/web/202.js +0 -1
- package/dist/client/web/270.js +0 -43
- package/dist/client/web/752.js +0 -1
- package/dist/client/web/main.js +0 -79
- package/dist/client/web/main.js.LICENSE.txt +0 -34
- package/dist/server/master/index.d.ts +0 -3
- package/dist/server/master/index.js.map +0 -1
- package/dist/server/selenium/browser.d.ts +0 -19
- package/dist/server/selenium/browser.js +0 -640
- package/dist/server/selenium/browser.js.map +0 -1
- package/dist/server/selenium/index.d.ts +0 -2
- package/dist/server/selenium/index.js +0 -19
- package/dist/server/selenium/index.js.map +0 -1
- package/dist/server/storybook/providers/browser.d.ts +0 -2
- package/dist/server/storybook/providers/browser.js.map +0 -1
- package/dist/server/storybook/providers/hybrid.d.ts +0 -2
- package/dist/server/storybook/providers/hybrid.js.map +0 -1
- package/dist/server/worker/helpers.d.ts +0 -8
- package/dist/server/worker/helpers.js +0 -57
- package/dist/server/worker/helpers.js.map +0 -1
- package/dist/server/worker/index.d.ts +0 -1
- package/dist/server/worker/index.js +0 -6
- package/dist/server/worker/index.js.map +0 -1
- package/dist/server/worker/reporter.d.ts +0 -8
- package/dist/server/worker/reporter.js.map +0 -1
- package/dist/server/worker/worker.d.ts +0 -4
- package/dist/server/worker/worker.js +0 -217
- package/dist/server/worker/worker.js.map +0 -1
- package/src/server/selenium/browser.ts +0 -840
- package/src/server/selenium/index.ts +0 -2
- package/src/server/worker/helpers.ts +0 -61
- package/src/server/worker/index.ts +0 -1
- package/src/server/worker/worker.ts +0 -245
- package/types/mocha.d.ts +0 -20
package/src/server/config.ts
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
import fs from 'fs';
|
2
2
|
import path from 'path';
|
3
3
|
import { pathToFileURL } from 'url';
|
4
|
-
import { loadStories as browserStoriesProvider } from './
|
5
|
-
import { Config,
|
4
|
+
import { loadStories as browserStoriesProvider } from './providers/browser.js';
|
5
|
+
import { Config, BrowserConfig, BrowserConfigObject, Options, isDefined } from '../types.js';
|
6
6
|
import { configExt, loadThroughTSX } from './utils.js';
|
7
|
+
import { CreeveyReporter, TeamcityReporter } from './reporter.js';
|
8
|
+
import { SeleniumWebdriver } from './selenium/webdriver.js';
|
7
9
|
|
8
10
|
export const defaultBrowser = 'chrome';
|
9
11
|
|
10
|
-
export const defaultConfig: Omit<Config, 'gridUrl' | '
|
12
|
+
export const defaultConfig: Omit<Config, 'gridUrl' | 'testsDir' | 'tsConfig'> = {
|
11
13
|
disableTelemetry: false,
|
12
14
|
useDocker: true,
|
13
15
|
dockerImage: 'aerokube/selenoid:latest-release',
|
@@ -17,15 +19,19 @@ export const defaultConfig: Omit<Config, 'gridUrl' | 'storiesProvider' | 'testsD
|
|
17
19
|
storybookUrl: 'http://localhost:6006',
|
18
20
|
screenDir: path.resolve('images'),
|
19
21
|
reportDir: path.resolve('report'),
|
22
|
+
reporter: process.env.TEAMCITY_VERSION ? TeamcityReporter : CreeveyReporter,
|
23
|
+
storiesProvider: browserStoriesProvider,
|
24
|
+
webdriver: SeleniumWebdriver,
|
20
25
|
maxRetries: 0,
|
21
|
-
|
26
|
+
testTimeout: 30000,
|
27
|
+
diffOptions: { threshold: 0.05, includeAA: false },
|
28
|
+
odiffOptions: { threshold: 0.05, antialiasing: true },
|
22
29
|
browsers: { [defaultBrowser]: true },
|
23
30
|
hooks: {},
|
24
|
-
babelOptions: (_) => _,
|
25
31
|
testsRegex: /\.creevey\.(t|j)s$/,
|
26
32
|
};
|
27
33
|
|
28
|
-
function normalizeBrowserConfig(name: string, config:
|
34
|
+
function normalizeBrowserConfig(name: string, config: BrowserConfig): BrowserConfigObject {
|
29
35
|
if (typeof config == 'boolean') return { browserName: name };
|
30
36
|
if (typeof config == 'string') return { browserName: config };
|
31
37
|
return config;
|
@@ -65,8 +71,6 @@ export async function readConfig(options: Options): Promise<Config> {
|
|
65
71
|
Object.assign(userConfig, configData);
|
66
72
|
}
|
67
73
|
|
68
|
-
if (!userConfig.storiesProvider) userConfig.storiesProvider = browserStoriesProvider;
|
69
|
-
|
70
74
|
if (options.failFast != undefined) userConfig.failFast = Boolean(options.failFast);
|
71
75
|
if (options.reportDir) userConfig.reportDir = path.resolve(options.reportDir);
|
72
76
|
if (options.screenDir) userConfig.screenDir = path.resolve(options.screenDir);
|
package/src/server/docker.ts
CHANGED
@@ -1,16 +1,14 @@
|
|
1
|
-
import
|
2
|
-
import ora from 'ora';
|
1
|
+
import tar from 'tar-stream';
|
3
2
|
import { Writable } from 'stream';
|
4
3
|
import Dockerode, { Container } from 'dockerode';
|
5
|
-
import {
|
6
|
-
import { subscribeOn
|
7
|
-
import { isInsideDocker, LOCALHOST_REGEXP } from './utils.js';
|
4
|
+
import { DockerAuth } from '../types.js';
|
5
|
+
import { subscribeOn } from './messages.js';
|
8
6
|
import { logger } from './logger.js';
|
9
7
|
|
10
8
|
const docker = new Dockerode();
|
11
9
|
|
12
10
|
class DevNull extends Writable {
|
13
|
-
_write(_chunk: unknown, _encoding: BufferEncoding, callback: (error?: Error | null
|
11
|
+
_write(_chunk: unknown, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
|
14
12
|
setImmediate(callback);
|
15
13
|
}
|
16
14
|
}
|
@@ -24,13 +22,15 @@ export async function pullImages(
|
|
24
22
|
if (platform) args.platform = platform;
|
25
23
|
|
26
24
|
logger.info('Pull docker images');
|
25
|
+
// TODO Replace with `import from`
|
26
|
+
const { default: yoctoSpinner } = await import('yocto-spinner');
|
27
27
|
for (const image of images) {
|
28
28
|
await new Promise<void>((resolve, reject) => {
|
29
|
-
const spinner =
|
29
|
+
const spinner = yoctoSpinner({ text: `${image}: Pull start` }).start();
|
30
30
|
|
31
31
|
docker.pull(image, args, (pullError: Error | null, stream?: NodeJS.ReadableStream) => {
|
32
32
|
if (pullError || !stream) {
|
33
|
-
spinner.
|
33
|
+
spinner.error(pullError?.message);
|
34
34
|
reject(pullError ?? new Error('Unknown error'));
|
35
35
|
return;
|
36
36
|
}
|
@@ -39,11 +39,11 @@ export async function pullImages(
|
|
39
39
|
|
40
40
|
function onFinished(error: Error | null): void {
|
41
41
|
if (error) {
|
42
|
-
spinner.
|
42
|
+
spinner.error(error.message);
|
43
43
|
reject(error);
|
44
44
|
return;
|
45
45
|
}
|
46
|
-
spinner.
|
46
|
+
spinner.success(`${image}: Pull complete`);
|
47
47
|
resolve();
|
48
48
|
}
|
49
49
|
|
@@ -57,6 +57,54 @@ export async function pullImages(
|
|
57
57
|
}
|
58
58
|
}
|
59
59
|
|
60
|
+
export async function buildImage(imageName: string, dockerfile: string): Promise<void> {
|
61
|
+
const images = await docker.listImages({ filters: { label: [`creevey=${imageName}`] } });
|
62
|
+
|
63
|
+
if (images.at(0)) {
|
64
|
+
logger.info(`Image ${imageName} already exists`);
|
65
|
+
return;
|
66
|
+
}
|
67
|
+
|
68
|
+
const pack = tar.pack();
|
69
|
+
pack.entry({ name: 'Dockerfile' }, dockerfile);
|
70
|
+
pack.finalize();
|
71
|
+
|
72
|
+
const { default: yoctoSpinner } = await import('yocto-spinner');
|
73
|
+
const spinner = yoctoSpinner({ text: `${imageName}: Build start` }).start();
|
74
|
+
await new Promise<void>((resolve, reject) => {
|
75
|
+
void docker.buildImage(
|
76
|
+
// @ts-expect-error Type incompatibility AsyncIterator and AsyncIterableIterator
|
77
|
+
pack,
|
78
|
+
{ t: imageName, labels: { creevey: imageName } },
|
79
|
+
(buildError: Error | null, stream) => {
|
80
|
+
if (buildError || !stream) {
|
81
|
+
spinner.error(buildError?.message);
|
82
|
+
reject(buildError ?? new Error('Unknown error'));
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
|
86
|
+
docker.modem.followProgress(stream, onFinished, onProgress);
|
87
|
+
|
88
|
+
function onFinished(error: Error | null): void {
|
89
|
+
if (error) {
|
90
|
+
spinner.error(error.message);
|
91
|
+
reject(error);
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
spinner.success(`${imageName}: Build complete`);
|
95
|
+
resolve();
|
96
|
+
}
|
97
|
+
|
98
|
+
function onProgress(event: { id: string; status: string; progress?: string }): void {
|
99
|
+
if (!/^[a-z0-9]{12}$/i.test(event.id)) return;
|
100
|
+
|
101
|
+
spinner.text = `${imageName}: [${event.id}] ${event.status} ${event.progress ? event.progress : ''}`;
|
102
|
+
}
|
103
|
+
},
|
104
|
+
);
|
105
|
+
});
|
106
|
+
}
|
107
|
+
|
60
108
|
export async function runImage(
|
61
109
|
image: string,
|
62
110
|
args: string[],
|
@@ -100,37 +148,3 @@ export async function runImage(
|
|
100
148
|
);
|
101
149
|
});
|
102
150
|
}
|
103
|
-
|
104
|
-
export async function initDocker(
|
105
|
-
config: Config,
|
106
|
-
browser: string | undefined,
|
107
|
-
startContainer: () => Promise<string>,
|
108
|
-
): Promise<void> {
|
109
|
-
if (cluster.isPrimary) {
|
110
|
-
const host = await startContainer();
|
111
|
-
let gridUrl = 'http://localhost:4444/wd/hub';
|
112
|
-
gridUrl = isInsideDocker ? gridUrl.replace(LOCALHOST_REGEXP, host) : gridUrl;
|
113
|
-
cluster.on('message', (worker, message: unknown) => {
|
114
|
-
if (!isDockerMessage(message)) return;
|
115
|
-
|
116
|
-
const dockerMessage = message;
|
117
|
-
if (dockerMessage.type != 'start') return;
|
118
|
-
|
119
|
-
sendDockerMessage(worker, {
|
120
|
-
type: 'success',
|
121
|
-
payload: { gridUrl },
|
122
|
-
});
|
123
|
-
});
|
124
|
-
} else {
|
125
|
-
if (browser && (config.browsers[browser] as BrowserConfig).gridUrl) return Promise.resolve();
|
126
|
-
return new Promise((resolve) => {
|
127
|
-
subscribeOn('docker', (message) => {
|
128
|
-
if (message.type == 'success') {
|
129
|
-
config.gridUrl = message.payload.gridUrl;
|
130
|
-
resolve();
|
131
|
-
}
|
132
|
-
});
|
133
|
-
emitDockerMessage({ type: 'start' });
|
134
|
-
});
|
135
|
-
}
|
136
|
-
}
|
package/src/server/index.ts
CHANGED
@@ -1,30 +1,70 @@
|
|
1
1
|
import cluster from 'cluster';
|
2
2
|
import { readConfig, defaultBrowser } from './config.js';
|
3
|
-
import { Options, Config,
|
3
|
+
import { Options, Config, BrowserConfigObject, isWorkerMessage } from '../types.js';
|
4
4
|
import { logger } from './logger.js';
|
5
|
+
import { SeleniumWebdriver } from './selenium/webdriver.js';
|
6
|
+
import { LOCALHOST_REGEXP } from './webdriver.js';
|
7
|
+
import { isInsideDocker } from './utils.js';
|
8
|
+
import { sendWorkerMessage } from './messages.js';
|
5
9
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
async function startWebdriverServer(browser: string, config: Config, options: Options): Promise<string | undefined> {
|
11
|
+
if (config.webdriver === SeleniumWebdriver) {
|
12
|
+
if (cluster.isPrimary) {
|
13
|
+
// TODO Get random free port
|
14
|
+
const { startSelenoidContainer, startSelenoidStandalone } = await import('./selenium/selenoid.js');
|
15
|
+
const gridUrl = 'http://localhost:4444/wd/hub';
|
16
|
+
if (config.useDocker) {
|
17
|
+
const host = await startSelenoidContainer(config, options.debug);
|
18
|
+
return isInsideDocker ? gridUrl.replace(LOCALHOST_REGEXP, host) : gridUrl;
|
19
|
+
}
|
20
|
+
await startSelenoidStandalone(config, options.debug);
|
21
|
+
return gridUrl;
|
22
|
+
}
|
23
|
+
// TODO Worker might want to use docker image of browser or start standalone selenium
|
12
24
|
} else {
|
13
|
-
|
25
|
+
// TODO start standalone playwright server (useDocker == false)
|
26
|
+
|
27
|
+
if (cluster.isWorker) {
|
28
|
+
// TODO Re-use dockerImage
|
29
|
+
|
30
|
+
const { startPlaywrightContainer } = await import('./playwright/docker.js');
|
31
|
+
const { browserName } = config.browsers[browser] as BrowserConfigObject;
|
32
|
+
const host = await startPlaywrightContainer(browserName, options.debug);
|
33
|
+
|
34
|
+
return host;
|
35
|
+
} else {
|
36
|
+
const { default: getPort } = await import('get-port');
|
37
|
+
|
38
|
+
cluster.on('message', (worker, message: unknown) => {
|
39
|
+
if (!isWorkerMessage(message)) return;
|
40
|
+
|
41
|
+
const workerMessage = message;
|
42
|
+
if (workerMessage.type != 'port') return;
|
43
|
+
|
44
|
+
void getPort().then((port) => {
|
45
|
+
sendWorkerMessage(worker, {
|
46
|
+
type: 'port',
|
47
|
+
payload: { port },
|
48
|
+
});
|
49
|
+
});
|
50
|
+
});
|
51
|
+
}
|
52
|
+
// TODO Support gridUrl for playwright
|
53
|
+
// NOTE: There is no grid for playwright right now
|
14
54
|
}
|
15
55
|
}
|
16
56
|
|
17
57
|
export default async function (options: Options): Promise<void> {
|
18
58
|
const config = await readConfig(options);
|
19
|
-
const { browser = defaultBrowser,
|
59
|
+
const { browser = defaultBrowser, update, ui, port } = options;
|
60
|
+
let gridUrl = cluster.isPrimary ? config.gridUrl : options.gridUrl;
|
20
61
|
|
21
|
-
// NOTE: We don't need docker nor selenoid for
|
62
|
+
// NOTE: We don't need docker nor selenoid for update option
|
22
63
|
if (
|
23
|
-
!(
|
24
|
-
!tests &&
|
64
|
+
!(gridUrl || (Object.values(config.browsers) as BrowserConfigObject[]).every(({ gridUrl }) => gridUrl)) &&
|
25
65
|
!update
|
26
66
|
) {
|
27
|
-
await startWebdriverServer(config, options);
|
67
|
+
gridUrl = await startWebdriverServer(browser, config, options);
|
28
68
|
}
|
29
69
|
|
30
70
|
switch (true) {
|
@@ -37,15 +77,14 @@ export default async function (options: Options): Promise<void> {
|
|
37
77
|
|
38
78
|
const resolveApi = (await import('./master/server.js')).start(config.reportDir, port, ui);
|
39
79
|
|
40
|
-
return (await import('./master/
|
80
|
+
return (await import('./master/start.js')).start(gridUrl, config, options, resolveApi);
|
41
81
|
}
|
42
82
|
default: {
|
43
83
|
logger.info(`Starting Worker for ${browser}`);
|
44
84
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
});
|
85
|
+
// NOTE: We assume that we pass `gridUrl` to worker CLI options
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
87
|
+
return (await import('./worker/start.js')).start(browser, gridUrl!, config, options);
|
49
88
|
}
|
50
89
|
}
|
51
90
|
}
|
@@ -21,11 +21,8 @@ function mergeTests(
|
|
21
21
|
return testsFromStories;
|
22
22
|
}
|
23
23
|
|
24
|
-
export default async function master(
|
25
|
-
config
|
26
|
-
options: { watch: boolean; debug: boolean; port: number },
|
27
|
-
): Promise<Runner> {
|
28
|
-
const runner = new Runner(config);
|
24
|
+
export default async function master(config: Config, gridUrl?: string): Promise<Runner> {
|
25
|
+
const runner = new Runner(config, gridUrl);
|
29
26
|
const reportDataPath = path.join(config.reportDir, 'data.js');
|
30
27
|
const testsFromReport = tryToLoadTestsData(reportDataPath) ?? {};
|
31
28
|
|
@@ -33,7 +30,7 @@ export default async function master(
|
|
33
30
|
|
34
31
|
const tests = await loadTestsFromStories(
|
35
32
|
Object.keys(config.browsers),
|
36
|
-
(listener) => config.storiesProvider(config,
|
33
|
+
(listener) => config.storiesProvider(config, listener),
|
37
34
|
(testsDiff) => {
|
38
35
|
runner.updateTests(testsDiff);
|
39
36
|
saveTestsJson(runner.tests, config.reportDir);
|
@@ -1,6 +1,14 @@
|
|
1
1
|
import cluster, { Worker as ClusterWorker } from 'cluster';
|
2
2
|
import { EventEmitter } from 'events';
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
Worker,
|
5
|
+
Config,
|
6
|
+
TestResult,
|
7
|
+
BrowserConfigObject,
|
8
|
+
WorkerMessage,
|
9
|
+
TestStatus,
|
10
|
+
isWorkerMessage,
|
11
|
+
} from '../../types.js';
|
4
12
|
import { sendTestMessage, sendShutdownMessage, subscribeOnWorker } from '../messages.js';
|
5
13
|
import { isShuttingDown } from '../utils.js';
|
6
14
|
|
@@ -14,23 +22,26 @@ interface WorkerTest {
|
|
14
22
|
|
15
23
|
export default class Pool extends EventEmitter {
|
16
24
|
private maxRetries: number;
|
17
|
-
private config:
|
25
|
+
private config: BrowserConfigObject;
|
18
26
|
private workers: Worker[] = [];
|
19
27
|
private queue: WorkerTest[] = [];
|
20
28
|
private forcedStop = false;
|
21
29
|
private failFast: boolean;
|
30
|
+
private gridUrl?: string;
|
22
31
|
public get isRunning(): boolean {
|
23
32
|
return this.workers.length !== this.freeWorkers.length;
|
24
33
|
}
|
25
34
|
constructor(
|
26
35
|
config: Config,
|
27
36
|
private browser: string,
|
37
|
+
gridUrl?: string,
|
28
38
|
) {
|
29
39
|
super();
|
30
40
|
|
31
41
|
this.failFast = config.failFast;
|
32
42
|
this.maxRetries = config.maxRetries;
|
33
|
-
this.config = config.browsers[browser] as
|
43
|
+
this.config = config.browsers[browser] as BrowserConfigObject;
|
44
|
+
this.gridUrl = this.config.gridUrl ?? gridUrl;
|
34
45
|
}
|
35
46
|
|
36
47
|
async init(): Promise<void> {
|
@@ -111,12 +122,12 @@ export default class Pool extends EventEmitter {
|
|
111
122
|
|
112
123
|
private async forkWorker(retry = 0): Promise<Worker | { error: string }> {
|
113
124
|
cluster.setupPrimary({
|
114
|
-
args: ['--browser', this.browser, ...process.argv.slice(2)],
|
125
|
+
args: ['--browser', this.browser, ...(this.gridUrl ? ['--gridUrl', this.gridUrl] : []), ...process.argv.slice(2)],
|
115
126
|
});
|
116
127
|
const worker = cluster.fork();
|
117
128
|
const message = await new Promise((resolve: (value: WorkerMessage) => void) => {
|
118
129
|
const readyHandler = (message: unknown): void => {
|
119
|
-
if (!isWorkerMessage(message)) return;
|
130
|
+
if (!isWorkerMessage(message) || message.type == 'port') return;
|
120
131
|
worker.off('message', readyHandler);
|
121
132
|
resolve(message);
|
122
133
|
};
|
@@ -188,9 +199,11 @@ export default class Pool extends EventEmitter {
|
|
188
199
|
unsubscribe();
|
189
200
|
});
|
190
201
|
|
191
|
-
|
202
|
+
if (message.payload.subtype == 'unknown') {
|
203
|
+
this.gracefullyKill(worker);
|
204
|
+
}
|
192
205
|
|
193
|
-
this.handleTestResult(worker, test, { status: 'failed',
|
206
|
+
this.handleTestResult(worker, test, { status: 'failed', error: message.payload.error });
|
194
207
|
}),
|
195
208
|
subscribeOnWorker(worker, 'test', (message) => {
|
196
209
|
if (message.type != 'end') return;
|
@@ -24,7 +24,7 @@ export default class Runner extends EventEmitter {
|
|
24
24
|
public get isRunning(): boolean {
|
25
25
|
return Object.values(this.pools).some((pool) => pool.isRunning);
|
26
26
|
}
|
27
|
-
constructor(config: Config) {
|
27
|
+
constructor(config: Config, gridUrl?: string) {
|
28
28
|
super();
|
29
29
|
|
30
30
|
this.failFast = config.failFast;
|
@@ -32,7 +32,7 @@ export default class Runner extends EventEmitter {
|
|
32
32
|
this.reportDir = config.reportDir;
|
33
33
|
this.browsers = Object.keys(config.browsers);
|
34
34
|
this.browsers
|
35
|
-
.map((browser) => (this.pools[browser] = new Pool(config, browser)))
|
35
|
+
.map((browser) => (this.pools[browser] = new Pool(config, browser, gridUrl)))
|
36
36
|
.map((pool) => pool.on('test', this.handlePoolMessage));
|
37
37
|
}
|
38
38
|
|
@@ -21,6 +21,7 @@ export function start(reportDir: string, port: number, ui: boolean): (api: Creev
|
|
21
21
|
let setStoriesCounter = 0;
|
22
22
|
const creeveyApi = new Promise<CreeveyApi>((resolve) => (resolveApi = resolve));
|
23
23
|
const app = new Koa();
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
24
25
|
const server = http.createServer(app.callback());
|
25
26
|
const wss = new WebSocket.Server({ server });
|
26
27
|
|
@@ -5,7 +5,7 @@ import { copyFile, readdir, mkdir, writeFile } from 'fs/promises';
|
|
5
5
|
import master from './master.js';
|
6
6
|
import creeveyApi, { CreeveyApi } from './api.js';
|
7
7
|
import { Config, Options, TestData, isDefined } from '../../types.js';
|
8
|
-
import {
|
8
|
+
import { shutdownWorkers, testsToImages, readDirRecursive } from '../utils.js';
|
9
9
|
import { subscribeOn } from '../messages.js';
|
10
10
|
import Runner from './runner.js';
|
11
11
|
import { logger } from '../logger.js';
|
@@ -46,13 +46,17 @@ function outputUnnecessaryImages(imagesDir: string, images: Set<string>): void {
|
|
46
46
|
}
|
47
47
|
}
|
48
48
|
|
49
|
-
export async function start(
|
49
|
+
export async function start(
|
50
|
+
gridUrl: string | undefined,
|
51
|
+
config: Config,
|
52
|
+
options: Options,
|
53
|
+
resolveApi: (api: CreeveyApi) => void,
|
54
|
+
): Promise<void> {
|
50
55
|
let runner: Runner | null = null;
|
51
56
|
if (config.hooks.before) {
|
52
57
|
await config.hooks.before();
|
53
58
|
}
|
54
59
|
subscribeOn('shutdown', () => config.hooks.after?.());
|
55
|
-
process.removeListener('SIGINT', shutdown);
|
56
60
|
process.on('SIGINT', () => {
|
57
61
|
runner?.removeAllListeners('stop');
|
58
62
|
if (runner?.isRunning) {
|
@@ -67,15 +71,13 @@ export async function start(config: Config, options: Options, resolveApi: (api:
|
|
67
71
|
}
|
68
72
|
});
|
69
73
|
|
70
|
-
runner = await master(config,
|
74
|
+
runner = await master(config, gridUrl);
|
71
75
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
});
|
78
|
-
}
|
76
|
+
runner.on('stop', () => {
|
77
|
+
void copyStatics(config.reportDir).then(() =>
|
78
|
+
writeFile(path.join(config.reportDir, 'data.js'), reportDataModule(runner.status.tests)),
|
79
|
+
);
|
80
|
+
});
|
79
81
|
|
80
82
|
if (options.ui) {
|
81
83
|
resolveApi(creeveyApi(runner));
|
package/src/server/messages.ts
CHANGED
@@ -3,14 +3,10 @@ import {
|
|
3
3
|
WorkerMessage,
|
4
4
|
StoriesMessage,
|
5
5
|
TestMessage,
|
6
|
-
WebpackMessage,
|
7
|
-
DockerMessage,
|
8
6
|
ProcessMessage,
|
9
7
|
WorkerHandler,
|
10
8
|
StoriesHandler,
|
11
9
|
TestHandler,
|
12
|
-
WebpackHandler,
|
13
|
-
DockerHandler,
|
14
10
|
ShutdownHandler,
|
15
11
|
} from '../types.js';
|
16
12
|
|
@@ -35,14 +31,6 @@ export function emitTestMessage(message: TestMessage): boolean {
|
|
35
31
|
return emitMessage({ scope: 'test', ...message });
|
36
32
|
}
|
37
33
|
|
38
|
-
export function emitWebpackMessage(message: WebpackMessage): boolean {
|
39
|
-
return emitMessage({ scope: 'webpack', ...message });
|
40
|
-
}
|
41
|
-
|
42
|
-
export function emitDockerMessage(message: DockerMessage): boolean {
|
43
|
-
return emitMessage({ scope: 'docker', ...message });
|
44
|
-
}
|
45
|
-
|
46
34
|
export function emitShutdownMessage(): boolean {
|
47
35
|
return emitMessage({ scope: 'shutdown' });
|
48
36
|
}
|
@@ -51,8 +39,6 @@ interface Handlers {
|
|
51
39
|
worker: Set<WorkerHandler>;
|
52
40
|
stories: Set<StoriesHandler>;
|
53
41
|
test: Set<TestHandler>;
|
54
|
-
webpack: Set<WebpackHandler>;
|
55
|
-
docker: Set<DockerHandler>;
|
56
42
|
shutdown: Set<ShutdownHandler>;
|
57
43
|
}
|
58
44
|
|
@@ -61,8 +47,6 @@ function createHandlers(): Handlers {
|
|
61
47
|
worker: new Set<WorkerHandler>(),
|
62
48
|
stories: new Set<StoriesHandler>(),
|
63
49
|
test: new Set<TestHandler>(),
|
64
|
-
webpack: new Set<WebpackHandler>(),
|
65
|
-
docker: new Set<DockerHandler>(),
|
66
50
|
shutdown: new Set<ShutdownHandler>(),
|
67
51
|
});
|
68
52
|
}
|
@@ -89,18 +73,6 @@ const handler = (message: ProcessMessage): void => {
|
|
89
73
|
});
|
90
74
|
return;
|
91
75
|
}
|
92
|
-
case 'webpack': {
|
93
|
-
handlers.webpack.forEach((h) => {
|
94
|
-
h(message);
|
95
|
-
});
|
96
|
-
return;
|
97
|
-
}
|
98
|
-
case 'docker': {
|
99
|
-
handlers.docker.forEach((h) => {
|
100
|
-
h(message);
|
101
|
-
});
|
102
|
-
return;
|
103
|
-
}
|
104
76
|
case 'shutdown': {
|
105
77
|
handlers.shutdown.forEach((h) => {
|
106
78
|
h(message);
|
@@ -117,27 +89,25 @@ export function sendStoriesMessage(target: NodeJS.Process | Worker, message: Sto
|
|
117
89
|
export function sendTestMessage(target: NodeJS.Process | Worker, message: TestMessage): void {
|
118
90
|
target.send?.({ scope: 'test', ...message });
|
119
91
|
}
|
120
|
-
export function sendDockerMessage(target: NodeJS.Process | Worker, message: DockerMessage): void {
|
121
|
-
target.send?.({ scope: 'docker', ...message });
|
122
|
-
}
|
123
92
|
export function sendShutdownMessage(target: NodeJS.Process | Worker): void {
|
124
93
|
target.send?.({ scope: 'shutdown' });
|
125
94
|
}
|
95
|
+
export function sendWorkerMessage(target: NodeJS.Process | Worker, message: WorkerMessage): void {
|
96
|
+
target.send?.({ scope: 'worker', ...message });
|
97
|
+
}
|
126
98
|
|
127
99
|
export function subscribeOn(scope: 'worker', handler: WorkerHandler): () => void;
|
128
100
|
export function subscribeOn(scope: 'stories', handler: StoriesHandler): () => void;
|
129
101
|
export function subscribeOn(scope: 'test', handler: TestHandler): () => void;
|
130
|
-
export function subscribeOn(scope: 'webpack', handler: WebpackHandler): () => void;
|
131
|
-
export function subscribeOn(scope: 'docker', handler: DockerHandler): () => void;
|
132
102
|
export function subscribeOn(scope: 'shutdown', handler: ShutdownHandler): () => void;
|
133
103
|
export function subscribeOn(
|
134
|
-
scope: 'worker' | 'stories' | 'test' | '
|
135
|
-
handler: WorkerHandler | StoriesHandler | TestHandler |
|
104
|
+
scope: 'worker' | 'stories' | 'test' | 'shutdown',
|
105
|
+
handler: WorkerHandler | StoriesHandler | TestHandler | ShutdownHandler,
|
136
106
|
): () => void;
|
137
107
|
|
138
108
|
export function subscribeOn(
|
139
|
-
scope: 'worker' | 'stories' | 'test' | '
|
140
|
-
handler: WorkerHandler | StoriesHandler | TestHandler |
|
109
|
+
scope: 'worker' | 'stories' | 'test' | 'shutdown',
|
110
|
+
handler: WorkerHandler | StoriesHandler | TestHandler | ShutdownHandler,
|
141
111
|
): () => void {
|
142
112
|
switch (scope) {
|
143
113
|
case 'worker': {
|
@@ -155,16 +125,6 @@ export function subscribeOn(
|
|
155
125
|
handlers.test.add(testHandler);
|
156
126
|
return () => handlers.test.delete(testHandler);
|
157
127
|
}
|
158
|
-
case 'webpack': {
|
159
|
-
const webpackHandler = handler as WebpackHandler;
|
160
|
-
handlers.webpack.add(webpackHandler);
|
161
|
-
return () => handlers.webpack.delete(webpackHandler);
|
162
|
-
}
|
163
|
-
case 'docker': {
|
164
|
-
const dockerHandler = handler as DockerHandler;
|
165
|
-
handlers.docker.add(dockerHandler);
|
166
|
-
return () => handlers.docker.delete(dockerHandler);
|
167
|
-
}
|
168
128
|
case 'shutdown': {
|
169
129
|
const shutdownHandler = handler as ShutdownHandler;
|
170
130
|
handlers.shutdown.add(shutdownHandler);
|
@@ -178,19 +138,17 @@ const workers = new Map<Worker, Handlers>();
|
|
178
138
|
export function subscribeOnWorker(worker: Worker, scope: 'worker', handler: WorkerHandler): () => void;
|
179
139
|
export function subscribeOnWorker(worker: Worker, scope: 'stories', handler: StoriesHandler): () => void;
|
180
140
|
export function subscribeOnWorker(worker: Worker, scope: 'test', handler: TestHandler): () => void;
|
181
|
-
export function subscribeOnWorker(worker: Worker, scope: 'webpack', handler: WebpackHandler): () => void;
|
182
|
-
export function subscribeOnWorker(worker: Worker, scope: 'docker', handler: DockerHandler): () => void;
|
183
141
|
export function subscribeOnWorker(worker: Worker, scope: 'shutdown', handler: ShutdownHandler): () => void;
|
184
142
|
export function subscribeOnWorker(
|
185
143
|
worker: Worker,
|
186
|
-
scope: 'worker' | 'stories' | 'test' | '
|
187
|
-
handler: WorkerHandler | StoriesHandler | TestHandler |
|
144
|
+
scope: 'worker' | 'stories' | 'test' | 'shutdown',
|
145
|
+
handler: WorkerHandler | StoriesHandler | TestHandler | ShutdownHandler,
|
188
146
|
): () => void;
|
189
147
|
|
190
148
|
export function subscribeOnWorker(
|
191
149
|
worker: Worker,
|
192
|
-
scope: 'worker' | 'stories' | 'test' | '
|
193
|
-
handler: WorkerHandler | StoriesHandler | TestHandler |
|
150
|
+
scope: 'worker' | 'stories' | 'test' | 'shutdown',
|
151
|
+
handler: WorkerHandler | StoriesHandler | TestHandler | ShutdownHandler,
|
194
152
|
): () => void {
|
195
153
|
const workerHandlers = workers.get(worker) ?? createHandlers();
|
196
154
|
if (!workers.has(worker)) {
|
@@ -216,18 +174,6 @@ export function subscribeOnWorker(
|
|
216
174
|
});
|
217
175
|
return;
|
218
176
|
}
|
219
|
-
case 'webpack': {
|
220
|
-
workerHandlers.webpack.forEach((h) => {
|
221
|
-
h(message);
|
222
|
-
});
|
223
|
-
return;
|
224
|
-
}
|
225
|
-
case 'docker': {
|
226
|
-
workerHandlers.docker.forEach((h) => {
|
227
|
-
h(message);
|
228
|
-
});
|
229
|
-
return;
|
230
|
-
}
|
231
177
|
case 'shutdown': {
|
232
178
|
workerHandlers.shutdown.forEach((h) => {
|
233
179
|
h(message);
|
@@ -254,16 +200,6 @@ export function subscribeOnWorker(
|
|
254
200
|
workerHandlers.test.add(testHandler);
|
255
201
|
return () => workerHandlers.test.delete(testHandler);
|
256
202
|
}
|
257
|
-
case 'webpack': {
|
258
|
-
const webpackHandler = handler as WebpackHandler;
|
259
|
-
workerHandlers.webpack.add(webpackHandler);
|
260
|
-
return () => workerHandlers.webpack.delete(webpackHandler);
|
261
|
-
}
|
262
|
-
case 'docker': {
|
263
|
-
const dockerHandler = handler as DockerHandler;
|
264
|
-
workerHandlers.docker.add(dockerHandler);
|
265
|
-
return () => workerHandlers.docker.delete(dockerHandler);
|
266
|
-
}
|
267
203
|
case 'shutdown': {
|
268
204
|
const shutdownHandler = handler as ShutdownHandler;
|
269
205
|
workerHandlers.shutdown.add(shutdownHandler);
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import semver from 'semver';
|
2
|
+
|
3
|
+
// TODO Support custom docker images
|
4
|
+
export function playwrightDockerFile(browser: string, version: string): string {
|
5
|
+
const sv = semver.coerce(version);
|
6
|
+
|
7
|
+
return `
|
8
|
+
FROM mcr.microsoft.com/playwright:v${sv?.format() ?? version}
|
9
|
+
|
10
|
+
WORKDIR /creevey
|
11
|
+
|
12
|
+
RUN echo "{ \\"type\\": \\"module\\" }" > package.json && \\
|
13
|
+
echo "import { ${browser} as browser } from 'playwright-core';" >> index.js && \\
|
14
|
+
echo "const ws = await browser.launchServer({ port: 4444, wsPath: 'creevey' })" >> index.js && \\
|
15
|
+
npm i playwright-core${sv ? `@${sv.format()}` : ''}
|
16
|
+
|
17
|
+
EXPOSE 4444
|
18
|
+
|
19
|
+
ENTRYPOINT [ "node", "./index.js" ]
|
20
|
+
`;
|
21
|
+
}
|