@wdio/visual-service 9.1.3 → 9.1.5

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,71 @@
1
1
  # @wdio/visual-service
2
2
 
3
+ ## 9.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 6ed0469: ## Fix: support `appium:options` nested capability format and `avd` fallback (#1118)
8
+
9
+ 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.
10
+
11
+ The following capabilities are now correctly read from both `appium:`-prefixed top-level format and the nested `appium:options` format:
12
+
13
+ - `deviceName`
14
+ - `nativeWebScreenshot`
15
+ - `avd` (new, see below)
16
+
17
+ 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.
18
+
19
+ # Committers: 1
20
+
21
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
22
+
23
+ ## 9.1.4
24
+
25
+ ### Patch Changes
26
+
27
+ - a3bc7a4: ## #1115 Respect `alwaysSaveActualImage: false` for `checkScreen` methods
28
+
29
+ When using visual matchers like `toMatchScreenSnapshot('tag', 0.9)` with `alwaysSaveActualImage: false`, the actual image was still being saved even when the comparison passed within the threshold.
30
+
31
+ The root cause was that the matcher's expected threshold was not being passed to the core comparison logic. The core used `saveAboveTolerance` (defaulting to 0) to decide whether to save images, while the matcher used the user-provided threshold to determine pass/fail - these were disconnected.
32
+
33
+ This fix ensures:
34
+
35
+ - When `alwaysSaveActualImage: false` and `saveAboveTolerance` is not explicitly set, actual images are never saved (respecting the literal meaning of the option)
36
+ - When `saveAboveTolerance` is explicitly set (like matchers do internally), actual images are saved only when the mismatch exceeds that threshold
37
+
38
+ # Committers: 1
39
+
40
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
41
+
42
+ - a3bc7a4: ## Fix: `save*` methods now always save files regardless of `alwaysSaveActualImage` setting
43
+
44
+ Previously, when `alwaysSaveActualImage: false` was set in the configuration, `save*` methods (`saveScreen`, `saveElement`, `saveFullPageScreen`, `saveAppScreen`, `saveAppElement`) were not saving files to disk, causing test failures.
45
+
46
+ The `alwaysSaveActualImage` option is intended to control whether actual images are saved during `check*` methods (comparison operations), not `save*` methods. Since `save*` methods are explicitly designed to save screenshots, they should always save files regardless of this setting.
47
+
48
+ This fix ensures:
49
+
50
+ - `save*` methods always save files to disk, even when `alwaysSaveActualImage: false` is set in the config
51
+ - `alwaysSaveActualImage: false` continues to work correctly for `check*` methods (as intended for issue #1115)
52
+ - The behavior is now consistent: `save*` = always save, `check*` = respect `alwaysSaveActualImage` setting
53
+
54
+ **Implementation details:**
55
+
56
+ - The visual service overrides `alwaysSaveActualImage: true` when calling `save*` methods directly from the browser API
57
+ - `save*` methods respect whatever `alwaysSaveActualImage` value is passed to them (no special logic needed)
58
+ - `check*` methods pass through the config value (which may be `false`), so `save*` methods respect it when called internally
59
+ - This clean separation ensures `save*` methods work correctly when called directly while still respecting `alwaysSaveActualImage` for `check*` methods
60
+
61
+ # Committers: 1
62
+
63
+ - Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
64
+
65
+ - Updated dependencies [a3bc7a4]
66
+ - Updated dependencies [a3bc7a4]
67
+ - @wdio/image-comparison-core@1.1.3
68
+
3
69
  ## 9.1.3
4
70
 
5
71
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EACH,SAAS,EAWZ,MAAM,6BAA6B,CAAA;AAiBpC,OAAO,KAAK,EAAc,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAepD,MAAM,CAAC,OAAO,OAAO,0BAA2B,SAAQ,SAAS;;IAM7D,OAAO,CAAC,eAAe,CAAC,CAAgB;IACxC,OAAO,CAAC,gBAAgB,CAAC,CAAyC;gBAEtD,OAAO,EAAE,oBAAoB,EAAE,CAAC,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM;IAMlG;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAIzE,MAAM,CACR,YAAY,EAAE,WAAW,CAAC,YAAY,EACtC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAgC3D,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI;IAOtC,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK;IA4ZtC,IAAI,cAAc,IAAI,cAAc,CAKnC;CAyCJ"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EACH,SAAS,EAWZ,MAAM,6BAA6B,CAAA;AAiBpC,OAAO,KAAK,EAAc,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAepD,MAAM,CAAC,OAAO,OAAO,0BAA2B,SAAQ,SAAS;;IAM7D,OAAO,CAAC,eAAe,CAAC,CAAgB;IACxC,OAAO,CAAC,gBAAgB,CAAC,CAAyC;gBAEtD,OAAO,EAAE,oBAAoB,EAAE,CAAC,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM;IAMlG;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAIzE,MAAM,CACR,YAAY,EAAE,WAAW,CAAC,YAAY,EACtC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAgC3D,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI;IAOtC,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK;IAwatC,IAAI,cAAc,IAAI,cAAc,CAKnC;CAyCJ"}
package/dist/service.js CHANGED
@@ -162,6 +162,11 @@ export default class WdioImageComparisonService extends BaseClass {
162
162
  deviceRectangles: self.contextManager.getViewportContext(),
163
163
  };
164
164
  const isCurrentContextNative = self.contextManager.isNativeContext;
165
+ // save* methods should always save files, regardless of alwaysSaveActualImage config
166
+ const isSaveCommand = commandName === 'saveElement';
167
+ const wicOptions = isSaveCommand
168
+ ? { ...self.defaultOptions, alwaysSaveActualImage: true }
169
+ : self.defaultOptions;
165
170
  return [{
166
171
  browserInstance,
167
172
  element,
@@ -170,7 +175,7 @@ export default class WdioImageComparisonService extends BaseClass {
170
175
  isNativeContext: isCurrentContextNative,
171
176
  tag,
172
177
  [elementOptionsKey]: {
173
- wic: self.defaultOptions,
178
+ wic: wicOptions,
174
179
  method: elementOptions,
175
180
  },
176
181
  testContext: enrichTestContext({
@@ -207,6 +212,11 @@ export default class WdioImageComparisonService extends BaseClass {
207
212
  deviceRectangles: self.contextManager.getViewportContext()
208
213
  };
209
214
  const isCurrentContextNative = self.contextManager.isNativeContext;
215
+ // save* methods should always save files, regardless of alwaysSaveActualImage config
216
+ const isSaveCommand = commandName === 'saveScreen' || commandName === 'saveFullPageScreen' || commandName === 'saveTabbablePage';
217
+ const wicOptions = isSaveCommand
218
+ ? { ...self.defaultOptions, alwaysSaveActualImage: true }
219
+ : self.defaultOptions;
210
220
  return [{
211
221
  browserInstance,
212
222
  folders: getFolders(pageOptions, self.folders, self.#getBaselineFolder()),
@@ -214,7 +224,7 @@ export default class WdioImageComparisonService extends BaseClass {
214
224
  isNativeContext: isCurrentContextNative,
215
225
  tag,
216
226
  [pageOptionsKey]: {
217
- wic: self.defaultOptions,
227
+ wic: wicOptions,
218
228
  method: pageOptions,
219
229
  },
220
230
  testContext: enrichTestContext({
@@ -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.3",
5
+ "version": "9.1.5",
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.2"
27
+ "@wdio/image-comparison-core": "1.1.3"
28
28
  },
29
29
  "scripts": {
30
30
  "build": "run-s clean build:*",