@wix-pilot/webdriverio-appium 1.0.1 → 1.0.3
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/README.md +77 -0
- package/dist/examples/example.test.js +6 -8
- package/dist/index.d.ts +7 -1
- package/dist/index.js +56 -75
- package/dist/utils/getStableViewHierarchy.d.ts +3 -0
- package/dist/utils/getStableViewHierarchy.js +37 -0
- package/dist/wdio.conf.d.ts +28 -0
- package/dist/wdio.conf.js +34 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @wix-pilot/appium 📱
|
|
2
|
+
|
|
3
|
+
> Appium driver for Wix Pilot - Cross-platform mobile testing with natural language
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The `@wix-pilot/webdriverio-appium` package provides Appium integration for Wix Pilot, enabling:
|
|
8
|
+
- Native iOS and Android app testing
|
|
9
|
+
- Hybrid app testing
|
|
10
|
+
- Mobile web testing
|
|
11
|
+
- Cross-platform test automation
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# npm
|
|
17
|
+
npm install --save-dev @wix-pilot/webdriverio-appium webdriverio @wix-pilot/core
|
|
18
|
+
|
|
19
|
+
# yarn
|
|
20
|
+
yarn add -D @wix-pilot/webdriverio-appium webdriverio @wix-pilot/core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### 1. Set up your LLM Handler
|
|
26
|
+
```typescript
|
|
27
|
+
import { PromptHandler } from '@wix-pilot/core';
|
|
28
|
+
|
|
29
|
+
class CustomPromptHandler implements PromptHandler {
|
|
30
|
+
async runPrompt(prompt: string, image?: string): Promise<string> {
|
|
31
|
+
// Integrate with your preferred LLM service
|
|
32
|
+
const response = await yourLLMService.complete({
|
|
33
|
+
prompt,
|
|
34
|
+
imageUrl: image, // Optional: for visual testing support
|
|
35
|
+
});
|
|
36
|
+
return response.text;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
isSnapshotImageSupported(): boolean {
|
|
40
|
+
return true; // Set to true if your LLM supports image analysis
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Create and Run Tests
|
|
46
|
+
```typescript
|
|
47
|
+
import pilot from '@wix-pilot/core';
|
|
48
|
+
import { WebdriverIOAppiumFrameworkDriver } from '@wix-pilot/webdriverio-appium';
|
|
49
|
+
|
|
50
|
+
describe('Mobile App Testing', () => {
|
|
51
|
+
beforeAll(async () => {
|
|
52
|
+
pilot.init({
|
|
53
|
+
driver: new WebdriverIOAppiumFrameworkDriver(),
|
|
54
|
+
promptHandler: new CustomPromptHandler(),
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
beforeEach(() => pilot.start());
|
|
59
|
+
afterEach(() => pilot.end());
|
|
60
|
+
|
|
61
|
+
it('should handle shopping cart flow', async () => {
|
|
62
|
+
await pilot.perform([
|
|
63
|
+
'Launch the app',
|
|
64
|
+
'Allow any permission prompts',
|
|
65
|
+
'Tap the "Products" tab',
|
|
66
|
+
'Scroll to "Wireless Headphones"',
|
|
67
|
+
'Add item to cart',
|
|
68
|
+
'The cart badge should show "1"'
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Related Packages
|
|
75
|
+
|
|
76
|
+
- [@wix-pilot/core](../../core) - Core Wix Pilot engine
|
|
77
|
+
- [@wix-pilot/detox](../detox) - Alternative React Native testing driver
|
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const core_1 =
|
|
3
|
+
const core_1 = require("@wix-pilot/core");
|
|
7
4
|
const promptHandler_1 = require("../utils/promptHandler");
|
|
8
5
|
const index_1 = require("../index");
|
|
9
6
|
describe("Example Test Suite", () => {
|
|
10
7
|
let frameworkDriver;
|
|
8
|
+
let pilot;
|
|
11
9
|
before(async () => {
|
|
12
10
|
const promptHandler = new promptHandler_1.PromptHandler();
|
|
13
11
|
frameworkDriver = new index_1.WebdriverIOAppiumFrameworkDriver();
|
|
14
|
-
core_1.
|
|
12
|
+
pilot = new core_1.Pilot({
|
|
15
13
|
frameworkDriver,
|
|
16
14
|
promptHandler,
|
|
17
15
|
});
|
|
18
16
|
});
|
|
19
17
|
beforeEach(async () => {
|
|
20
|
-
|
|
18
|
+
pilot.start();
|
|
21
19
|
});
|
|
22
20
|
afterEach(async () => {
|
|
23
|
-
|
|
21
|
+
pilot.end();
|
|
24
22
|
});
|
|
25
23
|
it("perform test with pilot", async () => {
|
|
26
|
-
await
|
|
24
|
+
await pilot.autopilot("earn 2 points in the game");
|
|
27
25
|
});
|
|
28
26
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { TestingFrameworkAPICatalog, TestingFrameworkDriver } from "@wix-pilot/core";
|
|
1
|
+
import { TestingFrameworkAPICatalog, TestingFrameworkDriver, TestingFrameworkDriverConfig } from "@wix-pilot/core";
|
|
2
2
|
export declare class WebdriverIOAppiumFrameworkDriver implements TestingFrameworkDriver {
|
|
3
3
|
constructor();
|
|
4
|
+
/**
|
|
5
|
+
* Additional driver configuration.
|
|
6
|
+
*
|
|
7
|
+
* @property useSnapshotStabilitySync - Indicates whether the driver should use wait for screen stability.
|
|
8
|
+
*/
|
|
9
|
+
get driverConfig(): TestingFrameworkDriverConfig;
|
|
4
10
|
/**
|
|
5
11
|
* Attempts to capture the current view hierarchy (source) of the mobile app as XML.
|
|
6
12
|
* If there's no active session or the app isn't running, returns an error message.
|
package/dist/index.js
CHANGED
|
@@ -36,18 +36,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.WebdriverIOAppiumFrameworkDriver = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
+
const getStableViewHierarchy_1 = require("./utils/getStableViewHierarchy");
|
|
39
40
|
class WebdriverIOAppiumFrameworkDriver {
|
|
40
41
|
constructor() { }
|
|
42
|
+
/**
|
|
43
|
+
* Additional driver configuration.
|
|
44
|
+
*
|
|
45
|
+
* @property useSnapshotStabilitySync - Indicates whether the driver should use wait for screen stability.
|
|
46
|
+
*/
|
|
47
|
+
get driverConfig() {
|
|
48
|
+
return { useSnapshotStabilitySync: true };
|
|
49
|
+
}
|
|
41
50
|
/**
|
|
42
51
|
* Attempts to capture the current view hierarchy (source) of the mobile app as XML.
|
|
43
52
|
* If there's no active session or the app isn't running, returns an error message.
|
|
44
53
|
*/
|
|
45
54
|
async captureViewHierarchyString() {
|
|
46
55
|
try {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const pageSource = await driver.getPageSource();
|
|
50
|
-
return pageSource;
|
|
56
|
+
const result = await (0, getStableViewHierarchy_1.waitForStableState)();
|
|
57
|
+
return result ?? "";
|
|
51
58
|
}
|
|
52
59
|
catch (_error) {
|
|
53
60
|
return "NO ACTIVE APP FOUND, LAUNCH THE APP TO SEE THE VIEW HIERARCHY";
|
|
@@ -99,31 +106,49 @@ class WebdriverIOAppiumFrameworkDriver {
|
|
|
99
106
|
signature: `$('~accessibilityId')`,
|
|
100
107
|
description: "Locate an element by its accessibility ID (commonly used in Appium).",
|
|
101
108
|
example: `const loginButton = await $('~loginButton'); // Accessibility ID`,
|
|
109
|
+
guidelines: [
|
|
110
|
+
"Always prefer using test IDs when available; if no ID is present, use another stable identifier.",
|
|
111
|
+
],
|
|
102
112
|
},
|
|
103
113
|
{
|
|
104
114
|
signature: `$('android=uiSelector')`,
|
|
105
115
|
description: "Locate an element using an Android UIAutomator selector.",
|
|
106
116
|
example: `const el = await $('android=new UiSelector().text("Login")');`,
|
|
117
|
+
guidelines: [
|
|
118
|
+
"For Android, use UIAutomator selectors to target elements by text, resource-id, or other properties. Ensure selectors are precise to avoid ambiguity.",
|
|
119
|
+
],
|
|
107
120
|
},
|
|
108
121
|
{
|
|
109
122
|
signature: `$('ios=predicateString')`,
|
|
110
123
|
description: "Locate an element using an iOS NSPredicate string.",
|
|
111
124
|
example: `const el = await $('ios=predicate string:type == "XCUIElementTypeButton" AND name == "Login"');`,
|
|
125
|
+
guidelines: [
|
|
126
|
+
"For iOS, use NSPredicate strings to define clear and concise conditions for element identification. Validate the predicate to ensure it uniquely identifies the element.",
|
|
127
|
+
],
|
|
112
128
|
},
|
|
113
129
|
{
|
|
114
130
|
signature: `$$('#elementSelector')`,
|
|
115
131
|
description: "Locate all elements with a given selector",
|
|
116
132
|
example: `const firstSite = await $$('#Site')[index];`,
|
|
133
|
+
guidelines: [
|
|
134
|
+
"Use this to select multiple elements. Make sure your selector targets a specific subset of elements to avoid excessive matches.",
|
|
135
|
+
],
|
|
117
136
|
},
|
|
118
137
|
{
|
|
119
138
|
signature: `$('//*[@text="Login"]')`,
|
|
120
139
|
description: "Locate an element using an XPath expression.",
|
|
121
140
|
example: `const el = await $('//*[@text="Login"]');`,
|
|
141
|
+
guidelines: [
|
|
142
|
+
"Use XPath as a last resort when other selectors are not available, as XPath can be slower and more brittle. Ensure your XPath expression is optimized for performance.",
|
|
143
|
+
],
|
|
122
144
|
},
|
|
123
145
|
{
|
|
124
146
|
signature: `$('#elementId'), $('elementTag'), $('.className')`,
|
|
125
147
|
description: "Web-like selectors (useful if your app is a hybrid or has a web context).",
|
|
126
148
|
example: `const el = await $('.someNativeClass');`,
|
|
149
|
+
guidelines: [
|
|
150
|
+
"Use web-like selectors in hybrid apps or web contexts. Ensure selectors are unique and adhere to best practices for CSS selectors.",
|
|
151
|
+
],
|
|
127
152
|
},
|
|
128
153
|
],
|
|
129
154
|
},
|
|
@@ -136,6 +161,9 @@ class WebdriverIOAppiumFrameworkDriver {
|
|
|
136
161
|
example: `
|
|
137
162
|
await (await $('~loginButton')).waitForEnabled();
|
|
138
163
|
await (await $('~loginButton')).click();`,
|
|
164
|
+
guidelines: [
|
|
165
|
+
"Allways use await (await $('~element')).waitForEnabled() before clicking on the element",
|
|
166
|
+
],
|
|
139
167
|
},
|
|
140
168
|
{
|
|
141
169
|
signature: `.setValue(value: string)`,
|
|
@@ -163,11 +191,6 @@ await (await $('~dragHandle')).touchAction([
|
|
|
163
191
|
]);
|
|
164
192
|
`,
|
|
165
193
|
},
|
|
166
|
-
{
|
|
167
|
-
signature: `.scrollIntoView() (web/hybrid context only)`,
|
|
168
|
-
description: "Scrolls the element into view (if in a web context).",
|
|
169
|
-
example: `await (await $('#someElement')).scrollIntoView();`,
|
|
170
|
-
},
|
|
171
194
|
{
|
|
172
195
|
signature: `.dragAndDrop(target, duration?)`,
|
|
173
196
|
description: "Drags the element to the target location (native or web context).",
|
|
@@ -187,31 +210,55 @@ await (await $('~draggable')).dragAndDrop(
|
|
|
187
210
|
signature: `toBeDisplayed()`,
|
|
188
211
|
description: "Asserts that the element is displayed (visible).",
|
|
189
212
|
example: `await expect(await $('~loginButton')).toBeDisplayed();`,
|
|
213
|
+
guidelines: [
|
|
214
|
+
"Use this matcher to verify that the element is visible to the user.",
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
signature: `.waitForEnabled()`,
|
|
219
|
+
description: "Waits until the element is enabled and ready to be clicked",
|
|
220
|
+
example: `await (await $('~usernameInput')).waitForEnabled();`,
|
|
221
|
+
guidelines: ["Allways use this before clicking on an element"],
|
|
190
222
|
},
|
|
191
223
|
{
|
|
192
224
|
signature: `toExist()`,
|
|
193
225
|
description: "Asserts that the element exists in the DOM/hierarchy.",
|
|
194
226
|
example: `await expect(await $('~usernameInput')).toExist();`,
|
|
227
|
+
guidelines: [
|
|
228
|
+
"Use this matcher to check that the element exists in the DOM or view hierarchy.",
|
|
229
|
+
],
|
|
195
230
|
},
|
|
196
231
|
{
|
|
197
232
|
signature: `toHaveText(text: string)`,
|
|
198
233
|
description: "Asserts that the element's text matches the given string.",
|
|
199
234
|
example: `await expect(await $('~welcomeMessage')).toHaveText('Welcome, user!');`,
|
|
235
|
+
guidelines: [
|
|
236
|
+
"Use this matcher to verify the text content of an element exactly matches the expected value.",
|
|
237
|
+
],
|
|
200
238
|
},
|
|
201
239
|
{
|
|
202
240
|
signature: `toHaveValue(value: string)`,
|
|
203
241
|
description: "Asserts that the element's value matches the given string (for inputs, etc.).",
|
|
204
242
|
example: `await expect(await $('~usernameInput')).toHaveValue('myusername');`,
|
|
243
|
+
guidelines: [
|
|
244
|
+
"Use this matcher for form elements to verify that the input value is correct.",
|
|
245
|
+
],
|
|
205
246
|
},
|
|
206
247
|
{
|
|
207
248
|
signature: `toBeEnabled() / toBeDisabled()`,
|
|
208
249
|
description: "Asserts that an element is enabled/disabled (if applicable).",
|
|
209
250
|
example: `await expect(await $('~submitButton')).toBeEnabled();`,
|
|
251
|
+
guidelines: [
|
|
252
|
+
"Use these matchers to assert that an element is enabled or disabled as required by the test scenario.",
|
|
253
|
+
],
|
|
210
254
|
},
|
|
211
255
|
{
|
|
212
256
|
signature: `not`,
|
|
213
257
|
description: "Negates the expectation.",
|
|
214
258
|
example: `await expect(await $('~spinner')).not.toBeDisplayed();`,
|
|
259
|
+
guidelines: [
|
|
260
|
+
"Use this matcher to invert the condition of any expectation, ensuring the element does not meet the specified criteria.",
|
|
261
|
+
],
|
|
215
262
|
},
|
|
216
263
|
],
|
|
217
264
|
},
|
|
@@ -270,29 +317,6 @@ await driver.setGeoLocation({
|
|
|
270
317
|
latitude: 37.7749,
|
|
271
318
|
longitude: -122.4194,
|
|
272
319
|
altitude: 10
|
|
273
|
-
});
|
|
274
|
-
`,
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
signature: `driver.getContext() / driver.switchContext(name: string)`,
|
|
278
|
-
description: "Gets or switches the current context (NATIVE_APP or WEBVIEW_xxx).",
|
|
279
|
-
example: `
|
|
280
|
-
const contexts = await driver.getContexts();
|
|
281
|
-
await driver.switchContext(contexts[1]); // Switch to webview
|
|
282
|
-
await driver.switchContext('NATIVE_APP'); // Switch back
|
|
283
|
-
`,
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
signature: `driver.rotate(params: { x: number; y: number; duration: number; radius: number; rotation: number; touchCount: number })`,
|
|
287
|
-
description: "Simulates a rotation gesture on the device (iOS only).",
|
|
288
|
-
example: `
|
|
289
|
-
await driver.rotate({
|
|
290
|
-
x: 100,
|
|
291
|
-
y: 100,
|
|
292
|
-
duration: 2,
|
|
293
|
-
radius: 50,
|
|
294
|
-
rotation: 180,
|
|
295
|
-
touchCount: 2
|
|
296
320
|
});
|
|
297
321
|
`,
|
|
298
322
|
},
|
|
@@ -331,49 +355,6 @@ await driver.performTouchAction({
|
|
|
331
355
|
},
|
|
332
356
|
],
|
|
333
357
|
},
|
|
334
|
-
{
|
|
335
|
-
title: "Web APIs (Hybrid / Mobile Web)",
|
|
336
|
-
items: [
|
|
337
|
-
{
|
|
338
|
-
signature: `driver.switchContext('WEBVIEW')`,
|
|
339
|
-
description: "Switches the context from native to web view (if a webview is present).",
|
|
340
|
-
example: `
|
|
341
|
-
const contexts = await driver.getContexts();
|
|
342
|
-
await driver.switchContext(contexts.find(c => c.includes('WEBVIEW')));
|
|
343
|
-
`,
|
|
344
|
-
guidelines: [
|
|
345
|
-
"Use this when your app has a webview or is a hybrid app.",
|
|
346
|
-
],
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
signature: `$('css or xpath').click()`,
|
|
350
|
-
description: "In a webview context, click (tap) a web element using CSS or XPath.",
|
|
351
|
-
example: `await (await $('button#login')).click();`,
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
signature: `$('selector').setValue('text')`,
|
|
355
|
-
description: "In a webview context, sets text in a web input field.",
|
|
356
|
-
example: `await (await $('input#username')).setValue('myusername');`,
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
signature: `.getText()`,
|
|
360
|
-
description: "Retrieves the visible text of a web element (hybrid/web context).",
|
|
361
|
-
example: `
|
|
362
|
-
const text = await (await $('h1.main-title')).getText();
|
|
363
|
-
expect(text).toBe('Welcome to My App');
|
|
364
|
-
`,
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
signature: `driver.executeScript(script: string, args?: any[])`,
|
|
368
|
-
description: "Executes JavaScript in the context of the webview.",
|
|
369
|
-
example: `
|
|
370
|
-
await driver.executeScript("document.getElementById('hidden-button').click()");
|
|
371
|
-
const title = await driver.executeScript('return document.title');
|
|
372
|
-
expect(title).toBe('My Page Title');
|
|
373
|
-
`,
|
|
374
|
-
},
|
|
375
|
-
],
|
|
376
|
-
},
|
|
377
358
|
],
|
|
378
359
|
};
|
|
379
360
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.waitForStableState = waitForStableState;
|
|
7
|
+
exports.compareViewHierarchies = compareViewHierarchies;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const DEFAULT_POLL_INTERVAL = 500; // ms
|
|
10
|
+
const DEFAULT_TIMEOUT = 5000; // ms
|
|
11
|
+
/** Waits till the view hierarchy is stable than returns it*/
|
|
12
|
+
async function waitForStableState(pollInterval = DEFAULT_POLL_INTERVAL, timeout = DEFAULT_TIMEOUT) {
|
|
13
|
+
const startTime = Date.now();
|
|
14
|
+
let lastSnapshot;
|
|
15
|
+
while (Date.now() - startTime < timeout) {
|
|
16
|
+
const currentSnapshot = (await driver.getPageSource()) || "";
|
|
17
|
+
if (!currentSnapshot) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
if (lastSnapshot) {
|
|
21
|
+
const isStable = compareViewHierarchies(currentSnapshot, lastSnapshot);
|
|
22
|
+
if (isStable) {
|
|
23
|
+
return currentSnapshot;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
lastSnapshot = currentSnapshot;
|
|
27
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
28
|
+
}
|
|
29
|
+
// Return the last snapshot if timeout is reached
|
|
30
|
+
return lastSnapshot;
|
|
31
|
+
}
|
|
32
|
+
function compareViewHierarchies(current, last) {
|
|
33
|
+
// Use MD5 for fast comparison of view hierarchies
|
|
34
|
+
const currentHash = crypto_1.default.createHash("md5").update(current).digest("hex");
|
|
35
|
+
const lastHash = crypto_1.default.createHash("md5").update(last).digest("hex");
|
|
36
|
+
return currentHash === lastHash;
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const config: {
|
|
2
|
+
runner: string;
|
|
3
|
+
specs: string[];
|
|
4
|
+
maxInstances: number;
|
|
5
|
+
capabilities: {
|
|
6
|
+
platformName: string;
|
|
7
|
+
deviceName: string;
|
|
8
|
+
automationName: string;
|
|
9
|
+
app: string;
|
|
10
|
+
}[];
|
|
11
|
+
logLevel: string;
|
|
12
|
+
bail: number;
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
waitforTimeout: number;
|
|
15
|
+
connectionRetryTimeout: number;
|
|
16
|
+
connectionRetryCount: number;
|
|
17
|
+
services: string[];
|
|
18
|
+
appium: {
|
|
19
|
+
command: string;
|
|
20
|
+
};
|
|
21
|
+
framework: string;
|
|
22
|
+
reporters: string[];
|
|
23
|
+
mochaOpts: {
|
|
24
|
+
ui: string;
|
|
25
|
+
timeout: number;
|
|
26
|
+
};
|
|
27
|
+
before: () => void;
|
|
28
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
// wdio.conf.ts
|
|
5
|
+
exports.config = {
|
|
6
|
+
runner: 'local',
|
|
7
|
+
specs: ['./examples/**/*.test.ts'],
|
|
8
|
+
maxInstances: 1,
|
|
9
|
+
capabilities: [{
|
|
10
|
+
platformName: 'iOS',
|
|
11
|
+
deviceName: 'iPhone 14',
|
|
12
|
+
automationName: 'XCUITest',
|
|
13
|
+
app: './Users/tzviels/Library/Developer/Xcode/DerivedData/ExampleApp-ccggovixskkojadmtpriqiridvii/Build/Products/Debug-iphonesimulator/ExampleApp.app',
|
|
14
|
+
}],
|
|
15
|
+
logLevel: 'info',
|
|
16
|
+
bail: 0,
|
|
17
|
+
baseUrl: 'http://localhost',
|
|
18
|
+
waitforTimeout: 10000,
|
|
19
|
+
connectionRetryTimeout: 90000,
|
|
20
|
+
connectionRetryCount: 3,
|
|
21
|
+
services: ['appium'],
|
|
22
|
+
appium: {
|
|
23
|
+
command: 'appium',
|
|
24
|
+
},
|
|
25
|
+
framework: 'mocha',
|
|
26
|
+
reporters: ['spec'],
|
|
27
|
+
mochaOpts: {
|
|
28
|
+
ui: 'bdd',
|
|
29
|
+
timeout: 60000,
|
|
30
|
+
},
|
|
31
|
+
before: function () {
|
|
32
|
+
global.driver = browser;
|
|
33
|
+
},
|
|
34
|
+
};
|