creevey 0.10.0-beta.8 → 0.10.0-rc.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/AUTHORS +2 -0
- package/CHANGELOG.md +281 -0
- package/README.md +19 -41
- package/dist/client/addon/components/Addon.js +18 -8
- package/dist/client/addon/components/Addon.js.map +1 -1
- package/dist/client/addon/components/Panel.js +4 -4
- package/dist/client/addon/components/Panel.js.map +1 -1
- package/dist/client/addon/components/TestSelect.js +2 -2
- package/dist/client/addon/components/TestSelect.js.map +1 -1
- package/dist/client/addon/components/Tools.js +19 -9
- 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 +3 -3
- 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/manager.js +38 -39
- package/dist/client/addon/manager.js.map +1 -1
- package/dist/client/addon/preset.d.ts +0 -1
- package/dist/client/addon/preset.js +3 -2
- package/dist/client/addon/preset.js.map +1 -1
- package/dist/client/addon/preview.d.ts +1 -1
- package/dist/client/addon/withCreevey.d.ts +5 -3
- package/dist/client/addon/withCreevey.js +14 -21
- package/dist/client/addon/withCreevey.js.map +1 -1
- package/dist/client/shared/components/ImagesView/BlendView.d.ts +2 -2
- package/dist/client/shared/components/ImagesView/BlendView.js +18 -8
- package/dist/client/shared/components/ImagesView/BlendView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/ImagesView.js +1 -1
- package/dist/client/shared/components/ImagesView/ImagesView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SideBySideView.d.ts +2 -2
- package/dist/client/shared/components/ImagesView/SideBySideView.js +19 -9
- package/dist/client/shared/components/ImagesView/SideBySideView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SlideView.d.ts +2 -2
- package/dist/client/shared/components/ImagesView/SlideView.js +19 -9
- package/dist/client/shared/components/ImagesView/SlideView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/SwapView.d.ts +2 -2
- package/dist/client/shared/components/ImagesView/SwapView.js +31 -9
- package/dist/client/shared/components/ImagesView/SwapView.js.map +1 -1
- package/dist/client/shared/components/ImagesView/common.d.ts +1 -1
- 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.js +1 -1
- package/dist/client/shared/components/PageFooter/Paging.js.map +1 -1
- package/dist/client/shared/components/PageHeader/ImagePreview.d.ts +2 -2
- package/dist/client/shared/components/PageHeader/ImagePreview.js +2 -1
- package/dist/client/shared/components/PageHeader/ImagePreview.js.map +1 -1
- package/dist/client/shared/components/PageHeader/PageHeader.js +34 -13
- 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 +45 -15
- package/dist/client/shared/components/ResultsPage.js.map +1 -1
- package/dist/client/shared/creeveyClientApi.js +18 -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.d.ts +1 -0
- package/dist/client/web/CreeveyApp.js +44 -15
- package/dist/client/web/CreeveyApp.js.map +1 -1
- package/dist/client/web/CreeveyContext.d.ts +6 -0
- package/dist/client/web/CreeveyContext.js +21 -7
- package/dist/client/web/CreeveyContext.js.map +1 -1
- package/dist/client/web/CreeveyLoader.d.ts +1 -1
- package/dist/client/web/CreeveyLoader.js +3 -3
- package/dist/client/web/CreeveyLoader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Checkbox.d.ts +4 -4
- package/dist/client/web/CreeveyView/SideBar/Checkbox.js +36 -6
- package/dist/client/web/CreeveyView/SideBar/Checkbox.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Search.js +20 -10
- package/dist/client/web/CreeveyView/SideBar/Search.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBar.js +26 -12
- package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +67 -13
- package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +32 -12
- package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.d.ts +6 -6
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +20 -13
- package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestLink.js +20 -13
- package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +2 -2
- package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js +2 -2
- package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.d.ts +2 -2
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.js +3 -2
- package/dist/client/web/CreeveyView/SideBar/TestsStatus.js.map +1 -1
- package/dist/client/web/CreeveyView/SideBar/Toggle.js +1 -1
- package/dist/client/web/CreeveyView/SideBar/Toggle.js.map +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-CtSq3IhG.js +518 -0
- package/dist/client/web/index.html +1 -1
- package/dist/client/web/index.js +26 -11
- 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.d.ts +1 -1
- package/dist/creevey.js +122 -41
- package/dist/creevey.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/playwright/generator.d.ts +25 -0
- package/dist/playwright/generator.js +243 -0
- package/dist/playwright/generator.js.map +1 -0
- package/dist/playwright/helpers.d.ts +2 -0
- package/dist/playwright/helpers.js +29 -0
- package/dist/playwright/helpers.js.map +1 -0
- package/dist/playwright/reporter.d.ts +83 -0
- package/dist/playwright/reporter.js +334 -0
- package/dist/playwright/reporter.js.map +1 -0
- package/dist/playwright/setup.d.ts +3 -0
- package/dist/playwright/setup.js +72 -0
- package/dist/playwright/setup.js.map +1 -0
- package/dist/playwright.d.ts +1 -0
- package/dist/playwright.js +3 -1
- package/dist/playwright.js.map +1 -1
- package/dist/server/compare.d.ts +18 -0
- package/dist/server/compare.js +182 -0
- package/dist/server/compare.js.map +1 -0
- package/dist/server/config.d.ts +3 -3
- package/dist/server/config.js +75 -8
- 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 +54 -32
- package/dist/server/docker.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +165 -64
- 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 +20 -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/pool.d.ts +1 -0
- package/dist/server/master/pool.js +5 -3
- package/dist/server/master/pool.js.map +1 -1
- package/dist/server/master/queue.d.ts +1 -1
- package/dist/server/master/queue.js +14 -6
- package/dist/server/master/queue.js.map +1 -1
- package/dist/server/master/runner.d.ts +6 -6
- package/dist/server/master/runner.js +98 -130
- package/dist/server/master/runner.js.map +1 -1
- package/dist/server/master/server.d.ts +1 -1
- package/dist/server/master/server.js +193 -88
- package/dist/server/master/server.js.map +1 -1
- package/dist/server/master/start.d.ts +1 -2
- package/dist/server/master/start.js +13 -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 +282 -0
- package/dist/server/master/testsManager.js.map +1 -0
- package/dist/server/playwright/docker-file.d.ts +1 -1
- package/dist/server/playwright/docker-file.js +17 -8
- 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 +7 -7
- package/dist/server/playwright/internal.js +144 -84
- package/dist/server/playwright/internal.js.map +1 -1
- package/dist/server/playwright/webdriver.d.ts +3 -3
- package/dist/server/playwright/webdriver.js +0 -6
- package/dist/server/playwright/webdriver.js.map +1 -1
- package/dist/server/providers/browser.js +4 -3
- package/dist/server/providers/browser.js.map +1 -1
- package/dist/server/providers/hybrid.js +2 -2
- package/dist/server/providers/hybrid.js.map +1 -1
- package/dist/server/report.d.ts +10 -0
- package/dist/server/report.js +45 -0
- package/dist/server/report.js.map +1 -0
- package/dist/server/reporters/creevey.d.ts +7 -0
- package/dist/server/reporters/creevey.js +63 -0
- package/dist/server/reporters/creevey.js.map +1 -0
- package/dist/server/reporters/index.d.ts +2 -0
- package/dist/server/reporters/index.js +16 -0
- package/dist/server/reporters/index.js.map +1 -0
- package/dist/server/reporters/junit.d.ts +16 -0
- package/dist/server/reporters/junit.js +167 -0
- package/dist/server/reporters/junit.js.map +1 -0
- package/dist/server/reporters/teamcity.d.ts +7 -0
- package/dist/server/reporters/teamcity.js +60 -0
- package/dist/server/reporters/teamcity.js.map +1 -0
- package/dist/server/selenium/internal.d.ts +4 -4
- package/dist/server/selenium/internal.js +56 -40
- package/dist/server/selenium/internal.js.map +1 -1
- package/dist/server/selenium/selenoid.js +12 -6
- package/dist/server/selenium/selenoid.js.map +1 -1
- package/dist/server/selenium/webdriver.d.ts +3 -3
- package/dist/server/selenium/webdriver.js +4 -8
- package/dist/server/selenium/webdriver.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/telemetry.js +3 -3
- package/dist/server/telemetry.js.map +1 -1
- package/dist/server/testsFiles/parser.js +45 -5
- package/dist/server/testsFiles/parser.js.map +1 -1
- package/dist/server/utils.d.ts +23 -0
- package/dist/server/utils.js +114 -15
- package/dist/server/utils.js.map +1 -1
- package/dist/server/webdriver.d.ts +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 +8 -12
- package/dist/server/worker/match-image.js +11 -178
- package/dist/server/worker/match-image.js.map +1 -1
- package/dist/server/worker/start.d.ts +2 -2
- package/dist/server/worker/start.js +41 -64
- package/dist/server/worker/start.js.map +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +9 -7
- package/dist/shared/index.js.map +1 -1
- package/dist/types.d.ts +84 -43
- package/dist/types.js +65 -1
- package/dist/types.js.map +1 -1
- package/docs/cli.md +80 -0
- package/docs/config.md +179 -165
- package/docs/examples/playwright-reporer/playwright.config.ts +37 -0
- package/docs/migration-0.9-to-0.10.md +144 -0
- package/docs/playwright-reporter.md +357 -0
- package/docs/storybook.md +60 -0
- package/docs/tests.md +50 -45
- package/package.json +78 -83
- package/playwright.config.mts +46 -0
- package/src/client/addon/components/Addon.tsx +1 -1
- package/src/client/addon/components/Panel.tsx +4 -4
- package/src/client/addon/components/TestSelect.tsx +2 -2
- package/src/client/addon/components/Tools.tsx +2 -2
- package/src/client/addon/controller.ts +4 -4
- package/src/client/addon/makeDecorator.ts +69 -0
- package/src/client/addon/manager.ts +38 -37
- package/src/client/addon/preset.ts +2 -1
- package/src/client/addon/withCreevey.ts +16 -19
- package/src/client/shared/components/ImagesView/BlendView.tsx +1 -1
- package/src/client/shared/components/ImagesView/ImagesView.tsx +1 -1
- package/src/client/shared/components/ImagesView/SideBySideView.tsx +2 -2
- package/src/client/shared/components/ImagesView/SlideView.tsx +2 -2
- package/src/client/shared/components/ImagesView/SwapView.tsx +20 -2
- package/src/client/shared/components/ImagesView/common.ts +1 -1
- package/src/client/shared/components/PageFooter/PageFooter.tsx +1 -1
- package/src/client/shared/components/PageFooter/Paging.tsx +1 -1
- package/src/client/shared/components/PageHeader/ImagePreview.tsx +2 -1
- package/src/client/shared/components/PageHeader/PageHeader.tsx +23 -7
- package/src/client/shared/components/ResultsPage.tsx +33 -10
- package/src/client/shared/creeveyClientApi.ts +19 -1
- package/src/client/shared/helpers.ts +4 -24
- package/src/client/web/CreeveyApp.tsx +30 -9
- package/src/client/web/CreeveyContext.tsx +11 -0
- package/src/client/web/CreeveyLoader.tsx +2 -2
- package/src/client/web/CreeveyView/SideBar/Checkbox.tsx +3 -3
- package/src/client/web/CreeveyView/SideBar/Search.tsx +4 -4
- package/src/client/web/CreeveyView/SideBar/SideBar.tsx +11 -6
- package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +48 -15
- package/src/client/web/CreeveyView/SideBar/SideBarHeader.tsx +20 -5
- package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +12 -12
- package/src/client/web/CreeveyView/SideBar/TestLink.tsx +10 -10
- package/src/client/web/CreeveyView/SideBar/TestStatusIcon.tsx +2 -2
- package/src/client/web/CreeveyView/SideBar/TestsStatus.tsx +3 -2
- package/src/client/web/CreeveyView/SideBar/Toggle.tsx +1 -1
- package/src/client/web/KeyboardEventsContext.tsx +61 -73
- package/src/client/web/index.tsx +10 -5
- package/src/client/web/themes.ts +24 -0
- package/src/creevey.ts +92 -38
- package/src/playwright/generator.ts +322 -0
- package/src/playwright/helpers.ts +31 -0
- package/src/playwright/reporter.ts +381 -0
- package/src/playwright/setup.ts +84 -0
- package/src/playwright.ts +1 -0
- package/src/server/compare.ts +260 -0
- package/src/server/config.ts +52 -9
- package/src/server/connection.ts +26 -0
- package/src/server/docker.ts +62 -34
- package/src/server/index.ts +166 -79
- 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 +16 -0
- package/src/server/master/handlers/stories-handler.ts +20 -0
- package/src/server/master/master.ts +10 -27
- package/src/server/master/pool.ts +7 -3
- package/src/server/master/queue.ts +21 -7
- package/src/server/master/runner.ts +123 -134
- package/src/server/master/server.ts +214 -101
- package/src/server/master/start.ts +19 -41
- package/src/server/master/testsManager.ts +316 -0
- package/src/server/playwright/docker-file.ts +20 -8
- package/src/server/playwright/docker.ts +16 -3
- package/src/server/playwright/index-source.mjs +16 -0
- package/src/server/playwright/internal.ts +176 -103
- package/src/server/playwright/webdriver.ts +4 -10
- package/src/server/providers/browser.ts +4 -3
- package/src/server/providers/hybrid.ts +2 -3
- package/src/server/report.ts +51 -0
- package/src/server/reporters/creevey.ts +71 -0
- package/src/server/reporters/index.ts +11 -0
- package/src/server/reporters/junit.ts +207 -0
- package/src/server/reporters/teamcity.ts +74 -0
- package/src/server/selenium/internal.ts +70 -53
- package/src/server/selenium/selenoid.ts +13 -6
- package/src/server/selenium/webdriver.ts +8 -12
- package/src/server/shutdown.ts +19 -0
- package/src/server/stories.ts +1 -12
- package/src/server/telemetry.ts +3 -3
- package/src/server/testsFiles/parser.ts +52 -4
- package/src/server/utils.ts +124 -16
- package/src/server/webdriver.ts +1 -1
- package/src/server/worker/context.ts +14 -0
- package/src/server/worker/match-image.ts +16 -248
- package/src/server/worker/start.ts +49 -79
- package/src/shared/index.ts +10 -8
- package/src/types.ts +91 -58
- package/types/global.d.ts +1 -0
- package/dist/client/web/assets/index-DB8lHlJw.js +0 -591
- package/dist/server/reporter.d.ts +0 -26
- package/dist/server/reporter.js +0 -108
- package/dist/server/reporter.js.map +0 -1
- package/dist/server/update.d.ts +0 -2
- package/dist/server/update.js +0 -53
- package/dist/server/update.js.map +0 -1
- package/src/server/reporter.ts +0 -139
- package/src/server/update.ts +0 -74
@@ -2,11 +2,12 @@ import path from 'path';
|
|
2
2
|
import assert from 'assert';
|
3
3
|
import { lstatSync, existsSync } from 'fs';
|
4
4
|
import { mkdir, writeFile, copyFile } from 'fs/promises';
|
5
|
-
import
|
5
|
+
import { exec, chmod } from 'shelljs';
|
6
6
|
import { Config, BrowserConfigObject } from '../../types.js';
|
7
|
-
import { downloadBinary, getCreeveyCache } from '../utils.js';
|
7
|
+
import { downloadBinary, getCreeveyCache, killTree } from '../utils.js';
|
8
8
|
import { pullImages, runImage } from '../docker.js';
|
9
9
|
import { subscribeOn } from '../messages.js';
|
10
|
+
import { removeWorkerContainer } from '../worker/context.js';
|
10
11
|
|
11
12
|
async function createSelenoidConfig(
|
12
13
|
browsers: BrowserConfigObject[],
|
@@ -34,7 +35,7 @@ async function createSelenoidConfig(
|
|
34
35
|
dockerImage = `selenoid/${browserName}:${browserVersion}`,
|
35
36
|
webdriverCommand = [],
|
36
37
|
}) => {
|
37
|
-
|
38
|
+
selenoidConfig[browserName] ??= { default: browserVersion, versions: {} };
|
38
39
|
if (!useDocker && webdriverCommand.length == 0)
|
39
40
|
throw new Error('Please specify "webdriverCommand" browser option with path to browser webdriver');
|
40
41
|
selenoidConfig[browserName].versions[browserVersion] = {
|
@@ -91,12 +92,12 @@ export async function startSelenoidStandalone(config: Config, debug: boolean): P
|
|
91
92
|
|
92
93
|
// TODO Download browser webdrivers
|
93
94
|
try {
|
94
|
-
if (process.platform != 'win32')
|
95
|
+
if (process.platform != 'win32') chmod('+x', binaryPath);
|
95
96
|
} catch {
|
96
97
|
/* noop */
|
97
98
|
}
|
98
99
|
|
99
|
-
const selenoidProcess =
|
100
|
+
const selenoidProcess = exec(`${binaryPath} -conf ./browsers.json -disable-docker`, {
|
100
101
|
async: true,
|
101
102
|
cwd: selenoidConfigDir,
|
102
103
|
});
|
@@ -106,7 +107,9 @@ export async function startSelenoidStandalone(config: Config, debug: boolean): P
|
|
106
107
|
selenoidProcess.stderr?.pipe(process.stderr);
|
107
108
|
}
|
108
109
|
|
109
|
-
subscribeOn('shutdown', () =>
|
110
|
+
subscribeOn('shutdown', () => {
|
111
|
+
if (selenoidProcess.pid) void killTree(selenoidProcess.pid);
|
112
|
+
});
|
110
113
|
}
|
111
114
|
|
112
115
|
export async function startSelenoidContainer(config: Config, debug: boolean): Promise<string> {
|
@@ -145,5 +148,9 @@ export async function startSelenoidContainer(config: Config, debug: boolean): Pr
|
|
145
148
|
},
|
146
149
|
};
|
147
150
|
|
151
|
+
subscribeOn('shutdown', () => {
|
152
|
+
void removeWorkerContainer();
|
153
|
+
});
|
154
|
+
|
148
155
|
return runImage(selenoidImage, ['-limit', String(limit)], selenoidOptions, debug);
|
149
156
|
}
|
@@ -1,10 +1,11 @@
|
|
1
1
|
/// <reference types="../../../types/selenium-context" />
|
2
|
-
import { Args } from '
|
3
|
-
import { Config, StorybookGlobals, StoryInput, StoriesRaw,
|
2
|
+
import type { Args } from 'storybook/internal/types';
|
3
|
+
import { Config, StorybookGlobals, StoryInput, StoriesRaw, ServerTest, WorkerOptions } from '../../types.js';
|
4
4
|
import { subscribeOn } from '../messages.js';
|
5
5
|
import { CreeveyWebdriverBase } from '../webdriver.js';
|
6
6
|
import type { InternalBrowser } from './internal.js';
|
7
7
|
import { logger } from '../logger.js';
|
8
|
+
import { removeWorkerContainer } from '../worker/context.js';
|
8
9
|
|
9
10
|
declare global {
|
10
11
|
interface Window {
|
@@ -21,8 +22,8 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
21
22
|
#browserName: string;
|
22
23
|
#gridUrl: string;
|
23
24
|
#config: Config;
|
24
|
-
#options:
|
25
|
-
constructor(browser: string, gridUrl: string, config: Config, options:
|
25
|
+
#options: WorkerOptions;
|
26
|
+
constructor(browser: string, gridUrl: string, config: Config, options: WorkerOptions) {
|
26
27
|
super();
|
27
28
|
|
28
29
|
this.#browserName = browser;
|
@@ -31,7 +32,9 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
31
32
|
this.#options = options;
|
32
33
|
|
33
34
|
subscribeOn('shutdown', () => {
|
34
|
-
void this.#browser?.closeBrowser().finally(() =>
|
35
|
+
void this.#browser?.closeBrowser().finally(() => {
|
36
|
+
void removeWorkerContainer().finally(() => process.exit());
|
37
|
+
});
|
35
38
|
this.#browser = null;
|
36
39
|
});
|
37
40
|
}
|
@@ -42,7 +45,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
42
45
|
|
43
46
|
getSessionId(): Promise<string> {
|
44
47
|
if (!this.#browser) {
|
45
|
-
// TODO Describe the error
|
46
48
|
throw new Error('Browser is not initialized');
|
47
49
|
}
|
48
50
|
|
@@ -89,7 +91,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
89
91
|
|
90
92
|
async loadStoriesFromBrowser(): Promise<StoriesRaw> {
|
91
93
|
if (!this.#browser) {
|
92
|
-
// TODO Describe the error
|
93
94
|
throw new Error('Browser is not initialized');
|
94
95
|
}
|
95
96
|
|
@@ -98,7 +99,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
98
99
|
|
99
100
|
afterTest(test: ServerTest): Promise<void> {
|
100
101
|
if (!this.#browser) {
|
101
|
-
// TODO Describe the error
|
102
102
|
throw new Error('Browser is not initialized');
|
103
103
|
}
|
104
104
|
|
@@ -110,7 +110,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
110
110
|
ignoreElements?: string | string[] | null,
|
111
111
|
): Promise<Buffer> {
|
112
112
|
if (!this.#browser) {
|
113
|
-
// TODO Describe the error
|
114
113
|
throw new Error('Browser is not initialized');
|
115
114
|
}
|
116
115
|
|
@@ -119,7 +118,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
119
118
|
|
120
119
|
protected waitForComplete(callback: (isCompleted: boolean) => void): void {
|
121
120
|
if (!this.#browser) {
|
122
|
-
// TODO Describe the error
|
123
121
|
throw new Error('Browser is not initialized');
|
124
122
|
}
|
125
123
|
|
@@ -128,7 +126,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
128
126
|
|
129
127
|
protected async selectStory(id: string, waitForReady?: boolean): Promise<boolean> {
|
130
128
|
if (!this.#browser) {
|
131
|
-
// TODO Describe the error
|
132
129
|
throw new Error('Browser is not initialized');
|
133
130
|
}
|
134
131
|
|
@@ -137,7 +134,6 @@ export class SeleniumWebdriver extends CreeveyWebdriverBase {
|
|
137
134
|
|
138
135
|
protected async updateStoryArgs(story: StoryInput, updatedArgs: Args): Promise<void> {
|
139
136
|
if (!this.#browser) {
|
140
|
-
// TODO Describe the error
|
141
137
|
throw new Error('Browser is not initialized');
|
142
138
|
}
|
143
139
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import cluster from 'cluster';
|
2
|
+
import { subscribeOn } from './messages.js';
|
3
|
+
import { shutdownOnException, isShuttingDown } from './utils.js';
|
4
|
+
|
5
|
+
if (cluster.isWorker) {
|
6
|
+
subscribeOn('shutdown', () => {
|
7
|
+
isShuttingDown.current = true;
|
8
|
+
});
|
9
|
+
}
|
10
|
+
|
11
|
+
process.on('uncaughtException', shutdownOnException);
|
12
|
+
process.on('unhandledRejection', shutdownOnException);
|
13
|
+
// TODO SIGINT Stuck with selenium
|
14
|
+
process.on('SIGINT', () => {
|
15
|
+
if (isShuttingDown.current) {
|
16
|
+
process.exit(-1);
|
17
|
+
}
|
18
|
+
isShuttingDown.current = true;
|
19
|
+
});
|
package/src/server/stories.ts
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
import path from 'path';
|
2
|
-
import { mkdirSync, writeFileSync } from 'fs';
|
3
1
|
import { createHash } from 'crypto';
|
4
2
|
import _ from 'lodash';
|
5
3
|
import type {
|
@@ -12,7 +10,7 @@ import type {
|
|
12
10
|
CreeveyTestFunction,
|
13
11
|
CreeveyTestContext,
|
14
12
|
} from '../types.js';
|
15
|
-
import { isDefined
|
13
|
+
import { isDefined } from '../types.js';
|
16
14
|
import { shouldSkip } from './utils.js';
|
17
15
|
|
18
16
|
function storyTestFabric(delay?: number, testFn?: CreeveyTestFunction) {
|
@@ -129,12 +127,3 @@ export async function loadTestsFromStories(
|
|
129
127
|
|
130
128
|
return tests;
|
131
129
|
}
|
132
|
-
|
133
|
-
export function saveTestsJson(tests: Record<string, unknown>, dstPath: string = process.cwd()): void {
|
134
|
-
mkdirSync(dstPath, { recursive: true });
|
135
|
-
writeFileSync(
|
136
|
-
path.join(dstPath, 'tests.json'),
|
137
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
138
|
-
JSON.stringify(tests, (_, value) => (isFunction(value) ? value.toString() : value), 2),
|
139
|
-
);
|
140
|
-
}
|
package/src/server/telemetry.ts
CHANGED
@@ -128,7 +128,7 @@ export async function sendScreenshotsCount(
|
|
128
128
|
repoUrl: repoUrl ?? 'unknown',
|
129
129
|
creeveyVersion: creeveyVersion ?? 'unknown',
|
130
130
|
storybookVersion: storybookVersion ?? 'unknown',
|
131
|
-
options
|
131
|
+
options,
|
132
132
|
gridUrl,
|
133
133
|
screenDir: config.screenDir ? path.relative(gitRootPath ?? process.cwd(), config.screenDir) : undefined,
|
134
134
|
useDocker: config.useDocker,
|
@@ -181,8 +181,8 @@ export async function sendScreenshotsCount(
|
|
181
181
|
const testsMeta = { runId: uuid, tests };
|
182
182
|
|
183
183
|
const fullPathname = buildPathname('tests', testsMeta);
|
184
|
-
// NOTE: Keep request path shorter than
|
185
|
-
const chunksCount = Math.ceil(fullPathname.length /
|
184
|
+
// NOTE: Keep request path shorter than 24k symbols
|
185
|
+
const chunksCount = Math.ceil(fullPathname.length / 24_000);
|
186
186
|
let chunks: string[] = [];
|
187
187
|
if (chunksCount > 1) {
|
188
188
|
const testsString = JSON.stringify(tests);
|
@@ -1,8 +1,58 @@
|
|
1
1
|
import { pathToFileURL } from 'url';
|
2
|
-
import { toId, storyNameFromExport } from '@storybook/csf';
|
3
2
|
import { CreeveyStoryParams, CreeveyTestFunction } from '../../types.js';
|
4
3
|
import { loadThroughTSX } from '../utils.js';
|
5
4
|
|
5
|
+
// NOTE: Copy-pasted from @storybook/csf
|
6
|
+
function toStartCaseStr(str: string) {
|
7
|
+
return str
|
8
|
+
.replace(/_/g, ' ')
|
9
|
+
.replace(/-/g, ' ')
|
10
|
+
.replace(/\./g, ' ')
|
11
|
+
.replace(/([^\n])([A-Z])([a-z])/g, (_, $1, $2, $3) => `${$1} ${$2}${$3}`)
|
12
|
+
.replace(/([a-z])([A-Z])/g, (_, $1, $2) => `${$1} ${$2}`)
|
13
|
+
.replace(/([a-z])([0-9])/gi, (_, $1, $2) => `${$1} ${$2}`)
|
14
|
+
.replace(/([0-9])([a-z])/gi, (_, $1, $2) => `${$1} ${$2}`)
|
15
|
+
.replace(/(\s|^)(\w)/g, (_, $1, $2: string) => `${$1}${$2.toUpperCase()}`)
|
16
|
+
.replace(/ +/g, ' ')
|
17
|
+
.trim();
|
18
|
+
}
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Remove punctuation and illegal characters from a story ID.
|
22
|
+
*
|
23
|
+
* See https://gist.github.com/davidjrice/9d2af51100e41c6c4b4a
|
24
|
+
*/
|
25
|
+
const sanitize = (string: string) => {
|
26
|
+
return (
|
27
|
+
string
|
28
|
+
.toLowerCase()
|
29
|
+
// eslint-disable-next-line no-useless-escape
|
30
|
+
.replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '-')
|
31
|
+
.replace(/-+/g, '-')
|
32
|
+
.replace(/^-+/, '')
|
33
|
+
.replace(/-+$/, '')
|
34
|
+
);
|
35
|
+
};
|
36
|
+
|
37
|
+
const sanitizeSafe = (string: string, part: string) => {
|
38
|
+
const sanitized = sanitize(string);
|
39
|
+
if (sanitized === '') {
|
40
|
+
throw new Error(`Invalid ${part} '${string}', must include alphanumeric characters`);
|
41
|
+
}
|
42
|
+
return sanitized;
|
43
|
+
};
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Generate a storybook ID from a component/kind and story name.
|
47
|
+
*/
|
48
|
+
const toId = (kind: string, name?: string) =>
|
49
|
+
`${sanitizeSafe(kind, 'kind')}${name ? `--${sanitizeSafe(name, 'name')}` : ''}`;
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Transform a CSF named export into a readable story name
|
53
|
+
*/
|
54
|
+
const storyNameFromExport = (key: string) => toStartCaseStr(key);
|
55
|
+
|
6
56
|
export type CreeveyParamsByStoryId = Record<string, CreeveyStoryParams>;
|
7
57
|
|
8
58
|
export default async function parse(files: string[]): Promise<CreeveyParamsByStoryId> {
|
@@ -55,8 +105,6 @@ export const story = (
|
|
55
105
|
|
56
106
|
export const test = (title: string, testFn: CreeveyTestFunction): void => {
|
57
107
|
const storyId = getStoryId(kindTitle, storyTitle);
|
58
|
-
|
59
|
-
result[storyId] = {};
|
60
|
-
}
|
108
|
+
result[storyId] ??= {};
|
61
109
|
result[storyId].tests = Object.assign({}, result[storyId].tests, { [title]: testFn });
|
62
110
|
};
|
package/src/server/utils.ts
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
import fs from 'fs';
|
2
|
-
import
|
2
|
+
import path from 'path';
|
3
|
+
import http from 'http';
|
4
|
+
import https from 'https';
|
5
|
+
import assert from 'assert';
|
3
6
|
import cluster from 'cluster';
|
4
|
-
import
|
7
|
+
import pidtree from 'pidtree';
|
5
8
|
import { fileURLToPath, pathToFileURL } from 'url';
|
6
|
-
import { createRequire } from 'module';
|
7
9
|
import { register as esmRegister } from 'tsx/esm/api';
|
8
10
|
import { register as cjsRegister } from 'tsx/cjs/api';
|
9
11
|
import { SkipOptions, SkipOption, isDefined, TestData, noop, ServerTest, Worker } from '../types.js';
|
10
|
-
import { emitShutdownMessage, sendShutdownMessage } from './messages.js';
|
12
|
+
import { emitShutdownMessage, emitWorkerMessage, sendShutdownMessage } from './messages.js';
|
13
|
+
import { LOCALHOST_REGEXP } from './webdriver.js';
|
14
|
+
import { logger } from './logger.js';
|
11
15
|
|
12
16
|
const importMetaUrl = pathToFileURL(__filename).href;
|
13
17
|
|
@@ -15,6 +19,19 @@ export const isShuttingDown = { current: false };
|
|
15
19
|
|
16
20
|
export const configExt = ['.js', '.mjs', '.ts', '.cjs', '.mts', '.cts'];
|
17
21
|
|
22
|
+
const browserTypes = {
|
23
|
+
chromium: 'chromium',
|
24
|
+
'chromium-headless-shell': 'chromium',
|
25
|
+
chrome: 'chromium',
|
26
|
+
'chrome-beta': 'chromium',
|
27
|
+
msedge: 'chromium',
|
28
|
+
'msedge-beta': 'chromium',
|
29
|
+
'msedge-dev': 'chromium',
|
30
|
+
'bidi-chromium': 'chromium',
|
31
|
+
firefox: 'firefox',
|
32
|
+
webkit: 'webkit',
|
33
|
+
} as const;
|
34
|
+
|
18
35
|
export const skipOptionKeys = ['in', 'kinds', 'stories', 'tests', 'reason'];
|
19
36
|
|
20
37
|
function matchBy(pattern: string | string[] | RegExp | undefined, value: string): boolean {
|
@@ -73,6 +90,18 @@ export function shouldSkipByOption(
|
|
73
90
|
return skipByBrowser && skipByKind && skipByStory && skipByTest && reason;
|
74
91
|
}
|
75
92
|
|
93
|
+
export function shutdownOnException(reason: unknown): void {
|
94
|
+
if (isShuttingDown.current) return;
|
95
|
+
|
96
|
+
const error = reason instanceof Error ? (reason.stack ?? reason.message) : (reason as string);
|
97
|
+
|
98
|
+
logger().error(error);
|
99
|
+
|
100
|
+
process.exitCode = -1;
|
101
|
+
if (cluster.isWorker) emitWorkerMessage({ type: 'error', payload: { subtype: 'unknown', error } });
|
102
|
+
if (cluster.isPrimary) void shutdownWorkers();
|
103
|
+
}
|
104
|
+
|
76
105
|
export async function shutdownWorkers(): Promise<void> {
|
77
106
|
isShuttingDown.current = true;
|
78
107
|
await Promise.all(
|
@@ -83,13 +112,14 @@ export async function shutdownWorkers(): Promise<void> {
|
|
83
112
|
(worker) =>
|
84
113
|
new Promise<void>((resolve) => {
|
85
114
|
const timeout = setTimeout(() => {
|
86
|
-
worker.
|
87
|
-
},
|
115
|
+
if (worker.process.pid) void killTree(worker.process.pid);
|
116
|
+
}, 10_000);
|
88
117
|
worker.on('exit', () => {
|
89
118
|
clearTimeout(timeout);
|
90
119
|
resolve();
|
91
120
|
});
|
92
121
|
sendShutdownMessage(worker);
|
122
|
+
worker.disconnect();
|
93
123
|
}),
|
94
124
|
),
|
95
125
|
);
|
@@ -99,7 +129,7 @@ export async function shutdownWorkers(): Promise<void> {
|
|
99
129
|
export function gracefullyKill(worker: Worker): void {
|
100
130
|
worker.isShuttingDown = true;
|
101
131
|
const timeout = setTimeout(() => {
|
102
|
-
worker.
|
132
|
+
if (worker.process.pid) void killTree(worker.process.pid);
|
103
133
|
}, 10000);
|
104
134
|
worker.on('exit', () => {
|
105
135
|
clearTimeout(timeout);
|
@@ -107,9 +137,34 @@ export function gracefullyKill(worker: Worker): void {
|
|
107
137
|
sendShutdownMessage(worker);
|
108
138
|
}
|
109
139
|
|
140
|
+
export async function killTree(rootPid: number): Promise<void> {
|
141
|
+
const pids = await pidtree(rootPid, { root: true });
|
142
|
+
|
143
|
+
pids.forEach((pid) => {
|
144
|
+
try {
|
145
|
+
process.kill(pid, 'SIGKILL');
|
146
|
+
} catch {
|
147
|
+
/* noop */
|
148
|
+
}
|
149
|
+
});
|
150
|
+
}
|
151
|
+
|
152
|
+
export function shutdownWithError(): void {
|
153
|
+
process.exit(1);
|
154
|
+
}
|
155
|
+
|
156
|
+
export function resolvePlaywrightBrowserType(browserName: string): (typeof browserTypes)[keyof typeof browserTypes] {
|
157
|
+
assert(
|
158
|
+
browserName in browserTypes,
|
159
|
+
new Error(`Failed to match browser name "${browserName}" to playwright browserType`),
|
160
|
+
);
|
161
|
+
|
162
|
+
return browserTypes[browserName as keyof typeof browserTypes];
|
163
|
+
}
|
164
|
+
|
110
165
|
export async function getCreeveyCache(): Promise<string | undefined> {
|
111
166
|
const { default: findCacheDir } = await import('find-cache-dir');
|
112
|
-
return findCacheDir({ name: 'creevey', cwd: dirname(fileURLToPath(importMetaUrl)) });
|
167
|
+
return findCacheDir({ name: 'creevey', cwd: path.dirname(fileURLToPath(importMetaUrl)) });
|
113
168
|
}
|
114
169
|
|
115
170
|
export async function runSequence(seq: (() => unknown)[], predicate: () => boolean): Promise<boolean> {
|
@@ -142,11 +197,12 @@ export function testsToImages(tests: (TestData | undefined)[]): Set<string> {
|
|
142
197
|
|
143
198
|
// https://tuhrig.de/how-to-know-you-are-inside-a-docker-container/
|
144
199
|
export const isInsideDocker =
|
145
|
-
fs.existsSync('/proc/1/cgroup') && fs.readFileSync('/proc/1/cgroup', 'utf-8').includes('docker')
|
200
|
+
(fs.existsSync('/proc/1/cgroup') && fs.readFileSync('/proc/1/cgroup', 'utf-8').includes('docker')) ||
|
201
|
+
process.env.DOCKER === 'true';
|
146
202
|
|
147
203
|
export const downloadBinary = (downloadUrl: string, destination: string): Promise<void> =>
|
148
204
|
new Promise((resolve, reject) =>
|
149
|
-
get(downloadUrl, (response) => {
|
205
|
+
https.get(downloadUrl, (response) => {
|
150
206
|
if (response.statusCode == 302) {
|
151
207
|
const { location } = response.headers;
|
152
208
|
if (!location) {
|
@@ -186,10 +242,10 @@ export function readDirRecursive(dirPath: string): string[] {
|
|
186
242
|
);
|
187
243
|
}
|
188
244
|
|
189
|
-
const _require = createRequire(importMetaUrl);
|
190
245
|
export function tryToLoadTestsData(filename: string): Partial<Record<string, ServerTest>> | undefined {
|
191
246
|
try {
|
192
|
-
|
247
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, import-x/no-dynamic-require
|
248
|
+
return require(filename) as Partial<Record<string, ServerTest>>;
|
193
249
|
} catch {
|
194
250
|
/* noop */
|
195
251
|
}
|
@@ -199,19 +255,71 @@ const [nodeVersion] = process.versions.node.split('.').map(Number);
|
|
199
255
|
export async function loadThroughTSX<T>(
|
200
256
|
callback: (load: (modulePath: string) => Promise<T>) => Promise<T>,
|
201
257
|
): Promise<T> {
|
202
|
-
|
203
|
-
const
|
258
|
+
const unregisterESM = nodeVersion > 18 ? esmRegister() : noop;
|
259
|
+
const unregisterCJS = cjsRegister();
|
204
260
|
|
205
261
|
const result = await callback((modulePath) =>
|
206
262
|
nodeVersion > 18
|
207
263
|
? import(modulePath)
|
208
|
-
: // eslint-disable-next-line @typescript-eslint/no-require-imports
|
264
|
+
: // eslint-disable-next-line @typescript-eslint/no-require-imports, import-x/no-dynamic-require
|
209
265
|
Promise.resolve(require(modulePath) as T),
|
210
266
|
);
|
211
267
|
|
212
268
|
// NOTE: `unregister` type is `(() => Promise<void>) | (() => void)`
|
213
269
|
// eslint-disable-next-line @typescript-eslint/await-thenable, @typescript-eslint/no-confusing-void-expression
|
214
|
-
await
|
270
|
+
await unregisterCJS();
|
271
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable, @typescript-eslint/no-confusing-void-expression
|
272
|
+
await unregisterESM();
|
215
273
|
|
216
274
|
return result;
|
217
275
|
}
|
276
|
+
|
277
|
+
export function waitOnUrl(waitUrl: string, timeout: number, delay: number) {
|
278
|
+
const urls = [waitUrl];
|
279
|
+
if (!LOCALHOST_REGEXP.test(waitUrl)) {
|
280
|
+
const parsedUrl = new URL(waitUrl);
|
281
|
+
parsedUrl.host = 'localhost';
|
282
|
+
urls.push(parsedUrl.toString());
|
283
|
+
}
|
284
|
+
const startTime = Date.now();
|
285
|
+
return Promise.race(
|
286
|
+
urls.map(
|
287
|
+
(url) =>
|
288
|
+
new Promise<void>((resolve, reject) => {
|
289
|
+
const interval = setInterval(() => {
|
290
|
+
http
|
291
|
+
.get(url, (response) => {
|
292
|
+
if (response.statusCode === 200) {
|
293
|
+
clearInterval(interval);
|
294
|
+
resolve();
|
295
|
+
}
|
296
|
+
})
|
297
|
+
.on('error', () => {
|
298
|
+
// Ignore HTTP errors
|
299
|
+
});
|
300
|
+
|
301
|
+
if (Date.now() - startTime > timeout) {
|
302
|
+
clearInterval(interval);
|
303
|
+
reject(new Error(`${url} didn't respond within ${timeout / 1000} seconds`));
|
304
|
+
}
|
305
|
+
}, delay);
|
306
|
+
}),
|
307
|
+
),
|
308
|
+
);
|
309
|
+
}
|
310
|
+
|
311
|
+
/**
|
312
|
+
* Copies static assets to the report directory
|
313
|
+
* @param reportDir Directory where the report will be generated
|
314
|
+
*/
|
315
|
+
export async function copyStatics(reportDir: string): Promise<void> {
|
316
|
+
const clientDir = path.join(path.dirname(fileURLToPath(importMetaUrl)), '../../dist/client/web');
|
317
|
+
const assets = (await fs.promises.readdir(path.join(clientDir, 'assets'), { withFileTypes: true }))
|
318
|
+
.filter((dirent) => dirent.isFile())
|
319
|
+
.map((dirent) => dirent.name);
|
320
|
+
await fs.promises.mkdir(path.join(reportDir, 'assets'), { recursive: true });
|
321
|
+
await fs.promises.copyFile(path.join(clientDir, 'index.html'), path.join(reportDir, 'index.html'));
|
322
|
+
for (const asset of assets) {
|
323
|
+
await fs.promises.copyFile(path.join(clientDir, 'assets', asset), path.join(reportDir, 'assets', asset));
|
324
|
+
}
|
325
|
+
}
|
package/src/server/webdriver.ts
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
import type { Container } from 'dockerode';
|
2
|
+
|
3
|
+
let workerContainer: Container | null = null;
|
4
|
+
|
5
|
+
export function setWorkerContainer(container: Container): void {
|
6
|
+
workerContainer = container;
|
7
|
+
}
|
8
|
+
|
9
|
+
export async function removeWorkerContainer(): Promise<void> {
|
10
|
+
if (workerContainer) {
|
11
|
+
await workerContainer.remove({ force: true });
|
12
|
+
workerContainer = null;
|
13
|
+
}
|
14
|
+
}
|