@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 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: Omit<Options.Testrunner, 'capabilities'>): void;
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;
@@ -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,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC,GAAG,IAAI;IAKrE,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,YAAY,MAAM;;CAIvC,CAAA"}
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
- import nock from 'nock';
2
- import { v4 as uuidv4 } from 'uuid';
3
- import WebDriverMock from './WebDriverMock.js';
4
- import { NO_SUCH_ELEMENT } from './constants.js';
5
- import { newSession, deleteSession } from './mocks/newSession.js';
6
- const ELEMENT_ID = '401c0039-3306-6a46-a98d-f5939870a249';
7
- const ELEMENT_REFETCHED = '80d860d0-b829-f540-812e-7078eb983795';
8
- const ELEMENT_ALT = '8bf4d107-a363-40d1-b823-d94bdbc58afb';
9
- const ELEM_PROP = 'element-6066-11e4-a52e-4f735466cecf';
10
- export default class WebdriverMockService {
11
- _browser;
12
- _mock = new WebDriverMock();
13
- constructor() {
14
- this.init();
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
- init() {
17
- // define required responses
18
- this._mock.command.status().times(Infinity).reply(200, { value: {} });
19
- this._mock.command.newSession().times(Infinity).reply(200, () => {
20
- newSession.value.sessionId = uuidv4();
21
- return newSession;
22
- });
23
- this._mock.command.deleteSession().times(2).reply(200, deleteSession);
24
- this._mock.command.getTitle().times(Infinity).reply(200, { value: 'Mock Page Title' });
25
- this._mock.command.getUrl().times(Infinity).reply(200, { value: 'https://mymockpage.com' });
26
- this._mock.command.getElementRect(ELEMENT_ID).times(2).reply(200, { value: { width: 1, height: 2, x: 3, y: 4 } });
27
- this._mock.command.getElementRect(ELEMENT_ALT).times(3).reply(200, { value: { width: 10, height: 20, x: 30, y: 40 } });
28
- this._mock.command.getElementRect(ELEMENT_REFETCHED).times(1).reply(200, { value: { width: 1, height: 2, x: 3, y: 4 } });
29
- this._mock.command.getLogTypes().reply(200, { value: [] });
30
- }
31
- beforeSession(config) {
32
- config.hostname = 'localhost';
33
- config.port = 4444;
34
- }
35
- before(caps, specs, browser) {
36
- this._browser = browser;
37
- /**
38
- * register request interceptors for specific scenarios
39
- */
40
- this._browser.addCommand('waitForElementScenario', this.waitForElementScenario.bind(this));
41
- this._browser.addCommand('isNeverDisplayedScenario', this.isNeverDisplayedScenario.bind(this));
42
- this._browser.addCommand('isEventuallyDisplayedScenario', this.isEventuallyDisplayedScenario.bind(this));
43
- this._browser.addCommand('staleElementRefetchScenario', this.staleElementRefetchScenario.bind(this));
44
- this._browser.addCommand('customCommandScenario', this.customCommandScenario.bind(this));
45
- this._browser.addCommand('customSelectorScenario', this.customSelectorScenario.bind(this));
46
- this._browser.addCommand('waitForDisplayedScenario', this.waitForDisplayedScenario.bind(this));
47
- this._browser.addCommand('cucumberScenario', this.cucumberScenario.bind(this));
48
- this._browser.addCommand('clickScenario', this.clickScenario.bind(this));
49
- this._browser.addCommand('isExistingScenario', this.isExistingScenario.bind(this));
50
- this._browser.addCommand('isNotExistingScenario', this.isNotExistingScenario.bind(this));
51
- this._browser.addCommand('multiremoteFetch', this.multiremoteFetch.bind(this));
52
- this._browser.addCommand('asyncIterationScenario', this.asyncIterationScenario.bind(this));
53
- this._browser.addCommand('parentElementChaining', this.parentNextPreviousElementChaining.bind(this));
54
- this._browser.addCommand('refetchElementScenario', this.refetchElementScenario.bind(this));
55
- }
56
- clickScenario() {
57
- this.nockReset();
58
- const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
59
- this._mock.command.findElement().times(2).reply(200, { value: elemResponse });
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
- // Clicks on the new element are successful
116
- this._mock.command.elementClick(ELEMENT_REFETCHED).times(4).reply(200, { value: null });
117
- // Wait for it to exist - but 2 failed iterations
118
- this._mock.command.findElements().times(2).reply(200, { value: [] });
119
- // Always appears thereafter
120
- this._mock.command.findElements().times(4).reply(200, { value: [elem2Response] });
121
- }
122
- refetchElementScenario() {
123
- const elemResponse1 = { [ELEM_PROP]: '1' };
124
- const elemResponse2 = { [ELEM_PROP]: '2' };
125
- const elemResponse3 = { [ELEM_PROP]: '3' };
126
- const elemResponse4 = { [ELEM_PROP]: '4' };
127
- this._mock.command.getElementText('1').reply(200, { value: 'some element text 1' });
128
- this._mock.command.getElementText('2').reply(200, { value: 'some element text 2' });
129
- this._mock.command.getElementText('3').reply(200, { value: 'some element text 3' });
130
- this._mock.command.getElementText('4').reply(200, { value: 'some element text 4' });
131
- this._mock.command.findElements().times(4).reply(200, { value: [] });
132
- this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1] });
133
- this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1, elemResponse2] });
134
- this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1, elemResponse2, elemResponse3] });
135
- this._mock.command.findElements().times(1).reply(200, { value: [elemResponse1, elemResponse2, elemResponse3, elemResponse4] });
136
- }
137
- asyncIterationScenario() {
138
- const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
139
- const elem2Response = { [ELEM_PROP]: ELEMENT_REFETCHED };
140
- this._mock.command.findElements().reply(200, { value: [elemResponse, elem2Response] });
141
- this._mock.command.getElementText(ELEMENT_ID).reply(200, { value: 'some element text' });
142
- this._mock.command.getElementText(ELEMENT_REFETCHED).reply(200, { value: 'some other element text' });
143
- return [ELEMENT_ID, ELEMENT_REFETCHED];
144
- }
145
- parentNextPreviousElementChaining() {
146
- const elemResponse = { [ELEM_PROP]: ELEMENT_ID };
147
- const elemParentResponse = { [ELEM_PROP]: ELEMENT_REFETCHED };
148
- this._mock.command.findElement().reply(200, { value: elemResponse });
149
- this._mock.command.executeScript().reply(200, { value: elemParentResponse });
150
- this._mock.command.getElementText(ELEMENT_REFETCHED).reply(200, { value: 'some element text' });
151
- }
152
- multiremoteFetch() {
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-alpha.78+fee2f8a88",
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
- ".": "./build/index.js",
24
- "./package.json": "./package.json"
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": "^9.0.0",
29
- "@wdio/protocols": "9.0.0-alpha.78+fee2f8a88",
30
- "@wdio/types": "9.0.0-alpha.78+fee2f8a88",
31
- "nock": "14.0.0-beta.5",
32
- "uuid": "^9.0.0",
33
- "webdriverio": "9.0.0-alpha.78+fee2f8a88"
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-alpha.78+fee2f8a88"
38
+ "@wdio/globals": "9.0.0"
37
39
  },
38
40
  "publishConfig": {
39
41
  "access": "public"
40
42
  },
41
- "gitHead": "fee2f8a88d132537795eaf144abf1a7e242f99ff"
43
+ "gitHead": "957693463371a4cb329395dcdbce8fb0c930ab93"
42
44
  }
@@ -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
- }
@@ -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
- };
File without changes