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
@@ -0,0 +1,71 @@
|
|
1
|
+
import chalk from 'chalk';
|
2
|
+
import Logger from 'loglevel';
|
3
|
+
import prefix from 'loglevel-plugin-prefix';
|
4
|
+
import { FakeTest, isImageError, TEST_EVENTS } from '../../types.js';
|
5
|
+
import EventEmitter from 'events';
|
6
|
+
|
7
|
+
const testLevels: Record<string, string> = {
|
8
|
+
INFO: chalk.green('PASS'),
|
9
|
+
WARN: chalk.yellow('START'),
|
10
|
+
ERROR: chalk.red('FAIL'),
|
11
|
+
};
|
12
|
+
|
13
|
+
export class CreeveyReporter {
|
14
|
+
private logger: Logger.Logger | null = null;
|
15
|
+
// TODO Output in better way, like vitest, maybe
|
16
|
+
constructor(runner: EventEmitter) {
|
17
|
+
runner.on(TEST_EVENTS.TEST_BEGIN, (test: FakeTest) => {
|
18
|
+
this.getLogger(test.creevey).warn(chalk.cyan(test.fullTitle()));
|
19
|
+
});
|
20
|
+
runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
|
21
|
+
this.getLogger(test.creevey).info(chalk.cyan(test.fullTitle()), chalk.gray(`(${test.duration} ms)`));
|
22
|
+
});
|
23
|
+
runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error) => {
|
24
|
+
this.getLogger(test.creevey).error(
|
25
|
+
chalk.cyan(test.fullTitle()),
|
26
|
+
chalk.gray(`(${test.duration} ms)`),
|
27
|
+
'\n ',
|
28
|
+
this.getErrors(
|
29
|
+
error,
|
30
|
+
(error, imageName) => `${chalk.bold(imageName ?? test.creevey.browserName)}:${error}`,
|
31
|
+
(error) => error.stack ?? error.message,
|
32
|
+
).join('\n '),
|
33
|
+
);
|
34
|
+
});
|
35
|
+
}
|
36
|
+
|
37
|
+
private getLogger(options: { sessionId: string; browserName: string }) {
|
38
|
+
if (this.logger) return this.logger;
|
39
|
+
const { sessionId, browserName } = options;
|
40
|
+
const testLogger = Logger.getLogger(sessionId);
|
41
|
+
|
42
|
+
this.logger = prefix.apply(testLogger, {
|
43
|
+
format(level) {
|
44
|
+
return `[${browserName}:${chalk.gray(process.pid)}] ${testLevels[level]} => ${chalk.gray(sessionId)}`;
|
45
|
+
},
|
46
|
+
});
|
47
|
+
|
48
|
+
return this.logger;
|
49
|
+
}
|
50
|
+
|
51
|
+
private getErrors(
|
52
|
+
error: unknown,
|
53
|
+
imageErrorToString: (error: string, imageName?: string) => string,
|
54
|
+
errorToString: (error: Error) => string,
|
55
|
+
): string[] {
|
56
|
+
const errors = [];
|
57
|
+
if (!(error instanceof Error)) {
|
58
|
+
errors.push(error as string);
|
59
|
+
} else if (!isImageError(error)) {
|
60
|
+
errors.push(errorToString(error));
|
61
|
+
} else if (typeof error.images == 'string') {
|
62
|
+
errors.push(imageErrorToString(error.images));
|
63
|
+
} else {
|
64
|
+
const imageErrors = error.images ?? {};
|
65
|
+
Object.keys(imageErrors).forEach((imageName) => {
|
66
|
+
errors.push(imageErrorToString(imageErrors[imageName] ?? '', imageName));
|
67
|
+
});
|
68
|
+
}
|
69
|
+
return errors;
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { BaseReporter } from '../../types.js';
|
2
|
+
import { CreeveyReporter } from './creevey.js';
|
3
|
+
import { JUnitReporter } from './junit.js';
|
4
|
+
import { TeamcityReporter } from './teamcity.js';
|
5
|
+
|
6
|
+
export function getReporter(reporter: BaseReporter | 'creevey' | 'teamcity' | 'junit'): BaseReporter {
|
7
|
+
if (reporter === 'creevey') return CreeveyReporter;
|
8
|
+
if (reporter === 'teamcity') return TeamcityReporter;
|
9
|
+
if (reporter === 'junit') return JUnitReporter;
|
10
|
+
return reporter;
|
11
|
+
}
|
@@ -0,0 +1,207 @@
|
|
1
|
+
import EventEmitter from 'events';
|
2
|
+
import { dirname, resolve } from 'path';
|
3
|
+
import { closeSync, existsSync, mkdirSync, openSync, writeFileSync } from 'fs';
|
4
|
+
import { TEST_EVENTS, FakeTest } from '../../types.js';
|
5
|
+
import { logger } from '../logger.js';
|
6
|
+
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
8
|
+
class IndentedLogger<T = any> {
|
9
|
+
private currentIndent = '';
|
10
|
+
|
11
|
+
constructor(private baseLog: (text: string) => T) {}
|
12
|
+
|
13
|
+
indent(): void {
|
14
|
+
this.currentIndent += ' ';
|
15
|
+
}
|
16
|
+
|
17
|
+
unindent(): void {
|
18
|
+
this.currentIndent = this.currentIndent.substring(0, this.currentIndent.length - 4);
|
19
|
+
}
|
20
|
+
|
21
|
+
log(text: string): T {
|
22
|
+
return this.baseLog(this.currentIndent + text);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
// NOTE: This is a reworked copy of the JUnitReporter class from Vitest.
|
27
|
+
export class JUnitReporter {
|
28
|
+
private reportFile: string;
|
29
|
+
private fileFd?: number;
|
30
|
+
private logger: IndentedLogger<void>;
|
31
|
+
private suites: Record<string, FakeTest[]> = {};
|
32
|
+
// TODO classnameTemplate
|
33
|
+
// TODO Output console logs
|
34
|
+
// TODO Output attachments
|
35
|
+
constructor(runner: EventEmitter, options: { reportDir: string; reporterOptions: { outputFile?: string } }) {
|
36
|
+
const { reportDir, reporterOptions } = options;
|
37
|
+
|
38
|
+
this.reportFile = reporterOptions.outputFile ?? resolve(reportDir, 'junit.xml');
|
39
|
+
|
40
|
+
this.logger = new IndentedLogger((text) => {
|
41
|
+
this.fileFd ??= openSync(this.reportFile, 'w+');
|
42
|
+
|
43
|
+
writeFileSync(this.fileFd, `${text}\n`);
|
44
|
+
});
|
45
|
+
|
46
|
+
runner.on(TEST_EVENTS.RUN_BEGIN, () => {
|
47
|
+
this.suites = {};
|
48
|
+
|
49
|
+
const outputDirectory = dirname(this.reportFile);
|
50
|
+
if (!existsSync(outputDirectory)) {
|
51
|
+
mkdirSync(outputDirectory, { recursive: true });
|
52
|
+
}
|
53
|
+
|
54
|
+
this.fileFd = openSync(this.reportFile, 'w+');
|
55
|
+
});
|
56
|
+
runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
|
57
|
+
const suite = (this.suites[test.parent.title] ??= []);
|
58
|
+
suite.push(test);
|
59
|
+
});
|
60
|
+
runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest) => {
|
61
|
+
const suite = (this.suites[test.parent.title] ??= []);
|
62
|
+
suite.push(test);
|
63
|
+
});
|
64
|
+
runner.on(TEST_EVENTS.RUN_END, () => {
|
65
|
+
this.onFinished();
|
66
|
+
});
|
67
|
+
}
|
68
|
+
|
69
|
+
private writeElement(name: string, attrs: Record<string, string | number | undefined>, children?: () => void): void {
|
70
|
+
const pairs: string[] = [];
|
71
|
+
for (const key in attrs) {
|
72
|
+
const attr = attrs[key];
|
73
|
+
if (attr === undefined) {
|
74
|
+
continue;
|
75
|
+
}
|
76
|
+
|
77
|
+
pairs.push(`${key}="${escapeXML(attr)}"`);
|
78
|
+
}
|
79
|
+
|
80
|
+
this.logger.log(`<${name}${pairs.length ? ` ${pairs.join(' ')}` : ''}>`);
|
81
|
+
this.logger.indent();
|
82
|
+
children?.call(this);
|
83
|
+
this.logger.unindent();
|
84
|
+
|
85
|
+
this.logger.log(`</${name}>`);
|
86
|
+
}
|
87
|
+
|
88
|
+
private writeTasks(tests: FakeTest[]): void {
|
89
|
+
for (const test of tests) {
|
90
|
+
const classname = test.parent.title;
|
91
|
+
|
92
|
+
this.writeElement(
|
93
|
+
'testcase',
|
94
|
+
{
|
95
|
+
classname,
|
96
|
+
name: test.title,
|
97
|
+
time: getDuration(test),
|
98
|
+
},
|
99
|
+
() => {
|
100
|
+
if (test.state === 'failed') {
|
101
|
+
const error = test.err;
|
102
|
+
this.writeElement('failure', { message: error });
|
103
|
+
}
|
104
|
+
},
|
105
|
+
);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
private onFinished(): void {
|
110
|
+
this.logger.log('<?xml version="1.0" encoding="UTF-8" ?>');
|
111
|
+
|
112
|
+
const suites = Object.entries(this.suites).map(([name, tests]) => {
|
113
|
+
return {
|
114
|
+
name,
|
115
|
+
tests,
|
116
|
+
failures: tests.filter((test) => test.state === 'failed').length,
|
117
|
+
time: tests.reduce((acc, test) => acc + (test.duration ?? 0), 0),
|
118
|
+
};
|
119
|
+
});
|
120
|
+
const stats = suites.reduce(
|
121
|
+
(s, { tests, failures, time }) => {
|
122
|
+
s.tests += tests.length;
|
123
|
+
s.failures += failures;
|
124
|
+
s.time += time;
|
125
|
+
return s;
|
126
|
+
},
|
127
|
+
{ name: 'creevey tests', tests: 0, failures: 0, time: 0 },
|
128
|
+
);
|
129
|
+
|
130
|
+
this.writeElement('testsuites', { ...stats, time: executionTime(stats.time) }, () => {
|
131
|
+
suites.forEach(({ name, tests, failures, time }) => {
|
132
|
+
this.writeElement(
|
133
|
+
'testsuite',
|
134
|
+
{
|
135
|
+
name,
|
136
|
+
tests: tests.length,
|
137
|
+
failures,
|
138
|
+
time: executionTime(time),
|
139
|
+
},
|
140
|
+
() => {
|
141
|
+
this.writeTasks(tests);
|
142
|
+
},
|
143
|
+
);
|
144
|
+
});
|
145
|
+
});
|
146
|
+
|
147
|
+
if (this.reportFile) {
|
148
|
+
logger().info(`JUNIT report written to ${this.reportFile}`);
|
149
|
+
}
|
150
|
+
|
151
|
+
if (this.fileFd) {
|
152
|
+
closeSync(this.fileFd);
|
153
|
+
this.fileFd = undefined;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
// https://gist.github.com/john-doherty/b9195065884cdbfd2017a4756e6409cc
|
159
|
+
function removeInvalidXMLCharacters(value: string, removeDiscouragedChars: boolean): string {
|
160
|
+
let regex =
|
161
|
+
// eslint-disable-next-line no-control-regex
|
162
|
+
/([\0-\x08\v\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g;
|
163
|
+
value = String(value).replace(regex, '');
|
164
|
+
|
165
|
+
if (removeDiscouragedChars) {
|
166
|
+
// remove everything discouraged by XML 1.0 specifications
|
167
|
+
regex = new RegExp(
|
168
|
+
'([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|\\uD83F[\\uDFFE\\uDFFF]|(?:\\uD87F[\\uDF' +
|
169
|
+
'FE\\uDFFF])|\\uD8BF[\\uDFFE\\uDFFF]|\\uD8FF[\\uDFFE\\uDFFF]|(?:\\uD93F[\\uDFFE\\uD' +
|
170
|
+
'FFF])|\\uD97F[\\uDFFE\\uDFFF]|\\uD9BF[\\uDFFE\\uDFFF]|\\uD9FF[\\uDFFE\\uDFFF]' +
|
171
|
+
'|\\uDA3F[\\uDFFE\\uDFFF]|\\uDA7F[\\uDFFE\\uDFFF]|\\uDABF[\\uDFFE\\uDFFF]|(?:\\' +
|
172
|
+
'uDAFF[\\uDFFE\\uDFFF])|\\uDB3F[\\uDFFE\\uDFFF]|\\uDB7F[\\uDFFE\\uDFFF]|(?:\\uDBBF' +
|
173
|
+
'[\\uDFFE\\uDFFF])|\\uDBFF[\\uDFFE\\uDFFF](?:[\\0-\\t\\v\\f\\x0E-\\u2027\\u202A-\\uD7FF\\' +
|
174
|
+
'uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|' +
|
175
|
+
'(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))',
|
176
|
+
'g',
|
177
|
+
);
|
178
|
+
|
179
|
+
value = value.replace(regex, '');
|
180
|
+
}
|
181
|
+
|
182
|
+
return value;
|
183
|
+
}
|
184
|
+
|
185
|
+
function escapeXML(value: string | number): string {
|
186
|
+
return removeInvalidXMLCharacters(
|
187
|
+
String(value)
|
188
|
+
.replace(/&/g, '&')
|
189
|
+
.replace(/"/g, '"')
|
190
|
+
.replace(/'/g, ''')
|
191
|
+
.replace(/</g, '<')
|
192
|
+
.replace(/>/g, '>'),
|
193
|
+
true,
|
194
|
+
);
|
195
|
+
}
|
196
|
+
|
197
|
+
function executionTime(durationMS: number) {
|
198
|
+
return (durationMS / 1000).toLocaleString('en-US', {
|
199
|
+
useGrouping: false,
|
200
|
+
maximumFractionDigits: 10,
|
201
|
+
});
|
202
|
+
}
|
203
|
+
|
204
|
+
function getDuration(task: FakeTest): string | undefined {
|
205
|
+
const duration = task.duration ?? 0;
|
206
|
+
return executionTime(duration);
|
207
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import { FakeTest, Images, isDefined, TEST_EVENTS } from '../../types.js';
|
2
|
+
import EventEmitter from 'events';
|
3
|
+
|
4
|
+
export class TeamcityReporter {
|
5
|
+
constructor(runner: EventEmitter, options: { reportDir: string }) {
|
6
|
+
const { reportDir } = options;
|
7
|
+
|
8
|
+
runner.on(TEST_EVENTS.TEST_BEGIN, (test: FakeTest) => {
|
9
|
+
console.log(`##teamcity[testStarted name='${this.escape(test.fullTitle())}' flowId='${test.creevey.workerId}']`);
|
10
|
+
});
|
11
|
+
|
12
|
+
runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
|
13
|
+
console.log(`##teamcity[testFinished name='${this.escape(test.fullTitle())}' flowId='${test.creevey.workerId}']`);
|
14
|
+
});
|
15
|
+
|
16
|
+
runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error: Error) => {
|
17
|
+
const browserName = this.escape(test.creevey.browserName);
|
18
|
+
Object.entries(test.creevey.images).forEach(([name, image]) => {
|
19
|
+
if (!image) return;
|
20
|
+
const filePath = test
|
21
|
+
.titlePath()
|
22
|
+
.slice(0, -1)
|
23
|
+
.concat(name == browserName ? [] : [browserName])
|
24
|
+
.map(this.escape)
|
25
|
+
.join('/');
|
26
|
+
|
27
|
+
const { error: _, ...rest } = image;
|
28
|
+
Object.values(rest as Partial<Images>)
|
29
|
+
.filter(isDefined)
|
30
|
+
.forEach((fileName) => {
|
31
|
+
console.log(`##teamcity[publishArtifacts '${reportDir}/${filePath}/${fileName} => report/${filePath}']`);
|
32
|
+
console.log(
|
33
|
+
`##teamcity[testMetadata testName='${this.escape(
|
34
|
+
test.fullTitle(),
|
35
|
+
)}' type='image' value='report/${filePath}/${fileName}' flowId='${test.creevey.workerId}']`,
|
36
|
+
);
|
37
|
+
});
|
38
|
+
});
|
39
|
+
|
40
|
+
// Output failed test as passed due TC don't support retry mechanic
|
41
|
+
// https://teamcity-support.jetbrains.com/hc/en-us/community/posts/207216829-Count-test-as-successful-if-at-least-one-try-is-successful?page=1#community_comment_207394125
|
42
|
+
|
43
|
+
if (test.creevey.willRetry)
|
44
|
+
console.log(
|
45
|
+
`##teamcity[testFinished name='${this.escape(test.fullTitle())}' flowId='${test.creevey.workerId}']`,
|
46
|
+
);
|
47
|
+
else
|
48
|
+
console.log(
|
49
|
+
`##teamcity[testFailed name='${this.escape(test.fullTitle())}' message='${this.escape(
|
50
|
+
error.message,
|
51
|
+
)}' details='${this.escape(error.stack ?? '')}' flowId='${test.creevey.workerId}']`,
|
52
|
+
);
|
53
|
+
});
|
54
|
+
}
|
55
|
+
|
56
|
+
private escape = (str: string): string => {
|
57
|
+
if (!str) return '';
|
58
|
+
return (
|
59
|
+
str
|
60
|
+
.toString()
|
61
|
+
// eslint-disable-next-line no-control-regex
|
62
|
+
.replace(/\x1B.*?m/g, '')
|
63
|
+
.replace(/\|/g, '||')
|
64
|
+
.replace(/\n/g, '|n')
|
65
|
+
.replace(/\r/g, '|r')
|
66
|
+
.replace(/\[/g, '|[')
|
67
|
+
.replace(/\]/g, '|]')
|
68
|
+
.replace(/\u0085/g, '|x')
|
69
|
+
.replace(/\u2028/g, '|l')
|
70
|
+
.replace(/\u2029/g, '|p')
|
71
|
+
.replace(/'/g, "|'")
|
72
|
+
);
|
73
|
+
};
|
74
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Args } from '
|
1
|
+
import type { Args } from 'storybook/internal/types';
|
2
2
|
import chalk from 'chalk';
|
3
3
|
import http from 'http';
|
4
4
|
import https from 'https';
|
@@ -19,12 +19,12 @@ import {
|
|
19
19
|
StorybookGlobals,
|
20
20
|
StoryInput,
|
21
21
|
StoriesRaw,
|
22
|
-
|
22
|
+
WorkerOptions,
|
23
23
|
ServerTest,
|
24
24
|
StorybookEvents,
|
25
25
|
} from '../../types.js';
|
26
26
|
import { colors, logger } from '../logger.js';
|
27
|
-
import { subscribeOn } from '../messages.js';
|
27
|
+
import { emitWorkerMessage, subscribeOn } from '../messages.js';
|
28
28
|
import { getTestPath, isShuttingDown, runSequence } from '../utils.js';
|
29
29
|
import {
|
30
30
|
appendIframePath,
|
@@ -97,7 +97,7 @@ async function buildWebdriver(
|
|
97
97
|
browser: string,
|
98
98
|
gridUrl: string,
|
99
99
|
config: Config,
|
100
|
-
options:
|
100
|
+
options: WorkerOptions,
|
101
101
|
): Promise<WebDriver | null> {
|
102
102
|
const browserConfig = config.browsers[browser] as BrowserConfigObject;
|
103
103
|
const { /*customizeBuilder,*/ seleniumCapabilities, browserName } = browserConfig;
|
@@ -191,11 +191,13 @@ export class InternalBrowser {
|
|
191
191
|
#browser: WebDriver;
|
192
192
|
#serverHost: string | null = null;
|
193
193
|
#serverPort: number;
|
194
|
+
#storybookGlobals?: StorybookGlobals;
|
194
195
|
#unsubscribe: () => void = noop;
|
195
196
|
#keepAliveInterval: NodeJS.Timeout | null = null;
|
196
|
-
constructor(browser: WebDriver, port: number) {
|
197
|
+
constructor(browser: WebDriver, port: number, storybookGlobals?: StorybookGlobals) {
|
197
198
|
this.#browser = browser;
|
198
199
|
this.#serverPort = port;
|
200
|
+
this.#storybookGlobals = storybookGlobals;
|
199
201
|
this.#unsubscribe = subscribeOn('shutdown', () => {
|
200
202
|
void this.closeBrowser();
|
201
203
|
});
|
@@ -247,7 +249,7 @@ export class InternalBrowser {
|
|
247
249
|
const rects = await this.#browser.executeScript<
|
248
250
|
{ elementRect: ElementRect; windowRect: ElementRect } | undefined
|
249
251
|
>(function (selector: string): { elementRect: ElementRect; windowRect: ElementRect } | undefined {
|
250
|
-
window.scrollTo(0, 0);
|
252
|
+
window.scrollTo(0, 0);
|
251
253
|
// eslint-disable-next-line no-var
|
252
254
|
var element = document.querySelector(selector);
|
253
255
|
if (!element) return;
|
@@ -264,9 +266,7 @@ export class InternalBrowser {
|
|
264
266
|
},
|
265
267
|
// NOTE page_Offset is used only for IE9-11
|
266
268
|
windowRect: {
|
267
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
268
269
|
top: Math.round(window.scrollY || window.pageYOffset),
|
269
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
270
270
|
left: Math.round(window.scrollX || window.pageXOffset),
|
271
271
|
width: window.innerWidth,
|
272
272
|
height: window.innerHeight,
|
@@ -295,12 +295,10 @@ export class InternalBrowser {
|
|
295
295
|
// ? context
|
296
296
|
// ? await context.captureElementScreenshot(await element.getId())
|
297
297
|
// : await browser.findElement(By.css(captureElement)).takeScreenshot()
|
298
|
-
// :
|
299
|
-
// await takeCompositeScreenshot(browser, windowRect, elementRect);
|
298
|
+
// : await takeCompositeScreenshot(browser, windowRect, elementRect);
|
300
299
|
screenshot = isFitIntoViewport
|
301
300
|
? await this.#browser.findElement(By.css(captureElement)).takeScreenshot()
|
302
|
-
:
|
303
|
-
await this.takeCompositeScreenshot(windowRect, elementRect);
|
301
|
+
: await this.takeCompositeScreenshot(windowRect, elementRect);
|
304
302
|
|
305
303
|
logger().debug(`${chalk.cyan(captureElement)} is captured`);
|
306
304
|
}
|
@@ -321,6 +319,7 @@ export class InternalBrowser {
|
|
321
319
|
|
322
320
|
async selectStory(id: string, waitForReady = false): Promise<boolean> {
|
323
321
|
// NOTE: Global variables might be reset after hot reload. I think it's workaround, maybe we need better solution
|
322
|
+
await this.updateStorybookGlobals();
|
324
323
|
await this.updateBrowserGlobalVariables();
|
325
324
|
await this.resetMousePosition();
|
326
325
|
|
@@ -374,12 +373,32 @@ export class InternalBrowser {
|
|
374
373
|
}
|
375
374
|
|
376
375
|
async loadStoriesFromBrowser(): Promise<StoriesRaw> {
|
377
|
-
const
|
378
|
-
|
376
|
+
const result = await this.#browser.executeAsyncScript<
|
377
|
+
[error?: { message: string; stack?: string } | null, stories?: StoriesRaw]
|
378
|
+
>(function (
|
379
|
+
callback: (response: [error?: { message: string; stack?: string } | null, stories?: StoriesRaw]) => void,
|
379
380
|
) {
|
380
|
-
|
381
|
+
window
|
382
|
+
.__CREEVEY_GET_STORIES__()
|
383
|
+
.then((stories) => {
|
384
|
+
callback([null, stories]);
|
385
|
+
})
|
386
|
+
.catch((error: unknown) => {
|
387
|
+
const errorInfo = {
|
388
|
+
message: error instanceof Error ? error.message : String(error),
|
389
|
+
stack: error instanceof Error ? error.stack : undefined,
|
390
|
+
};
|
391
|
+
callback([errorInfo]);
|
392
|
+
});
|
381
393
|
});
|
382
394
|
|
395
|
+
const [error, stories] = result;
|
396
|
+
|
397
|
+
if (error) {
|
398
|
+
const errorObj = new Error(error.message);
|
399
|
+
if (error.stack) errorObj.stack = error.stack;
|
400
|
+
throw errorObj;
|
401
|
+
}
|
383
402
|
if (!stories) throw new Error("Can't get stories, it seems creevey or storybook API isn't available");
|
384
403
|
|
385
404
|
return stories;
|
@@ -407,17 +426,24 @@ export class InternalBrowser {
|
|
407
426
|
browserName: string,
|
408
427
|
gridUrl: string,
|
409
428
|
config: Config,
|
410
|
-
options:
|
429
|
+
options: WorkerOptions,
|
411
430
|
): Promise<InternalBrowser | null> {
|
412
431
|
const browserConfig = config.browsers[browserName] as BrowserConfigObject;
|
413
|
-
const {
|
432
|
+
const {
|
433
|
+
storybookUrl: address = config.storybookUrl,
|
434
|
+
limit,
|
435
|
+
viewport,
|
436
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
437
|
+
_storybookGlobals,
|
438
|
+
storybookGlobals = _storybookGlobals,
|
439
|
+
} = browserConfig;
|
414
440
|
void limit;
|
415
441
|
|
416
442
|
const browser = await buildWebdriver(browserName, gridUrl, config, options);
|
417
443
|
|
418
444
|
if (!browser) return null;
|
419
445
|
|
420
|
-
const internalBrowser = new InternalBrowser(browser, options.port);
|
446
|
+
const internalBrowser = new InternalBrowser(browser, options.port, storybookGlobals);
|
421
447
|
|
422
448
|
try {
|
423
449
|
if (isShuttingDown.current) return null;
|
@@ -427,8 +453,6 @@ export class InternalBrowser {
|
|
427
453
|
gridUrl,
|
428
454
|
viewport,
|
429
455
|
storybookUrl: address,
|
430
|
-
storybookGlobals: _storybookGlobals,
|
431
|
-
resolveStorybookUrl: config.resolveStorybookUrl,
|
432
456
|
});
|
433
457
|
|
434
458
|
return done ? internalBrowser : null;
|
@@ -451,15 +475,11 @@ export class InternalBrowser {
|
|
451
475
|
gridUrl,
|
452
476
|
viewport,
|
453
477
|
storybookUrl,
|
454
|
-
storybookGlobals,
|
455
|
-
resolveStorybookUrl,
|
456
478
|
}: {
|
457
479
|
browserName: string;
|
458
480
|
gridUrl: string;
|
459
481
|
viewport?: { width: number; height: number };
|
460
482
|
storybookUrl: string;
|
461
|
-
storybookGlobals?: StorybookGlobals;
|
462
|
-
resolveStorybookUrl?: () => Promise<string>;
|
463
483
|
}): Promise<boolean> {
|
464
484
|
const sessionId = (await this.#browser.getSession()).getId();
|
465
485
|
let browserHost = '';
|
@@ -483,9 +503,9 @@ export class InternalBrowser {
|
|
483
503
|
return await runSequence(
|
484
504
|
[
|
485
505
|
() => this.#browser.manage().setTimeouts({ pageLoad: 60000, script: 60000 }),
|
486
|
-
() => this.openStorybookPage(storybookUrl
|
506
|
+
() => this.openStorybookPage(storybookUrl),
|
487
507
|
() => this.waitForStorybook(),
|
488
|
-
() => this.updateStorybookGlobals(
|
508
|
+
() => this.updateStorybookGlobals(),
|
489
509
|
() => this.resolveCreeveyHost(),
|
490
510
|
() => this.updateBrowserGlobalVariables(),
|
491
511
|
// NOTE: Selenium draws automation toolbar with some delay after webdriver initialization
|
@@ -500,25 +520,14 @@ export class InternalBrowser {
|
|
500
520
|
);
|
501
521
|
}
|
502
522
|
|
503
|
-
private async openStorybookPage(storybookUrl: string
|
523
|
+
private async openStorybookPage(storybookUrl: string): Promise<void> {
|
504
524
|
if (!LOCALHOST_REGEXP.test(storybookUrl)) {
|
505
525
|
return this.#browser.get(appendIframePath(storybookUrl));
|
506
526
|
}
|
507
527
|
|
508
528
|
try {
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
const resolvedUrl = await resolver();
|
513
|
-
|
514
|
-
logger().debug(`Resolver storybook url ${resolvedUrl}`);
|
515
|
-
|
516
|
-
await this.#browser.get(appendIframePath(resolvedUrl));
|
517
|
-
} else {
|
518
|
-
// TODO Pageload timeout 10s
|
519
|
-
// NOTE: getUrlChecker already calls `browser.get` so we don't need another one
|
520
|
-
await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
|
521
|
-
}
|
529
|
+
// NOTE: getUrlChecker already calls `browser.get` so we don't need another one
|
530
|
+
await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
|
522
531
|
} catch (error) {
|
523
532
|
logger().error('Failed to resolve storybook URL', error instanceof Error ? error.message : '');
|
524
533
|
throw error;
|
@@ -554,7 +563,7 @@ export class InternalBrowser {
|
|
554
563
|
}
|
555
564
|
|
556
565
|
private async waitForStorybook(): Promise<void> {
|
557
|
-
logger().debug('Waiting for
|
566
|
+
logger().debug('Waiting for Storybook to initiate');
|
558
567
|
|
559
568
|
const isTimeout = await Promise.race([
|
560
569
|
new Promise<boolean>((resolve) => {
|
@@ -567,9 +576,6 @@ export class InternalBrowser {
|
|
567
576
|
do {
|
568
577
|
// TODO Research a different way to ensure storybook is initiated
|
569
578
|
wait = await this.#browser.executeScript<boolean>(function (SET_GLOBALS: string): boolean {
|
570
|
-
// TODO Maybe use
|
571
|
-
// import { global } from '@storybook/global';
|
572
|
-
// global.IS_STORYBOOK
|
573
579
|
if (typeof window.__STORYBOOK_ADDONS_CHANNEL__ == 'undefined') return true;
|
574
580
|
if (window.__STORYBOOK_ADDONS_CHANNEL__.last(SET_GLOBALS) == undefined) return true;
|
575
581
|
return false;
|
@@ -579,21 +585,22 @@ export class InternalBrowser {
|
|
579
585
|
})(),
|
580
586
|
]);
|
581
587
|
|
582
|
-
|
583
|
-
if (isTimeout) throw new Error('Failed to wait `setStories` event');
|
588
|
+
if (isTimeout) throw new Error('Failed to wait Storybook init');
|
584
589
|
}
|
585
590
|
|
586
|
-
private async updateStorybookGlobals(
|
587
|
-
if (!
|
591
|
+
private async updateStorybookGlobals(): Promise<void> {
|
592
|
+
if (!this.#storybookGlobals) return;
|
588
593
|
|
589
594
|
logger().debug('Applying storybook globals');
|
590
595
|
await this.#browser.executeScript(function (globals: StorybookGlobals) {
|
591
596
|
window.__CREEVEY_UPDATE_GLOBALS__(globals);
|
592
|
-
},
|
597
|
+
}, this.#storybookGlobals);
|
593
598
|
}
|
594
599
|
|
595
600
|
private async resolveCreeveyHost(): Promise<void> {
|
596
|
-
const
|
601
|
+
const storybookUrl = await this.#browser.getCurrentUrl();
|
602
|
+
const storybookHost = new URL(storybookUrl).hostname;
|
603
|
+
const addresses = [storybookHost, ...getAddresses()];
|
597
604
|
|
598
605
|
this.#serverHost = await this.#browser.executeAsyncScript(
|
599
606
|
function (hosts: string[], port: number, callback: (host?: string | null) => void) {
|
@@ -633,6 +640,7 @@ export class InternalBrowser {
|
|
633
640
|
private async updateBrowserGlobalVariables() {
|
634
641
|
await this.#browser.executeScript(
|
635
642
|
function (workerId: number, creeveyHost: string, creeveyPort: number) {
|
643
|
+
window.__CREEVEY_ENV__ = true;
|
636
644
|
window.__CREEVEY_WORKER_ID__ = workerId;
|
637
645
|
window.__CREEVEY_SERVER_HOST__ = creeveyHost;
|
638
646
|
window.__CREEVEY_SERVER_PORT__ = creeveyPort;
|
@@ -831,9 +839,18 @@ export class InternalBrowser {
|
|
831
839
|
private keepAlive(): void {
|
832
840
|
this.#keepAliveInterval = setInterval(() => {
|
833
841
|
// NOTE Simple way to keep session alive
|
834
|
-
void this.#browser
|
835
|
-
|
836
|
-
|
842
|
+
void this.#browser
|
843
|
+
.getCurrentUrl()
|
844
|
+
.then((url) => {
|
845
|
+
logger().debug('current url', chalk.magenta(url));
|
846
|
+
})
|
847
|
+
.catch((error: unknown) => {
|
848
|
+
logger().error(error);
|
849
|
+
emitWorkerMessage({
|
850
|
+
type: 'error',
|
851
|
+
payload: { subtype: 'browser', error: 'Failed to ping browser' },
|
852
|
+
});
|
853
|
+
});
|
837
854
|
}, 10 * 1000);
|
838
855
|
}
|
839
856
|
}
|