creevey 0.7.39 → 0.8.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -2
- package/README.md +9 -1
- package/addon/README.md +3 -0
- package/addon/package.json +4 -0
- package/docs/config.md +37 -5
- package/docs/grid.md +2 -1
- package/jest.config.js +6 -0
- package/lib/cjs/client/addon/Manager.js +124 -271
- package/lib/cjs/client/addon/components/Addon.js +17 -38
- package/lib/cjs/client/addon/components/Icons.js +11 -7
- package/lib/cjs/client/addon/components/Panel.js +17 -13
- package/lib/cjs/client/addon/components/TestSelect.js +11 -9
- package/lib/cjs/client/addon/components/Tools.js +21 -40
- package/lib/cjs/client/addon/decorator.js +1 -1
- package/lib/cjs/client/addon/index.js +31 -0
- package/lib/cjs/client/addon/preset.ie11.js +74 -0
- package/lib/cjs/client/addon/preset.js +13 -31
- package/lib/cjs/client/addon/readyForCapture.js +12 -0
- package/lib/cjs/client/addon/register.js +46 -70
- package/lib/cjs/client/addon/utils.js +5 -41
- package/lib/cjs/client/addon/withCreevey.js +221 -155
- package/lib/cjs/client/shared/components/ImagesView/BlendView.js +26 -24
- package/lib/cjs/client/shared/components/ImagesView/ImagesView.js +22 -18
- package/lib/cjs/client/shared/components/ImagesView/SideBySideView.js +44 -66
- package/lib/cjs/client/shared/components/ImagesView/SlideView.js +38 -50
- package/lib/cjs/client/shared/components/ImagesView/SwapView.js +26 -45
- package/lib/cjs/client/shared/components/ImagesView/index.js +9 -9
- package/lib/cjs/client/shared/components/PageFooter/PageFooter.js +12 -8
- package/lib/cjs/client/shared/components/PageFooter/Paging.js +14 -18
- package/lib/cjs/client/shared/components/PageHeader/ImagePreview.js +22 -18
- package/lib/cjs/client/shared/components/PageHeader/PageHeader.js +42 -67
- package/lib/cjs/client/shared/components/ResultsPage.js +39 -69
- package/lib/cjs/client/shared/creeveyClientApi.js +55 -82
- package/lib/cjs/client/shared/helpers.js +140 -211
- package/lib/cjs/client/shared/viewMode.js +5 -5
- package/lib/cjs/client/web/142.js +2 -0
- package/lib/cjs/client/web/142.js.LICENSE.txt +12 -0
- package/lib/cjs/client/web/32.js +1 -0
- package/lib/cjs/client/web/551.js +1 -0
- package/lib/cjs/client/web/566.js +2 -0
- package/lib/cjs/client/web/566.js.LICENSE.txt +31 -0
- package/lib/cjs/client/web/691.js +2 -0
- package/lib/cjs/client/web/691.js.LICENSE.txt +8 -0
- package/lib/cjs/client/web/725.js +1 -0
- package/lib/cjs/client/web/main.js +2 -38
- package/lib/cjs/client/web/main.js.LICENSE.txt +49 -0
- package/lib/cjs/creevey.js +3 -5
- package/lib/cjs/index.js +10 -15
- package/lib/cjs/server/config.js +5 -4
- package/lib/cjs/server/docker.js +3 -7
- package/lib/cjs/server/extract.js +7 -4
- package/lib/cjs/server/index.js +3 -5
- package/lib/cjs/server/loaders/babel/creevey-plugin.js +1 -3
- package/lib/cjs/server/loaders/babel/helpers.js +13 -23
- package/lib/cjs/server/loaders/babel/register.js +3 -4
- package/lib/cjs/server/loaders/webpack/compile.js +33 -50
- package/lib/cjs/server/loaders/webpack/creevey-loader.js +20 -22
- package/lib/cjs/server/loaders/webpack/dummy-hmr.js +2 -7
- package/lib/cjs/server/loaders/webpack/mdx-loader.js +2 -2
- package/lib/cjs/server/loaders/webpack/start.js +1 -1
- package/lib/cjs/server/logger.js +2 -1
- package/lib/cjs/server/master/index.js +4 -4
- package/lib/cjs/server/master/master.js +1 -0
- package/lib/cjs/server/master/pool.js +38 -47
- package/lib/cjs/server/master/runner.js +53 -66
- package/lib/cjs/server/master/server.js +78 -4
- package/lib/cjs/server/messages.js +128 -18
- package/lib/cjs/server/selenium/browser.js +129 -55
- package/lib/cjs/server/selenium/selenoid.js +6 -8
- package/lib/cjs/server/stories.js +58 -84
- package/lib/cjs/server/storybook/entry.js +8 -22
- package/lib/cjs/server/storybook/helpers.js +22 -21
- package/lib/cjs/server/storybook/providers/browser.js +74 -0
- package/lib/cjs/server/storybook/{nodejs-provider.js → providers/nodejs.js} +44 -22
- package/lib/cjs/server/update.js +1 -5
- package/lib/cjs/server/utils.js +36 -15
- package/lib/cjs/server/worker/helpers.js +2 -6
- package/lib/cjs/server/worker/reporter.js +8 -20
- package/lib/cjs/server/worker/worker.js +21 -19
- package/lib/cjs/shared/index.js +101 -0
- package/lib/cjs/shared/serializeRegExp.js +42 -0
- package/lib/cjs/types.js +11 -6
- package/lib/esm/client/addon/Manager.js +124 -272
- package/lib/esm/client/addon/components/Addon.js +15 -34
- package/lib/esm/client/addon/components/Icons.js +10 -6
- package/lib/esm/client/addon/components/Panel.js +17 -13
- package/lib/esm/client/addon/components/TestSelect.js +11 -9
- package/lib/esm/client/addon/components/Tools.js +19 -36
- package/lib/esm/client/addon/decorator.js +1 -1
- package/lib/esm/client/addon/index.js +2 -0
- package/lib/esm/client/addon/preset.ie11.js +59 -0
- package/lib/esm/client/addon/preset.js +12 -26
- package/lib/esm/client/addon/readyForCapture.js +5 -0
- package/lib/esm/client/addon/register.js +42 -66
- package/lib/esm/client/addon/utils.js +3 -34
- package/lib/esm/client/addon/withCreevey.js +209 -156
- package/lib/esm/client/shared/components/ImagesView/BlendView.js +23 -20
- package/lib/esm/client/shared/components/ImagesView/ImagesView.js +21 -17
- package/lib/esm/client/shared/components/ImagesView/SideBySideView.js +42 -63
- package/lib/esm/client/shared/components/ImagesView/SlideView.js +36 -47
- package/lib/esm/client/shared/components/ImagesView/SwapView.js +24 -42
- package/lib/esm/client/shared/components/PageFooter/PageFooter.js +12 -8
- package/lib/esm/client/shared/components/PageFooter/Paging.js +14 -18
- package/lib/esm/client/shared/components/PageHeader/ImagePreview.js +22 -18
- package/lib/esm/client/shared/components/PageHeader/PageHeader.js +37 -60
- package/lib/esm/client/shared/components/ResultsPage.js +36 -64
- package/lib/esm/client/shared/creeveyClientApi.js +57 -84
- package/lib/esm/client/shared/helpers.js +124 -195
- package/lib/esm/client/shared/viewMode.js +4 -4
- package/lib/esm/creevey.js +3 -5
- package/lib/esm/index.js +2 -3
- package/lib/esm/server/config.js +4 -5
- package/lib/esm/server/docker.js +2 -2
- package/lib/esm/server/extract.js +6 -4
- package/lib/esm/server/index.js +3 -4
- package/lib/esm/server/loaders/babel/creevey-plugin.js +1 -3
- package/lib/esm/server/loaders/babel/helpers.js +12 -22
- package/lib/esm/server/loaders/babel/register.js +3 -4
- package/lib/esm/server/loaders/webpack/compile.js +34 -51
- package/lib/esm/server/loaders/webpack/creevey-loader.js +9 -10
- package/lib/esm/server/loaders/webpack/dummy-hmr.js +2 -6
- package/lib/esm/server/loaders/webpack/mdx-loader.js +2 -2
- package/lib/esm/server/loaders/webpack/start.js +1 -1
- package/lib/esm/server/master/index.js +4 -4
- package/lib/esm/server/master/master.js +1 -0
- package/lib/esm/server/master/pool.js +38 -49
- package/lib/esm/server/master/runner.js +53 -66
- package/lib/esm/server/master/server.js +76 -6
- package/lib/esm/server/messages.js +118 -14
- package/lib/esm/server/selenium/browser.js +126 -57
- package/lib/esm/server/selenium/selenoid.js +5 -7
- package/lib/esm/server/stories.js +60 -83
- package/lib/esm/server/storybook/entry.js +7 -24
- package/lib/esm/server/storybook/helpers.js +13 -16
- package/lib/esm/server/storybook/providers/browser.js +60 -0
- package/lib/esm/server/storybook/{nodejs-provider.js → providers/nodejs.js} +42 -21
- package/lib/esm/server/update.js +1 -5
- package/lib/esm/server/utils.js +28 -10
- package/lib/esm/server/worker/helpers.js +2 -6
- package/lib/esm/server/worker/reporter.js +8 -20
- package/lib/esm/server/worker/worker.js +22 -20
- package/lib/esm/shared/index.js +78 -0
- package/lib/esm/shared/serializeRegExp.js +24 -0
- package/lib/esm/types.js +3 -0
- package/lib/types/cli.d.ts +1 -1
- package/lib/types/client/addon/Manager.d.ts +37 -37
- package/lib/types/client/addon/components/Addon.d.ts +8 -8
- package/lib/types/client/addon/components/Icons.d.ts +7 -7
- package/lib/types/client/addon/components/Panel.d.ts +9 -9
- package/lib/types/client/addon/components/TestSelect.d.ts +8 -9
- package/lib/types/client/addon/components/Tools.d.ts +6 -6
- package/lib/types/client/addon/decorator.d.ts +1 -1
- package/lib/types/client/addon/index.d.ts +2 -0
- package/lib/types/client/addon/preset.d.ts +23 -22
- package/lib/types/client/addon/preset.ie11.d.ts +10 -0
- package/lib/types/client/addon/readyForCapture.d.ts +6 -0
- package/lib/types/client/addon/register.d.ts +3 -3
- package/lib/types/client/addon/utils.d.ts +3 -6
- package/lib/types/client/addon/withCreevey.d.ts +24 -13
- package/lib/types/client/shared/components/ImagesView/BlendView.d.ts +3 -3
- package/lib/types/client/shared/components/ImagesView/ImagesView.d.ts +24 -25
- package/lib/types/client/shared/components/ImagesView/SideBySideView.d.ts +3 -3
- package/lib/types/client/shared/components/ImagesView/SlideView.d.ts +3 -3
- package/lib/types/client/shared/components/ImagesView/SwapView.d.ts +3 -3
- package/lib/types/client/shared/components/ImagesView/index.d.ts +5 -5
- package/lib/types/client/shared/components/PageFooter/PageFooter.d.ts +8 -9
- package/lib/types/client/shared/components/PageFooter/Paging.d.ts +7 -8
- package/lib/types/client/shared/components/PageHeader/ImagePreview.d.ts +12 -12
- package/lib/types/client/shared/components/PageHeader/PageHeader.d.ts +16 -17
- package/lib/types/client/shared/components/ResultsPage.d.ts +18 -18
- package/lib/types/client/shared/creeveyClientApi.d.ts +9 -9
- package/lib/types/client/shared/helpers.d.ts +46 -46
- package/lib/types/client/shared/viewMode.d.ts +4 -4
- package/lib/types/client/web/CreeveyApp.d.ts +11 -12
- package/lib/types/client/web/CreeveyContext.d.ts +11 -11
- package/lib/types/client/web/CreeveyLoader.d.ts +2 -3
- package/lib/types/client/web/CreeveyView/SideBar/Checkbox.d.ts +19 -19
- package/lib/types/client/web/CreeveyView/SideBar/Search.d.ts +6 -6
- package/lib/types/client/web/CreeveyView/SideBar/SideBar.d.ts +14 -14
- package/lib/types/client/web/CreeveyView/SideBar/SideBarHeader.d.ts +12 -13
- package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +33 -33
- package/lib/types/client/web/CreeveyView/SideBar/TestLink.d.ts +7 -8
- package/lib/types/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +10 -10
- package/lib/types/client/web/CreeveyView/SideBar/TestsStatus.d.ts +9 -9
- package/lib/types/client/web/CreeveyView/SideBar/Toggle.d.ts +6 -6
- package/lib/types/client/web/CreeveyView/SideBar/index.d.ts +1 -1
- package/lib/types/client/web/KeyboardEventsContext.d.ts +13 -13
- package/lib/types/client/web/index.d.ts +4 -4
- package/lib/types/creevey.d.ts +1 -1
- package/lib/types/index.d.ts +0 -1
- package/lib/types/server/config.d.ts +4 -4
- package/lib/types/server/docker.d.ts +7 -7
- package/lib/types/server/extract.d.ts +2 -2
- package/lib/types/server/index.d.ts +2 -2
- package/lib/types/server/loaders/babel/creevey-plugin.d.ts +1 -1
- package/lib/types/server/loaders/babel/helpers.d.ts +19 -19
- package/lib/types/server/loaders/babel/register.d.ts +5 -5
- package/lib/types/server/loaders/hooks/mdx.d.ts +1 -1
- package/lib/types/server/loaders/hooks/svelte.d.ts +1 -1
- package/lib/types/server/loaders/webpack/compile.d.ts +2 -2
- package/lib/types/server/loaders/webpack/creevey-loader.d.ts +4 -2
- package/lib/types/server/loaders/webpack/dummy-hmr.d.ts +10 -10
- package/lib/types/server/loaders/webpack/mdx-loader.d.ts +6 -6
- package/lib/types/server/loaders/webpack/start.d.ts +1 -1
- package/lib/types/server/logger.d.ts +10 -6
- package/lib/types/server/master/api.d.ts +7 -7
- package/lib/types/server/master/index.d.ts +3 -3
- package/lib/types/server/master/master.d.ts +7 -6
- package/lib/types/server/master/pool.d.ts +31 -30
- package/lib/types/server/master/runner.d.ts +26 -26
- package/lib/types/server/master/server.d.ts +2 -2
- package/lib/types/server/messages.d.ts +29 -18
- package/lib/types/server/selenium/browser.d.ts +17 -14
- package/lib/types/server/selenium/index.d.ts +2 -2
- package/lib/types/server/selenium/selenoid.d.ts +3 -3
- package/lib/types/server/stories.d.ts +8 -9
- package/lib/types/server/storybook/entry.d.ts +17 -14
- package/lib/types/server/storybook/helpers.d.ts +24 -23
- package/lib/types/server/storybook/providers/browser.d.ts +4 -0
- package/lib/types/server/storybook/providers/nodejs.d.ts +9 -0
- package/lib/types/server/update.d.ts +2 -2
- package/lib/types/server/utils.d.ts +19 -18
- package/lib/types/server/worker/chai-image.d.ts +6 -6
- package/lib/types/server/worker/helpers.d.ts +8 -7
- package/lib/types/server/worker/index.d.ts +1 -1
- package/lib/types/server/worker/reporter.d.ts +8 -8
- package/lib/types/server/worker/worker.d.ts +4 -4
- package/lib/types/shared/index.d.ts +7 -0
- package/lib/types/shared/serializeRegExp.d.ts +9 -0
- package/lib/types/types.d.ts +487 -459
- package/package.json +121 -99
- package/preset/ie11.js +5 -0
- package/{preset.js → preset/index.js} +2 -2
- package/types/mdx.d.ts +3 -2
- package/types/mocha.d.ts +1 -0
- package/lib/cjs/client/web/1.js +0 -13
- package/lib/cjs/client/web/2.js +0 -1
- package/lib/types/server/storybook/nodejs-provider.d.ts +0 -5
- package/storybook-static/stories.json +0 -530
@@ -40,21 +40,19 @@ export function getStorybookVersion() {
|
|
40
40
|
return version;
|
41
41
|
}
|
42
42
|
export function isStorybookVersionLessThan(major, minor) {
|
43
|
-
|
44
|
-
|
45
|
-
const [sbMajor, sbMinor] = ((_process$env$__CREEVE = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE !== void 0 ? _process$env$__CREEVE : getStorybookVersion()).split('.');
|
43
|
+
const [sbMajor, sbMinor] = (process.env.__CREEVEY_STORYBOOK_VERSION__ ?? getStorybookVersion()).split('.');
|
46
44
|
return Number(sbMajor) < major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) < minor;
|
47
45
|
}
|
46
|
+
export function isStorybookVersionGreaterThan(major, minor) {
|
47
|
+
const [sbMajor, sbMinor] = (process.env.__CREEVEY_STORYBOOK_VERSION__ ?? getStorybookVersion()).split('.');
|
48
|
+
return Number(sbMajor) > major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) > minor;
|
49
|
+
}
|
48
50
|
export function isStorybookVersion(major, minor) {
|
49
|
-
|
50
|
-
|
51
|
-
const [sbMajor, sbMinor] = ((_process$env$__CREEVE2 = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE2 !== void 0 ? _process$env$__CREEVE2 : getStorybookVersion()).split('.');
|
51
|
+
const [sbMajor, sbMinor] = (process.env.__CREEVEY_STORYBOOK_VERSION__ ?? getStorybookVersion()).split('.');
|
52
52
|
return Number(sbMajor) == major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) == minor;
|
53
53
|
}
|
54
54
|
export function getStorybookFramework() {
|
55
|
-
|
56
|
-
|
57
|
-
const framework = (_process$env$__CREEVE3 = process.env.__CREEVEY_STORYBOOK_FRAMEWORK__) !== null && _process$env$__CREEVE3 !== void 0 ? _process$env$__CREEVE3 : supportedFrameworks.find(framework => {
|
55
|
+
const framework = process.env.__CREEVEY_STORYBOOK_FRAMEWORK__ ?? supportedFrameworks.find(framework => {
|
58
56
|
try {
|
59
57
|
return require.resolve(resolveFromStorybook(`@storybook/${framework}`));
|
60
58
|
} catch (_) {
|
@@ -75,8 +73,8 @@ export async function importStorybookConfig() {
|
|
75
73
|
try {
|
76
74
|
return storybookConfigRef.current = (await import(require.resolve(configPath))).default;
|
77
75
|
} catch (_) {
|
78
|
-
const storybookUtilsPath =
|
79
|
-
const serverRequireModule =
|
76
|
+
const storybookUtilsPath = '@storybook/core-common/dist/cjs/utils';
|
77
|
+
const serverRequireModule = 'interpret-require'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
80
78
|
|
81
79
|
const {
|
82
80
|
getInterpretedFile
|
@@ -85,16 +83,15 @@ export async function importStorybookConfig() {
|
|
85
83
|
const {
|
86
84
|
default: serverRequireFallback,
|
87
85
|
serverRequire = serverRequireFallback
|
88
|
-
} = await import(resolveFromStorybook(`${storybookUtilsPath}/${serverRequireModule}`)); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
86
|
+
} = await import(resolveFromStorybook(`${storybookUtilsPath}/${serverRequireModule}`)); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
89
87
|
|
90
|
-
const mainConfigFile =
|
91
|
-
getInterpretedFile(configPath); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
88
|
+
const mainConfigFile = getInterpretedFile(configPath); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
92
89
|
|
93
90
|
return storybookConfigRef.current = serverRequire(mainConfigFile);
|
94
91
|
}
|
95
92
|
}
|
96
93
|
export async function isCSFv3Enabled() {
|
97
|
-
var _await$importStoryboo, _await$importStoryboo2
|
94
|
+
var _await$importStoryboo, _await$importStoryboo2;
|
98
95
|
|
99
|
-
return (_await$importStoryboo =
|
96
|
+
return ((_await$importStoryboo = await importStorybookConfig()) === null || _await$importStoryboo === void 0 ? void 0 : (_await$importStoryboo2 = _await$importStoryboo.features) === null || _await$importStoryboo2 === void 0 ? void 0 : _await$importStoryboo2.previewCsfV3) ?? false;
|
100
97
|
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import cluster from 'cluster';
|
2
|
+
import { loadStoriesFromBrowser } from '../../selenium';
|
3
|
+
import { emitStoriesMessage, sendStoriesMessage, subscribeOn, subscribeOnWorker } from '../../messages';
|
4
|
+
import { isDefined } from '../../../types';
|
5
|
+
import { logger } from '../../logger';
|
6
|
+
export async function loadStories(_config, {
|
7
|
+
port
|
8
|
+
}, storiesListener) {
|
9
|
+
if (cluster.isPrimary) {
|
10
|
+
return new Promise(resolve => {
|
11
|
+
const worker = Object.values(cluster.workers ?? {}).filter(isDefined).find(worker => worker.isConnected());
|
12
|
+
|
13
|
+
if (worker) {
|
14
|
+
const unsubscribe = subscribeOnWorker(worker, 'stories', message => {
|
15
|
+
if (message.type == 'set') {
|
16
|
+
const {
|
17
|
+
stories,
|
18
|
+
oldTests
|
19
|
+
} = message.payload;
|
20
|
+
if (oldTests.length > 0) logger.warn(`If you use browser stories provider of CSFv3 Storybook feature\n` + `Creevey will not load tests defined in story parameters from following stories:\n` + oldTests.join('\n'));
|
21
|
+
unsubscribe();
|
22
|
+
resolve(stories);
|
23
|
+
}
|
24
|
+
});
|
25
|
+
sendStoriesMessage(worker, {
|
26
|
+
type: 'get'
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
subscribeOn('stories', message => {
|
31
|
+
// TODO updates only one browser :(
|
32
|
+
if (message.type == 'update') storiesListener(new Map(message.payload));
|
33
|
+
});
|
34
|
+
});
|
35
|
+
} else {
|
36
|
+
subscribeOn('stories', message => {
|
37
|
+
if (message.type == 'get') emitStoriesMessage({
|
38
|
+
type: 'set',
|
39
|
+
payload: {
|
40
|
+
stories,
|
41
|
+
oldTests: storiesWithOldTests
|
42
|
+
}
|
43
|
+
});
|
44
|
+
if (message.type == 'update') storiesListener(new Map(message.payload));
|
45
|
+
});
|
46
|
+
const stories = await loadStoriesFromBrowser(port);
|
47
|
+
const storiesWithOldTests = [];
|
48
|
+
Object.values(stories).forEach(story => {
|
49
|
+
var _parameters, _parameters$creevey;
|
50
|
+
|
51
|
+
if ((_parameters = story.parameters) !== null && _parameters !== void 0 && (_parameters$creevey = _parameters.creevey) !== null && _parameters$creevey !== void 0 && _parameters$creevey.tests) {
|
52
|
+
var _parameters2, _parameters2$creevey;
|
53
|
+
|
54
|
+
(_parameters2 = story.parameters) === null || _parameters2 === void 0 ? true : (_parameters2$creevey = _parameters2.creevey) === null || _parameters2$creevey === void 0 ? true : delete _parameters2$creevey.tests;
|
55
|
+
storiesWithOldTests.push(`${story.kind}/${story.name}`);
|
56
|
+
}
|
57
|
+
});
|
58
|
+
return stories;
|
59
|
+
}
|
60
|
+
}
|
@@ -1,16 +1,15 @@
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/ban-ts-comment */
|
2
2
|
import path from 'path';
|
3
|
-
import
|
3
|
+
import cluster from 'cluster';
|
4
4
|
import chokidar from 'chokidar';
|
5
|
-
import { noop } from '
|
6
|
-
import { getCreeveyCache } from '
|
7
|
-
import { subscribeOn } from '
|
8
|
-
import { importStorybookClientLogger, importStorybookConfig, importStorybookCoreCommon, importStorybookCoreEvents
|
9
|
-
import { logger } from '
|
10
|
-
import { flatStories } from '../stories';
|
5
|
+
import { noop } from '../../../types';
|
6
|
+
import { getCreeveyCache } from '../../utils';
|
7
|
+
import { subscribeOn } from '../../messages';
|
8
|
+
import { importStorybookClientLogger, importStorybookConfig, importStorybookCoreCommon, importStorybookCoreEvents } from '../helpers';
|
9
|
+
import { logger } from '../../logger';
|
11
10
|
|
12
11
|
async function initStorybookEnvironment() {
|
13
|
-
// @ts-
|
12
|
+
// @ts-expect-error There is no @types/global-jsdom package
|
14
13
|
(await import('global-jsdom')).default(undefined, {
|
15
14
|
url: 'http://localhost'
|
16
15
|
}); // NOTE Cutoff `jsdom` part from userAgent, because storybook check enviroment and create events channel if runs in browser
|
@@ -25,10 +24,10 @@ async function initStorybookEnvironment() {
|
|
25
24
|
logger
|
26
25
|
} = await importStorybookClientLogger(); // NOTE: Disable duplication warnings for >=6.2 storybook
|
27
26
|
|
28
|
-
if (isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
|
27
|
+
if (cluster.isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
|
29
28
|
|
30
29
|
logger.debug = noop;
|
31
|
-
return import('
|
30
|
+
return import('../entry');
|
32
31
|
}
|
33
32
|
|
34
33
|
function watchStories(channel, watcher, initialFiles) {
|
@@ -39,7 +38,7 @@ function watchStories(channel, watcher, initialFiles) {
|
|
39
38
|
watcher.on('change', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
|
40
39
|
watcher.on('unlink', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
|
41
40
|
return data => {
|
42
|
-
const stories =
|
41
|
+
const stories = data.stories;
|
43
42
|
const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
|
44
43
|
const addedFiles = Array.from(files).filter(filePath => !watchingFiles.has(filePath));
|
45
44
|
const removedFiles = Array.from(watchingFiles).filter(filePath => !files.has(filePath));
|
@@ -84,13 +83,14 @@ async function loadStoriesDirectly(config, {
|
|
84
83
|
debug
|
85
84
|
}) {
|
86
85
|
const {
|
87
|
-
toRequireContext
|
86
|
+
toRequireContext,
|
87
|
+
normalizeStoriesEntry
|
88
88
|
} = await importStorybookCoreCommon();
|
89
89
|
const {
|
90
90
|
addParameters,
|
91
91
|
configure
|
92
|
-
} = await import('
|
93
|
-
const requireContext = await (await import('
|
92
|
+
} = await import('../entry');
|
93
|
+
const requireContext = await (await import('../../loaders/babel/register')).default(config, debug);
|
94
94
|
|
95
95
|
const preview = (() => {
|
96
96
|
try {
|
@@ -103,12 +103,16 @@ async function loadStoriesDirectly(config, {
|
|
103
103
|
const {
|
104
104
|
stories
|
105
105
|
} = await importStorybookConfig();
|
106
|
-
const contexts = stories.map(
|
106
|
+
const contexts = stories.map(entry => {
|
107
|
+
const normalizedEntry = normalizeStoriesEntry(entry, {
|
108
|
+
configDir: config.storybookDir,
|
109
|
+
workingDir: process.cwd()
|
110
|
+
});
|
107
111
|
const {
|
108
112
|
path: storiesPath,
|
109
113
|
recursive,
|
110
114
|
match
|
111
|
-
} = toRequireContext(
|
115
|
+
} = toRequireContext(normalizedEntry);
|
112
116
|
watcher === null || watcher === void 0 ? void 0 : watcher.add(path.resolve(config.storybookDir, storiesPath));
|
113
117
|
return () => requireContext(storiesPath, recursive, new RegExp(match));
|
114
118
|
});
|
@@ -149,7 +153,7 @@ async function loadStoriesDirectly(config, {
|
|
149
153
|
try {
|
150
154
|
configure(contexts.map(ctx => ctx()), module, false);
|
151
155
|
} catch (error) {
|
152
|
-
if (
|
156
|
+
if (cluster.isPrimary) logger.error(error);
|
153
157
|
}
|
154
158
|
}
|
155
159
|
|
@@ -162,7 +166,8 @@ async function loadStoriesDirectly(config, {
|
|
162
166
|
void startStorybook();
|
163
167
|
});
|
164
168
|
void startStorybook();
|
165
|
-
}
|
169
|
+
} // TODO Do we need to support multiple storybooks here?
|
170
|
+
|
166
171
|
|
167
172
|
export async function loadStories(config, {
|
168
173
|
watch,
|
@@ -175,16 +180,16 @@ export async function loadStories(config, {
|
|
175
180
|
} = storybookApi;
|
176
181
|
channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
|
177
182
|
channel.on('storiesUpdated', storiesListener);
|
178
|
-
let watcher
|
183
|
+
let watcher;
|
179
184
|
if (watch) watcher = chokidar.watch([], {
|
180
185
|
ignoreInitial: true
|
181
186
|
});
|
182
187
|
const loadPromise = new Promise(resolve => {
|
183
188
|
channel.once(Events.SET_STORIES, data => {
|
184
|
-
const stories =
|
189
|
+
const stories = data.stories;
|
185
190
|
const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
|
186
191
|
if (watcher) channel.on(Events.SET_STORIES, watchStories(channel, watcher, files));
|
187
|
-
resolve(
|
192
|
+
resolve(stories);
|
188
193
|
});
|
189
194
|
});
|
190
195
|
if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
|
@@ -192,4 +197,20 @@ export async function loadStories(config, {
|
|
192
197
|
debug
|
193
198
|
});
|
194
199
|
return loadPromise;
|
200
|
+
}
|
201
|
+
export async function extractStoriesData(config, {
|
202
|
+
watch,
|
203
|
+
debug
|
204
|
+
}) {
|
205
|
+
const storybookApi = await initStorybookEnvironment();
|
206
|
+
const Events = await importStorybookCoreEvents();
|
207
|
+
const {
|
208
|
+
channel
|
209
|
+
} = storybookApi;
|
210
|
+
channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
|
211
|
+
const loadPromise = new Promise(resolve => channel.once(Events.SET_STORIES, resolve));
|
212
|
+
if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
|
213
|
+
debug
|
214
|
+
});
|
215
|
+
return loadPromise;
|
195
216
|
}
|
package/lib/esm/server/update.js
CHANGED
@@ -15,11 +15,7 @@ function tryToLoadTestsData(filename) {
|
|
15
15
|
const actualRegex = /^(.*)-actual-(\d+)\.png$/i;
|
16
16
|
|
17
17
|
function approve(dirents, srcPath, dstPath, testPaths, isMatch) {
|
18
|
-
dirents.filter(dirent => dirent.isFile()).map(dirent => actualRegex.exec(dirent.name)).filter(isDefined).filter(([fileName, imageName]) => !testPaths || testPaths.find(([token]) => token == imageName) && isMatch(path.join(srcPath, fileName))).reduce((images, [, imageName, retry]) => {
|
19
|
-
var _images$get;
|
20
|
-
|
21
|
-
return Number(retry) > ((_images$get = images.get(imageName)) !== null && _images$get !== void 0 ? _images$get : -1) ? images.set(imageName, Number(retry)) : images;
|
22
|
-
}, new Map()).forEach((retry, imageName) => {
|
18
|
+
dirents.filter(dirent => dirent.isFile()).map(dirent => actualRegex.exec(dirent.name)).filter(isDefined).filter(([fileName, imageName]) => !testPaths || testPaths.find(([token]) => token == imageName) && isMatch(path.join(srcPath, fileName))).reduce((images, [, imageName, retry]) => Number(retry) > (images.get(imageName) ?? -1) ? images.set(imageName, Number(retry)) : images, new Map()).forEach((retry, imageName) => {
|
23
19
|
mkdirSync(dstPath, {
|
24
20
|
recursive: true
|
25
21
|
});
|
package/lib/esm/server/utils.js
CHANGED
@@ -9,6 +9,7 @@ export const isShuttingDown = {
|
|
9
9
|
};
|
10
10
|
export const LOCALHOST_REGEXP = /(localhost|127\.0\.0\.1)/i;
|
11
11
|
export const extensions = ['.js', '.jsx', '.ts', '.tsx'];
|
12
|
+
export const skipOptionKeys = ['in', 'kinds', 'stories', 'tests', 'reason'];
|
12
13
|
|
13
14
|
function matchBy(pattern, value) {
|
14
15
|
return typeof pattern == 'string' && pattern == value || Array.isArray(pattern) && pattern.includes(value) || pattern instanceof RegExp && pattern.test(value) || !isDefined(pattern);
|
@@ -20,9 +21,30 @@ export function shouldSkip(browser, meta, skipOptions, test) {
|
|
20
21
|
}
|
21
22
|
|
22
23
|
if (Array.isArray(skipOptions)) {
|
23
|
-
|
24
|
+
for (const skip of skipOptions) {
|
25
|
+
const reason = shouldSkip(browser, meta, skip, test);
|
26
|
+
if (reason) return reason;
|
27
|
+
}
|
28
|
+
|
29
|
+
return false;
|
24
30
|
}
|
25
31
|
|
32
|
+
let hasSkipOptionKeys = false;
|
33
|
+
|
34
|
+
for (const skipKey in skipOptions) {
|
35
|
+
if (skipOptionKeys.includes(skipKey)) {
|
36
|
+
hasSkipOptionKeys = true;
|
37
|
+
continue;
|
38
|
+
}
|
39
|
+
|
40
|
+
const reason = shouldSkip(browser, meta, {
|
41
|
+
reason: skipKey,
|
42
|
+
...skipOptions[skipKey]
|
43
|
+
}, test);
|
44
|
+
if (reason) return reason;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (!hasSkipOptionKeys) return false;
|
26
48
|
const {
|
27
49
|
in: browsers,
|
28
50
|
kinds,
|
@@ -42,7 +64,7 @@ export function shouldSkip(browser, meta, skipOptions, test) {
|
|
42
64
|
}
|
43
65
|
export async function shutdownWorkers() {
|
44
66
|
isShuttingDown.current = true;
|
45
|
-
await Promise.all(Object.values(cluster.workers).filter(isDefined).filter(worker => worker.isConnected()).map(worker => new Promise(resolve => {
|
67
|
+
await Promise.all(Object.values(cluster.workers ?? {}).filter(isDefined).filter(worker => worker.isConnected()).map(worker => new Promise(resolve => {
|
46
68
|
const timeout = setTimeout(() => worker.kill(), 10000);
|
47
69
|
worker.on('exit', () => {
|
48
70
|
clearTimeout(timeout);
|
@@ -74,27 +96,23 @@ export function testsToImages(tests) {
|
|
74
96
|
storyPath,
|
75
97
|
results
|
76
98
|
}) => {
|
77
|
-
var _results$slice
|
99
|
+
var _results$slice$;
|
78
100
|
|
79
|
-
return Object.keys((
|
101
|
+
return Object.keys((results === null || results === void 0 ? void 0 : (_results$slice$ = results.slice(-1)[0]) === null || _results$slice$ === void 0 ? void 0 : _results$slice$.images) ?? {}).map(image => `${[...storyPath, testName, browser, browser == image ? undefined : image].filter(isDefined).join('/')}.png`);
|
80
102
|
})));
|
81
103
|
} // https://tuhrig.de/how-to-know-you-are-inside-a-docker-container/
|
82
104
|
|
83
105
|
export const isInsideDocker = existsSync('/proc/1/cgroup') && /docker/.test(readFileSync('/proc/1/cgroup', 'utf8'));
|
84
106
|
export const downloadBinary = (downloadUrl, destination) => new Promise((resolve, reject) => get(downloadUrl, response => {
|
85
|
-
var _response$statusCode2;
|
86
|
-
|
87
107
|
if (response.statusCode == 302) {
|
88
|
-
var _response$statusCode;
|
89
|
-
|
90
108
|
const {
|
91
109
|
location
|
92
110
|
} = response.headers;
|
93
|
-
if (!location) return reject(new Error(`Couldn't download selenoid. Status code: ${
|
111
|
+
if (!location) return reject(new Error(`Couldn't download selenoid. Status code: ${response.statusCode ?? 'UNKNOWN'}`));
|
94
112
|
return resolve(downloadBinary(location, destination));
|
95
113
|
}
|
96
114
|
|
97
|
-
if (response.statusCode != 200) return reject(new Error(`Couldn't download selenoid. Status code: ${
|
115
|
+
if (response.statusCode != 200) return reject(new Error(`Couldn't download selenoid. Status code: ${response.statusCode ?? 'UNKNOWN'}`));
|
98
116
|
const fileStream = createWriteStream(destination);
|
99
117
|
response.pipe(fileStream);
|
100
118
|
fileStream.on('finish', () => {
|
@@ -47,14 +47,10 @@ function removeTestOrSuite(testOrSuite) {
|
|
47
47
|
|
48
48
|
export async function addTestsFromStories(rootSuite, config, {
|
49
49
|
browser,
|
50
|
-
|
51
|
-
debug
|
50
|
+
...options
|
52
51
|
}) {
|
53
52
|
const mochaTestsById = new Map();
|
54
|
-
const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, {
|
55
|
-
watch,
|
56
|
-
debug
|
57
|
-
}, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
|
53
|
+
const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, options, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
|
58
54
|
const oldTest = mochaTestsById.get(id);
|
59
55
|
mochaTestsById.delete(id);
|
60
56
|
if (oldTest) removeTestOrSuite(oldTest);
|
@@ -1,5 +1,3 @@
|
|
1
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
2
|
-
|
3
1
|
import chalk from 'chalk';
|
4
2
|
import { reporters } from 'mocha';
|
5
3
|
import prefix from 'loglevel-plugin-prefix';
|
@@ -26,31 +24,18 @@ export class CreeveyReporter extends reporters.Base {
|
|
26
24
|
});
|
27
25
|
runner.on('test', test => testLogger.warn(chalk.cyan(test.titlePath().join('/'))));
|
28
26
|
runner.on('pass', test => testLogger.info(chalk.cyan(test.titlePath().join('/'))));
|
29
|
-
runner.on('fail', (test, error) => testLogger.error(chalk.cyan(test.titlePath().join('/')), '\n ', getErrors(error, (error, imageName) => `${chalk.bold(imageName
|
30
|
-
var _error$stack;
|
31
|
-
|
32
|
-
return `${(_error$stack = error.stack) !== null && _error$stack !== void 0 ? _error$stack : error.message}`;
|
33
|
-
}).join('\n ')));
|
27
|
+
runner.on('fail', (test, error) => testLogger.error(chalk.cyan(test.titlePath().join('/')), '\n ', getErrors(error, (error, imageName) => `${chalk.bold(imageName ?? topLevelSuite)}:${error}`, error => `${error.stack ?? error.message}`).join('\n ')));
|
34
28
|
}
|
35
29
|
|
36
30
|
}
|
37
31
|
export class TeamcityReporter extends reporters.Base {
|
38
32
|
constructor(runner, options) {
|
39
33
|
super(runner);
|
40
|
-
|
41
|
-
_defineProperty(this, "escape", str => {
|
42
|
-
if (!str) return '';
|
43
|
-
return str.toString() // eslint-disable-next-line no-control-regex
|
44
|
-
.replace(/\x1B.*?m/g, '').replace(/\|/g, '||').replace(/\n/g, '|n').replace(/\r/g, '|r').replace(/\[/g, '|[').replace(/\]/g, '|]').replace(/\u0085/g, '|x').replace(/\u2028/g, '|l').replace(/\u2029/g, '|p').replace(/'/g, "|'");
|
45
|
-
});
|
46
|
-
|
47
34
|
const topLevelSuite = this.escape(options.reporterOptions.topLevelSuite);
|
48
35
|
const reporterOptions = options.reporterOptions;
|
49
36
|
runner.on('suite', suite => suite.root ? console.log(`##teamcity[testSuiteStarted name='${topLevelSuite}' flowId='${process.pid}']`) : console.log(`##teamcity[testSuiteStarted name='${this.escape(suite.title)}' flowId='${process.pid}']`));
|
50
37
|
runner.on('test', test => console.log(`##teamcity[testStarted name='${this.escape(test.title)}' flowId='${process.pid}']`));
|
51
38
|
runner.on('fail', (test, error) => {
|
52
|
-
var _error$stack2;
|
53
|
-
|
54
39
|
Object.entries(reporterOptions.images).forEach(([name, image]) => {
|
55
40
|
if (!image) return;
|
56
41
|
const filePath = test.titlePath().concat(name == topLevelSuite ? [] : [topLevelSuite]).map(this.escape).join('/'); // eslint-disable-next-line @typescript-eslint/no-unused-vars
|
@@ -66,7 +51,7 @@ export class TeamcityReporter extends reporters.Base {
|
|
66
51
|
}); // Output failed test as passed due TC don't support retry mechanic
|
67
52
|
// 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
|
68
53
|
|
69
|
-
reporterOptions.willRetry ? console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`) : console.log(`##teamcity[testFailed name='${this.escape(test.title)}' message='${this.escape(error.message)}' details='${this.escape(
|
54
|
+
reporterOptions.willRetry ? console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`) : console.log(`##teamcity[testFailed name='${this.escape(test.title)}' message='${this.escape(error.message)}' details='${this.escape(error.stack ?? '')}' flowId='${process.pid}']`);
|
70
55
|
});
|
71
56
|
runner.on('pending', test => console.log(`##teamcity[testIgnored name='${this.escape(test.title)}' message='${this.escape(typeof test.skipReason == 'boolean' ? test.title : test.skipReason)}' flowId='${process.pid}']`));
|
72
57
|
runner.on('test end', test => console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`));
|
@@ -74,6 +59,11 @@ export class TeamcityReporter extends reporters.Base {
|
|
74
59
|
runner.on('end', () => console.log(`##teamcity[testSuiteFinished name='${topLevelSuite}' flowId='${process.pid}']`));
|
75
60
|
}
|
76
61
|
|
62
|
+
escape = str => {
|
63
|
+
if (!str) return '';
|
64
|
+
return str.toString() // eslint-disable-next-line no-control-regex
|
65
|
+
.replace(/\x1B.*?m/g, '').replace(/\|/g, '||').replace(/\n/g, '|n').replace(/\r/g, '|r').replace(/\[/g, '|[').replace(/\]/g, '|]').replace(/\u0085/g, '|x').replace(/\u2028/g, '|l').replace(/\u2029/g, '|p').replace(/'/g, "|'");
|
66
|
+
};
|
77
67
|
}
|
78
68
|
|
79
69
|
function getErrors(error, imageErrorToString, errorToString) {
|
@@ -88,9 +78,7 @@ function getErrors(error, imageErrorToString, errorToString) {
|
|
88
78
|
} else {
|
89
79
|
const imageErrors = error.images;
|
90
80
|
Object.keys(imageErrors).forEach(imageName => {
|
91
|
-
|
92
|
-
|
93
|
-
errors.push(imageErrorToString((_imageErrors$imageNam = imageErrors[imageName]) !== null && _imageErrors$imageNam !== void 0 ? _imageErrors$imageNam : '', imageName));
|
81
|
+
errors.push(imageErrorToString(imageErrors[imageName] ?? '', imageName));
|
94
82
|
});
|
95
83
|
}
|
96
84
|
|
@@ -8,7 +8,7 @@ import { Key, until } from 'selenium-webdriver';
|
|
8
8
|
import { isImageError } from '../../types';
|
9
9
|
import { subscribeOn, emitTestMessage, emitWorkerMessage } from '../messages';
|
10
10
|
import chaiImage from './chai-image';
|
11
|
-
import { getBrowser, switchStory } from '../selenium';
|
11
|
+
import { closeBrowser, getBrowser, switchStory } from '../selenium';
|
12
12
|
import { CreeveyReporter, TeamcityReporter } from './reporter';
|
13
13
|
import { addTestsFromStories } from './helpers';
|
14
14
|
import { logger } from '../logger';
|
@@ -34,9 +34,7 @@ async function getLastImageNumber(imageDir, imageName) {
|
|
34
34
|
const actualImagesRegexp = new RegExp(`${imageName}-actual-(\\d+)\\.png`);
|
35
35
|
|
36
36
|
try {
|
37
|
-
|
38
|
-
|
39
|
-
return (_await$readdirAsync$m = (await readdirAsync(imageDir)).map(filename => filename.replace(actualImagesRegexp, '$1')).map(Number).filter(x => !isNaN(x)).sort((a, b) => b - a)[0]) !== null && _await$readdirAsync$m !== void 0 ? _await$readdirAsync$m : 0;
|
37
|
+
return (await readdirAsync(imageDir)).map(filename => filename.replace(actualImagesRegexp, '$1')).map(Number).filter(x => !isNaN(x)).sort((a, b) => b - a)[0] ?? 0;
|
40
38
|
} catch (_error) {
|
41
39
|
return 0;
|
42
40
|
}
|
@@ -49,12 +47,11 @@ export default async function worker(config, options) {
|
|
49
47
|
let retries = 0;
|
50
48
|
let images = {};
|
51
49
|
let error = undefined;
|
50
|
+
const screenshots = [];
|
52
51
|
const testScope = [];
|
53
52
|
|
54
53
|
function runHandler(failures) {
|
55
54
|
if (failures > 0 && (error || Object.values(images).some(image => (image === null || image === void 0 ? void 0 : image.error) != null))) {
|
56
|
-
var _error2;
|
57
|
-
|
58
55
|
const isTimeout = hasTimeout(error) || Object.values(images).some(image => hasTimeout(image === null || image === void 0 ? void 0 : image.error));
|
59
56
|
const payload = {
|
60
57
|
status: 'failed',
|
@@ -64,7 +61,7 @@ export default async function worker(config, options) {
|
|
64
61
|
isTimeout ? emitWorkerMessage({
|
65
62
|
type: 'error',
|
66
63
|
payload: {
|
67
|
-
error:
|
64
|
+
error: error ?? 'Unknown error'
|
68
65
|
}
|
69
66
|
}) : emitTestMessage({
|
70
67
|
type: 'end',
|
@@ -95,18 +92,16 @@ export default async function worker(config, options) {
|
|
95
92
|
}
|
96
93
|
|
97
94
|
async function getExpected(assertImageName) {
|
98
|
-
var _images$imageName;
|
99
|
-
|
100
95
|
// context => [kind, story, test, browser]
|
101
96
|
// rootSuite -> kindSuite -> storyTest -> [browsers.png]
|
102
97
|
// rootSuite -> kindSuite -> storySuite -> test -> [browsers.png]
|
103
98
|
const testPath = [...testScope];
|
104
|
-
const imageName = assertImageName
|
99
|
+
const imageName = assertImageName ?? testPath.pop();
|
105
100
|
const imagesMeta = [];
|
106
101
|
const reportImageDir = path.join(config.reportDir, ...testPath);
|
107
102
|
const imageNumber = (await getLastImageNumber(reportImageDir, imageName)) + 1;
|
108
103
|
const actualImageName = `${imageName}-actual-${imageNumber}.png`;
|
109
|
-
const image = images[imageName] =
|
104
|
+
const image = images[imageName] = images[imageName] ?? {
|
110
105
|
actual: actualImageName
|
111
106
|
};
|
112
107
|
|
@@ -168,18 +163,26 @@ export default async function worker(config, options) {
|
|
168
163
|
|
169
164
|
}
|
170
165
|
};
|
171
|
-
const mocha = new Mocha(mochaOptions);
|
172
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
173
|
-
|
166
|
+
const mocha = new Mocha(mochaOptions);
|
174
167
|
mocha.cleanReferencesAfterRun(false);
|
175
168
|
chai.use(chaiImage(getExpected, config.diffOptions));
|
169
|
+
if ((await getBrowser(config, options.browser)) == null) return;
|
176
170
|
await addTestsFromStories(mocha.suite, config, {
|
177
171
|
browser: options.browser,
|
178
172
|
watch: options.ui,
|
179
|
-
debug: options.debug
|
173
|
+
debug: options.debug,
|
174
|
+
port: options.port
|
180
175
|
});
|
181
|
-
|
182
|
-
|
176
|
+
|
177
|
+
try {
|
178
|
+
var _await$getBrowser;
|
179
|
+
|
180
|
+
await ((_await$getBrowser = await getBrowser(config, options.browser)) === null || _await$getBrowser === void 0 ? void 0 : _await$getBrowser.getCurrentUrl());
|
181
|
+
} catch (_) {
|
182
|
+
await closeBrowser();
|
183
|
+
}
|
184
|
+
|
185
|
+
const browser = await getBrowser(config, options.browser);
|
183
186
|
const sessionId = (_await$browser$getSes = await (browser === null || browser === void 0 ? void 0 : browser.getSession())) === null || _await$browser$getSes === void 0 ? void 0 : _await$browser$getSes.getId();
|
184
187
|
if (browser == null) return;
|
185
188
|
const interval = setInterval(() => void browser.getCurrentUrl().then(url => {
|
@@ -194,6 +197,7 @@ export default async function worker(config, options) {
|
|
194
197
|
this.expect = chai.expect;
|
195
198
|
this.browserName = options.browser;
|
196
199
|
this.testScope = testScope;
|
200
|
+
this.screenshots = screenshots;
|
197
201
|
});
|
198
202
|
mocha.suite.beforeEach(switchStory);
|
199
203
|
subscribeOn('test', message => {
|
@@ -210,9 +214,7 @@ export default async function worker(config, options) {
|
|
210
214
|
if (!(reason instanceof Error)) {
|
211
215
|
error = reason;
|
212
216
|
} else if (!isImageError(reason)) {
|
213
|
-
|
214
|
-
|
215
|
-
error = (_reason$stack = reason.stack) !== null && _reason$stack !== void 0 ? _reason$stack : reason.message;
|
217
|
+
error = reason.stack ?? reason.message;
|
216
218
|
} else if (typeof reason.images == 'string') {
|
217
219
|
const image = images[testScope.slice(-1)[0]];
|
218
220
|
if (image) image.error = reason.images;
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import { mapValues, mergeWith, cloneDeepWith } from 'lodash';
|
2
|
+
import { deserializeRegExp, isSerializedRegExp, isRegExp, serializeRegExp } from './serializeRegExp'; // NOTE: Copy-paste from storybook/api
|
3
|
+
|
4
|
+
export const combineParameters = function () {
|
5
|
+
for (var _len = arguments.length, parameterSets = new Array(_len), _key = 0; _key < _len; _key++) {
|
6
|
+
parameterSets[_key] = arguments[_key];
|
7
|
+
}
|
8
|
+
|
9
|
+
return (// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
10
|
+
mergeWith({}, ...parameterSets, (_, srcValue) => {
|
11
|
+
// Treat arrays as scalars:
|
12
|
+
if (Array.isArray(srcValue)) return srcValue;
|
13
|
+
return undefined;
|
14
|
+
})
|
15
|
+
);
|
16
|
+
}; // NOTE: Copy-paste from storybook/api
|
17
|
+
|
18
|
+
export const denormalizeStoryParameters = _ref => {
|
19
|
+
let {
|
20
|
+
globalParameters,
|
21
|
+
kindParameters,
|
22
|
+
stories
|
23
|
+
} = _ref;
|
24
|
+
return mapValues(stories, storyData => {
|
25
|
+
var _kindParameters$story;
|
26
|
+
|
27
|
+
return { ...storyData,
|
28
|
+
parameters: combineParameters(globalParameters, (_kindParameters$story = kindParameters[storyData.kind]) !== null && _kindParameters$story !== void 0 ? _kindParameters$story : {}, storyData.parameters)
|
29
|
+
};
|
30
|
+
});
|
31
|
+
};
|
32
|
+
export const serializeRawStories = stories => {
|
33
|
+
return mapValues(stories, storyData => {
|
34
|
+
const creevey = storyData.parameters.creevey;
|
35
|
+
|
36
|
+
if (creevey !== null && creevey !== void 0 && creevey.skip) {
|
37
|
+
return { ...storyData,
|
38
|
+
parameters: { ...storyData.parameters,
|
39
|
+
creevey: { ...creevey,
|
40
|
+
skip: cloneDeepWith(creevey.skip, value => {
|
41
|
+
if (isRegExp(value)) {
|
42
|
+
return serializeRegExp(value);
|
43
|
+
}
|
44
|
+
|
45
|
+
return undefined;
|
46
|
+
})
|
47
|
+
}
|
48
|
+
}
|
49
|
+
};
|
50
|
+
}
|
51
|
+
|
52
|
+
return storyData;
|
53
|
+
});
|
54
|
+
};
|
55
|
+
export const deserializeRawStories = stories => {
|
56
|
+
return mapValues(stories, deserializeStory);
|
57
|
+
};
|
58
|
+
export const deserializeStory = story => {
|
59
|
+
const creevey = story.parameters.creevey;
|
60
|
+
|
61
|
+
if (creevey !== null && creevey !== void 0 && creevey.skip) {
|
62
|
+
return { ...story,
|
63
|
+
parameters: { ...story.parameters,
|
64
|
+
creevey: { ...creevey,
|
65
|
+
skip: cloneDeepWith(creevey.skip, value => {
|
66
|
+
if (isSerializedRegExp(value)) {
|
67
|
+
return deserializeRegExp(value);
|
68
|
+
}
|
69
|
+
|
70
|
+
return undefined;
|
71
|
+
})
|
72
|
+
}
|
73
|
+
}
|
74
|
+
};
|
75
|
+
}
|
76
|
+
|
77
|
+
return story;
|
78
|
+
};
|