@wdio/visual-service 5.1.0 → 5.1.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 +23 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/matcher.d.ts +0 -1
- package/dist/matcher.d.ts.map +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +134 -51
- package/dist/types.d.ts +13 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +6 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +24 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @wdio/visual-service
|
|
2
2
|
|
|
3
|
+
## 5.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 26c1a17: This release contains better support for Multiremote tests on the instances and global level, including better Native App support. This is related to issue https://github.com/webdriverio/visual-testing/issues/418 which is fixed by this release
|
|
8
|
+
|
|
9
|
+
# 💅 Polish
|
|
10
|
+
|
|
11
|
+
- cab1219: Update dependencies
|
|
12
|
+
- 2583542 / 8b1f837: add new tests
|
|
13
|
+
- eec29e1 / e2b2d38: update images
|
|
14
|
+
|
|
15
|
+
# 🐛 Bug Fixes
|
|
16
|
+
|
|
17
|
+
- 29f6f82 / 1ba9817: fix issue https://github.com/webdriverio/visual-testing/issues/418
|
|
18
|
+
|
|
19
|
+
# Committers: 1
|
|
20
|
+
|
|
21
|
+
- Wim Selles ([@wswebcreation](https://github.com/wswebcreation))
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [26c1a17]
|
|
24
|
+
- webdriver-image-comparison@6.0.2
|
|
25
|
+
|
|
3
26
|
## 5.1.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,0BAA0B,MAAM,cAAc,CAAA;AACrD,OAAO,cAAc,MAAM,yBAAyB,CAAA;AACpD,OAAO,KAAK,EACR,MAAM,EACN,MAAM,EACN,8BAA8B,EAC9B,6BAA6B,EAC7B,4BAA4B,EAC5B,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC/B,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAE/E,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,OAAO;YACb;;eAEG;YACH,WAAW,CACP,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,EACX,kBAAkB,CAAC,EAAE,4BAA4B,GAClD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,UAAU,CACN,GAAG,EAAE,MAAM,EACX,iBAAiB,CAAC,EAAE,2BAA2B,GAChD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,kBAAkB,CACd,GAAG,EAAE,MAAM,EACX,yBAAyB,CAAC,EAAE,6BAA6B,GAC1D,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,gBAAgB,CACZ,GAAG,EAAE,MAAM,EACX,mBAAmB,CAAC,EAAE,6BAA6B,GACpD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,YAAY,CACR,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,EACX,mBAAmB,CAAC,EAAE,6BAA6B,GACpD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,WAAW,CACP,GAAG,EAAE,MAAM,EACX,kBAAkB,CAAC,EAAE,4BAA4B,GAClD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,mBAAmB,CACf,GAAG,EAAE,MAAM,EACX,oBAAoB,CAAC,EAAE,8BAA8B,GACtD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,iBAAiB,CACb,GAAG,EAAE,MAAM,EACX,oBAAoB,CAAC,EAAE,8BAA8B,GACtD,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnB;;eAEG;YACH,mCAAmC,CAC/B,OAAO,EAAE,mCAAmC,GAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;SACpB;QACD,UAAU,OAAO;SAAG;QACpB,UAAU,YAAY;YAClB,kBAAkB,CAAC,EAAC;gBAChB,OAAO,CAAC,EAAE,MAAM,CAAC;aACpB,CAAA;SACJ;KACJ;IAED,UAAU,iBAAiB,CAAC;QAGxB,UAAU,QAAQ,CAAC,CAAC,EAAE,CAAC;YACnB;;;;;eAKG;YACH,qBAAqB,CACjB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EAC1D,OAAO,CAAC,EAAE,4BAA4B,GACvC,CAAC,CAAA;YACJ,qBAAqB,CACjB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,4BAA4B,GACvC,CAAC,CAAA;YACJ;;;;;eAKG;YACH,uBAAuB,CACnB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EAC1D,OAAO,CAAC,EAAE,8BAA8B,GACzC,CAAC,CAAA;YACJ,uBAAuB,CACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,8BAA8B,GACzC,CAAC,CAAA;YACJ;;;;;eAKG;YACH,sBAAsB,CAClB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EAC1D,OAAO,CAAC,EAAE,6BAA6B,GACxC,CAAC,CAAA;YACJ,sBAAsB,CAClB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,6BAA6B,GACxC,CAAC,CAAA;YACJ;;;;;eAKG;YACH,2BAA2B,CACvB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EAC1D,OAAO,CAAC,EAAE,8BAA8B,GACzC,CAAC,CAAA;YACJ,2BAA2B,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,8BAA8B,GACzC,CAAC,CAAA;SACP;KACJ;CACJ;AAED,eAAe,0BAA0B,CAAA;AACzC,eAAO,MAAM,QAAQ,uBAAiB,CAAA"}
|
package/dist/matcher.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="./expect-webdriverio.js" />
|
|
2
1
|
import type { WdioCheckFullPageMethodOptions, WdioCheckElementMethodOptions, WdioCheckScreenMethodOptions } from './types.js';
|
|
3
2
|
export declare function toMatchScreenSnapshot(browser: WebdriverIO.Browser, tag: string, expectedResultOrOptions?: number | ExpectWebdriverIO.PartialMatcher, optionsOrUndefined?: WdioCheckScreenMethodOptions): Promise<{
|
|
4
3
|
pass: boolean;
|
package/dist/matcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,8BAA8B,EAC9B,6BAA6B,EAC7B,4BAA4B,EAC/B,MAAM,YAAY,CAAA;AA2FnB,wBAAsB,qBAAqB,CACvC,OAAO,EAAE,WAAW,CAAC,OAAO,EAC5B,GAAG,EAAE,MAAM,EACX,uBAAuB,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EACnE,kBAAkB,CAAC,EAAE,4BAA4B;;;GAKpD;AAED,wBAAsB,uBAAuB,CACzC,OAAO,EAAE,WAAW,CAAC,OAAO,EAC5B,GAAG,EAAE,MAAM,EACX,uBAAuB,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EACnE,kBAAkB,CAAC,EAAE,8BAA8B;;;GAKtD;AAED,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,WAAW,CAAC,OAAO,EAC5B,GAAG,EAAE,MAAM,EACX,uBAAuB,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EACnE,kBAAkB,CAAC,EAAE,6BAA6B;;;GAMrD;AAED,wBAAsB,2BAA2B,CAC7C,OAAO,EAAE,WAAW,CAAC,OAAO,EAC5B,GAAG,EAAE,MAAM,EACX,uBAAuB,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC,cAAc,EACnE,kBAAkB,CAAC,EAAE,8BAA8B;;;GAKtD"}
|
package/dist/service.d.ts.map
CHANGED
|
@@ -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,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EACH,SAAS,EAUZ,MAAM,4BAA4B,CAAA;AAwBnC,MAAM,CAAC,OAAO,OAAO,0BAA2B,SAAQ,SAAS;;IAI7D,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,OAAO,CAAC,gBAAgB,
|
|
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,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EACH,SAAS,EAUZ,MAAM,4BAA4B,CAAA;AAwBnC,MAAM,CAAC,OAAO,OAAO,0BAA2B,SAAQ,SAAS;;IAI7D,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,OAAO,CAAC,gBAAgB,CAA+B;gBAE3C,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM;IAM1F;;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;IAgCjE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI;IAKhC,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG;CAkQzF"}
|
package/dist/service.js
CHANGED
|
@@ -2,7 +2,7 @@ import logger from '@wdio/logger';
|
|
|
2
2
|
import { expect } from '@wdio/globals';
|
|
3
3
|
import { dirname, normalize, resolve } from 'node:path';
|
|
4
4
|
import { BaseClass, checkElement, checkFullPageScreen, checkScreen, saveElement, saveFullPageScreen, saveScreen, saveTabbablePage, checkTabbablePage, FOLDERS, } from 'webdriver-image-comparison';
|
|
5
|
-
import { determineNativeContext, getFolders, getInstanceData } from './utils.js';
|
|
5
|
+
import { determineNativeContext, getFolders, getInstanceData, getNativeContext } from './utils.js';
|
|
6
6
|
import { toMatchScreenSnapshot, toMatchFullPageSnapshot, toMatchElementSnapshot, toMatchTabbablePageSnapshot } from './matcher.js';
|
|
7
7
|
import { waitForStorybookComponentToBeLoaded } from './storybook/utils.js';
|
|
8
8
|
const log = logger('@wdio/visual-service');
|
|
@@ -43,6 +43,9 @@ export default class WdioImageComparisonService extends BaseClass {
|
|
|
43
43
|
else {
|
|
44
44
|
await this.#extendMultiremoteBrowser(capabilities);
|
|
45
45
|
}
|
|
46
|
+
if (browser.isMultiremote) {
|
|
47
|
+
this.#setupMultiremoteContextListener();
|
|
48
|
+
}
|
|
46
49
|
/**
|
|
47
50
|
* add custom matcher for visual comparison when expect has been added.
|
|
48
51
|
* this is not the case in standalone mode
|
|
@@ -66,7 +69,8 @@ export default class WdioImageComparisonService extends BaseClass {
|
|
|
66
69
|
afterCommand(commandName, _args, result, error) {
|
|
67
70
|
// This is for the cases where in the E2E tests we switch to a WEBVIEW or back to NATIVE_APP context
|
|
68
71
|
if (commandName === 'getContext' && error === undefined && typeof result === 'string') {
|
|
69
|
-
|
|
72
|
+
// Multiremote logic is handled in the `before` method during an event listener
|
|
73
|
+
this._isNativeContext = this._browser?.isMultiremote ? this._isNativeContext : result.includes('NATIVE');
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
#getBaselineFolder() {
|
|
@@ -86,81 +90,160 @@ export default class WdioImageComparisonService extends BaseClass {
|
|
|
86
90
|
}
|
|
87
91
|
return baselineFolder;
|
|
88
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Add commands to the Multi Remote browser object
|
|
95
|
+
*/
|
|
89
96
|
async #extendMultiremoteBrowser(capabilities) {
|
|
90
97
|
const browser = this._browser;
|
|
91
98
|
const browserNames = Object.keys(capabilities);
|
|
92
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Add all the commands to each browser in the Multi Remote
|
|
101
|
+
*/
|
|
93
102
|
for (const browserName of browserNames) {
|
|
94
|
-
|
|
95
|
-
const browserInstance =
|
|
103
|
+
log.info(`Adding commands to Multi Browser: ${browserName}`);
|
|
104
|
+
const browserInstance = browser.getInstance(browserName);
|
|
96
105
|
await this.#addCommandsToBrowser(browserInstance);
|
|
97
106
|
}
|
|
98
107
|
/**
|
|
99
108
|
* Add all the commands to the global browser object that will execute
|
|
100
109
|
* on each browser in the Multi Remote
|
|
110
|
+
* Start with the page commands
|
|
101
111
|
*/
|
|
102
|
-
for (const command of
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const returnData = {};
|
|
112
|
-
for (const browserName of browserNames) {
|
|
113
|
-
const multiremoteBrowser = browser;
|
|
114
|
-
const browserInstance = multiremoteBrowser.getInstance(browserName);
|
|
115
|
-
/**
|
|
116
|
-
* casting command to `checkScreen` to simplify type handling here
|
|
117
|
-
*/
|
|
118
|
-
returnData[browserName] = browserInstance[command].call(browserInstance, ...args);
|
|
119
|
-
}
|
|
120
|
-
return returnData;
|
|
121
|
-
});
|
|
122
|
-
}
|
|
112
|
+
for (const [commandName, command] of Object.entries(pageCommands)) {
|
|
113
|
+
this.#addMultiremoteCommand(browser, browserNames, commandName, command);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Add all the element commands to the global browser object that will execute
|
|
117
|
+
* on each browser in the Multi Remote
|
|
118
|
+
*/
|
|
119
|
+
for (const [commandName, command] of Object.entries(elementCommands)) {
|
|
120
|
+
this.#addMultiremoteElementCommand(browser, browserNames, commandName, command);
|
|
123
121
|
}
|
|
124
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Add commands to the "normal" browser object
|
|
125
|
+
*/
|
|
125
126
|
async #addCommandsToBrowser(currentBrowser) {
|
|
126
127
|
const instanceData = await getInstanceData(currentBrowser);
|
|
127
|
-
const
|
|
128
|
+
const isNativeContext = getNativeContext(this._browser, currentBrowser, this._isNativeContext);
|
|
128
129
|
for (const [commandName, command] of Object.entries(elementCommands)) {
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
this.#addElementCommand(currentBrowser, commandName, command, instanceData, isNativeContext);
|
|
131
|
+
}
|
|
132
|
+
for (const [commandName, command] of Object.entries(pageCommands)) {
|
|
133
|
+
this.#addPageCommand(currentBrowser, commandName, command, instanceData, isNativeContext);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Add new element commands to the browser object
|
|
138
|
+
*/
|
|
139
|
+
#addElementCommand(browser, commandName, command, instanceData, isNativeContext) {
|
|
140
|
+
log.info(`Adding element command "${commandName}" to browser object`);
|
|
141
|
+
const self = this;
|
|
142
|
+
browser.addCommand(commandName, function (element, tag, elementOptions = {}) {
|
|
143
|
+
return command({
|
|
144
|
+
executor: (script, ...varArgs) => {
|
|
145
|
+
return this.execute.bind(browser)(script, ...varArgs);
|
|
146
|
+
},
|
|
147
|
+
getElementRect: this.getElementRect.bind(browser),
|
|
148
|
+
screenShot: this.takeScreenshot.bind(browser),
|
|
149
|
+
takeElementScreenshot: this.takeElementScreenshot.bind(browser),
|
|
150
|
+
}, instanceData, getFolders(elementOptions, self.folders, self.#getBaselineFolder()), element, tag, {
|
|
151
|
+
wic: self.defaultOptions,
|
|
152
|
+
method: elementOptions,
|
|
153
|
+
}, isNativeContext);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Add new page commands to the browser object
|
|
158
|
+
*/
|
|
159
|
+
#addPageCommand(browser, commandName, command, instanceData, isNativeContext) {
|
|
160
|
+
log.info(`Adding browser command "${commandName}" to browser object`);
|
|
161
|
+
const self = this;
|
|
162
|
+
if (commandName === 'waitForStorybookComponentToBeLoaded') {
|
|
163
|
+
browser.addCommand(commandName, (options) => waitForStorybookComponentToBeLoaded(options));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
browser.addCommand(commandName, function (tag, pageOptions = {}) {
|
|
131
167
|
return command({
|
|
132
168
|
executor: (script, ...varArgs) => {
|
|
133
|
-
return this.execute.bind(
|
|
169
|
+
return this.execute.bind(browser)(script, ...varArgs);
|
|
134
170
|
},
|
|
135
|
-
getElementRect: this.getElementRect.bind(
|
|
136
|
-
screenShot: this.takeScreenshot.bind(
|
|
137
|
-
|
|
138
|
-
}, instanceData, getFolders(elementOptions, self.folders, self.#getBaselineFolder()), element, tag, {
|
|
171
|
+
getElementRect: this.getElementRect.bind(browser),
|
|
172
|
+
screenShot: this.takeScreenshot.bind(browser),
|
|
173
|
+
}, instanceData, getFolders(pageOptions, self.folders, self.#getBaselineFolder()), tag, {
|
|
139
174
|
wic: self.defaultOptions,
|
|
140
|
-
method:
|
|
141
|
-
},
|
|
175
|
+
method: pageOptions,
|
|
176
|
+
}, isNativeContext);
|
|
142
177
|
});
|
|
143
178
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
179
|
+
}
|
|
180
|
+
#addMultiremoteCommand(browser, browserNames, commandName, command) {
|
|
181
|
+
log.info(`Adding browser command "${commandName}" to Multi browser object`);
|
|
182
|
+
const self = this;
|
|
183
|
+
if (commandName === 'waitForStorybookComponentToBeLoaded') {
|
|
184
|
+
browser.addCommand(commandName, waitForStorybookComponentToBeLoaded);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
browser.addCommand(commandName, async function (tag, pageOptions = {}) {
|
|
188
|
+
const returnData = {};
|
|
189
|
+
for (const browserName of browserNames) {
|
|
190
|
+
const browserInstance = browser.getInstance(browserName);
|
|
191
|
+
const isNativeContext = getNativeContext(self._browser, browserInstance, self._isNativeContext);
|
|
192
|
+
const instanceData = await getInstanceData(browserInstance);
|
|
193
|
+
returnData[browserName] = await command({
|
|
152
194
|
executor: (script, ...varArgs) => {
|
|
153
|
-
return
|
|
195
|
+
return browserInstance.execute.bind(browserInstance)(script, ...varArgs);
|
|
154
196
|
},
|
|
155
|
-
getElementRect:
|
|
156
|
-
screenShot:
|
|
157
|
-
}
|
|
158
|
-
return command(options, instanceData, getFolders(pageOptions, self.folders, self.#getBaselineFolder()), tag, {
|
|
197
|
+
getElementRect: browserInstance.getElementRect.bind(browserInstance),
|
|
198
|
+
screenShot: browserInstance.takeScreenshot.bind(browserInstance),
|
|
199
|
+
}, instanceData, getFolders(pageOptions, self.folders, self.#getBaselineFolder()), tag, {
|
|
159
200
|
wic: self.defaultOptions,
|
|
160
201
|
method: pageOptions,
|
|
161
|
-
},
|
|
162
|
-
}
|
|
202
|
+
}, isNativeContext);
|
|
203
|
+
}
|
|
204
|
+
return returnData;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
#addMultiremoteElementCommand(browser, browserNames, commandName, command) {
|
|
209
|
+
log.info(`Adding element command "${commandName}" to Multi browser object`);
|
|
210
|
+
const self = this;
|
|
211
|
+
browser.addCommand(commandName, async function (tag, element, pageOptions = {}) {
|
|
212
|
+
const returnData = {};
|
|
213
|
+
for (const browserName of browserNames) {
|
|
214
|
+
const browserInstance = browser.getInstance(browserName);
|
|
215
|
+
const isNativeContext = getNativeContext(self._browser, browserInstance, self._isNativeContext);
|
|
216
|
+
const instanceData = await getInstanceData(browserInstance);
|
|
217
|
+
returnData[browserName] = await command({
|
|
218
|
+
executor: (script, ...varArgs) => {
|
|
219
|
+
return browserInstance.execute.bind(browserInstance)(script, ...varArgs);
|
|
220
|
+
},
|
|
221
|
+
getElementRect: browserInstance.getElementRect.bind(browserInstance),
|
|
222
|
+
screenShot: browserInstance.takeScreenshot.bind(browserInstance),
|
|
223
|
+
takeElementScreenshot: browserInstance.takeElementScreenshot.bind(browserInstance),
|
|
224
|
+
}, instanceData, getFolders(pageOptions, self.folders, self.#getBaselineFolder()), tag, element, {
|
|
225
|
+
wic: self.defaultOptions,
|
|
226
|
+
method: pageOptions,
|
|
227
|
+
}, isNativeContext);
|
|
163
228
|
}
|
|
229
|
+
return returnData;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
#setupMultiremoteContextListener() {
|
|
233
|
+
const multiremoteBrowser = this._browser;
|
|
234
|
+
const browserInstances = multiremoteBrowser.instances;
|
|
235
|
+
for (const instanceName of browserInstances) {
|
|
236
|
+
const instance = multiremoteBrowser[instanceName];
|
|
237
|
+
instance.on('result', (result) => {
|
|
238
|
+
if (result.command === 'getContext') {
|
|
239
|
+
const value = result.result.value;
|
|
240
|
+
const sessionId = instance.sessionId;
|
|
241
|
+
if (typeof this._isNativeContext !== 'object' || this._isNativeContext === null) {
|
|
242
|
+
this._isNativeContext = {};
|
|
243
|
+
}
|
|
244
|
+
this._isNativeContext[sessionId] = value.includes('NATIVE');
|
|
245
|
+
}
|
|
246
|
+
});
|
|
164
247
|
}
|
|
165
248
|
}
|
|
166
249
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { ScreenshotOutput, ImageCompareResult, CheckScreenMethodOptions, SaveScreenMethodOptions, CheckElementMethodOptions, SaveElementMethodOptions, CheckFullPageMethodOptions, SaveFullPageMethodOptions, ClassOptions } from 'webdriver-image-comparison';
|
|
2
|
-
import type { RectanglesOutput } from 'webdriver-image-comparison/dist/methods/rectangles.interfaces.js';
|
|
3
|
-
import type { WaitForStorybookComponentToBeLoaded } from './storybook/Types.js';
|
|
4
2
|
type MultiOutput = {
|
|
5
3
|
[browserName: string]: ScreenshotOutput;
|
|
6
4
|
};
|
|
@@ -9,6 +7,19 @@ type MultiResult = {
|
|
|
9
7
|
[browserName: string]: ImageCompareResult | number;
|
|
10
8
|
};
|
|
11
9
|
export type Result = MultiResult | (ImageCompareResult | number);
|
|
10
|
+
export type NativeContextType = boolean | Record<string, boolean>;
|
|
11
|
+
export type MultiremoteCommandResult = {
|
|
12
|
+
command: string;
|
|
13
|
+
method: string;
|
|
14
|
+
endpoint: string;
|
|
15
|
+
body: Record<string, any>;
|
|
16
|
+
result: {
|
|
17
|
+
value: string;
|
|
18
|
+
};
|
|
19
|
+
sessionId: string | undefined;
|
|
20
|
+
cid: string;
|
|
21
|
+
type: string;
|
|
22
|
+
};
|
|
12
23
|
export interface WdioIcsCommonOptions {
|
|
13
24
|
hideElements?: WebdriverIO.Element[];
|
|
14
25
|
removeElements?: WebdriverIO.Element[];
|
|
@@ -30,14 +41,5 @@ export interface WdioCheckScreenMethodOptions extends Omit<CheckScreenMethodOpti
|
|
|
30
41
|
}
|
|
31
42
|
export interface VisualServiceOptions extends ClassOptions {
|
|
32
43
|
}
|
|
33
|
-
export type PageCommandOptions = {
|
|
34
|
-
executor: <T>(script: string | ((...innerArgs: any[]) => unknown), ...varArgs: any[]) => Promise<T>;
|
|
35
|
-
getElementRect: (elementId: string) => Promise<RectanglesOutput>;
|
|
36
|
-
screenShot: () => Promise<string>;
|
|
37
|
-
};
|
|
38
|
-
export type PageCommand = (options: PageCommandOptions, ...args: any[]) => Promise<any>;
|
|
39
|
-
export interface PageCommands {
|
|
40
|
-
[commandName: string]: PageCommand | ((options: WaitForStorybookComponentToBeLoaded) => Promise<void>);
|
|
41
|
-
}
|
|
42
44
|
export {};
|
|
43
45
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,YAAY,EACf,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,EACzB,YAAY,EACf,MAAM,4BAA4B,CAAA;AAEnC,KAAK,WAAW,GAAG;IACf,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC3C,CAAC;AACF,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,gBAAgB,CAAC;AACpD,KAAK,WAAW,GAAG;IACf,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,MAAM,CAAC;CACtD,CAAC;AACF,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,CAAC,kBAAkB,GAAG,MAAM,CAAC,CAAC;AACjE,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AACjE,MAAM,MAAM,wBAAwB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACpB,CAAA;AAED,MAAM,WAAW,oBAAoB;IACjC,YAAY,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IACrC,cAAc,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAC9D,oBAAoB,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,8BACb,SAAQ,IAAI,CAAC,0BAA0B,EAAE,MAAM,oBAAoB,CAAC,EAChE,oBAAoB;CAAG;AAC/B,MAAM,WAAW,6BACb,SAAQ,IAAI,CAAC,yBAAyB,EAAE,MAAM,oBAAoB,CAAC,EAC/D,oBAAoB;CAAG;AAC/B,MAAM,WAAW,4BACb,SAAQ,IAAI,CAAC,wBAAwB,EAAE,MAAM,oBAAoB,CAAC,EAC9D,oBAAoB;CAAG;AAC/B,MAAM,WAAW,2BACb,SAAQ,IAAI,CAAC,uBAAuB,EAAE,MAAM,oBAAoB,CAAC,EAC7D,oBAAoB;CAAG;AAC/B,MAAM,WAAW,6BACb,SAAQ,IAAI,CAAC,yBAAyB,EAAE,MAAM,oBAAoB,CAAC,EAC/D,oBAAoB;CAAG;AAC/B,MAAM,WAAW,4BACb,SAAQ,IAAI,CAAC,wBAAwB,EAAE,MAAM,oBAAoB,CAAC,EAC9D,oBAAoB;CAAG;AAE/B,MAAM,WAAW,oBAAqB,SAAQ,YAAY;CAAI"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Folders, InstanceData, CheckScreenMethodOptions, SaveScreenMethodOptions, CheckFullPageMethodOptions, SaveFullPageMethodOptions, CheckElementMethodOptions, SaveElementMethodOptions } from 'webdriver-image-comparison';
|
|
2
|
+
import type { NativeContextType } from './types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Get the folders data
|
|
4
5
|
*
|
|
@@ -32,6 +33,10 @@ export declare function getBrowserObject(elem: WebdriverIO.Element | WebdriverIO
|
|
|
32
33
|
/**
|
|
33
34
|
* We can't say it's native context if the autoWebview is provided and set to true, for all other cases we can say it's native
|
|
34
35
|
*/
|
|
35
|
-
export declare function determineNativeContext(driver: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser):
|
|
36
|
+
export declare function determineNativeContext(driver: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser): NativeContextType;
|
|
37
|
+
/**
|
|
38
|
+
* Get the native context for the current browser
|
|
39
|
+
*/
|
|
40
|
+
export declare function getNativeContext(browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, currentBrowser: WebdriverIO.Browser, nativeContext: NativeContextType): boolean;
|
|
36
41
|
export {};
|
|
37
42
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,OAAO,EACP,YAAY,EACZ,wBAAwB,EACxB,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EAC3B,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,OAAO,EACP,YAAY,EACZ,wBAAwB,EACxB,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EAC3B,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAOnD;;;;;GAKG;AACH,KAAK,sBAAsB,GACrB,yBAAyB,GACzB,0BAA0B,GAC1B,wBAAwB,GACxB,wBAAwB,GACxB,yBAAyB,GACzB,uBAAuB,CAAC;AAE9B,wBAAgB,UAAU,CACtB,aAAa,EAAE,sBAAsB,EACrC,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,MAAM,GACxB,OAAO,CAMT;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,SAAI,GAAG;IAC1E,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;AA4GD;;GAEG;AACH,wBAAsB,eAAe,CAAC,cAAc,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CA4DhG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAE,IAAI,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAGtG;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB,GAC7D,iBAAiB,CA0BnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB,EAC7D,cAAc,EAAE,WAAW,CAAC,OAAO,EACnC,aAAa,EAAE,iBAAiB,GACjC,OAAO,CAQT"}
|
package/dist/utils.js
CHANGED
|
@@ -173,6 +173,17 @@ export function getBrowserObject(elem) {
|
|
|
173
173
|
* We can't say it's native context if the autoWebview is provided and set to true, for all other cases we can say it's native
|
|
174
174
|
*/
|
|
175
175
|
export function determineNativeContext(driver) {
|
|
176
|
+
// First check if it's multi remote
|
|
177
|
+
if (driver.isMultiremote) {
|
|
178
|
+
return Object.keys(driver).reduce((acc, instanceName) => {
|
|
179
|
+
const instance = driver[instanceName];
|
|
180
|
+
if (instance.sessionId) {
|
|
181
|
+
acc[instance.sessionId] = determineNativeContext(instance);
|
|
182
|
+
}
|
|
183
|
+
return acc;
|
|
184
|
+
}, {});
|
|
185
|
+
}
|
|
186
|
+
// If not check if it's a mobile
|
|
176
187
|
if (driver.isMobile) {
|
|
177
188
|
return !!driver.requestedCapabilities?.browserName === false
|
|
178
189
|
&& (driver.requestedCapabilities?.['appium:app'] !== undefined
|
|
@@ -180,5 +191,18 @@ export function determineNativeContext(driver) {
|
|
|
180
191
|
|| driver.requestedCapabilities?.['appium:appPackage'] !== undefined)
|
|
181
192
|
&& driver.requestedCapabilities?.['appium:autoWebview'] !== true;
|
|
182
193
|
}
|
|
194
|
+
// If not, it's webcontext
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the native context for the current browser
|
|
199
|
+
*/
|
|
200
|
+
export function getNativeContext(browser, currentBrowser, nativeContext) {
|
|
201
|
+
if (browser.isMultiremote) {
|
|
202
|
+
return nativeContext[currentBrowser.sessionId];
|
|
203
|
+
}
|
|
204
|
+
else if (typeof nativeContext === 'boolean') {
|
|
205
|
+
return nativeContext;
|
|
206
|
+
}
|
|
183
207
|
return false;
|
|
184
208
|
}
|
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": "5.1.
|
|
5
|
+
"version": "5.1.1",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://webdriver.io/docs/visual-testing",
|
|
8
8
|
"repository": {
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"type": "module",
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@wdio/globals": "^8.
|
|
23
|
+
"@wdio/globals": "^8.39.1",
|
|
24
24
|
"@wdio/logger": "^8.38.0",
|
|
25
|
-
"@wdio/types": "^8.
|
|
25
|
+
"@wdio/types": "^8.39.0",
|
|
26
26
|
"node-fetch": "^3.3.2",
|
|
27
|
-
"webdriver-image-comparison": "^6.0.
|
|
27
|
+
"webdriver-image-comparison": "^6.0.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {},
|
|
30
30
|
"scripts": {
|