@allwright.dev/vitest 0.1.15 → 0.1.16
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 +48 -3
- package/dist/index.d.ts +10 -1
- package/dist/index.js +77 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @allwright.dev/vitest
|
|
2
2
|
|
|
3
|
-
Vitest fixtures for allwright with Playwright-style `browser` and `page`
|
|
3
|
+
Vitest fixtures for allwright with Playwright-style `browser` and `page`
|
|
4
|
+
injection, plus Android and iOS mobile fixtures for native and hybrid tests.
|
|
4
5
|
|
|
5
6
|
Wrap the Vitest configuration with `allwrightVitestConfig`. It starts Allwright once before workers run and shuts it down once after the complete test run. Existing user global setup files remain supported and run after Allwright starts, then tear down before Allwright stops.
|
|
6
7
|
|
|
@@ -35,6 +36,10 @@ test("opens a page", async ({ page }) => {
|
|
|
35
36
|
test("opens an Android app", async ({ androidApp }) => {
|
|
36
37
|
await androidApp.click('Id=com.example.airticket:id/bottom_nav_account');
|
|
37
38
|
});
|
|
39
|
+
|
|
40
|
+
test("opens an iOS app", async ({ iosApp }) => {
|
|
41
|
+
await iosApp.locator("text=Login").click();
|
|
42
|
+
});
|
|
38
43
|
```
|
|
39
44
|
|
|
40
45
|
A checked-in example spec also lives in [examples/basic.spec.ts](./examples/basic.spec.ts).
|
|
@@ -105,7 +110,40 @@ test("hybrid web and android", async ({ page, androidApp }) => {
|
|
|
105
110
|
});
|
|
106
111
|
```
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
iOS uses the same app and locator shape. Configure the native agent endpoint
|
|
114
|
+
and bundle identifier once, then keep platform bootstrap out of test bodies:
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
# allwright.config.yaml
|
|
118
|
+
mobile:
|
|
119
|
+
ios:
|
|
120
|
+
device: iPhone 17 Pro
|
|
121
|
+
app:
|
|
122
|
+
binary: https://allwright.dev/Flights-simulator.ipa
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Set `ALLWRIGHT_IOS_AGENT_ENDPOINT` when the agent is not reachable at
|
|
126
|
+
`http://127.0.0.1:8100`. The app value may also be a local `.app`, `.zip`, or
|
|
127
|
+
`.ipa`; the fixture downloads/extracts it when needed, installs it on the
|
|
128
|
+
selected simulator, derives its bundle identifier, and launches it. Override
|
|
129
|
+
it with `ALLWRIGHT_IOS_APP_PATH`. No manual installation or polling belongs in
|
|
130
|
+
the test. The test remains platform-client code only:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { expect, test } from "@allwright.dev/vitest";
|
|
134
|
+
|
|
135
|
+
test("logs in", async ({ iosApp }) => {
|
|
136
|
+
await iosApp.locator("text=Login").click();
|
|
137
|
+
await iosApp.locator("className=XCUIElementTypeTextField").fill("user@example.com");
|
|
138
|
+
await expect(iosApp.locator("text=Welcome back")).toBeVisible();
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Fixtures are lazy on first use. Injecting `browser`, `page`, `android`,
|
|
143
|
+
`androidApp`, `ios`, or `iosApp` does not launch or connect immediately; the
|
|
144
|
+
underlying session is created only when the test first performs an action
|
|
145
|
+
through that fixture. Sync metadata properties are only available after the
|
|
146
|
+
lazy fixture has been realized by a prior awaited call.
|
|
109
147
|
|
|
110
148
|
Available fixtures:
|
|
111
149
|
|
|
@@ -113,10 +151,17 @@ Available fixtures:
|
|
|
113
151
|
- `page`: initial web page
|
|
114
152
|
- `android`: connected Android device session
|
|
115
153
|
- `androidApp`: launched Android app page
|
|
154
|
+
- `ios`: connected iOS device session
|
|
155
|
+
- `iosApp`: launched iOS app page
|
|
116
156
|
|
|
117
157
|
`androidApp` launches using `allwright.android.launchOptions` first, then falls back to `config.mobile.android`.
|
|
158
|
+
`iosApp` does the same with `allwright.ios.launchOptions` and `config.mobile.ios`.
|
|
118
159
|
|
|
119
|
-
Android apps and locators support the
|
|
160
|
+
Android and iOS apps and locators support the mobile action and expectation
|
|
161
|
+
subset: `click`, `count`, `focus`, `fill`, `press`, `textContent`, `innerText`,
|
|
162
|
+
`waitForSelector`, and `screenshot`. Mobile expectations provide `toHaveText`,
|
|
163
|
+
`toContainText`, `toHaveCount`, and `toBeVisible` with the same retry controls
|
|
164
|
+
as web fixtures. Hover and highlight remain web-only.
|
|
120
165
|
|
|
121
166
|
The opt-in accessibility integration test exercises the public page fixture,
|
|
122
167
|
bundled protobuf, running engine and dynamically loaded web plugin. From this
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PageExpectMatchers, LocatorExpectMatchers, MobilePageExpectMatchers, MobileLocatorExpectMatchers } from "./expectations.js";
|
|
2
2
|
export type { RetryExpectationOptions, TextExpectationOptions, VisibleExpectationOptions, SelectedOptionExpectation, PageExpectMatchers, LocatorExpectMatchers, MobilePageExpectMatchers, MobileLocatorExpectMatchers } from "./expectations.js";
|
|
3
|
-
import { type MobileAndroidConnectOptions, type MobileAndroidDevice, type MobileAndroidLaunchOptions, type MobileAndroidApp, type Browser, type BrowserKind, type LaunchOptions, type Locator, type MobileAndroidLocator, type Page } from "@allwright.dev/core";
|
|
3
|
+
import { type MobileAndroidConnectOptions, type MobileAndroidDevice, type MobileAndroidLaunchOptions, type MobileAndroidApp, type MobileIosConnectOptions, type MobileIosDevice, type MobileIosLaunchOptions, type MobileIosApp, type Browser, type BrowserKind, type LaunchOptions, type Locator, type MobileAndroidLocator, type Page } from "@allwright.dev/core";
|
|
4
4
|
import { expect as vitestExpect, type Assertion } from "vitest";
|
|
5
5
|
export interface AllwrightVitestOptions {
|
|
6
6
|
launchOptions?: LaunchOptions;
|
|
@@ -11,6 +11,10 @@ export interface AllwrightVitestOptions {
|
|
|
11
11
|
connectOptions?: MobileAndroidConnectOptions;
|
|
12
12
|
launchOptions?: MobileAndroidLaunchOptions;
|
|
13
13
|
};
|
|
14
|
+
ios?: {
|
|
15
|
+
connectOptions?: MobileIosConnectOptions;
|
|
16
|
+
launchOptions?: MobileIosLaunchOptions;
|
|
17
|
+
};
|
|
14
18
|
configFile?: string;
|
|
15
19
|
suite?: string;
|
|
16
20
|
}
|
|
@@ -19,6 +23,8 @@ export interface AllwrightVitestFixtures {
|
|
|
19
23
|
page: Page;
|
|
20
24
|
android: MobileAndroidDevice;
|
|
21
25
|
androidApp: MobileAndroidApp;
|
|
26
|
+
ios: MobileIosDevice;
|
|
27
|
+
iosApp: MobileIosApp;
|
|
22
28
|
}
|
|
23
29
|
interface LazyResource<T> {
|
|
24
30
|
peek(): T | null;
|
|
@@ -30,9 +36,12 @@ export declare const test: import("vitest").TestAPI<{
|
|
|
30
36
|
page: Page;
|
|
31
37
|
android: MobileAndroidDevice;
|
|
32
38
|
androidApp: MobileAndroidApp;
|
|
39
|
+
ios: MobileIosDevice;
|
|
40
|
+
iosApp: MobileAndroidApp;
|
|
33
41
|
allwright: AllwrightVitestOptions;
|
|
34
42
|
_browserResource: LazyResource<Browser>;
|
|
35
43
|
_androidResource: LazyResource<MobileAndroidDevice>;
|
|
44
|
+
_iosResource: LazyResource<MobileIosDevice>;
|
|
36
45
|
}>;
|
|
37
46
|
type VitestExpect = typeof vitestExpect;
|
|
38
47
|
interface AllwrightExpect extends VitestExpect {
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import { launchConfiguredBrowser, mobile, resolveConfig, setServerAddr, } from "
|
|
|
3
3
|
import { expect as vitestExpect, test as base } from "vitest";
|
|
4
4
|
const DEFAULT_ANDROID_CONNECT_TIMEOUT_MS = 30_000;
|
|
5
5
|
const DEFAULT_ANDROID_LAUNCH_TIMEOUT_MS = 60_000;
|
|
6
|
+
const DEFAULT_IOS_CONNECT_TIMEOUT_MS = 30_000;
|
|
7
|
+
const DEFAULT_IOS_LAUNCH_TIMEOUT_MS = 60_000;
|
|
6
8
|
function createLazyResource(factory) {
|
|
7
9
|
let value = null;
|
|
8
10
|
let promise = null;
|
|
@@ -330,13 +332,13 @@ function createLazyBrowser(browserResource) {
|
|
|
330
332
|
};
|
|
331
333
|
return lazyBrowser;
|
|
332
334
|
}
|
|
333
|
-
function
|
|
335
|
+
function createLazyMobileApp(appResource) {
|
|
334
336
|
const lazyApp = {
|
|
335
337
|
get sessionId() {
|
|
336
338
|
return getLazySyncProperty(appResource, "sessionId");
|
|
337
339
|
},
|
|
338
340
|
locator(selector) {
|
|
339
|
-
return
|
|
341
|
+
return createLazyMobileLocator(appResource, async () => selector);
|
|
340
342
|
},
|
|
341
343
|
async registerHook(type) {
|
|
342
344
|
return (await appResource.get()).registerHook(type);
|
|
@@ -374,13 +376,13 @@ function createLazyAndroidApp(appResource) {
|
|
|
374
376
|
};
|
|
375
377
|
return lazyApp;
|
|
376
378
|
}
|
|
377
|
-
function
|
|
379
|
+
function createLazyMobileLocator(appResource, selectorFactory) {
|
|
378
380
|
const lazyLocator = {
|
|
379
381
|
get page() {
|
|
380
|
-
return
|
|
382
|
+
return createLazyMobileApp(appResource);
|
|
381
383
|
},
|
|
382
384
|
get selector() {
|
|
383
|
-
throw new Error("lazy
|
|
385
|
+
throw new Error("lazy mobile locator selector is not available before the app fixture is initialized");
|
|
384
386
|
},
|
|
385
387
|
async click(options) {
|
|
386
388
|
return (await appResource.get()).locator(await selectorFactory()).click(options);
|
|
@@ -407,7 +409,7 @@ function createLazyAndroidLocator(appResource, selectorFactory) {
|
|
|
407
409
|
return (await appResource.get()).locator(await selectorFactory()).waitFor(options);
|
|
408
410
|
},
|
|
409
411
|
locator(selector) {
|
|
410
|
-
return
|
|
412
|
+
return createLazyMobileLocator(appResource, async () => (await appResource.get()).locator(await selectorFactory()).locator(selector).selector);
|
|
411
413
|
},
|
|
412
414
|
};
|
|
413
415
|
return lazyLocator;
|
|
@@ -419,10 +421,10 @@ function createLazyAndroidDevice(deviceResource) {
|
|
|
419
421
|
return getLazySyncProperty(deviceResource, "sessionId");
|
|
420
422
|
},
|
|
421
423
|
app() {
|
|
422
|
-
return
|
|
424
|
+
return createLazyMobileApp(initialAppResource);
|
|
423
425
|
},
|
|
424
426
|
initialApp() {
|
|
425
|
-
return
|
|
427
|
+
return createLazyMobileApp(initialAppResource);
|
|
426
428
|
},
|
|
427
429
|
async launch(options) {
|
|
428
430
|
return (await deviceResource.get()).launch(options);
|
|
@@ -430,6 +432,23 @@ function createLazyAndroidDevice(deviceResource) {
|
|
|
430
432
|
};
|
|
431
433
|
return lazyDevice;
|
|
432
434
|
}
|
|
435
|
+
function createLazyIosDevice(deviceResource) {
|
|
436
|
+
const initialAppResource = createLazyResource(async () => (await deviceResource.get()).app());
|
|
437
|
+
return {
|
|
438
|
+
get sessionId() {
|
|
439
|
+
return getLazySyncProperty(deviceResource, "sessionId");
|
|
440
|
+
},
|
|
441
|
+
app() {
|
|
442
|
+
return createLazyMobileApp(initialAppResource);
|
|
443
|
+
},
|
|
444
|
+
initialApp() {
|
|
445
|
+
return createLazyMobileApp(initialAppResource);
|
|
446
|
+
},
|
|
447
|
+
async launch(options) {
|
|
448
|
+
return (await deviceResource.get()).launch(options);
|
|
449
|
+
},
|
|
450
|
+
};
|
|
451
|
+
}
|
|
433
452
|
export const test = base.extend({
|
|
434
453
|
allwright: async ({}, use) => {
|
|
435
454
|
await use({});
|
|
@@ -459,6 +478,14 @@ export const test = base.extend({
|
|
|
459
478
|
const androidResource = createLazyResource(async () => mobile.android.connect(resolveAndroidConnectOptions(config, allwright)));
|
|
460
479
|
await use(androidResource);
|
|
461
480
|
},
|
|
481
|
+
_iosResource: async ({ allwright }, use) => {
|
|
482
|
+
const config = resolveVitestConfig(allwright);
|
|
483
|
+
if (config.serverAddr) {
|
|
484
|
+
setServerAddr(config.serverAddr);
|
|
485
|
+
}
|
|
486
|
+
const iosResource = createLazyResource(async () => mobile.ios.connect(resolveIosConnectOptions(config, allwright)));
|
|
487
|
+
await use(iosResource);
|
|
488
|
+
},
|
|
462
489
|
browser: async ({ _browserResource }, use) => {
|
|
463
490
|
try {
|
|
464
491
|
await use(createLazyBrowser(_browserResource));
|
|
@@ -479,7 +506,18 @@ export const test = base.extend({
|
|
|
479
506
|
const launchOptions = resolveAndroidLaunchOptions(config, allwright);
|
|
480
507
|
return (await _androidResource.get()).launch(launchOptions);
|
|
481
508
|
});
|
|
482
|
-
await use(
|
|
509
|
+
await use(createLazyMobileApp(appResource));
|
|
510
|
+
},
|
|
511
|
+
ios: async ({ _iosResource }, use) => {
|
|
512
|
+
await use(createLazyIosDevice(_iosResource));
|
|
513
|
+
},
|
|
514
|
+
iosApp: async ({ _iosResource, allwright }, use) => {
|
|
515
|
+
const appResource = createLazyResource(async () => {
|
|
516
|
+
const config = resolveVitestConfig(allwright);
|
|
517
|
+
const launchOptions = resolveIosLaunchOptions(config, allwright);
|
|
518
|
+
return (await _iosResource.get()).launch(launchOptions);
|
|
519
|
+
});
|
|
520
|
+
await use(createLazyMobileApp(appResource));
|
|
483
521
|
},
|
|
484
522
|
});
|
|
485
523
|
function isPage(value) {
|
|
@@ -498,7 +536,7 @@ function resolveVitestConfig(options) {
|
|
|
498
536
|
});
|
|
499
537
|
return {
|
|
500
538
|
...config,
|
|
501
|
-
serverAddr: options.serverAddr ?? config.serverAddr,
|
|
539
|
+
serverAddr: options.serverAddr ?? process.env.ALLWRIGHT_SERVER_ADDR ?? config.serverAddr,
|
|
502
540
|
browserName: options.browser ?? config.browserName,
|
|
503
541
|
browserBinary: options.browserBinary ?? config.browserBinary,
|
|
504
542
|
launchOptions: {
|
|
@@ -535,6 +573,35 @@ function resolveAndroidLaunchOptions(config, options) {
|
|
|
535
573
|
}
|
|
536
574
|
return launchOptions;
|
|
537
575
|
}
|
|
576
|
+
function resolveIosConnectOptions(config, options) {
|
|
577
|
+
return {
|
|
578
|
+
device: options.ios?.connectOptions?.device ??
|
|
579
|
+
process.env.ALLWRIGHT_IOS_DEVICE ??
|
|
580
|
+
config.mobile.ios?.device,
|
|
581
|
+
agentEndpoint: options.ios?.connectOptions?.agentEndpoint ??
|
|
582
|
+
process.env.ALLWRIGHT_IOS_AGENT_ENDPOINT,
|
|
583
|
+
preserveAppState: options.ios?.connectOptions?.preserveAppState ?? false,
|
|
584
|
+
timeoutMs: options.ios?.connectOptions?.timeoutMs ??
|
|
585
|
+
DEFAULT_IOS_CONNECT_TIMEOUT_MS,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
function resolveIosLaunchOptions(config, options) {
|
|
589
|
+
const launchOptions = {
|
|
590
|
+
appPath: options.ios?.launchOptions?.appPath ??
|
|
591
|
+
process.env.ALLWRIGHT_IOS_APP_PATH ??
|
|
592
|
+
config.mobile.ios?.appBinary,
|
|
593
|
+
appId: options.ios?.launchOptions?.appId ??
|
|
594
|
+
process.env.ALLWRIGHT_IOS_APP_ID ??
|
|
595
|
+
config.mobile.ios?.appId,
|
|
596
|
+
stopBeforeLaunch: options.ios?.launchOptions?.stopBeforeLaunch ?? false,
|
|
597
|
+
timeoutMs: options.ios?.launchOptions?.timeoutMs ??
|
|
598
|
+
DEFAULT_IOS_LAUNCH_TIMEOUT_MS,
|
|
599
|
+
};
|
|
600
|
+
if (!launchOptions.appPath && !launchOptions.appId) {
|
|
601
|
+
throw new Error("iosApp fixture requires iOS launch options with `appPath` or `appId`, or config.mobile.ios.app configured");
|
|
602
|
+
}
|
|
603
|
+
return launchOptions;
|
|
604
|
+
}
|
|
538
605
|
let activeExpectDefaults = {};
|
|
539
606
|
function currentExpectDefaults() {
|
|
540
607
|
return activeExpectDefaults;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allwright.dev/vitest",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Vitest fixtures for the allwright TypeScript client.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"prepublishOnly": "bun run build"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@allwright.dev/core": "0.1.
|
|
50
|
+
"@allwright.dev/core": "0.1.16"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"typescript": "^5.9.2",
|