@wdio/webdriver-mock-service 9.0.0-alpha.78 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +307 -200
- package/package.json +13 -11
- package/build/WebDriverMock.js +0 -85
- package/build/constants.js +0 -7
- package/build/mocks/newSession.js +0 -27
- /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export default class WebdriverMockService implements Services.ServiceInstance {
|
|
|
5
5
|
private _mock;
|
|
6
6
|
constructor();
|
|
7
7
|
init(): void;
|
|
8
|
-
beforeSession(config:
|
|
8
|
+
beforeSession(config: Options.Testrunner): void;
|
|
9
9
|
before(caps: unknown, specs: unknown, browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser): void;
|
|
10
10
|
clickScenario(): void;
|
|
11
11
|
isExistingScenario(): void;
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAEpD,OAAO,aAAa,MAAM,oBAAoB,CAAA;AAW9C,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,QAAQ,CAAC,eAAe;IACzE,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,OAAO,CAAC,KAAK,CAAsB;;IAMnC,IAAI;IAgBJ,aAAa,CAAC,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAEpD,OAAO,aAAa,MAAM,oBAAoB,CAAA;AAW9C,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,QAAQ,CAAC,eAAe;IACzE,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,OAAO,CAAC,KAAK,CAAsB;;IAMnC,IAAI;IAgBJ,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,GAAG,IAAI;IAK/C,MAAM,CACF,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,kBAAkB;IAwBjE,aAAa;IAQb,kBAAkB;IASlB,qBAAqB;IAKrB,sBAAsB;IAYtB,wBAAwB;IAUxB,6BAA6B;IAU7B,2BAA2B;IA+B3B,sBAAsB;IAgBtB,sBAAsB;IAStB,iCAAiC;IAQjC,gBAAgB;IAShB,qBAAqB,CAAC,KAAK,SAAI;IAa/B,sBAAsB;IAUtB,wBAAwB;IASxB,gBAAgB;IAShB,SAAS;CAIZ;AAED;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,eAAO,MAAM,QAAQ;;0BACC,WAAW,CAAC,MAAM;;CAIvC,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -1,205 +1,312 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import nock2 from "nock";
|
|
3
|
+
import { v4 as uuidv4 } from "uuid";
|
|
4
|
+
|
|
5
|
+
// src/WebDriverMock.ts
|
|
6
|
+
import nock from "nock";
|
|
7
|
+
import {
|
|
8
|
+
WebDriverProtocol,
|
|
9
|
+
MJsonWProtocol,
|
|
10
|
+
AppiumProtocol,
|
|
11
|
+
ChromiumProtocol,
|
|
12
|
+
SauceLabsProtocol,
|
|
13
|
+
SeleniumProtocol
|
|
14
|
+
} from "@wdio/protocols";
|
|
15
|
+
var REGEXP_SESSION_ID = /\/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}/;
|
|
16
|
+
var SESSION_ID = "XXX";
|
|
17
|
+
var protocols = [
|
|
18
|
+
WebDriverProtocol,
|
|
19
|
+
MJsonWProtocol,
|
|
20
|
+
AppiumProtocol,
|
|
21
|
+
ChromiumProtocol,
|
|
22
|
+
SauceLabsProtocol,
|
|
23
|
+
SeleniumProtocol
|
|
24
|
+
];
|
|
25
|
+
var protocolFlattened = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const protocol of protocols) {
|
|
27
|
+
for (const [endpoint, methods] of Object.entries(protocol)) {
|
|
28
|
+
for (const [method, commandData] of Object.entries(methods)) {
|
|
29
|
+
protocolFlattened.set(commandData.command, { method, endpoint, commandData });
|
|
15
30
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
this._mock.command.elementClick(ELEMENT_ID).once().reply(200, { value: null });
|
|
61
|
-
}
|
|
62
|
-
isExistingScenario() {
|
|
63
|
-
this.nockReset();
|
|
64
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
65
|
-
this._mock.command.findElement().times(1).reply(200, { value: elemResponse });
|
|
66
|
-
this._mock.command.findElementFromElement(ELEMENT_ID).times(2).reply(200, { value: elemResponse });
|
|
67
|
-
this._mock.command.findElementsFromElement(ELEMENT_ID).times(2).reply(200, { value: [elemResponse] });
|
|
68
|
-
}
|
|
69
|
-
isNotExistingScenario() {
|
|
70
|
-
this.nockReset();
|
|
71
|
-
this._mock.command.findElement().reply(404, NO_SUCH_ELEMENT);
|
|
72
|
-
}
|
|
73
|
-
waitForElementScenario() {
|
|
74
|
-
this.nockReset();
|
|
75
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
76
|
-
this._mock.command.findElement().once().reply(404, NO_SUCH_ELEMENT);
|
|
77
|
-
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
78
|
-
this._mock.command.findElements().times(5).reply(200, { value: [] });
|
|
79
|
-
this._mock.command.findElements().reply(200, { value: [elemResponse] });
|
|
80
|
-
this._mock.command.elementClick(ELEMENT_ID).once().reply(200, { value: null });
|
|
81
|
-
}
|
|
82
|
-
isNeverDisplayedScenario() {
|
|
83
|
-
this.nockReset();
|
|
84
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
85
|
-
this._mock.command.findElement().times(2).reply(404, NO_SUCH_ELEMENT);
|
|
86
|
-
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
87
|
-
this._mock.command.executeScript(ELEMENT_ID).once().reply(200, { value: false });
|
|
88
|
-
}
|
|
89
|
-
isEventuallyDisplayedScenario() {
|
|
90
|
-
this.nockReset();
|
|
91
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
92
|
-
this._mock.command.findElement().times(1).reply(404, NO_SUCH_ELEMENT);
|
|
93
|
-
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
94
|
-
this._mock.command.executeScript(ELEMENT_ID).once().reply(200, { value: true });
|
|
95
|
-
}
|
|
96
|
-
staleElementRefetchScenario() {
|
|
97
|
-
this.nockReset();
|
|
98
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
99
|
-
const elem2Response = { [ELEM_PROP]: ELEMENT_REFETCHED };
|
|
100
|
-
// Found initially
|
|
101
|
-
this._mock.command.findElement().once().reply(200, { value: elemResponse });
|
|
102
|
-
// Initiate refetch, but its not ready
|
|
103
|
-
this._mock.command.findElement().once().reply(404, NO_SUCH_ELEMENT);
|
|
104
|
-
// Always return the new element after
|
|
105
|
-
this._mock.command.findElement().times(4).reply(200, { value: elem2Response });
|
|
106
|
-
// First click works
|
|
107
|
-
this._mock.command.elementClick(ELEMENT_ID).once().reply(200, { value: null });
|
|
108
|
-
// Additional clicks won't for the original element
|
|
109
|
-
this._mock.command.elementClick(ELEMENT_ID).times(8).reply(500, {
|
|
110
|
-
value: {
|
|
111
|
-
error: 'stale element reference',
|
|
112
|
-
message: 'element is not attached to the page document'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
var WebDriverMock = class _WebDriverMock {
|
|
34
|
+
constructor(host = "localhost", port = 4444, path = "/") {
|
|
35
|
+
this.path = path;
|
|
36
|
+
this.scope = nock(`http://${host}:${port}`, { "encodedQueryParams": true });
|
|
37
|
+
this.command = new Proxy({}, { get: this.get.bind(this) });
|
|
38
|
+
}
|
|
39
|
+
command;
|
|
40
|
+
scope;
|
|
41
|
+
/**
|
|
42
|
+
* To allow random session IDs in url paths we have to set up a custom
|
|
43
|
+
* matcher that strips out the sessionID part from the expected url
|
|
44
|
+
* and actual url and replaces it with a constant session id
|
|
45
|
+
* @param {String} expectedPath path to match against
|
|
46
|
+
* @returns {Function} to be called by Nock to match actual path
|
|
47
|
+
*/
|
|
48
|
+
static pathMatcher(expectedPath) {
|
|
49
|
+
return (path) => {
|
|
50
|
+
const sessionId = path.match(REGEXP_SESSION_ID);
|
|
51
|
+
if (!sessionId) {
|
|
52
|
+
return path === expectedPath;
|
|
53
|
+
}
|
|
54
|
+
expectedPath = expectedPath.replace(":sessionId", SESSION_ID);
|
|
55
|
+
path = path.replace(`${sessionId[0].slice(1)}`, SESSION_ID);
|
|
56
|
+
return path === expectedPath;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
get(obj, commandName) {
|
|
60
|
+
const { method, endpoint, commandData } = protocolFlattened.get(commandName);
|
|
61
|
+
return (...args) => {
|
|
62
|
+
let urlPath = endpoint;
|
|
63
|
+
for (const [i, param] of Object.entries(commandData.variables || [])) {
|
|
64
|
+
urlPath = urlPath.replace(`:${param.name}`, args[parseInt(i)]);
|
|
65
|
+
}
|
|
66
|
+
if (method === "POST") {
|
|
67
|
+
const reqMethod2 = method.toLowerCase();
|
|
68
|
+
return this.scope[reqMethod2](_WebDriverMock.pathMatcher(urlPath), (body) => {
|
|
69
|
+
for (const param of commandData.parameters) {
|
|
70
|
+
if (!body[param.name]) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (param.required && typeof body[param.name] === "undefined") {
|
|
74
|
+
return false;
|
|
113
75
|
}
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
114
78
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
154
|
-
const elem2Response = { [ELEM_PROP]: ELEMENT_REFETCHED };
|
|
155
|
-
this._mock.command.findElement().twice().reply(200, { value: elemResponse });
|
|
156
|
-
this._mock.command.findElementFromElement(ELEMENT_ID).twice().reply(200, { value: elem2Response });
|
|
157
|
-
this._mock.command.elementClick(ELEMENT_REFETCHED).twice().reply(200, { value: null });
|
|
158
|
-
}
|
|
159
|
-
customCommandScenario(times = 1) {
|
|
160
|
-
this.nockReset();
|
|
161
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
162
|
-
const elemAltResponse = { [ELEM_PROP]: ELEMENT_ALT };
|
|
163
|
-
this._mock.command.findElement().times(times).reply(200, { value: elemResponse });
|
|
164
|
-
this._mock.command.findElement().times(times).reply(200, { value: elemAltResponse });
|
|
165
|
-
this._mock.command.executeScript().times(times).reply(200, { value: '2' });
|
|
166
|
-
// overwrite
|
|
167
|
-
this._mock.command.deleteAllCookies().times(times).reply(200, { value: 'deleteAllCookies' });
|
|
168
|
-
}
|
|
169
|
-
customSelectorScenario() {
|
|
170
|
-
this.nockReset();
|
|
171
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
172
|
-
const elemAltResponse = { [ELEM_PROP]: ELEMENT_ALT };
|
|
173
|
-
this._mock.command.findElement().reply(200, { value: elemResponse });
|
|
174
|
-
this._mock.command.executeScript().reply(200, { value: elemAltResponse });
|
|
175
|
-
this._mock.command.findElementFromElement(ELEMENT_ALT).reply(200, { value: elemResponse });
|
|
176
|
-
}
|
|
177
|
-
waitForDisplayedScenario() {
|
|
178
|
-
this.nockReset();
|
|
179
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
180
|
-
this._mock.command.findElement().once().reply(200, { value: elemResponse });
|
|
181
|
-
this._mock.command.executeScript(ELEMENT_ID).times(4).reply(200, { value: false });
|
|
182
|
-
this._mock.command.executeScript(ELEMENT_ID).once().reply(200, { value: true });
|
|
183
|
-
}
|
|
184
|
-
cucumberScenario() {
|
|
185
|
-
this.nockReset();
|
|
186
|
-
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
187
|
-
this._mock.command.navigateTo().reply(200, { value: null });
|
|
188
|
-
this._mock.command.findElement().times(4).reply(200, { value: elemResponse });
|
|
189
|
-
this._mock.command.elementClick(ELEMENT_ID).reply(200, { value: null });
|
|
190
|
-
}
|
|
191
|
-
nockReset() {
|
|
192
|
-
nock.cleanAll();
|
|
193
|
-
this.init();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* export for 3rd party usage
|
|
198
|
-
*/
|
|
199
|
-
export { WebDriverMock };
|
|
200
|
-
export const launcher = class WebdriverMockLauncher {
|
|
201
|
-
onPrepare(config) {
|
|
202
|
-
config.hostname = 'localhost';
|
|
203
|
-
config.port = 4444;
|
|
79
|
+
}
|
|
80
|
+
const reqMethod = method.toLowerCase();
|
|
81
|
+
return this.scope[reqMethod](_WebDriverMock.pathMatcher(urlPath));
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// src/constants.ts
|
|
87
|
+
var NO_SUCH_ELEMENT = {
|
|
88
|
+
value: {
|
|
89
|
+
error: "no such element",
|
|
90
|
+
message: "Unable to locate element: bodys",
|
|
91
|
+
stacktrace: "WebDriverError@chrome://marionette/content/error.js:179:5\nNoSuchElementError@chrome://marionette/content/error.js:389:5\nelement.find/</<@chrome://marionette/content/element.js:339:16\n"
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/mocks/newSession.ts
|
|
96
|
+
var newSession = {
|
|
97
|
+
value: {
|
|
98
|
+
sessionId: "undefined",
|
|
99
|
+
capabilities: {
|
|
100
|
+
acceptInsecureCerts: false,
|
|
101
|
+
browserName: "firefox",
|
|
102
|
+
browserVersion: 64,
|
|
103
|
+
pageLoadStrategy: "normal",
|
|
104
|
+
platformName: "mac",
|
|
105
|
+
platformVersion: "17.7.0",
|
|
106
|
+
rotatable: false,
|
|
107
|
+
setWindowRect: true,
|
|
108
|
+
timeouts: [{}],
|
|
109
|
+
unhandledPromptBehavior: "dismiss and notify",
|
|
110
|
+
"moz:accessibilityChecks": false,
|
|
111
|
+
"moz:geckodriverVersion": "0.23.0",
|
|
112
|
+
"moz:headless": false,
|
|
113
|
+
"moz:processID": 15867,
|
|
114
|
+
"moz:profile": "/var/folders/ns/8mj2mh0x27b_gsdddy1knnsm0000gn/T/rust_mozprofile.yUuH0ktcRJPN",
|
|
115
|
+
"moz:shutdownTimeout": 6e4,
|
|
116
|
+
"moz:webdriverClick": true
|
|
204
117
|
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var deleteSession = {
|
|
121
|
+
value: null
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/index.ts
|
|
125
|
+
var ELEMENT_ID = "401c0039-3306-6a46-a98d-f5939870a249";
|
|
126
|
+
var ELEMENT_REFETCHED = "80d860d0-b829-f540-812e-7078eb983795";
|
|
127
|
+
var ELEMENT_ALT = "8bf4d107-a363-40d1-b823-d94bdbc58afb";
|
|
128
|
+
var ELEM_PROP = "element-6066-11e4-a52e-4f735466cecf";
|
|
129
|
+
var WebdriverMockService = class {
|
|
130
|
+
_browser;
|
|
131
|
+
_mock = new WebDriverMock();
|
|
132
|
+
constructor() {
|
|
133
|
+
this.init();
|
|
134
|
+
}
|
|
135
|
+
init() {
|
|
136
|
+
this._mock.command.status().times(Infinity).reply(200, { value: {} });
|
|
137
|
+
this._mock.command.newSession().times(Infinity).reply(200, () => {
|
|
138
|
+
newSession.value.sessionId = uuidv4();
|
|
139
|
+
return newSession;
|
|
140
|
+
});
|
|
141
|
+
this._mock.command.deleteSession().times(2).reply(200, deleteSession);
|
|
142
|
+
this._mock.command.getTitle().times(Infinity).reply(200, { value: "Mock Page Title" });
|
|
143
|
+
this._mock.command.getUrl().times(Infinity).reply(200, { value: "https://mymockpage.com" });
|
|
144
|
+
this._mock.command.getElementRect(ELEMENT_ID).times(2).reply(200, { value: { width: 1, height: 2, x: 3, y: 4 } });
|
|
145
|
+
this._mock.command.getElementRect(ELEMENT_ALT).times(3).reply(200, { value: { width: 10, height: 20, x: 30, y: 40 } });
|
|
146
|
+
this._mock.command.getElementRect(ELEMENT_REFETCHED).times(1).reply(200, { value: { width: 1, height: 2, x: 3, y: 4 } });
|
|
147
|
+
this._mock.command.getLogTypes().reply(200, { value: [] });
|
|
148
|
+
}
|
|
149
|
+
beforeSession(config) {
|
|
150
|
+
config.hostname = "localhost";
|
|
151
|
+
config.port = 4444;
|
|
152
|
+
}
|
|
153
|
+
before(caps, specs, browser) {
|
|
154
|
+
this._browser = browser;
|
|
155
|
+
this._browser.addCommand("waitForElementScenario", this.waitForElementScenario.bind(this));
|
|
156
|
+
this._browser.addCommand("isNeverDisplayedScenario", this.isNeverDisplayedScenario.bind(this));
|
|
157
|
+
this._browser.addCommand("isEventuallyDisplayedScenario", this.isEventuallyDisplayedScenario.bind(this));
|
|
158
|
+
this._browser.addCommand("staleElementRefetchScenario", this.staleElementRefetchScenario.bind(this));
|
|
159
|
+
this._browser.addCommand("customCommandScenario", this.customCommandScenario.bind(this));
|
|
160
|
+
this._browser.addCommand("customSelectorScenario", this.customSelectorScenario.bind(this));
|
|
161
|
+
this._browser.addCommand("waitForDisplayedScenario", this.waitForDisplayedScenario.bind(this));
|
|
162
|
+
this._browser.addCommand("cucumberScenario", this.cucumberScenario.bind(this));
|
|
163
|
+
this._browser.addCommand("clickScenario", this.clickScenario.bind(this));
|
|
164
|
+
this._browser.addCommand("isExistingScenario", this.isExistingScenario.bind(this));
|
|
165
|
+
this._browser.addCommand("isNotExistingScenario", this.isNotExistingScenario.bind(this));
|
|
166
|
+
this._browser.addCommand("multiremoteFetch", this.multiremoteFetch.bind(this));
|
|
167
|
+
this._browser.addCommand("asyncIterationScenario", this.asyncIterationScenario.bind(this));
|
|
168
|
+
this._browser.addCommand("parentElementChaining", this.parentNextPreviousElementChaining.bind(this));
|
|
169
|
+
this._browser.addCommand("refetchElementScenario", this.refetchElementScenario.bind(this));
|
|
170
|
+
}
|
|
171
|
+
clickScenario() {
|
|
172
|
+
this.nockReset();
|
|
173
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
174
|
+
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
175
|
+
this._mock.command.elementClick(ELEMENT_ID).once().reply(200, { value: null });
|
|
176
|
+
}
|
|
177
|
+
isExistingScenario() {
|
|
178
|
+
this.nockReset();
|
|
179
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
180
|
+
this._mock.command.findElement().times(1).reply(200, { value: elemResponse });
|
|
181
|
+
this._mock.command.findElementFromElement(ELEMENT_ID).times(2).reply(200, { value: elemResponse });
|
|
182
|
+
this._mock.command.findElementsFromElement(ELEMENT_ID).times(2).reply(200, { value: [elemResponse] });
|
|
183
|
+
}
|
|
184
|
+
isNotExistingScenario() {
|
|
185
|
+
this.nockReset();
|
|
186
|
+
this._mock.command.findElement().reply(404, NO_SUCH_ELEMENT);
|
|
187
|
+
}
|
|
188
|
+
waitForElementScenario() {
|
|
189
|
+
this.nockReset();
|
|
190
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
191
|
+
this._mock.command.findElement().once().reply(404, NO_SUCH_ELEMENT);
|
|
192
|
+
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
193
|
+
this._mock.command.findElements().times(5).reply(200, { value: [] });
|
|
194
|
+
this._mock.command.findElements().reply(200, { value: [elemResponse] });
|
|
195
|
+
this._mock.command.elementClick(ELEMENT_ID).once().reply(200, { value: null });
|
|
196
|
+
}
|
|
197
|
+
isNeverDisplayedScenario() {
|
|
198
|
+
this.nockReset();
|
|
199
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
200
|
+
this._mock.command.findElement().times(2).reply(404, NO_SUCH_ELEMENT);
|
|
201
|
+
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
202
|
+
this._mock.command.executeScript(ELEMENT_ID).once().reply(200, { value: false });
|
|
203
|
+
}
|
|
204
|
+
isEventuallyDisplayedScenario() {
|
|
205
|
+
this.nockReset();
|
|
206
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
207
|
+
this._mock.command.findElement().times(1).reply(404, NO_SUCH_ELEMENT);
|
|
208
|
+
this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
|
|
209
|
+
this._mock.command.executeScript(ELEMENT_ID).once().reply(200, { value: true });
|
|
210
|
+
}
|
|
211
|
+
staleElementRefetchScenario() {
|
|
212
|
+
this.nockReset();
|
|
213
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
214
|
+
const elem2Response = { [ELEM_PROP]: ELEMENT_REFETCHED };
|
|
215
|
+
this._mock.command.findElement().once().reply(200, { value: elemResponse });
|
|
216
|
+
this._mock.command.findElement().once().reply(404, NO_SUCH_ELEMENT);
|
|
217
|
+
this._mock.command.findElement().times(4).reply(200, { value: elem2Response });
|
|
218
|
+
this._mock.command.elementClick(ELEMENT_ID).once().reply(200, { value: null });
|
|
219
|
+
this._mock.command.elementClick(ELEMENT_ID).times(8).reply(500, {
|
|
220
|
+
value: {
|
|
221
|
+
error: "stale element reference",
|
|
222
|
+
message: "element is not attached to the page document"
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
this._mock.command.elementClick(ELEMENT_REFETCHED).times(4).reply(200, { value: null });
|
|
226
|
+
this._mock.command.findElements().times(2).reply(200, { value: [] });
|
|
227
|
+
this._mock.command.findElements().times(4).reply(200, { value: [elem2Response] });
|
|
228
|
+
}
|
|
229
|
+
refetchElementScenario() {
|
|
230
|
+
const elemResponse1 = { [ELEM_PROP]: "1" };
|
|
231
|
+
const elemResponse2 = { [ELEM_PROP]: "2" };
|
|
232
|
+
const elemResponse3 = { [ELEM_PROP]: "3" };
|
|
233
|
+
const elemResponse4 = { [ELEM_PROP]: "4" };
|
|
234
|
+
this._mock.command.getElementText("1").reply(200, { value: "some element text 1" });
|
|
235
|
+
this._mock.command.getElementText("2").reply(200, { value: "some element text 2" });
|
|
236
|
+
this._mock.command.getElementText("3").reply(200, { value: "some element text 3" });
|
|
237
|
+
this._mock.command.getElementText("4").reply(200, { value: "some element text 4" });
|
|
238
|
+
this._mock.command.findElements().times(4).reply(200, { value: [] });
|
|
239
|
+
this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1] });
|
|
240
|
+
this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1, elemResponse2] });
|
|
241
|
+
this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1, elemResponse2, elemResponse3] });
|
|
242
|
+
this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1, elemResponse2, elemResponse3, elemResponse4] });
|
|
243
|
+
}
|
|
244
|
+
asyncIterationScenario() {
|
|
245
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
246
|
+
const elem2Response = { [ELEM_PROP]: ELEMENT_REFETCHED };
|
|
247
|
+
this._mock.command.findElements().reply(200, { value: [elemResponse, elem2Response] });
|
|
248
|
+
this._mock.command.getElementText(ELEMENT_ID).reply(200, { value: "some element text" });
|
|
249
|
+
this._mock.command.getElementText(ELEMENT_REFETCHED).reply(200, { value: "some other element text" });
|
|
250
|
+
return [ELEMENT_ID, ELEMENT_REFETCHED];
|
|
251
|
+
}
|
|
252
|
+
parentNextPreviousElementChaining() {
|
|
253
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
254
|
+
const elemParentResponse = { [ELEM_PROP]: ELEMENT_REFETCHED };
|
|
255
|
+
this._mock.command.findElement().reply(200, { value: elemResponse });
|
|
256
|
+
this._mock.command.executeScript().reply(200, { value: elemParentResponse });
|
|
257
|
+
this._mock.command.getElementText(ELEMENT_REFETCHED).reply(200, { value: "some element text" });
|
|
258
|
+
}
|
|
259
|
+
multiremoteFetch() {
|
|
260
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
261
|
+
const elem2Response = { [ELEM_PROP]: ELEMENT_REFETCHED };
|
|
262
|
+
this._mock.command.findElement().twice().reply(200, { value: elemResponse });
|
|
263
|
+
this._mock.command.findElementFromElement(ELEMENT_ID).twice().reply(200, { value: elem2Response });
|
|
264
|
+
this._mock.command.elementClick(ELEMENT_REFETCHED).twice().reply(200, { value: null });
|
|
265
|
+
}
|
|
266
|
+
customCommandScenario(times = 1) {
|
|
267
|
+
this.nockReset();
|
|
268
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
269
|
+
const elemAltResponse = { [ELEM_PROP]: ELEMENT_ALT };
|
|
270
|
+
this._mock.command.findElement().times(times).reply(200, { value: elemResponse });
|
|
271
|
+
this._mock.command.findElement().times(times).reply(200, { value: elemAltResponse });
|
|
272
|
+
this._mock.command.executeScript().times(times).reply(200, { value: "2" });
|
|
273
|
+
this._mock.command.deleteAllCookies().times(times).reply(200, { value: "deleteAllCookies" });
|
|
274
|
+
}
|
|
275
|
+
customSelectorScenario() {
|
|
276
|
+
this.nockReset();
|
|
277
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
278
|
+
const elemAltResponse = { [ELEM_PROP]: ELEMENT_ALT };
|
|
279
|
+
this._mock.command.findElement().reply(200, { value: elemResponse });
|
|
280
|
+
this._mock.command.executeScript().reply(200, { value: elemAltResponse });
|
|
281
|
+
this._mock.command.findElementFromElement(ELEMENT_ALT).reply(200, { value: elemResponse });
|
|
282
|
+
}
|
|
283
|
+
waitForDisplayedScenario() {
|
|
284
|
+
this.nockReset();
|
|
285
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
286
|
+
this._mock.command.findElement().once().reply(200, { value: elemResponse });
|
|
287
|
+
this._mock.command.executeScript(ELEMENT_ID).times(4).reply(200, { value: false });
|
|
288
|
+
this._mock.command.executeScript(ELEMENT_ID).once().reply(200, { value: true });
|
|
289
|
+
}
|
|
290
|
+
cucumberScenario() {
|
|
291
|
+
this.nockReset();
|
|
292
|
+
const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
|
|
293
|
+
this._mock.command.navigateTo().reply(200, { value: null });
|
|
294
|
+
this._mock.command.findElement().times(4).reply(200, { value: elemResponse });
|
|
295
|
+
this._mock.command.elementClick(ELEMENT_ID).reply(200, { value: null });
|
|
296
|
+
}
|
|
297
|
+
nockReset() {
|
|
298
|
+
nock2.cleanAll();
|
|
299
|
+
this.init();
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
var launcher = class WebdriverMockLauncher {
|
|
303
|
+
onPrepare(config) {
|
|
304
|
+
config.hostname = "localhost";
|
|
305
|
+
config.port = 4444;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
export {
|
|
309
|
+
WebDriverMock,
|
|
310
|
+
WebdriverMockService as default,
|
|
311
|
+
launcher
|
|
205
312
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wdio/webdriver-mock-service",
|
|
3
|
-
"version": "9.0.0
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "A WebdriverIO service to stub all endpoints for internal testing purposes.",
|
|
5
5
|
"author": "Christian Bromann <mail@bromann.dev>",
|
|
6
6
|
"homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-webdriver-mock-service",
|
|
@@ -20,23 +20,25 @@
|
|
|
20
20
|
"type": "module",
|
|
21
21
|
"types": "./build/index.d.ts",
|
|
22
22
|
"exports": {
|
|
23
|
-
".":
|
|
24
|
-
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./build/index.d.ts",
|
|
25
|
+
"import": "./build/index.js"
|
|
26
|
+
}
|
|
25
27
|
},
|
|
26
28
|
"typeScriptVersion": "3.8.3",
|
|
27
29
|
"dependencies": {
|
|
28
|
-
"@types/uuid": "^
|
|
29
|
-
"@wdio/protocols": "9.0.0
|
|
30
|
-
"@wdio/types": "9.0.0
|
|
31
|
-
"nock": "14.0.0-beta.
|
|
32
|
-
"uuid": "^
|
|
33
|
-
"webdriverio": "9.0.0
|
|
30
|
+
"@types/uuid": "^10.0.0",
|
|
31
|
+
"@wdio/protocols": "9.0.0",
|
|
32
|
+
"@wdio/types": "9.0.0",
|
|
33
|
+
"nock": "14.0.0-beta.6",
|
|
34
|
+
"uuid": "^10.0.0",
|
|
35
|
+
"webdriverio": "9.0.0"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
|
-
"@wdio/globals": "9.0.0
|
|
38
|
+
"@wdio/globals": "9.0.0"
|
|
37
39
|
},
|
|
38
40
|
"publishConfig": {
|
|
39
41
|
"access": "public"
|
|
40
42
|
},
|
|
41
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "957693463371a4cb329395dcdbce8fb0c930ab93"
|
|
42
44
|
}
|
package/build/WebDriverMock.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import nock from 'nock';
|
|
2
|
-
import { WebDriverProtocol, MJsonWProtocol, AppiumProtocol, ChromiumProtocol, SauceLabsProtocol, SeleniumProtocol } from '@wdio/protocols';
|
|
3
|
-
const REGEXP_SESSION_ID = /\/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}/;
|
|
4
|
-
const SESSION_ID = 'XXX';
|
|
5
|
-
const protocols = [
|
|
6
|
-
WebDriverProtocol, MJsonWProtocol, AppiumProtocol,
|
|
7
|
-
ChromiumProtocol, SauceLabsProtocol, SeleniumProtocol
|
|
8
|
-
];
|
|
9
|
-
const protocolFlattened = new Map();
|
|
10
|
-
for (const protocol of protocols) {
|
|
11
|
-
for (const [endpoint, methods] of Object.entries(protocol)) {
|
|
12
|
-
for (const [method, commandData] of Object.entries(methods)) {
|
|
13
|
-
protocolFlattened.set(commandData.command, { method, endpoint, commandData });
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export default class WebDriverMock {
|
|
18
|
-
path;
|
|
19
|
-
command;
|
|
20
|
-
scope;
|
|
21
|
-
constructor(host = 'localhost', port = 4444, path = '/') {
|
|
22
|
-
this.path = path;
|
|
23
|
-
this.scope = nock(`http://${host}:${port}`, { 'encodedQueryParams': true });
|
|
24
|
-
this.command = new Proxy({}, { get: this.get.bind(this) });
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* To allow random session IDs in url paths we have to set up a custom
|
|
28
|
-
* matcher that strips out the sessionID part from the expected url
|
|
29
|
-
* and actual url and replaces it with a constant session id
|
|
30
|
-
* @param {String} expectedPath path to match against
|
|
31
|
-
* @returns {Function} to be called by Nock to match actual path
|
|
32
|
-
*/
|
|
33
|
-
static pathMatcher(expectedPath) {
|
|
34
|
-
return (path) => {
|
|
35
|
-
const sessionId = path.match(REGEXP_SESSION_ID);
|
|
36
|
-
/**
|
|
37
|
-
* no session ID found so we can check against expected path directly
|
|
38
|
-
*/
|
|
39
|
-
if (!sessionId) {
|
|
40
|
-
return path === expectedPath;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* remove the session ID from expected and actual path
|
|
44
|
-
* to only compare non arbitrary parts
|
|
45
|
-
*/
|
|
46
|
-
expectedPath = expectedPath.replace(':sessionId', SESSION_ID);
|
|
47
|
-
path = path.replace(`${sessionId[0].slice(1)}`, SESSION_ID);
|
|
48
|
-
return path === expectedPath;
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
get(obj, commandName) {
|
|
52
|
-
const { method, endpoint, commandData } = protocolFlattened.get(commandName);
|
|
53
|
-
return (...args) => {
|
|
54
|
-
let urlPath = endpoint;
|
|
55
|
-
for (const [i, param] of Object.entries(commandData.variables || [])) {
|
|
56
|
-
urlPath = urlPath.replace(`:${param.name}`, args[parseInt(i)]);
|
|
57
|
-
}
|
|
58
|
-
if (method === 'POST') {
|
|
59
|
-
const reqMethod = method.toLowerCase();
|
|
60
|
-
return this.scope[reqMethod](WebDriverMock.pathMatcher(urlPath), (body) => {
|
|
61
|
-
for (const param of commandData.parameters) {
|
|
62
|
-
/**
|
|
63
|
-
* check if parameter was set
|
|
64
|
-
*/
|
|
65
|
-
if (!body[param.name]) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* check if parameter has correct type
|
|
70
|
-
*/
|
|
71
|
-
if (param.required && typeof body[param.name] === 'undefined') {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* all parameters are valid
|
|
77
|
-
*/
|
|
78
|
-
return true;
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
const reqMethod = method.toLowerCase();
|
|
82
|
-
return this.scope[reqMethod](WebDriverMock.pathMatcher(urlPath));
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
}
|
package/build/constants.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export const NO_SUCH_ELEMENT = {
|
|
2
|
-
value: {
|
|
3
|
-
error: 'no such element',
|
|
4
|
-
message: 'Unable to locate element: bodys',
|
|
5
|
-
stacktrace: 'WebDriverError@chrome://marionette/content/error.js:179:5\nNoSuchElementError@chrome://marionette/content/error.js:389:5\nelement.find/</<@chrome://marionette/content/element.js:339:16\n'
|
|
6
|
-
}
|
|
7
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export const newSession = {
|
|
2
|
-
value: {
|
|
3
|
-
sessionId: 'undefined',
|
|
4
|
-
capabilities: {
|
|
5
|
-
acceptInsecureCerts: false,
|
|
6
|
-
browserName: 'firefox',
|
|
7
|
-
browserVersion: 64.0,
|
|
8
|
-
pageLoadStrategy: 'normal',
|
|
9
|
-
platformName: 'mac',
|
|
10
|
-
platformVersion: '17.7.0',
|
|
11
|
-
rotatable: false,
|
|
12
|
-
setWindowRect: true,
|
|
13
|
-
timeouts: [{}],
|
|
14
|
-
unhandledPromptBehavior: 'dismiss and notify',
|
|
15
|
-
'moz:accessibilityChecks': false,
|
|
16
|
-
'moz:geckodriverVersion': '0.23.0',
|
|
17
|
-
'moz:headless': false,
|
|
18
|
-
'moz:processID': 15867,
|
|
19
|
-
'moz:profile': '/var/folders/ns/8mj2mh0x27b_gsdddy1knnsm0000gn/T/rust_mozprofile.yUuH0ktcRJPN',
|
|
20
|
-
'moz:shutdownTimeout': 60000,
|
|
21
|
-
'moz:webdriverClick': true
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
export const deleteSession = {
|
|
26
|
-
value: null
|
|
27
|
-
};
|
/package/{LICENSE-MIT → LICENSE}
RENAMED
|
File without changes
|