@wdio/visual-service 9.1.4 → 9.1.6

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 CHANGED
@@ -1,5 +1,51 @@
1
1
  # @wdio/visual-service
2
2
 
3
+ ## 9.1.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 0a19d78: Fix `clearRuntimeFolder` clearing the actual and diff folders after each spec/feature execution instead of once before all workers start. This caused only the last spec's visual data to be present in the output when running multiple specs.
8
+
9
+ # Committers: 1
10
+
11
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
12
+
13
+ - ed0bea6: Fix `EISDIR` error when using `resolveSnapshotPath` with the visual service. The service now uses `dirname()` of the resolved path as the baseline folder, preventing it from creating a directory at a path that `expect-webdriverio`'s snapshot service expects to be a file. Fixes #984.
14
+
15
+ # Committers: 1
16
+
17
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
18
+
19
+ - cbf1d22: Fix incomplete `wdio-ics:options` type augmentation on `WebdriverIO.Capabilities`. The global type declaration now uses the `WdioIcsOptions` interface directly, ensuring all supported properties (`logName`, `name`) are available to TypeScript users in both standalone and multiremote configurations. Fixes #732.
20
+
21
+ # Committers: 1
22
+
23
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
24
+
25
+ - Updated dependencies [0a19d78]
26
+ - Updated dependencies [ce74703]
27
+ - @wdio/image-comparison-core@1.1.4
28
+
29
+ ## 9.1.5
30
+
31
+ ### Patch Changes
32
+
33
+ - 6ed0469: ## Fix: support `appium:options` nested capability format and `avd` fallback (#1118)
34
+
35
+ Appium caps need to be prefixed with `appium:`, but this can feel redundant when you have a lot of caps. So you can also put them inside the `appium:options`-object. This was not supported by the visual module and was reported in #1118. It is now supported.
36
+
37
+ The following capabilities are now correctly read from both `appium:`-prefixed top-level format and the nested `appium:options` format:
38
+
39
+ - `deviceName`
40
+ - `nativeWebScreenshot`
41
+ - `avd` (new, see below)
42
+
43
+ Second issue that is fixed is that for Android the `deviceName` could be left away and the `avd` could be provided. This is now also supported where `deviceName` takes priority over `avd` if both are provided.
44
+
45
+ # Committers: 1
46
+
47
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
48
+
3
49
  ## 9.1.4
4
50
 
5
51
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { WicElement } from '@wdio/image-comparison-core';
2
2
  import WdioImageComparisonService from './service.js';
3
- import VisualLauncher from './storybook/launcher.js';
4
- import type { Output, Result, VisualServiceOptions, WdioCheckFullPageMethodOptions, WdioSaveFullPageMethodOptions, WdioSaveElementMethodOptions, WdioSaveScreenMethodOptions, WdioCheckElementMethodOptions, WdioCheckScreenMethodOptions } from './types.js';
3
+ import VisualLauncher from './launcher.js';
4
+ import type { Output, Result, VisualServiceOptions, WdioIcsOptions, WdioCheckFullPageMethodOptions, WdioSaveFullPageMethodOptions, WdioSaveElementMethodOptions, WdioSaveScreenMethodOptions, WdioCheckElementMethodOptions, WdioCheckScreenMethodOptions } from './types.js';
5
5
  import type { WaitForStorybookComponentToBeLoaded } from './storybook/Types.js';
6
6
  declare global {
7
7
  namespace WebdriverIO {
@@ -50,9 +50,7 @@ declare global {
50
50
  interface Element {
51
51
  }
52
52
  interface Capabilities {
53
- 'wdio-ics:options'?: {
54
- logName?: string;
55
- };
53
+ 'wdio-ics:options'?: WdioIcsOptions;
56
54
  }
57
55
  }
58
56
  namespace ExpectWebdriverIO {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import WdioImageComparisonService from './service.js';
2
- import VisualLauncher from './storybook/launcher.js';
2
+ import VisualLauncher from './launcher.js';
3
3
  export default WdioImageComparisonService;
4
4
  export const launcher = VisualLauncher;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../src/launcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAIvD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,SAAS;;gBAGrC,OAAO,EAAE,YAAY;IAK3B,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,CAAC,sBAAsB;IAQvF,UAAU;CASnB"}
@@ -0,0 +1,22 @@
1
+ import { BaseClass } from '@wdio/image-comparison-core';
2
+ import { prepareStorybook, cleanupStorybook } from './storybook/hooks.js';
3
+ import generateVisualReport from './reporter.js';
4
+ export default class VisualLauncher extends BaseClass {
5
+ #options;
6
+ constructor(options) {
7
+ super(options);
8
+ this.#options = options;
9
+ }
10
+ async onPrepare(config, capabilities) {
11
+ if (this.#options.clearRuntimeFolder) {
12
+ this._clearRuntimeFolders();
13
+ }
14
+ await prepareStorybook(config, capabilities, this.#options, this.folders);
15
+ }
16
+ async onComplete() {
17
+ cleanupStorybook();
18
+ if (this.#options.createJsonReportFiles) {
19
+ new generateVisualReport({ directoryPath: this.folders.actualFolder }).generate();
20
+ }
21
+ }
22
+ }
package/dist/service.js CHANGED
@@ -91,7 +91,7 @@ export default class WdioImageComparisonService extends BaseClass {
91
91
  * We also check `this.#config` because for standalone usage of the service, the config is not available
92
92
  */
93
93
  if (this.#config && typeof this.#config.resolveSnapshotPath === 'function' && this.#currentFile && isDefaultBaselineFolder) {
94
- return this.#config.resolveSnapshotPath(this.#currentFile, '.png');
94
+ return dirname(this.#config.resolveSnapshotPath(this.#currentFile, '.png'));
95
95
  }
96
96
  return baselineFolder;
97
97
  }
@@ -0,0 +1,5 @@
1
+ import type { Capabilities } from '@wdio/types';
2
+ import type { ClassOptions, Folders } from '@wdio/image-comparison-core';
3
+ export declare function prepareStorybook(config: WebdriverIO.Config, capabilities: Capabilities.TestrunnerCapabilities, options: ClassOptions, folders: Folders): Promise<void>;
4
+ export declare function cleanupStorybook(): void;
5
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/storybook/hooks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAA6B,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAcnG,wBAAsB,gBAAgB,CAClC,MAAM,EAAE,WAAW,CAAC,MAAM,EAC1B,YAAY,EAAE,YAAY,CAAC,sBAAsB,EACjD,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,OAAO,GACjB,OAAO,CAAC,IAAI,CAAC,CAsFf;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAiBvC"}
@@ -0,0 +1,100 @@
1
+ import { rmdirSync } from 'node:fs';
2
+ import logger from '@wdio/logger';
3
+ import { SevereServiceError } from 'webdriverio';
4
+ import { createStorybookCapabilities, createTestFiles, getArgvValue, isCucumberFramework, isStorybookMode, parseSkipStories, scanStorybook, } from './utils.js';
5
+ import { CLIP_SELECTOR, NUM_SHARDS, V6_CLIP_SELECTOR } from '../constants.js';
6
+ const log = logger('@wdio/visual-service');
7
+ export async function prepareStorybook(config, capabilities, options, folders) {
8
+ const isStorybook = isStorybookMode();
9
+ const framework = config.framework;
10
+ const isCucumber = isCucumberFramework(framework);
11
+ if (isCucumber && isStorybook) {
12
+ throw new SevereServiceError('\n\nRunning Storybook in combination with the cucumber framework adapter is not supported.\nOnly Jasmine and Mocha are supported.\n\n');
13
+ }
14
+ if (!isStorybook) {
15
+ return;
16
+ }
17
+ log.info('Running `@wdio/visual-service` in Storybook mode.');
18
+ const { storiesJson, storybookUrl, tempDir } = await scanStorybook(config, options);
19
+ process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER = tempDir;
20
+ process.env.VISUAL_STORYBOOK_URL = storybookUrl;
21
+ if (typeof capabilities === 'object' && !Array.isArray(capabilities)) {
22
+ throw new SevereServiceError('\n\nRunning Storybook in combination with Multiremote is not supported.\nRemove your `capabilities` property from your config or assign an empty array to it like `capabilities: [],`.\n\n');
23
+ }
24
+ capabilities.length = 0;
25
+ log.info('Clearing the current capabilities.');
26
+ const compareOptions = {
27
+ blockOutSideBar: options.blockOutSideBar,
28
+ blockOutStatusBar: options.blockOutStatusBar,
29
+ blockOutToolBar: options.blockOutToolBar,
30
+ ignoreAlpha: options.ignoreAlpha,
31
+ ignoreAntialiasing: options.ignoreAntialiasing,
32
+ ignoreColors: options.ignoreColors,
33
+ ignoreLess: options.ignoreLess,
34
+ ignoreNothing: options.ignoreNothing,
35
+ rawMisMatchPercentage: options.rawMisMatchPercentage,
36
+ returnAllCompareData: options.returnAllCompareData,
37
+ saveAboveTolerance: options.saveAboveTolerance,
38
+ scaleImagesToSameSize: options.scaleImagesToSameSize,
39
+ };
40
+ // --version
41
+ const versionOption = options?.storybook?.version;
42
+ const versionArgv = getArgvValue('--version', value => Math.floor(parseFloat(value)));
43
+ const version = versionOption ?? versionArgv ?? 7;
44
+ // --numShards
45
+ const maxInstances = config?.maxInstances ?? 1;
46
+ const numShardsOption = options?.storybook?.numShards;
47
+ const numShardsArgv = getArgvValue('--numShards', value => parseInt(value, 10));
48
+ const numShards = Math.min(numShardsOption || numShardsArgv || NUM_SHARDS, maxInstances);
49
+ // --clip
50
+ const clipOption = options?.storybook?.clip;
51
+ const clipArgv = getArgvValue('--clip', value => value !== 'false');
52
+ const clip = clipOption ?? clipArgv ?? true;
53
+ // --clipSelector
54
+ const clipSelectorOption = options?.storybook?.clipSelector;
55
+ const clipSelectorArgv = getArgvValue('--clipSelector', value => value);
56
+ const clipSelector = (clipSelectorOption ?? clipSelectorArgv) ?? (version === 6 ? V6_CLIP_SELECTOR : CLIP_SELECTOR);
57
+ process.env.VISUAL_STORYBOOK_CLIP_SELECTOR = clipSelector;
58
+ // --skipStories
59
+ const skipStoriesOption = options?.storybook?.skipStories;
60
+ const skipStoriesArgv = getArgvValue('--skipStories', value => value);
61
+ const skipStories = skipStoriesOption ?? skipStoriesArgv ?? [];
62
+ const parsedSkipStories = parseSkipStories(skipStories);
63
+ // --additionalSearchParams
64
+ const additionalSearchParamsOption = options?.storybook?.additionalSearchParams;
65
+ const additionalSearchParamsArgv = getArgvValue('--additionalSearchParams', value => new URLSearchParams(value));
66
+ const additionalSearchParams = additionalSearchParamsOption ?? additionalSearchParamsArgv ?? new URLSearchParams();
67
+ const getStoriesBaselinePath = options?.storybook?.getStoriesBaselinePath;
68
+ createTestFiles({
69
+ additionalSearchParams,
70
+ clip,
71
+ clipSelector,
72
+ compareOptions,
73
+ directoryPath: tempDir,
74
+ folders,
75
+ framework,
76
+ getStoriesBaselinePath,
77
+ numShards,
78
+ skipStories: parsedSkipStories,
79
+ storiesJson,
80
+ storybookUrl,
81
+ });
82
+ createStorybookCapabilities(capabilities);
83
+ }
84
+ export function cleanupStorybook() {
85
+ const tempDir = process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER;
86
+ if (!tempDir) {
87
+ return;
88
+ }
89
+ log.info(`Cleaning up temporary folder for storybook specs: ${tempDir}`);
90
+ try {
91
+ rmdirSync(tempDir, { recursive: true });
92
+ log.info(`Temporary folder for storybook specs has been removed: ${tempDir}`);
93
+ }
94
+ catch (err) {
95
+ log.error(`Failed to remove temporary folder for storybook specs: ${tempDir} due to: ${err.message}`);
96
+ }
97
+ delete process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER;
98
+ delete process.env.VISUAL_STORYBOOK_URL;
99
+ delete process.env.VISUAL_STORYBOOK_CLIP_SELECTOR;
100
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AACrF,OAAO,KAAK,EACR,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EAIzB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AAEH,wBAAgB,UAAU,CACtB,aAAa,EAAE,sBAAsB,EACrC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,GACxB,OAAO,CAMT;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,SAAI,GAAG;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACjB,CAKA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAAC,MAAM,EAAC,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GAAG,MAAM,CAOhH;AAuFD;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,WAAW,CAAC,YAAY,GAAG,GAAG,GAAG,SAAS,CAMpF;AAmCD;;GAEG;AACH,wBAAsB,eAAe,CAAC,EAClC,eAAe,EACf,uBAAuB,EACvB,eAAe,EAClB,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoEhD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAE,IAAI,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAGtG;AAOD,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EACvD;IAAE,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAuBT;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,EACI,WAAW,EACX,kBAAkB,EAAE,EAChB,SAAS,EACT,MAAM,EACN,KAAK,GACR,EACD,YAAY,EAAE,EACV,OAAO,EACP,WAAW,EACX,cAAc,EACd,UAAU,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,eAAe,GAClB,EACD,GAAG,GACN,EAAE,wBAAwB,GAAG,WAAW,CAuB5C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AACrF,OAAO,KAAK,EACR,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EAIzB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AAEH,wBAAgB,UAAU,CACtB,aAAa,EAAE,sBAAsB,EACrC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,GACxB,OAAO,CAMT;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,SAAI,GAAG;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACjB,CAKA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAAC,MAAM,EAAC,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GAAG,MAAM,CAOhH;AAuFD;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,WAAW,CAAC,YAAY,GAAG,GAAG,GAAG,SAAS,CAMpF;AA+CD;;GAEG;AACH,wBAAsB,eAAe,CAAC,EAClC,eAAe,EACf,uBAAuB,EACvB,eAAe,EAClB,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoEhD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAE,IAAI,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAGtG;AAOD,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EACvD;IAAE,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAuBT;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,EACI,WAAW,EACX,kBAAkB,EAAE,EAChB,SAAS,EACT,MAAM,EACN,KAAK,GACR,EACD,YAAY,EAAE,EACV,OAAO,EACP,WAAW,EACX,cAAc,EACd,UAAU,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,eAAe,GAClB,EACD,GAAG,GACN,EAAE,wBAAwB,GAAG,WAAW,CAuB5C"}
package/dist/utils.js CHANGED
@@ -115,6 +115,14 @@ export function getLtOptions(capabilities) {
115
115
  const key = Object.keys(capabilities).find((k) => k.toLowerCase() === 'lt:options');
116
116
  return key ? capabilities[key] : undefined;
117
117
  }
118
+ /**
119
+ * Get a requested Appium capability value by checking both the `appium:`-prefixed
120
+ * top-level format and the nested `appium:options` format.
121
+ */
122
+ function getRequestedAppiumCapability(requestedCapabilities, capName) {
123
+ return requestedCapabilities[`appium:${capName}`]
124
+ ?? requestedCapabilities['appium:options']?.[capName];
125
+ }
118
126
  /**
119
127
  * Get the device name
120
128
  */
@@ -140,7 +148,8 @@ function getDeviceName(browserInstance) {
140
148
  if (isLambdaTest && ltOptions && capName in ltOptions) {
141
149
  deviceName = ltOptions[capName];
142
150
  }
143
- const { 'appium:deviceName': requestedDeviceName } = requestedCapabilities;
151
+ const requestedDeviceName = (getRequestedAppiumCapability(requestedCapabilities, 'deviceName')
152
+ || getRequestedAppiumCapability(requestedCapabilities, 'avd'));
144
153
  return (deviceName !== NOT_KNOWN ? deviceName : requestedDeviceName || returnedDeviceName || NOT_KNOWN).toLowerCase();
145
154
  }
146
155
  /**
@@ -179,7 +188,7 @@ export async function getInstanceData({ browserInstance, initialDeviceRectangles
179
188
  const ltOptions = getLtOptions(requestedCapabilities);
180
189
  // @TODO: Figure this one out in the future when we know more about the Appium capabilities from LT
181
190
  // 20241216: LT doesn't have the option to take a ChromeDriver screenshot, so if it's Android it's always native
182
- const nativeWebScreenshot = isAndroid && ltOptions || !!(requestedCapabilities['appium:nativeWebScreenshot']);
191
+ const nativeWebScreenshot = isAndroid && ltOptions || !!getRequestedAppiumCapability(requestedCapabilities, 'nativeWebScreenshot');
183
192
  const platformVersion = (rawPlatformVersion === undefined || rawPlatformVersion === '') ? NOT_KNOWN : rawPlatformVersion.toLowerCase();
184
193
  const { devicePixelRatio: mobileDevicePixelRatio, deviceRectangles, } = await getMobileInstanceData({ browserInstance, initialDeviceRectangles, isNativeContext, nativeWebScreenshot });
185
194
  devicePixelRatio = isMobile ? mobileDevicePixelRatio : devicePixelRatio;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@wdio/visual-service",
3
3
  "author": "Wim Selles - wswebcreation",
4
4
  "description": "Image comparison / visual regression testing for WebdriverIO",
5
- "version": "9.1.4",
5
+ "version": "9.1.6",
6
6
  "license": "MIT",
7
7
  "homepage": "https://webdriver.io/docs/visual-testing",
8
8
  "repository": {
@@ -24,7 +24,7 @@
24
24
  "@wdio/logger": "^9.18.0",
25
25
  "@wdio/types": "^9.20.0",
26
26
  "expect-webdriverio": "^5.6.1",
27
- "@wdio/image-comparison-core": "1.1.3"
27
+ "@wdio/image-comparison-core": "1.1.4"
28
28
  },
29
29
  "scripts": {
30
30
  "build": "run-s clean build:*",
@@ -1 +0,0 @@
1
- {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../../src/storybook/launcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAA8B,MAAM,6BAA6B,CAAA;AAC3F,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAevD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,SAAS;;gBAGrC,OAAO,EAAE,YAAY;IAK3B,SAAS,CAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,CAAC,sBAAsB;IA+FxF,UAAU;CAuBnB"}
@@ -1,122 +0,0 @@
1
- import { rmdirSync } from 'node:fs';
2
- import logger from '@wdio/logger';
3
- import { SevereServiceError } from 'webdriverio';
4
- import { BaseClass } from '@wdio/image-comparison-core';
5
- import { createStorybookCapabilities, createTestFiles, getArgvValue, isCucumberFramework, isStorybookMode, parseSkipStories, scanStorybook, } from './utils.js';
6
- import { CLIP_SELECTOR, NUM_SHARDS, V6_CLIP_SELECTOR } from '../constants.js';
7
- import generateVisualReport from '../reporter.js';
8
- const log = logger('@wdio/visual-service');
9
- export default class VisualLauncher extends BaseClass {
10
- #options;
11
- constructor(options) {
12
- super(options);
13
- this.#options = options;
14
- }
15
- async onPrepare(config, capabilities) {
16
- const isStorybook = isStorybookMode();
17
- const framework = config.framework;
18
- const isCucumber = isCucumberFramework(framework);
19
- if (isCucumber && isStorybook) {
20
- throw new SevereServiceError('\n\nRunning Storybook in combination with the cucumber framework adapter is not supported.\nOnly Jasmine and Mocha are supported.\n\n');
21
- }
22
- else if (isStorybook) {
23
- log.info('Running `@wdio/visual-service` in Storybook mode.');
24
- const { storiesJson, storybookUrl, tempDir } = await scanStorybook(config, this.#options);
25
- // Set an environment variable so it can be used in the onComplete hook
26
- process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER = tempDir;
27
- // Add the storybook URL to the environment variables
28
- process.env.VISUAL_STORYBOOK_URL = storybookUrl;
29
- // Check the capabilities
30
- // Multiremote capabilities are not supported
31
- if (typeof capabilities === 'object' && !Array.isArray(capabilities)) {
32
- throw new SevereServiceError('\n\nRunning Storybook in combination with Multiremote is not supported.\nRemove your `capabilities` property from your config or assign an empty array to it like `capabilities: [],`.\n\n');
33
- }
34
- // Clear the capabilities
35
- capabilities.length = 0;
36
- log.info('Clearing the current capabilities.');
37
- // Get compare options from config
38
- const compareOptions = {
39
- blockOutSideBar: this.#options.blockOutSideBar,
40
- blockOutStatusBar: this.#options.blockOutStatusBar,
41
- blockOutToolBar: this.#options.blockOutToolBar,
42
- ignoreAlpha: this.#options.ignoreAlpha,
43
- ignoreAntialiasing: this.#options.ignoreAntialiasing,
44
- ignoreColors: this.#options.ignoreColors,
45
- ignoreLess: this.#options.ignoreLess,
46
- ignoreNothing: this.#options.ignoreNothing,
47
- rawMisMatchPercentage: this.#options.rawMisMatchPercentage,
48
- returnAllCompareData: this.#options.returnAllCompareData,
49
- saveAboveTolerance: this.#options.saveAboveTolerance,
50
- scaleImagesToSameSize: this.#options.scaleImagesToSameSize,
51
- };
52
- // Determine some run options
53
- // --version
54
- const versionOption = this.#options?.storybook?.version;
55
- const versionArgv = getArgvValue('--version', value => Math.floor(parseFloat(value)));
56
- const version = versionOption ?? versionArgv ?? 7;
57
- // --numShards
58
- const maxInstances = config?.maxInstances ?? 1;
59
- const numShardsOption = this.#options?.storybook?.numShards;
60
- const numShardsArgv = getArgvValue('--numShards', value => parseInt(value, 10));
61
- const numShards = Math.min(numShardsOption || numShardsArgv || NUM_SHARDS, maxInstances);
62
- // --clip
63
- const clipOption = this.#options?.storybook?.clip;
64
- const clipArgv = getArgvValue('--clip', value => value !== 'false');
65
- const clip = clipOption ?? clipArgv ?? true;
66
- // --clipSelector
67
- const clipSelectorOption = this.#options?.storybook?.clipSelector;
68
- const clipSelectorArgv = getArgvValue('--clipSelector', value => value);
69
- // V6 has '#root' as the root element, V7 has '#storybook-root'
70
- const clipSelector = (clipSelectorOption ?? clipSelectorArgv) ?? (version === 6 ? V6_CLIP_SELECTOR : CLIP_SELECTOR);
71
- // Add the clip selector to the environment variables
72
- process.env.VISUAL_STORYBOOK_CLIP_SELECTOR = clipSelector;
73
- // --skipStories
74
- const skipStoriesOption = this.#options?.storybook?.skipStories;
75
- const skipStoriesArgv = getArgvValue('--skipStories', value => value);
76
- const skipStories = skipStoriesOption ?? skipStoriesArgv ?? [];
77
- const parsedSkipStories = parseSkipStories(skipStories);
78
- // --additionalSearchParams
79
- const additionalSearchParamsOption = this.#options?.storybook?.additionalSearchParams;
80
- const additionalSearchParamsArgv = getArgvValue('--additionalSearchParams', value => new URLSearchParams(value));
81
- const additionalSearchParams = additionalSearchParamsOption ?? additionalSearchParamsArgv ?? new URLSearchParams();
82
- const getStoriesBaselinePath = this.#options?.storybook?.getStoriesBaselinePath;
83
- // Create the test files
84
- createTestFiles({
85
- additionalSearchParams,
86
- clip,
87
- clipSelector,
88
- compareOptions,
89
- directoryPath: tempDir,
90
- folders: this.folders,
91
- framework,
92
- getStoriesBaselinePath,
93
- numShards,
94
- skipStories: parsedSkipStories,
95
- storiesJson,
96
- storybookUrl,
97
- });
98
- // Create the capabilities
99
- createStorybookCapabilities(capabilities);
100
- }
101
- }
102
- async onComplete() {
103
- const tempDir = process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER;
104
- if (tempDir) {
105
- log.info(`Cleaning up temporary folder for storybook specs: ${tempDir}`);
106
- try {
107
- rmdirSync(tempDir, { recursive: true });
108
- log.info(`Temporary folder for storybook specs has been removed: ${tempDir}`);
109
- }
110
- catch (err) {
111
- log.error(`Failed to remove temporary folder for storybook specs: ${tempDir} due to: ${err.message}`);
112
- }
113
- // Remove the environment variables
114
- delete process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER;
115
- delete process.env.VISUAL_STORYBOOK_URL;
116
- delete process.env.VISUAL_STORYBOOK_CLIP_SELECTOR;
117
- }
118
- if (this.#options.createJsonReportFiles) {
119
- new generateVisualReport({ directoryPath: this.folders.actualFolder }).generate();
120
- }
121
- }
122
- }
File without changes