@samsara-dev/appwright 0.9.5 → 0.9.7
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 +30 -0
- package/README.md +34 -0
- package/dist/device/index.d.ts +24 -0
- package/dist/device/index.d.ts.map +1 -1
- package/dist/device/index.js +40 -0
- package/dist/gptDriver/index.d.ts +38 -0
- package/dist/gptDriver/index.d.ts.map +1 -0
- package/dist/gptDriver/index.js +187 -0
- package/dist/providers/appiumSettings.d.ts +10 -0
- package/dist/providers/appiumSettings.d.ts.map +1 -0
- package/dist/providers/appiumSettings.js +122 -0
- package/dist/providers/browserstack/index.d.ts.map +1 -1
- package/dist/providers/browserstack/index.js +32 -1
- package/dist/providers/emulator/index.d.ts.map +1 -1
- package/dist/providers/emulator/index.js +29 -18
- package/dist/providers/local/index.d.ts.map +1 -1
- package/dist/providers/local/index.js +28 -16
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +43 -30
- package/dist/tests/reporter.spec.js +37 -0
- package/dist/types/index.d.ts +118 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# appwright
|
|
2
2
|
|
|
3
|
+
## 0.9.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- dbd26ca: feat(gptDriver): integrate GPT Driver SDK for AI-powered test automation
|
|
8
|
+
|
|
9
|
+
Add GPT Driver SDK integration enabling natural language test automation via `device.gptDriver.*` methods:
|
|
10
|
+
- `aiExecute(instruction)` - execute AI-powered actions
|
|
11
|
+
- `assert(condition)` - verify screen state with natural language
|
|
12
|
+
- `assertBulk(conditions)` - verify multiple conditions at once
|
|
13
|
+
- `checkBulk(conditions)` - check conditions without failing test
|
|
14
|
+
- `extract(extractions)` - extract data from screen
|
|
15
|
+
|
|
16
|
+
Requires `GPT_DRIVER_API_KEY` environment variable. Tests gracefully skip when not configured.
|
|
17
|
+
|
|
18
|
+
## 0.9.6
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- b6c5799: Add configurable Appium settings for emulator/local devices via `AppiumSettings`
|
|
23
|
+
(`waitForIdleTimeout`, `newCommandTimeout`, `snapshotMaxDepth`,
|
|
24
|
+
`waitForSelectorTimeout`, `actionAcknowledgmentTimeout`, `ignoreUnimportantViews`,
|
|
25
|
+
`customSnapshotTimeout`, `waitForQuiescence`, `animationCoolOffTimeout`,
|
|
26
|
+
`reduceMotion`, `snapshotTimeout`, `includeSafariInWebviews`,
|
|
27
|
+
`chromedriverAutodownload`) to tune Android/iOS behavior for apps that never
|
|
28
|
+
become idle.
|
|
29
|
+
|
|
30
|
+
BrowserStack adds geolocation, Appium updateSettings tuning, and a video
|
|
31
|
+
download opt-out that also skips waits when downloads are disabled.
|
|
32
|
+
|
|
3
33
|
## 0.9.5
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -234,6 +234,40 @@ npm run extract:app
|
|
|
234
234
|
npx appwright test --project ios
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
+
## GPT Driver Integration
|
|
238
|
+
|
|
239
|
+
Appwright supports [GPT Driver](https://docs.mobileboost.io/gpt-driver-sdk) for AI-powered test automation. This enables natural language commands and AI assertions.
|
|
240
|
+
|
|
241
|
+
### Setup
|
|
242
|
+
|
|
243
|
+
Set the `GPT_DRIVER_API_KEY` environment variable:
|
|
244
|
+
|
|
245
|
+
```sh
|
|
246
|
+
export GPT_DRIVER_API_KEY=your-api-key
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Usage
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
import { test } from "@samsara-dev/appwright";
|
|
253
|
+
|
|
254
|
+
test("User can add item to cart", async ({ device }) => {
|
|
255
|
+
// Natural language commands
|
|
256
|
+
await device.gptDriver.aiExecute("tap on the login button");
|
|
257
|
+
await device.gptDriver.aiExecute("enter 'admin' in the username field");
|
|
258
|
+
|
|
259
|
+
// AI-powered assertions
|
|
260
|
+
await device.gptDriver.assert("welcome message is visible");
|
|
261
|
+
await device.gptDriver.assert("cart shows 1 item");
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Data Privacy Notice
|
|
266
|
+
|
|
267
|
+
GPT Driver sends screenshots to Mobileboost's external API for AI processing. Do not use GPT Driver in tests that handle sensitive data displayed on screen.
|
|
268
|
+
|
|
269
|
+
Tests skip automatically when `GPT_DRIVER_API_KEY` is not set.
|
|
270
|
+
|
|
237
271
|
## Docs
|
|
238
272
|
|
|
239
273
|
- [Basics](docs/basics.md)
|
package/dist/device/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare class Device {
|
|
|
16
16
|
private persistentSyncEnabled;
|
|
17
17
|
private activePersistentKey?;
|
|
18
18
|
private cleanupCallback?;
|
|
19
|
+
private _gptDriverProvider;
|
|
19
20
|
constructor(webDriverClient: WebDriverClient, bundleId: string | undefined, timeoutOpts: TimeoutOptions, provider: string, deviceProvider?: DeviceProvider, cleanupCallback?: () => Promise<void>);
|
|
20
21
|
attachDeviceProvider(provider: DeviceProvider): void;
|
|
21
22
|
enablePersistentStatusSync(): void;
|
|
@@ -60,6 +61,29 @@ export declare class Device {
|
|
|
60
61
|
};
|
|
61
62
|
}) => Promise<ExtractType<T>>;
|
|
62
63
|
};
|
|
64
|
+
private gptDriverProvider;
|
|
65
|
+
/**
|
|
66
|
+
* GPT Driver AI-powered test automation.
|
|
67
|
+
* Requires GPT_DRIVER_API_KEY environment variable.
|
|
68
|
+
*
|
|
69
|
+
* Note: Screenshots are sent to GPT Driver's external API for AI processing.
|
|
70
|
+
*
|
|
71
|
+
* **Usage:**
|
|
72
|
+
* ```js
|
|
73
|
+
* await device.gptDriver.aiExecute("tap on the login button");
|
|
74
|
+
* await device.gptDriver.assert("welcome message is visible");
|
|
75
|
+
* await device.gptDriver.assertBulk(["button is visible", "text shows 'Hello'"]);
|
|
76
|
+
* const results = await device.gptDriver.checkBulk(["logged in", "menu open"]);
|
|
77
|
+
* const data = await device.gptDriver.extract(["total price", "item count"]);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
gptDriver: {
|
|
81
|
+
aiExecute: (instruction: string) => Promise<void>;
|
|
82
|
+
assert: (condition: string) => Promise<void>;
|
|
83
|
+
assertBulk: (conditions: string[]) => Promise<void>;
|
|
84
|
+
checkBulk: (conditions: string[]) => Promise<Record<string, boolean>>;
|
|
85
|
+
extract: (extractions: string[]) => Promise<Record<string, any>>;
|
|
86
|
+
};
|
|
63
87
|
/**
|
|
64
88
|
* Closes the automation session. This is called automatically after each test.
|
|
65
89
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/device/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,cAAc,EACd,qBAAqB,EACrB,QAAQ,EACR,cAAc,EACd,iBAAiB,EAClB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/device/index.ts"],"names":[],"mappings":"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"}
|
package/dist/device/index.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.Device = void 0;
|
|
|
38
38
|
const locator_1 = require("../locator");
|
|
39
39
|
const types_1 = require("../types");
|
|
40
40
|
const vision_1 = require("../vision");
|
|
41
|
+
const gptDriver_1 = require("../gptDriver");
|
|
41
42
|
const utils_1 = require("../utils");
|
|
42
43
|
const utils_2 = require("../providers/browserstack/utils");
|
|
43
44
|
const utils_3 = require("../providers/lambdatest/utils");
|
|
@@ -104,6 +105,7 @@ let Device = (() => {
|
|
|
104
105
|
persistentSyncEnabled = false;
|
|
105
106
|
activePersistentKey;
|
|
106
107
|
cleanupCallback;
|
|
108
|
+
_gptDriverProvider = null;
|
|
107
109
|
constructor(webDriverClient, bundleId, timeoutOpts, provider, deviceProvider, cleanupCallback) {
|
|
108
110
|
this.webDriverClient = webDriverClient;
|
|
109
111
|
this.bundleId = bundleId;
|
|
@@ -219,6 +221,44 @@ let Device = (() => {
|
|
|
219
221
|
return await this.vision().query(prompt, options);
|
|
220
222
|
},
|
|
221
223
|
};
|
|
224
|
+
gptDriverProvider() {
|
|
225
|
+
if (!this._gptDriverProvider) {
|
|
226
|
+
this._gptDriverProvider = new gptDriver_1.GptDriverProvider(this.webDriverClient);
|
|
227
|
+
}
|
|
228
|
+
return this._gptDriverProvider;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* GPT Driver AI-powered test automation.
|
|
232
|
+
* Requires GPT_DRIVER_API_KEY environment variable.
|
|
233
|
+
*
|
|
234
|
+
* Note: Screenshots are sent to GPT Driver's external API for AI processing.
|
|
235
|
+
*
|
|
236
|
+
* **Usage:**
|
|
237
|
+
* ```js
|
|
238
|
+
* await device.gptDriver.aiExecute("tap on the login button");
|
|
239
|
+
* await device.gptDriver.assert("welcome message is visible");
|
|
240
|
+
* await device.gptDriver.assertBulk(["button is visible", "text shows 'Hello'"]);
|
|
241
|
+
* const results = await device.gptDriver.checkBulk(["logged in", "menu open"]);
|
|
242
|
+
* const data = await device.gptDriver.extract(["total price", "item count"]);
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
gptDriver = {
|
|
246
|
+
aiExecute: async (instruction) => {
|
|
247
|
+
return await this.gptDriverProvider().aiExecute(instruction);
|
|
248
|
+
},
|
|
249
|
+
assert: async (condition) => {
|
|
250
|
+
return await this.gptDriverProvider().assert(condition);
|
|
251
|
+
},
|
|
252
|
+
assertBulk: async (conditions) => {
|
|
253
|
+
return await this.gptDriverProvider().assertBulk(conditions);
|
|
254
|
+
},
|
|
255
|
+
checkBulk: async (conditions) => {
|
|
256
|
+
return await this.gptDriverProvider().checkBulk(conditions);
|
|
257
|
+
},
|
|
258
|
+
extract: async (extractions) => {
|
|
259
|
+
return await this.gptDriverProvider().extract(extractions);
|
|
260
|
+
},
|
|
261
|
+
};
|
|
222
262
|
/**
|
|
223
263
|
* Closes the automation session. This is called automatically after each test.
|
|
224
264
|
*
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Client as WebDriverClient } from "webdriver";
|
|
2
|
+
/**
|
|
3
|
+
* GptDriverApi defines the public interface for AI-powered test automation.
|
|
4
|
+
*/
|
|
5
|
+
export interface GptDriverApi {
|
|
6
|
+
aiExecute(instruction: string): Promise<void>;
|
|
7
|
+
assert(condition: string): Promise<void>;
|
|
8
|
+
assertBulk(conditions: string[]): Promise<void>;
|
|
9
|
+
checkBulk(conditions: string[]): Promise<Record<string, boolean>>;
|
|
10
|
+
extract(extractions: string[]): Promise<Record<string, any>>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* GptDriverProvider wraps the gpt-driver-node SDK for AI-powered test automation.
|
|
14
|
+
*
|
|
15
|
+
* Pattern: Lazy-initialized singleton per Device instance.
|
|
16
|
+
* - Driver is created on first use (not in constructor)
|
|
17
|
+
* - Cached for subsequent calls
|
|
18
|
+
* - Gracefully skips tests when API key is not configured
|
|
19
|
+
*
|
|
20
|
+
* Similar to: VisionProvider
|
|
21
|
+
*/
|
|
22
|
+
export declare class GptDriverProvider implements GptDriverApi {
|
|
23
|
+
private webDriverClient;
|
|
24
|
+
private driver;
|
|
25
|
+
constructor(webDriverClient: WebDriverClient);
|
|
26
|
+
private getAppiumUrl;
|
|
27
|
+
private getDriver;
|
|
28
|
+
private requireDriver;
|
|
29
|
+
private validateInstruction;
|
|
30
|
+
private validateConditions;
|
|
31
|
+
private sanitizeError;
|
|
32
|
+
aiExecute(instruction: string): Promise<void>;
|
|
33
|
+
assert(condition: string): Promise<void>;
|
|
34
|
+
assertBulk(conditions: string[]): Promise<void>;
|
|
35
|
+
checkBulk(conditions: string[]): Promise<Record<string, boolean>>;
|
|
36
|
+
extract(extractions: string[]): Promise<Record<string, any>>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gptDriver/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAM3D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;CAC9D;AAED;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IAGxC,OAAO,CAAC,eAAe;IAFnC,OAAO,CAAC,MAAM,CAA0B;gBAEpB,eAAe,EAAE,eAAe;IAEpD,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,aAAa;IAMf,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa7C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/C,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAajE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAWnE"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
3
|
+
var useValue = arguments.length > 2;
|
|
4
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
5
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
6
|
+
}
|
|
7
|
+
return useValue ? value : void 0;
|
|
8
|
+
};
|
|
9
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
10
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
11
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
12
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
13
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
14
|
+
var _, done = false;
|
|
15
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
16
|
+
var context = {};
|
|
17
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
18
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
19
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
20
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
21
|
+
if (kind === "accessor") {
|
|
22
|
+
if (result === void 0) continue;
|
|
23
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
24
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
25
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
26
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
27
|
+
}
|
|
28
|
+
else if (_ = accept(result)) {
|
|
29
|
+
if (kind === "field") initializers.unshift(_);
|
|
30
|
+
else descriptor[key] = _;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
34
|
+
done = true;
|
|
35
|
+
};
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.GptDriverProvider = void 0;
|
|
41
|
+
const gpt_driver_node_1 = __importDefault(require("gpt-driver-node"));
|
|
42
|
+
const utils_1 = require("../utils");
|
|
43
|
+
const test_1 = __importDefault(require("@playwright/test"));
|
|
44
|
+
const MAX_INSTRUCTION_LENGTH = 10000;
|
|
45
|
+
/**
|
|
46
|
+
* GptDriverProvider wraps the gpt-driver-node SDK for AI-powered test automation.
|
|
47
|
+
*
|
|
48
|
+
* Pattern: Lazy-initialized singleton per Device instance.
|
|
49
|
+
* - Driver is created on first use (not in constructor)
|
|
50
|
+
* - Cached for subsequent calls
|
|
51
|
+
* - Gracefully skips tests when API key is not configured
|
|
52
|
+
*
|
|
53
|
+
* Similar to: VisionProvider
|
|
54
|
+
*/
|
|
55
|
+
let GptDriverProvider = (() => {
|
|
56
|
+
let _instanceExtraInitializers = [];
|
|
57
|
+
let _aiExecute_decorators;
|
|
58
|
+
let _assert_decorators;
|
|
59
|
+
let _assertBulk_decorators;
|
|
60
|
+
let _checkBulk_decorators;
|
|
61
|
+
let _extract_decorators;
|
|
62
|
+
return class GptDriverProvider {
|
|
63
|
+
static {
|
|
64
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
65
|
+
_aiExecute_decorators = [utils_1.boxedStep];
|
|
66
|
+
_assert_decorators = [utils_1.boxedStep];
|
|
67
|
+
_assertBulk_decorators = [utils_1.boxedStep];
|
|
68
|
+
_checkBulk_decorators = [utils_1.boxedStep];
|
|
69
|
+
_extract_decorators = [utils_1.boxedStep];
|
|
70
|
+
__esDecorate(this, null, _aiExecute_decorators, { kind: "method", name: "aiExecute", static: false, private: false, access: { has: obj => "aiExecute" in obj, get: obj => obj.aiExecute }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
71
|
+
__esDecorate(this, null, _assert_decorators, { kind: "method", name: "assert", static: false, private: false, access: { has: obj => "assert" in obj, get: obj => obj.assert }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
72
|
+
__esDecorate(this, null, _assertBulk_decorators, { kind: "method", name: "assertBulk", static: false, private: false, access: { has: obj => "assertBulk" in obj, get: obj => obj.assertBulk }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
73
|
+
__esDecorate(this, null, _checkBulk_decorators, { kind: "method", name: "checkBulk", static: false, private: false, access: { has: obj => "checkBulk" in obj, get: obj => obj.checkBulk }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
74
|
+
__esDecorate(this, null, _extract_decorators, { kind: "method", name: "extract", static: false, private: false, access: { has: obj => "extract" in obj, get: obj => obj.extract }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
75
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
76
|
+
}
|
|
77
|
+
webDriverClient = __runInitializers(this, _instanceExtraInitializers);
|
|
78
|
+
driver = null;
|
|
79
|
+
constructor(webDriverClient) {
|
|
80
|
+
this.webDriverClient = webDriverClient;
|
|
81
|
+
}
|
|
82
|
+
getAppiumUrl() {
|
|
83
|
+
const { protocol, hostname, port, path, user, key } = this.webDriverClient.options;
|
|
84
|
+
// Include basic auth for cloud providers (BrowserStack, LambdaTest)
|
|
85
|
+
const auth = user && key ? `${user}:${key}@` : "";
|
|
86
|
+
return `${protocol}://${auth}${hostname}:${port}${path}`;
|
|
87
|
+
}
|
|
88
|
+
getDriver() {
|
|
89
|
+
if (this.driver)
|
|
90
|
+
return this.driver;
|
|
91
|
+
const apiKey = process.env.GPT_DRIVER_API_KEY;
|
|
92
|
+
if (!apiKey) {
|
|
93
|
+
console.debug("[GptDriver] GPT_DRIVER_API_KEY not set, GPT Driver features disabled");
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
this.driver = new gpt_driver_node_1.default({
|
|
97
|
+
apiKey,
|
|
98
|
+
// gpt-driver-node expects webdriverio Browser type but webdriver Client is API-compatible at runtime
|
|
99
|
+
driver: this.webDriverClient,
|
|
100
|
+
serverConfig: { url: this.getAppiumUrl() },
|
|
101
|
+
cachingMode: "FULL_SCREEN",
|
|
102
|
+
testId: test_1.default.info()?.testId ?? `test-${Date.now()}`,
|
|
103
|
+
});
|
|
104
|
+
console.debug("[GptDriver] Initialized successfully");
|
|
105
|
+
return this.driver;
|
|
106
|
+
}
|
|
107
|
+
requireDriver() {
|
|
108
|
+
const driver = this.getDriver();
|
|
109
|
+
if (!driver) {
|
|
110
|
+
test_1.default.skip(true, "GPT Driver not configured. Set GPT_DRIVER_API_KEY environment variable.");
|
|
111
|
+
throw new Error("GPT Driver not configured");
|
|
112
|
+
}
|
|
113
|
+
return driver;
|
|
114
|
+
}
|
|
115
|
+
validateInstruction(instruction, methodName) {
|
|
116
|
+
if (!instruction || typeof instruction !== "string") {
|
|
117
|
+
throw new Error(`${methodName} requires a non-empty instruction string`);
|
|
118
|
+
}
|
|
119
|
+
if (instruction.length > MAX_INSTRUCTION_LENGTH) {
|
|
120
|
+
throw new Error(`${methodName} instruction exceeds maximum length of ${MAX_INSTRUCTION_LENGTH}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
validateConditions(conditions, methodName) {
|
|
124
|
+
if (!Array.isArray(conditions) || conditions.length === 0) {
|
|
125
|
+
throw new Error(`${methodName} requires a non-empty array of conditions`);
|
|
126
|
+
}
|
|
127
|
+
for (const condition of conditions) {
|
|
128
|
+
this.validateInstruction(condition, methodName);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
sanitizeError(error) {
|
|
132
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
133
|
+
return message.replace(/[a-zA-Z0-9]{32,}/g, "[REDACTED]");
|
|
134
|
+
}
|
|
135
|
+
async aiExecute(instruction) {
|
|
136
|
+
this.validateInstruction(instruction, "aiExecute");
|
|
137
|
+
const driver = this.requireDriver();
|
|
138
|
+
try {
|
|
139
|
+
await driver.aiExecute(instruction);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
throw new Error(`GPT Driver aiExecute failed: ${this.sanitizeError(error)}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async assert(condition) {
|
|
146
|
+
this.validateInstruction(condition, "assert");
|
|
147
|
+
const driver = this.requireDriver();
|
|
148
|
+
try {
|
|
149
|
+
await driver.assert(condition, {});
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
throw new Error(`GPT Driver assertion failed: ${this.sanitizeError(error)}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async assertBulk(conditions) {
|
|
156
|
+
this.validateConditions(conditions, "assertBulk");
|
|
157
|
+
const driver = this.requireDriver();
|
|
158
|
+
try {
|
|
159
|
+
await driver.assertBulk(conditions, {});
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
throw new Error(`GPT Driver assertBulk failed: ${this.sanitizeError(error)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async checkBulk(conditions) {
|
|
166
|
+
this.validateConditions(conditions, "checkBulk");
|
|
167
|
+
const driver = this.requireDriver();
|
|
168
|
+
try {
|
|
169
|
+
return await driver.checkBulk(conditions);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
throw new Error(`GPT Driver checkBulk failed: ${this.sanitizeError(error)}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async extract(extractions) {
|
|
176
|
+
this.validateConditions(extractions, "extract");
|
|
177
|
+
const driver = this.requireDriver();
|
|
178
|
+
try {
|
|
179
|
+
return await driver.extract(extractions);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
throw new Error(`GPT Driver extract failed: ${this.sanitizeError(error)}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
})();
|
|
187
|
+
exports.GptDriverProvider = GptDriverProvider;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AppiumSettings, Platform } from "../types";
|
|
2
|
+
type AppiumCapabilities = Record<string, unknown>;
|
|
3
|
+
type AppiumSettingsOptions = {
|
|
4
|
+
includeBrowserStackSettings?: boolean;
|
|
5
|
+
includeUpdateSettingsCapabilities?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function buildAppiumUpdateSettings(appiumSettings: AppiumSettings | undefined, platformName: Platform | undefined): Record<string, unknown> | undefined;
|
|
8
|
+
export declare function applyAppiumSettingsToCapabilities(capabilities: AppiumCapabilities, appiumSettings: AppiumSettings | undefined, platformName: Platform | undefined, options?: AppiumSettingsOptions): void;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=appiumSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appiumSettings.d.ts","sourceRoot":"","sources":["../../src/providers/appiumSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpD,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,KAAK,qBAAqB,GAAG;IAC3B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,iCAAiC,CAAC,EAAE,OAAO,CAAC;CAC7C,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,YAAY,EAAE,QAAQ,GAAG,SAAS,uCA4CnC;AAED,wBAAgB,iCAAiC,CAC/C,YAAY,EAAE,kBAAkB,EAChC,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,YAAY,EAAE,QAAQ,GAAG,SAAS,EAClC,OAAO,GAAE,qBAA0B,QAqFpC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAppiumUpdateSettings = buildAppiumUpdateSettings;
|
|
4
|
+
exports.applyAppiumSettingsToCapabilities = applyAppiumSettingsToCapabilities;
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
function buildAppiumUpdateSettings(appiumSettings, platformName) {
|
|
7
|
+
if (!appiumSettings) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const settings = {};
|
|
11
|
+
const includeAndroidSettings = platformName === types_1.Platform.ANDROID || platformName === undefined;
|
|
12
|
+
const includeIosSettings = platformName === types_1.Platform.IOS || platformName === undefined;
|
|
13
|
+
if (includeAndroidSettings) {
|
|
14
|
+
if (appiumSettings.snapshotMaxDepth !== undefined) {
|
|
15
|
+
settings.snapshotMaxDepth = appiumSettings.snapshotMaxDepth;
|
|
16
|
+
}
|
|
17
|
+
if (appiumSettings.waitForIdleTimeout !== undefined) {
|
|
18
|
+
settings.waitForIdleTimeout = appiumSettings.waitForIdleTimeout;
|
|
19
|
+
}
|
|
20
|
+
if (appiumSettings.waitForSelectorTimeout !== undefined) {
|
|
21
|
+
settings.waitForSelectorTimeout = appiumSettings.waitForSelectorTimeout;
|
|
22
|
+
}
|
|
23
|
+
if (appiumSettings.actionAcknowledgmentTimeout !== undefined) {
|
|
24
|
+
settings.actionAcknowledgmentTimeout =
|
|
25
|
+
appiumSettings.actionAcknowledgmentTimeout;
|
|
26
|
+
}
|
|
27
|
+
if (appiumSettings.ignoreUnimportantViews !== undefined) {
|
|
28
|
+
settings.ignoreUnimportantViews = appiumSettings.ignoreUnimportantViews;
|
|
29
|
+
}
|
|
30
|
+
if (appiumSettings.customSnapshotTimeout !== undefined) {
|
|
31
|
+
settings.customSnapshotTimeout = appiumSettings.customSnapshotTimeout;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (includeIosSettings) {
|
|
35
|
+
if (appiumSettings.snapshotTimeout !== undefined) {
|
|
36
|
+
settings.snapshotTimeout = appiumSettings.snapshotTimeout;
|
|
37
|
+
}
|
|
38
|
+
if (appiumSettings.waitForQuiescence !== undefined) {
|
|
39
|
+
settings.shouldWaitForQuiescence = appiumSettings.waitForQuiescence;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return Object.keys(settings).length > 0 ? settings : undefined;
|
|
43
|
+
}
|
|
44
|
+
function applyAppiumSettingsToCapabilities(capabilities, appiumSettings, platformName, options = {}) {
|
|
45
|
+
if (!appiumSettings) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const includeUpdateSettingsCapabilities = options.includeUpdateSettingsCapabilities !== false;
|
|
49
|
+
if (includeUpdateSettingsCapabilities && platformName === types_1.Platform.ANDROID) {
|
|
50
|
+
if (appiumSettings.snapshotMaxDepth !== undefined) {
|
|
51
|
+
capabilities["appium:settings[snapshotMaxDepth]"] =
|
|
52
|
+
appiumSettings.snapshotMaxDepth;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (appiumSettings.newCommandTimeout !== undefined) {
|
|
56
|
+
capabilities["appium:newCommandTimeout"] = appiumSettings.newCommandTimeout;
|
|
57
|
+
}
|
|
58
|
+
if (platformName === types_1.Platform.ANDROID) {
|
|
59
|
+
if (includeUpdateSettingsCapabilities) {
|
|
60
|
+
if (appiumSettings.waitForIdleTimeout !== undefined) {
|
|
61
|
+
capabilities["appium:settings[waitForIdleTimeout]"] =
|
|
62
|
+
appiumSettings.waitForIdleTimeout;
|
|
63
|
+
}
|
|
64
|
+
if (appiumSettings.waitForSelectorTimeout !== undefined) {
|
|
65
|
+
capabilities["appium:settings[waitForSelectorTimeout]"] =
|
|
66
|
+
appiumSettings.waitForSelectorTimeout;
|
|
67
|
+
}
|
|
68
|
+
if (appiumSettings.actionAcknowledgmentTimeout !== undefined) {
|
|
69
|
+
capabilities["appium:settings[actionAcknowledgmentTimeout]"] =
|
|
70
|
+
appiumSettings.actionAcknowledgmentTimeout;
|
|
71
|
+
}
|
|
72
|
+
if (appiumSettings.ignoreUnimportantViews !== undefined) {
|
|
73
|
+
capabilities["appium:settings[ignoreUnimportantViews]"] =
|
|
74
|
+
appiumSettings.ignoreUnimportantViews;
|
|
75
|
+
}
|
|
76
|
+
if (appiumSettings.customSnapshotTimeout !== undefined) {
|
|
77
|
+
capabilities["appium:settings[customSnapshotTimeout]"] =
|
|
78
|
+
appiumSettings.customSnapshotTimeout;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (appiumSettings.disableWindowAnimation !== undefined) {
|
|
82
|
+
capabilities["appium:disableWindowAnimation"] =
|
|
83
|
+
appiumSettings.disableWindowAnimation;
|
|
84
|
+
}
|
|
85
|
+
if (appiumSettings.skipDeviceInitialization !== undefined) {
|
|
86
|
+
capabilities["appium:skipDeviceInitialization"] =
|
|
87
|
+
appiumSettings.skipDeviceInitialization;
|
|
88
|
+
}
|
|
89
|
+
if (appiumSettings.chromedriverAutodownload !== undefined) {
|
|
90
|
+
capabilities["appium:chromedriverAutodownload"] =
|
|
91
|
+
appiumSettings.chromedriverAutodownload;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (platformName === types_1.Platform.IOS) {
|
|
95
|
+
if (includeUpdateSettingsCapabilities) {
|
|
96
|
+
if (appiumSettings.waitForQuiescence !== undefined) {
|
|
97
|
+
capabilities["appium:settings[shouldWaitForQuiescence]"] =
|
|
98
|
+
appiumSettings.waitForQuiescence;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (appiumSettings.animationCoolOffTimeout !== undefined) {
|
|
102
|
+
capabilities["appium:animationCoolOffTimeout"] =
|
|
103
|
+
appiumSettings.animationCoolOffTimeout;
|
|
104
|
+
}
|
|
105
|
+
if (appiumSettings.reduceMotion !== undefined) {
|
|
106
|
+
capabilities["appium:reduceMotion"] = appiumSettings.reduceMotion;
|
|
107
|
+
}
|
|
108
|
+
if (includeUpdateSettingsCapabilities) {
|
|
109
|
+
if (appiumSettings.snapshotTimeout !== undefined) {
|
|
110
|
+
capabilities["appium:settings[snapshotTimeout]"] =
|
|
111
|
+
appiumSettings.snapshotTimeout;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (appiumSettings.includeSafariInWebviews !== undefined) {
|
|
115
|
+
capabilities["appium:includeSafariInWebviews"] =
|
|
116
|
+
appiumSettings.includeSafariInWebviews;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (options.includeBrowserStackSettings && appiumSettings.bstackPageSource) {
|
|
120
|
+
capabilities["appium:bstackPageSource"] = appiumSettings.bstackPageSource;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/browserstack/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/browserstack/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA0DtC,qBAAa,0BAA2B,YAAW,cAAc;IAC/D,OAAO,CAAC,cAAc,CAAC,CAA6B;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,OAAO,CAA+B;gBAG5C,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EACrC,WAAW,EAAE,MAAM,GAAG,SAAS;IAU3B,WAAW;IA0EX,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAMlC,OAAO,CAAC,cAAc;YASR,YAAY;YAkCZ,iBAAiB;YAKjB,yBAAyB;WAK1B,aAAa,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA+FlD,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IA2BD,OAAO,CAAC,YAAY;CA4KrB"}
|
|
@@ -12,6 +12,7 @@ const types_1 = require("../../types");
|
|
|
12
12
|
const device_1 = require("../../device");
|
|
13
13
|
const logger_1 = require("../../logger");
|
|
14
14
|
const s3_1 = require("./s3");
|
|
15
|
+
const appiumSettings_1 = require("../appiumSettings");
|
|
15
16
|
const API_BASE_URL = "https://api-cloud.browserstack.com/app-automate";
|
|
16
17
|
const envVarKeyForBuild = (projectName) => `BROWSERSTACK_APP_URL_${projectName.toUpperCase()}`;
|
|
17
18
|
function getAuthHeader() {
|
|
@@ -120,6 +121,19 @@ class BrowserStackDeviceProvider {
|
|
|
120
121
|
async createDriver(config) {
|
|
121
122
|
const WebDriver = (await import("webdriver")).default;
|
|
122
123
|
const webDriverClient = await WebDriver.newSession(config);
|
|
124
|
+
const deviceConfig = this.project.use.device;
|
|
125
|
+
const platformName = this.project.use.platform;
|
|
126
|
+
const updateSettings = (0, appiumSettings_1.buildAppiumUpdateSettings)(deviceConfig?.appiumSettings, platformName);
|
|
127
|
+
if (updateSettings) {
|
|
128
|
+
try {
|
|
129
|
+
await webDriverClient.updateSettings(updateSettings);
|
|
130
|
+
logger_1.logger.log("Applied Appium settings via updateSettings.");
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
134
|
+
throw new Error(`Failed to apply appiumSettings via updateSettings: ${message}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
123
137
|
this.sessionId = webDriverClient.sessionId;
|
|
124
138
|
const bundleId = await this.getAppBundleIdFromSession();
|
|
125
139
|
const testOptions = {
|
|
@@ -136,6 +150,10 @@ class BrowserStackDeviceProvider {
|
|
|
136
150
|
return this.sessionDetails?.app_details.app_name ?? "";
|
|
137
151
|
}
|
|
138
152
|
static async downloadVideo(sessionId, outputDir, fileName) {
|
|
153
|
+
if (process.env.APPWRIGHT_DISABLE_VIDEO_DOWNLOAD === "true") {
|
|
154
|
+
logger_1.logger.log("BrowserStack video download disabled via APPWRIGHT_DISABLE_VIDEO_DOWNLOAD.");
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
139
157
|
const sessionData = await getSessionDetails(sessionId);
|
|
140
158
|
const sessionDetails = sessionData?.automation_session;
|
|
141
159
|
const videoURL = sessionDetails?.video_url;
|
|
@@ -293,6 +311,12 @@ class BrowserStackDeviceProvider {
|
|
|
293
311
|
if (typeof deviceConfig?.appProfiling === "boolean") {
|
|
294
312
|
bstackOptions.appProfiling = deviceConfig.appProfiling;
|
|
295
313
|
}
|
|
314
|
+
if (deviceConfig?.geoLocation) {
|
|
315
|
+
bstackOptions.geoLocation = deviceConfig.geoLocation;
|
|
316
|
+
}
|
|
317
|
+
if (deviceConfig?.gpsLocation) {
|
|
318
|
+
bstackOptions.gpsLocation = deviceConfig.gpsLocation;
|
|
319
|
+
}
|
|
296
320
|
// iOS App Settings support (capability-based for session start)
|
|
297
321
|
if (platformName === types_1.Platform.IOS) {
|
|
298
322
|
// Support environment variable override for CI/CD
|
|
@@ -323,8 +347,15 @@ class BrowserStackDeviceProvider {
|
|
|
323
347
|
"bstack:options": bstackOptions,
|
|
324
348
|
"appium:app": process.env[envVarKey],
|
|
325
349
|
"appium:fullReset": true,
|
|
326
|
-
"appium:settings[snapshotMaxDepth]": 62,
|
|
327
350
|
};
|
|
351
|
+
if (platformName === types_1.Platform.ANDROID) {
|
|
352
|
+
capabilities["appium:settings[snapshotMaxDepth]"] =
|
|
353
|
+
deviceConfig.appiumSettings?.snapshotMaxDepth ?? 62;
|
|
354
|
+
}
|
|
355
|
+
(0, appiumSettings_1.applyAppiumSettingsToCapabilities)(capabilities, deviceConfig.appiumSettings, platformName, {
|
|
356
|
+
includeBrowserStackSettings: true,
|
|
357
|
+
includeUpdateSettingsCapabilities: false,
|
|
358
|
+
});
|
|
328
359
|
if (platformName === types_1.Platform.ANDROID) {
|
|
329
360
|
const grantPreference = permissionPrompts?.android?.grantPermissions;
|
|
330
361
|
if (grantPreference !== "manual") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/emulator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/emulator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAQtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI/C,qBAAa,gBAAiB,YAAW,cAAc;IAInD,OAAO,CAAC,OAAO;IAHjB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGT,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EAC7C,WAAW,EAAE,MAAM,GAAG,SAAS;IAS3B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,WAAW;YA8BH,YAAY;YAyBZ,YAAY;CAuD3B"}
|
|
@@ -4,6 +4,7 @@ exports.EmulatorProvider = void 0;
|
|
|
4
4
|
const types_1 = require("../../types");
|
|
5
5
|
const device_1 = require("../../device");
|
|
6
6
|
const appium_1 = require("../appium");
|
|
7
|
+
const appiumSettings_1 = require("../appiumSettings");
|
|
7
8
|
const utils_1 = require("../../utils");
|
|
8
9
|
const logger_1 = require("../../logger");
|
|
9
10
|
class EmulatorProvider {
|
|
@@ -53,7 +54,12 @@ Follow the steps mentioned in ${androidSimulatorConfigDocLink} to run test on An
|
|
|
53
54
|
}
|
|
54
55
|
async createConfig() {
|
|
55
56
|
const platformName = this.project.use.platform;
|
|
56
|
-
|
|
57
|
+
if (!this.project.use.device) {
|
|
58
|
+
throw new Error("Device configuration is required for emulator provider.");
|
|
59
|
+
}
|
|
60
|
+
const deviceConfig = this.project.use.device;
|
|
61
|
+
const udid = deviceConfig.udid;
|
|
62
|
+
const appiumSettings = deviceConfig.appiumSettings;
|
|
57
63
|
let appPackageName;
|
|
58
64
|
let appLaunchableActivity;
|
|
59
65
|
if (platformName == types_1.Platform.ANDROID) {
|
|
@@ -61,25 +67,30 @@ Follow the steps mentioned in ${androidSimulatorConfigDocLink} to run test on An
|
|
|
61
67
|
appPackageName = packageName;
|
|
62
68
|
appLaunchableActivity = launchableActivity;
|
|
63
69
|
}
|
|
70
|
+
// Build capabilities with configurable appium settings
|
|
71
|
+
const capabilities = {
|
|
72
|
+
"appium:deviceName": deviceConfig.name,
|
|
73
|
+
"appium:udid": udid,
|
|
74
|
+
"appium:automationName": platformName == types_1.Platform.ANDROID ? "uiautomator2" : "xcuitest",
|
|
75
|
+
"appium:platformVersion": deviceConfig.osVersion,
|
|
76
|
+
platformName: platformName,
|
|
77
|
+
"appium:autoGrantPermissions": true,
|
|
78
|
+
"appium:app": this.project.use.buildPath,
|
|
79
|
+
"appium:autoAcceptAlerts": true,
|
|
80
|
+
"appium:fullReset": true,
|
|
81
|
+
"appium:deviceOrientation": deviceConfig.orientation,
|
|
82
|
+
"appium:wdaLaunchTimeout": 300_000,
|
|
83
|
+
};
|
|
84
|
+
if (platformName == types_1.Platform.ANDROID) {
|
|
85
|
+
capabilities["appium:appActivity"] = appLaunchableActivity;
|
|
86
|
+
capabilities["appium:appPackage"] = appPackageName;
|
|
87
|
+
capabilities["appium:settings[snapshotMaxDepth]"] =
|
|
88
|
+
appiumSettings?.snapshotMaxDepth ?? 62;
|
|
89
|
+
}
|
|
90
|
+
(0, appiumSettings_1.applyAppiumSettingsToCapabilities)(capabilities, appiumSettings, platformName);
|
|
64
91
|
return {
|
|
65
92
|
port: 4723,
|
|
66
|
-
capabilities
|
|
67
|
-
"appium:deviceName": this.project.use.device?.name,
|
|
68
|
-
"appium:udid": udid,
|
|
69
|
-
"appium:automationName": platformName == types_1.Platform.ANDROID ? "uiautomator2" : "xcuitest",
|
|
70
|
-
"appium:platformVersion": this.project.use.device
|
|
71
|
-
.osVersion,
|
|
72
|
-
"appium:appActivity": appLaunchableActivity,
|
|
73
|
-
"appium:appPackage": appPackageName,
|
|
74
|
-
platformName: platformName,
|
|
75
|
-
"appium:autoGrantPermissions": true,
|
|
76
|
-
"appium:app": this.project.use.buildPath,
|
|
77
|
-
"appium:autoAcceptAlerts": true,
|
|
78
|
-
"appium:fullReset": true,
|
|
79
|
-
"appium:deviceOrientation": this.project.use.device?.orientation,
|
|
80
|
-
"appium:settings[snapshotMaxDepth]": 62,
|
|
81
|
-
"appium:wdaLaunchTimeout": 300_000,
|
|
82
|
-
},
|
|
93
|
+
capabilities,
|
|
83
94
|
};
|
|
84
95
|
}
|
|
85
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAa/C,qBAAa,mBAAoB,YAAW,cAAc;IAItD,OAAO,CAAC,OAAO;IAHjB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGT,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EAC7C,WAAW,EAAE,MAAM,GAAG,SAAS;IAS3B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,WAAW;YAgBH,YAAY;YA0BZ,YAAY;CAkE3B"}
|
|
@@ -4,6 +4,7 @@ exports.LocalDeviceProvider = void 0;
|
|
|
4
4
|
const types_1 = require("../../types");
|
|
5
5
|
const device_1 = require("../../device");
|
|
6
6
|
const appium_1 = require("../appium");
|
|
7
|
+
const appiumSettings_1 = require("../appiumSettings");
|
|
7
8
|
const utils_1 = require("../../utils");
|
|
8
9
|
const logger_1 = require("../../logger");
|
|
9
10
|
class LocalDeviceProvider {
|
|
@@ -44,6 +45,11 @@ class LocalDeviceProvider {
|
|
|
44
45
|
}
|
|
45
46
|
async createConfig() {
|
|
46
47
|
const platformName = this.project.use.platform;
|
|
48
|
+
if (!this.project.use.device) {
|
|
49
|
+
throw new Error("Device configuration is required for local device provider.");
|
|
50
|
+
}
|
|
51
|
+
const deviceConfig = this.project.use.device;
|
|
52
|
+
const appiumSettings = deviceConfig.appiumSettings;
|
|
47
53
|
let appPackageName;
|
|
48
54
|
let appLaunchableActivity;
|
|
49
55
|
if (platformName == types_1.Platform.ANDROID) {
|
|
@@ -51,7 +57,7 @@ class LocalDeviceProvider {
|
|
|
51
57
|
appPackageName = packageName;
|
|
52
58
|
appLaunchableActivity = launchableActivity;
|
|
53
59
|
}
|
|
54
|
-
let udid =
|
|
60
|
+
let udid = deviceConfig.udid;
|
|
55
61
|
if (!udid) {
|
|
56
62
|
if (platformName == types_1.Platform.IOS) {
|
|
57
63
|
udid = await (0, appium_1.getConnectedIOSDeviceUDID)();
|
|
@@ -59,27 +65,33 @@ class LocalDeviceProvider {
|
|
|
59
65
|
else {
|
|
60
66
|
const activeAndroidDevices = await (0, appium_1.getActiveAndroidDevices)();
|
|
61
67
|
if (activeAndroidDevices > 1) {
|
|
62
|
-
logger_1.logger.warn(`Multiple active devices detected. Selecting one for the test.
|
|
68
|
+
logger_1.logger.warn(`Multiple active devices detected. Selecting one for the test.
|
|
63
69
|
To specify a device, use the udid property. Run "adb devices" to get the UDID for active devices.`);
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
}
|
|
73
|
+
// Build capabilities with configurable appium settings
|
|
74
|
+
const capabilities = {
|
|
75
|
+
"appium:deviceName": deviceConfig.name,
|
|
76
|
+
"appium:udid": udid,
|
|
77
|
+
"appium:automationName": platformName == types_1.Platform.ANDROID ? "uiautomator2" : "xcuitest",
|
|
78
|
+
platformName: platformName,
|
|
79
|
+
"appium:autoGrantPermissions": true,
|
|
80
|
+
"appium:app": this.project.use.buildPath,
|
|
81
|
+
"appium:autoAcceptAlerts": true,
|
|
82
|
+
"appium:fullReset": true,
|
|
83
|
+
"appium:deviceOrientation": deviceConfig.orientation,
|
|
84
|
+
};
|
|
85
|
+
if (platformName == types_1.Platform.ANDROID) {
|
|
86
|
+
capabilities["appium:appActivity"] = appLaunchableActivity;
|
|
87
|
+
capabilities["appium:appPackage"] = appPackageName;
|
|
88
|
+
capabilities["appium:settings[snapshotMaxDepth]"] =
|
|
89
|
+
appiumSettings?.snapshotMaxDepth ?? 62;
|
|
90
|
+
}
|
|
91
|
+
(0, appiumSettings_1.applyAppiumSettingsToCapabilities)(capabilities, appiumSettings, platformName);
|
|
67
92
|
return {
|
|
68
93
|
port: 4723,
|
|
69
|
-
capabilities
|
|
70
|
-
"appium:deviceName": this.project.use.device?.name,
|
|
71
|
-
"appium:udid": udid,
|
|
72
|
-
"appium:automationName": platformName == types_1.Platform.ANDROID ? "uiautomator2" : "xcuitest",
|
|
73
|
-
platformName: platformName,
|
|
74
|
-
"appium:autoGrantPermissions": true,
|
|
75
|
-
"appium:app": this.project.use.buildPath,
|
|
76
|
-
"appium:appActivity": appLaunchableActivity,
|
|
77
|
-
"appium:appPackage": appPackageName,
|
|
78
|
-
"appium:autoAcceptAlerts": true,
|
|
79
|
-
"appium:fullReset": true,
|
|
80
|
-
"appium:deviceOrientation": this.project.use.device?.orientation,
|
|
81
|
-
"appium:settings[snapshotMaxDepth]": 62,
|
|
82
|
-
},
|
|
94
|
+
capabilities,
|
|
83
95
|
};
|
|
84
96
|
}
|
|
85
97
|
}
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAUhF,cAAM,eAAgB,YAAW,QAAQ;IACvC,OAAO,CAAC,gBAAgB,CAAsB;IAE9C,OAAO;IAQP,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAU9C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAUhF,cAAM,eAAgB,YAAW,QAAQ;IACvC,OAAO,CAAC,gBAAgB,CAAsB;IAE9C,OAAO;IAQP,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAU9C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAsGtC,KAAK;YAKG,kCAAkC;IA6ChD,OAAO,CAAC,4BAA4B;IAyBpC,OAAO,CAAC,qBAAqB;CAU9B;AA8ED,eAAe,eAAe,CAAC"}
|
package/dist/reporter.js
CHANGED
|
@@ -35,8 +35,10 @@ class VideoDownloader {
|
|
|
35
35
|
// This is a test that ran with the `device` fixture
|
|
36
36
|
const sessionId = sessionIdAnnotation.description;
|
|
37
37
|
const providerName = providerNameAnnotation.description;
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if (this.providerSupportsVideo(providerName)) {
|
|
39
|
+
const provider = (0, providers_1.getProviderClass)(providerName);
|
|
40
|
+
this.downloadAndAttachDeviceVideo(test, result, provider, sessionId);
|
|
41
|
+
}
|
|
40
42
|
const otherAnnotations = test.annotations.filter(({ type }) => type !== "sessionId" && type !== "providerName");
|
|
41
43
|
test.annotations = otherAnnotations;
|
|
42
44
|
}
|
|
@@ -54,36 +56,43 @@ class VideoDownloader {
|
|
|
54
56
|
// The `onTestEnd` is method is called before the worker ends and
|
|
55
57
|
// the worker's `endTime` is saved to disk. We add a 5 secs delay
|
|
56
58
|
// to prevent a harmful race condition.
|
|
57
|
-
const workerDownload =
|
|
58
|
-
.then(() =>
|
|
59
|
-
|
|
60
|
-
if (!
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
const { providerName, sessionId, endTime } = workerInfo;
|
|
64
|
-
if (!providerName || !sessionId) {
|
|
65
|
-
throw new Error(`Provider name or session id not found for worker: ${workerIndex}`);
|
|
66
|
-
}
|
|
67
|
-
if (!this.providerSupportsVideo(providerName)) {
|
|
68
|
-
return; // Nothing to do here
|
|
59
|
+
const workerDownload = getWorkerInfo(workerIndex)
|
|
60
|
+
.then((initialWorkerInfo) => {
|
|
61
|
+
const providerName = initialWorkerInfo?.providerName;
|
|
62
|
+
if (providerName && !this.providerSupportsVideo(providerName)) {
|
|
63
|
+
return;
|
|
69
64
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (!downloaded) {
|
|
76
|
-
return;
|
|
65
|
+
return waitFiveSeconds()
|
|
66
|
+
.then(() => getWorkerInfo(workerIndex))
|
|
67
|
+
.then(async (workerInfo) => {
|
|
68
|
+
if (!workerInfo) {
|
|
69
|
+
throw new Error(`Worker info not found for idx: ${workerIndex}`);
|
|
77
70
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
71
|
+
const { providerName, sessionId, endTime } = workerInfo;
|
|
72
|
+
if (!providerName || !sessionId) {
|
|
73
|
+
throw new Error(`Provider name or session id not found for worker: ${workerIndex}`);
|
|
74
|
+
}
|
|
75
|
+
if (!this.providerSupportsVideo(providerName)) {
|
|
76
|
+
return; // Nothing to do here
|
|
77
|
+
}
|
|
78
|
+
const workerVideoBaseName = `worker-${workerIndex}-${sessionId}-video`;
|
|
79
|
+
if (endTime) {
|
|
80
|
+
// This is the last test in the worker, so let's download the video
|
|
81
|
+
const provider = (0, providers_1.getProviderClass)(providerName);
|
|
82
|
+
const downloaded = await provider.downloadVideo(sessionId, (0, utils_1.basePath)(), workerVideoBaseName);
|
|
83
|
+
if (!downloaded) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
return this.trimAndAttachPersistentDeviceVideo(test, result, downloaded.path);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// This is an intermediate test in the worker, so let's wait for the
|
|
90
|
+
// video file to be found on disk. Once it is, we trim and attach it.
|
|
91
|
+
const expectedWorkerVideoPath = path_1.default.join((0, utils_1.basePath)(), `${workerVideoBaseName}.mp4`);
|
|
92
|
+
await waitFor(() => fs_1.default.existsSync(expectedWorkerVideoPath));
|
|
93
|
+
return this.trimAndAttachPersistentDeviceVideo(test, result, expectedWorkerVideoPath);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
87
96
|
})
|
|
88
97
|
.catch((e) => {
|
|
89
98
|
logger_1.logger.error("Failed to get worker end time:", e);
|
|
@@ -156,6 +165,10 @@ class VideoDownloader {
|
|
|
156
165
|
this.downloadPromises.push(downloadPromise);
|
|
157
166
|
}
|
|
158
167
|
providerSupportsVideo(providerName) {
|
|
168
|
+
if (providerName === "browserstack" &&
|
|
169
|
+
process.env.APPWRIGHT_DISABLE_VIDEO_DOWNLOAD === "true") {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
159
172
|
const provider = (0, providers_1.getProviderClass)(providerName);
|
|
160
173
|
return !!provider.downloadVideo;
|
|
161
174
|
}
|
|
@@ -73,6 +73,7 @@ let VideoDownloader;
|
|
|
73
73
|
mockBasePath = "";
|
|
74
74
|
getProviderClassMock.mockClear();
|
|
75
75
|
vitest_1.vi.useRealTimers();
|
|
76
|
+
delete process.env.APPWRIGHT_DISABLE_VIDEO_DOWNLOAD;
|
|
76
77
|
if (basePathToDelete) {
|
|
77
78
|
await promises_1.default.rm(basePathToDelete, { recursive: true, force: true });
|
|
78
79
|
}
|
|
@@ -164,4 +165,40 @@ let VideoDownloader;
|
|
|
164
165
|
},
|
|
165
166
|
]);
|
|
166
167
|
});
|
|
168
|
+
(0, vitest_1.test)("skips BrowserStack video handling when video download is disabled", async () => {
|
|
169
|
+
vitest_1.vi.useFakeTimers();
|
|
170
|
+
process.env.APPWRIGHT_DISABLE_VIDEO_DOWNLOAD = "true";
|
|
171
|
+
mockBasePath = await promises_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), "appwright-videos-"));
|
|
172
|
+
const workerIndex = 0;
|
|
173
|
+
const sessionId = "session-xyz";
|
|
174
|
+
const providerName = "browserstack";
|
|
175
|
+
const workerStart = new Date("2025-01-01T00:00:00.000Z");
|
|
176
|
+
await promises_1.default.writeFile(path_1.default.join(mockBasePath, `worker-info-${workerIndex}.json`), JSON.stringify({
|
|
177
|
+
idx: workerIndex,
|
|
178
|
+
sessionId,
|
|
179
|
+
providerName,
|
|
180
|
+
startTime: {
|
|
181
|
+
beforeAppiumSession: workerStart.toISOString(),
|
|
182
|
+
afterAppiumSession: workerStart.toISOString(),
|
|
183
|
+
},
|
|
184
|
+
tests: [],
|
|
185
|
+
}, null, 2));
|
|
186
|
+
const reporter = new VideoDownloader();
|
|
187
|
+
const testCase = {
|
|
188
|
+
id: "test-1",
|
|
189
|
+
title: "persistent",
|
|
190
|
+
annotations: [],
|
|
191
|
+
};
|
|
192
|
+
const testResult = {
|
|
193
|
+
workerIndex,
|
|
194
|
+
duration: 1,
|
|
195
|
+
startTime: new Date("2025-01-01T00:00:10.000Z"),
|
|
196
|
+
attachments: [],
|
|
197
|
+
};
|
|
198
|
+
reporter.onTestEnd(testCase, testResult);
|
|
199
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
200
|
+
await reporter.onEnd();
|
|
201
|
+
(0, vitest_1.expect)(downloadVideoMock).not.toHaveBeenCalled();
|
|
202
|
+
(0, vitest_1.expect)(testResult.attachments).toEqual([]);
|
|
203
|
+
});
|
|
167
204
|
});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -100,6 +100,14 @@ export type BrowserStackConfig = {
|
|
|
100
100
|
* Defaults to Appium 3.1.0. Override if your account requires a different version.
|
|
101
101
|
*/
|
|
102
102
|
appiumVersion?: string;
|
|
103
|
+
/**
|
|
104
|
+
* BrowserStack geolocation code (for example: "HK").
|
|
105
|
+
*/
|
|
106
|
+
geoLocation?: string;
|
|
107
|
+
/**
|
|
108
|
+
* BrowserStack GPS location coordinates ("lat,long").
|
|
109
|
+
*/
|
|
110
|
+
gpsLocation?: string;
|
|
103
111
|
/**
|
|
104
112
|
* Enable BrowserStack App Performance profiling (appProfiling capability).
|
|
105
113
|
* Defaults to false. When true, BrowserStack captures detailed performance metrics.
|
|
@@ -111,6 +119,11 @@ export type BrowserStackConfig = {
|
|
|
111
119
|
* Defaults to 180 seconds (3 minutes).
|
|
112
120
|
*/
|
|
113
121
|
idleTimeout?: number;
|
|
122
|
+
/**
|
|
123
|
+
* Appium settings applied after session start via driver.updateSettings.
|
|
124
|
+
* Use to tune selector/idle behavior for flaky runs.
|
|
125
|
+
*/
|
|
126
|
+
appiumSettings?: AppiumSettings;
|
|
114
127
|
/**
|
|
115
128
|
* iOS app settings to configure at session start.
|
|
116
129
|
* Can include Permission Settings and/or custom Settings Bundle entries.
|
|
@@ -251,6 +264,103 @@ export type AWSDeviceFarmConfig = {
|
|
|
251
264
|
*/
|
|
252
265
|
externalId?: string;
|
|
253
266
|
};
|
|
267
|
+
/**
|
|
268
|
+
* Appium settings for controlling UIAutomator2/XCUITest behavior.
|
|
269
|
+
* These settings affect how Appium interacts with the device during automation.
|
|
270
|
+
*/
|
|
271
|
+
export type AppiumSettings = {
|
|
272
|
+
/**
|
|
273
|
+
* Maximum time (in milliseconds) that UIAutomator2 will wait for the UI to become idle
|
|
274
|
+
* before performing actions. Lower values speed up tests on apps with animations
|
|
275
|
+
* or dynamic content that never become truly "idle".
|
|
276
|
+
* Default: 10000 (10 seconds). Recommended for animated apps: 0-2000.
|
|
277
|
+
* Only applies to Android.
|
|
278
|
+
*/
|
|
279
|
+
waitForIdleTimeout?: number;
|
|
280
|
+
/**
|
|
281
|
+
* Maximum time (in seconds) between Appium commands before the session times out.
|
|
282
|
+
* Useful for long-running tests or tests that include extended wait periods.
|
|
283
|
+
* Default: 60 seconds.
|
|
284
|
+
*/
|
|
285
|
+
newCommandTimeout?: number;
|
|
286
|
+
/**
|
|
287
|
+
* Maximum depth of the element tree snapshot. Higher values capture more nested elements
|
|
288
|
+
* but may slow down element lookups on complex screens.
|
|
289
|
+
* Default: 50. Max recommended: 62.
|
|
290
|
+
* Only applies to Android.
|
|
291
|
+
*/
|
|
292
|
+
snapshotMaxDepth?: number;
|
|
293
|
+
/**
|
|
294
|
+
* Maximum time (in milliseconds) to wait for an element to appear.
|
|
295
|
+
* Only applies to Android.
|
|
296
|
+
*/
|
|
297
|
+
waitForSelectorTimeout?: number;
|
|
298
|
+
/**
|
|
299
|
+
* Timeout (in milliseconds) for UIAutomator2 action acknowledgments.
|
|
300
|
+
* Only applies to Android.
|
|
301
|
+
*/
|
|
302
|
+
actionAcknowledgmentTimeout?: number;
|
|
303
|
+
/**
|
|
304
|
+
* Whether to ignore non-important views in the Android view hierarchy.
|
|
305
|
+
* Only applies to Android.
|
|
306
|
+
*/
|
|
307
|
+
ignoreUnimportantViews?: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* Snapshot timeout (in milliseconds) for Android UIAutomator2.
|
|
310
|
+
* Only applies to Android.
|
|
311
|
+
*/
|
|
312
|
+
customSnapshotTimeout?: number;
|
|
313
|
+
/**
|
|
314
|
+
* Snapshot timeout (in milliseconds) for iOS XCUITest.
|
|
315
|
+
* Only applies to iOS.
|
|
316
|
+
*/
|
|
317
|
+
snapshotTimeout?: number;
|
|
318
|
+
/**
|
|
319
|
+
* Whether to wait for app quiescence on iOS.
|
|
320
|
+
* Only applies to iOS.
|
|
321
|
+
*/
|
|
322
|
+
waitForQuiescence?: boolean;
|
|
323
|
+
/**
|
|
324
|
+
* Cool-off timeout (in milliseconds) for animations on iOS.
|
|
325
|
+
* Only applies to iOS.
|
|
326
|
+
*/
|
|
327
|
+
animationCoolOffTimeout?: number;
|
|
328
|
+
/**
|
|
329
|
+
* Reduce motion on iOS during automation.
|
|
330
|
+
* Only applies to iOS.
|
|
331
|
+
*/
|
|
332
|
+
reduceMotion?: boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Disable window animations on Android.
|
|
335
|
+
* Only applies to Android.
|
|
336
|
+
*/
|
|
337
|
+
disableWindowAnimation?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Skip device initialization to speed up Android sessions.
|
|
340
|
+
* Only applies to Android.
|
|
341
|
+
*/
|
|
342
|
+
skipDeviceInitialization?: boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Include Safari in webviews for iOS.
|
|
345
|
+
* Only applies to iOS.
|
|
346
|
+
*/
|
|
347
|
+
includeSafariInWebviews?: boolean;
|
|
348
|
+
/**
|
|
349
|
+
* Allow Appium to auto-download Chromedriver binaries.
|
|
350
|
+
* Only applies to Android.
|
|
351
|
+
*/
|
|
352
|
+
chromedriverAutodownload?: boolean;
|
|
353
|
+
/**
|
|
354
|
+
* BrowserStack page source sampling configuration.
|
|
355
|
+
* Only applies to BrowserStack.
|
|
356
|
+
*/
|
|
357
|
+
bstackPageSource?: {
|
|
358
|
+
enable?: boolean;
|
|
359
|
+
samplesX?: number;
|
|
360
|
+
samplesY?: number;
|
|
361
|
+
maxDepth?: number;
|
|
362
|
+
};
|
|
363
|
+
} & Record<string, unknown>;
|
|
254
364
|
/**
|
|
255
365
|
* Configuration for locally connected physical devices.
|
|
256
366
|
*/
|
|
@@ -266,6 +376,10 @@ export type LocalDeviceConfig = {
|
|
|
266
376
|
* Default orientation is "portrait".
|
|
267
377
|
*/
|
|
268
378
|
orientation?: DeviceOrientation;
|
|
379
|
+
/**
|
|
380
|
+
* Appium settings for controlling UIAutomator2/XCUITest behavior.
|
|
381
|
+
*/
|
|
382
|
+
appiumSettings?: AppiumSettings;
|
|
269
383
|
};
|
|
270
384
|
/**
|
|
271
385
|
* Configuration for running tests on an Android or iOS emulator.
|
|
@@ -283,6 +397,10 @@ export type EmulatorConfig = {
|
|
|
283
397
|
* Default orientation is "portrait".
|
|
284
398
|
*/
|
|
285
399
|
orientation?: DeviceOrientation;
|
|
400
|
+
/**
|
|
401
|
+
* Appium settings for controlling UIAutomator2/XCUITest behavior.
|
|
402
|
+
*/
|
|
403
|
+
appiumSettings?: AppiumSettings;
|
|
286
404
|
};
|
|
287
405
|
/**
|
|
288
406
|
* iOS permission settings structure (based on BrowserStack API).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samsara-dev/appwright",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"form-data": "4.0.5",
|
|
51
51
|
"node-fetch": "^3.3.2",
|
|
52
52
|
"picocolors": "^1.1.0",
|
|
53
|
-
"webdriver": "^8.36.1"
|
|
53
|
+
"webdriver": "^8.36.1",
|
|
54
|
+
"gpt-driver-node": "^1.0.4"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@changesets/cli": "^2.29.8",
|