@allwright.dev/vitest 0.1.19 → 0.1.21
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 +38 -7
- package/dist/expectations.js +7 -6
- package/dist/index.d.ts +10 -1
- package/dist/index.js +64 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @allwright.dev/vitest
|
|
2
2
|
|
|
3
3
|
Vitest fixtures for allwright with Playwright-style `browser` and `page`
|
|
4
|
-
injection, plus Android and
|
|
4
|
+
injection, plus Android, iOS, and macOS app fixtures for native and hybrid tests.
|
|
5
5
|
|
|
6
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.
|
|
7
7
|
|
|
@@ -40,9 +40,14 @@ test("opens an Android app", async ({ androidApp }) => {
|
|
|
40
40
|
test("opens an iOS app", async ({ iosApp }) => {
|
|
41
41
|
await iosApp.getByRole("button", { name: "Login", exact: true }).click();
|
|
42
42
|
});
|
|
43
|
+
|
|
44
|
+
test("opens a macOS app", async ({ macosApp }) => {
|
|
45
|
+
await macosApp.getByRole("button", { name: "New Document", exact: true }).click();
|
|
46
|
+
});
|
|
43
47
|
```
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
Checked-in example specs live in [examples/basic.spec.ts](./examples/basic.spec.ts)
|
|
50
|
+
and [examples/ios-flights.spec.ts](./examples/ios-flights.spec.ts).
|
|
46
51
|
|
|
47
52
|
The fixture package reads the shared stack-agnostic config format through `@allwright.dev/core`.
|
|
48
53
|
Use `allwright.config.yaml` by default, or `allwright.config.json` if you prefer. Both follow the same root schema in `allwright.schema.json`.
|
|
@@ -139,11 +144,34 @@ test("logs in", async ({ iosApp }) => {
|
|
|
139
144
|
});
|
|
140
145
|
```
|
|
141
146
|
|
|
147
|
+
macOS apps use an installed application bundle identifier. The fixture starts
|
|
148
|
+
the bundled desktop XCUITest runner and launches the configured app lazily:
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
# allwright.config.yaml
|
|
152
|
+
desktop:
|
|
153
|
+
mac:
|
|
154
|
+
app:
|
|
155
|
+
id: com.apple.TextEdit
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { expect, test } from "@allwright.dev/vitest";
|
|
160
|
+
|
|
161
|
+
test("opens a document window", async ({ macosApp }) => {
|
|
162
|
+
await macosApp.getByRole("button", { name: "New Document", exact: true }).click();
|
|
163
|
+
await expect(macosApp.getByRole("textField")).toBeVisible();
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Use `ALLWRIGHT_MAC_AGENT_ENDPOINT` for an external agent or
|
|
168
|
+
`ALLWRIGHT_MAC_APP_ID` to override the configured bundle identifier.
|
|
169
|
+
|
|
142
170
|
Fixtures are lazy on first use. Injecting `browser`, `page`, `android`,
|
|
143
|
-
`androidApp`, `ios`, or `
|
|
144
|
-
underlying session is created only when the test first
|
|
145
|
-
through that fixture. Sync metadata properties are only
|
|
146
|
-
lazy fixture has been realized by a prior awaited call.
|
|
171
|
+
`androidApp`, `ios`, `iosApp`, `macos`, or `macosApp` does not launch or connect
|
|
172
|
+
immediately; the underlying session is created only when the test first
|
|
173
|
+
performs an action through that fixture. Sync metadata properties are only
|
|
174
|
+
available after the lazy fixture has been realized by a prior awaited call.
|
|
147
175
|
|
|
148
176
|
Available fixtures:
|
|
149
177
|
|
|
@@ -153,11 +181,14 @@ Available fixtures:
|
|
|
153
181
|
- `androidApp`: launched Android app page
|
|
154
182
|
- `ios`: connected iOS device session
|
|
155
183
|
- `iosApp`: launched iOS app page
|
|
184
|
+
- `macos`: connected macOS desktop session
|
|
185
|
+
- `macosApp`: launched macOS app page
|
|
156
186
|
|
|
157
187
|
`androidApp` launches using `allwright.android.launchOptions` first, then falls back to `config.mobile.android`.
|
|
158
188
|
`iosApp` does the same with `allwright.ios.launchOptions` and `config.mobile.ios`.
|
|
189
|
+
`macosApp` does the same with `allwright.macos.launchOptions` and `config.desktop.mac`.
|
|
159
190
|
|
|
160
|
-
Android and
|
|
191
|
+
Android, iOS, and macOS apps and locators support the native action and expectation
|
|
161
192
|
subset: `click`, `count`, `focus`, `fill`, `press`, `textContent`, `innerText`,
|
|
162
193
|
`waitForSelector`, and `screenshot`. Mobile expectations provide `toHaveText`,
|
|
163
194
|
`toContainText`, `toHaveCount`, and `toBeVisible` with the same retry controls
|
package/dist/expectations.js
CHANGED
|
@@ -46,14 +46,15 @@ function expectedText(expected) {
|
|
|
46
46
|
}
|
|
47
47
|
async function isVisible(locator, command) {
|
|
48
48
|
if ("filter" in locator) {
|
|
49
|
-
return (await locator.filter({ visible: true }).count(command))
|
|
49
|
+
return (await locator.filter({ visible: true }).count(command)) > 0;
|
|
50
50
|
}
|
|
51
51
|
// Android has no visibility-filter query. An absent node is not visible; only
|
|
52
52
|
// its explicit native visibility failure is a negative observation.
|
|
53
|
-
if ((await locator.count(command))
|
|
53
|
+
if ((await locator.count(command)) === 0)
|
|
54
54
|
return false;
|
|
55
55
|
try {
|
|
56
|
-
|
|
56
|
+
await locator.waitFor({ ...command, visible: true });
|
|
57
|
+
return true;
|
|
57
58
|
}
|
|
58
59
|
catch (error) {
|
|
59
60
|
if (error instanceof Error && error.message.startsWith("selector found but not visible: "))
|
|
@@ -67,7 +68,7 @@ export function createLocatorExpect(locator, defaults, negated = false) {
|
|
|
67
68
|
get not() { return callableMatchers(createLocatorExpect(locator, defaults, !negated)); },
|
|
68
69
|
async toHaveText(expected, options = {}) {
|
|
69
70
|
await retryExpectation(async (command) => {
|
|
70
|
-
const
|
|
71
|
+
const text = await locator.textContent(command);
|
|
71
72
|
if (expected instanceof RegExp)
|
|
72
73
|
assertion(text).toMatch(new RegExp(expected.source, expected.flags));
|
|
73
74
|
else
|
|
@@ -76,7 +77,7 @@ export function createLocatorExpect(locator, defaults, negated = false) {
|
|
|
76
77
|
},
|
|
77
78
|
async toContainText(expected, options = {}) {
|
|
78
79
|
await retryExpectation(async (command) => {
|
|
79
|
-
const
|
|
80
|
+
const text = await locator.textContent(command);
|
|
80
81
|
if (expected instanceof RegExp)
|
|
81
82
|
assertion(text).toMatch(new RegExp(expected.source, expected.flags));
|
|
82
83
|
else
|
|
@@ -85,7 +86,7 @@ export function createLocatorExpect(locator, defaults, negated = false) {
|
|
|
85
86
|
},
|
|
86
87
|
async toHaveCount(expected, options = {}) {
|
|
87
88
|
await retryExpectation(async (command) => {
|
|
88
|
-
assertion(
|
|
89
|
+
assertion(await locator.count(command)).toBe(expected);
|
|
89
90
|
}, options, defaults());
|
|
90
91
|
},
|
|
91
92
|
async toBeVisible(options = {}) {
|
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 MobileIosConnectOptions, type MobileIosDevice, type MobileIosLaunchOptions, type MobileIosApp, 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 DesktopMacApp, type DesktopMacConnectOptions, type DesktopMacDesktop, type DesktopMacLaunchOptions, 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;
|
|
@@ -15,6 +15,10 @@ export interface AllwrightVitestOptions {
|
|
|
15
15
|
connectOptions?: MobileIosConnectOptions;
|
|
16
16
|
launchOptions?: MobileIosLaunchOptions;
|
|
17
17
|
};
|
|
18
|
+
macos?: {
|
|
19
|
+
connectOptions?: DesktopMacConnectOptions;
|
|
20
|
+
launchOptions?: DesktopMacLaunchOptions;
|
|
21
|
+
};
|
|
18
22
|
configFile?: string;
|
|
19
23
|
suite?: string;
|
|
20
24
|
}
|
|
@@ -25,6 +29,8 @@ export interface AllwrightVitestFixtures {
|
|
|
25
29
|
androidApp: MobileAndroidApp;
|
|
26
30
|
ios: MobileIosDevice;
|
|
27
31
|
iosApp: MobileIosApp;
|
|
32
|
+
macos: DesktopMacDesktop;
|
|
33
|
+
macosApp: DesktopMacApp;
|
|
28
34
|
}
|
|
29
35
|
interface LazyResource<T> {
|
|
30
36
|
peek(): T | null;
|
|
@@ -38,10 +44,13 @@ export declare const test: import("vitest").TestAPI<{
|
|
|
38
44
|
androidApp: MobileAndroidApp;
|
|
39
45
|
ios: MobileIosDevice;
|
|
40
46
|
iosApp: MobileAndroidApp;
|
|
47
|
+
macos: DesktopMacDesktop;
|
|
48
|
+
macosApp: MobileAndroidApp;
|
|
41
49
|
allwright: AllwrightVitestOptions;
|
|
42
50
|
_browserResource: LazyResource<Browser>;
|
|
43
51
|
_androidResource: LazyResource<MobileAndroidDevice>;
|
|
44
52
|
_iosResource: LazyResource<MobileIosDevice>;
|
|
53
|
+
_macosResource: LazyResource<DesktopMacDesktop>;
|
|
45
54
|
}>;
|
|
46
55
|
type VitestExpect = typeof vitestExpect;
|
|
47
56
|
interface AllwrightExpect extends VitestExpect {
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createLocatorExpect, createPageExpect } from "./expectations.js";
|
|
2
|
-
import { launchConfiguredBrowser, mobile, resolveConfig, setServerAddr, } from "@allwright.dev/core";
|
|
2
|
+
import { launchConfiguredBrowser, desktop, mobile, resolveConfig, setServerAddr, } from "@allwright.dev/core";
|
|
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
6
|
const DEFAULT_IOS_CONNECT_TIMEOUT_MS = 30_000;
|
|
7
7
|
const DEFAULT_IOS_LAUNCH_TIMEOUT_MS = 60_000;
|
|
8
|
+
const DEFAULT_MACOS_CONNECT_TIMEOUT_MS = 30_000;
|
|
9
|
+
const DEFAULT_MACOS_LAUNCH_TIMEOUT_MS = 60_000;
|
|
8
10
|
function createLazyResource(factory) {
|
|
9
11
|
let value = null;
|
|
10
12
|
let promise = null;
|
|
@@ -355,6 +357,12 @@ function createLazyMobileApp(appResource) {
|
|
|
355
357
|
async registerHook(type) {
|
|
356
358
|
return (await appResource.get()).registerHook(type);
|
|
357
359
|
},
|
|
360
|
+
async goto(url, options) {
|
|
361
|
+
return (await appResource.get()).goto(url, options);
|
|
362
|
+
},
|
|
363
|
+
async navigate(url, options) {
|
|
364
|
+
return (await appResource.get()).navigate(url, options);
|
|
365
|
+
},
|
|
358
366
|
async click(selector, options) {
|
|
359
367
|
return (await appResource.get()).click(selector, options);
|
|
360
368
|
},
|
|
@@ -473,6 +481,20 @@ function createLazyIosDevice(deviceResource) {
|
|
|
473
481
|
},
|
|
474
482
|
};
|
|
475
483
|
}
|
|
484
|
+
function createLazyMacosDesktop(desktopResource) {
|
|
485
|
+
const initialAppResource = createLazyResource(async () => (await desktopResource.get()).app());
|
|
486
|
+
return {
|
|
487
|
+
get sessionId() {
|
|
488
|
+
return getLazySyncProperty(desktopResource, "sessionId");
|
|
489
|
+
},
|
|
490
|
+
app() {
|
|
491
|
+
return createLazyMobileApp(initialAppResource);
|
|
492
|
+
},
|
|
493
|
+
async launch(options) {
|
|
494
|
+
return (await desktopResource.get()).launch(options);
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
}
|
|
476
498
|
export const test = base.extend({
|
|
477
499
|
allwright: async ({}, use) => {
|
|
478
500
|
await use({});
|
|
@@ -510,6 +532,14 @@ export const test = base.extend({
|
|
|
510
532
|
const iosResource = createLazyResource(async () => mobile.ios.connect(resolveIosConnectOptions(config, allwright)));
|
|
511
533
|
await use(iosResource);
|
|
512
534
|
},
|
|
535
|
+
_macosResource: async ({ allwright }, use) => {
|
|
536
|
+
const config = resolveVitestConfig(allwright);
|
|
537
|
+
if (config.serverAddr) {
|
|
538
|
+
setServerAddr(config.serverAddr);
|
|
539
|
+
}
|
|
540
|
+
const macosResource = createLazyResource(async () => desktop.mac.connect(resolveMacosConnectOptions(config, allwright)));
|
|
541
|
+
await use(macosResource);
|
|
542
|
+
},
|
|
513
543
|
browser: async ({ _browserResource }, use) => {
|
|
514
544
|
try {
|
|
515
545
|
await use(createLazyBrowser(_browserResource));
|
|
@@ -543,6 +573,17 @@ export const test = base.extend({
|
|
|
543
573
|
});
|
|
544
574
|
await use(createLazyMobileApp(appResource));
|
|
545
575
|
},
|
|
576
|
+
macos: async ({ _macosResource }, use) => {
|
|
577
|
+
await use(createLazyMacosDesktop(_macosResource));
|
|
578
|
+
},
|
|
579
|
+
macosApp: async ({ _macosResource, allwright }, use) => {
|
|
580
|
+
const appResource = createLazyResource(async () => {
|
|
581
|
+
const config = resolveVitestConfig(allwright);
|
|
582
|
+
const launchOptions = resolveMacosLaunchOptions(config, allwright);
|
|
583
|
+
return (await _macosResource.get()).launch(launchOptions);
|
|
584
|
+
});
|
|
585
|
+
await use(createLazyMobileApp(appResource));
|
|
586
|
+
},
|
|
546
587
|
});
|
|
547
588
|
function isPage(value) {
|
|
548
589
|
return !!value && typeof value === "object" && typeof value.locator === "function";
|
|
@@ -626,6 +667,28 @@ function resolveIosLaunchOptions(config, options) {
|
|
|
626
667
|
}
|
|
627
668
|
return launchOptions;
|
|
628
669
|
}
|
|
670
|
+
function resolveMacosConnectOptions(config, options) {
|
|
671
|
+
return {
|
|
672
|
+
agentEndpoint: options.macos?.connectOptions?.agentEndpoint ??
|
|
673
|
+
process.env.ALLWRIGHT_MAC_AGENT_ENDPOINT,
|
|
674
|
+
timeoutMs: options.macos?.connectOptions?.timeoutMs ??
|
|
675
|
+
DEFAULT_MACOS_CONNECT_TIMEOUT_MS,
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
function resolveMacosLaunchOptions(config, options) {
|
|
679
|
+
const appId = options.macos?.launchOptions?.appId ??
|
|
680
|
+
process.env.ALLWRIGHT_MAC_APP_ID ??
|
|
681
|
+
config.desktop.mac?.appId;
|
|
682
|
+
if (!appId) {
|
|
683
|
+
throw new Error("macosApp fixture requires macOS launch options with `appId`, or config.desktop.mac.app configured");
|
|
684
|
+
}
|
|
685
|
+
return {
|
|
686
|
+
appId,
|
|
687
|
+
terminateRunning: options.macos?.launchOptions?.terminateRunning ?? false,
|
|
688
|
+
timeoutMs: options.macos?.launchOptions?.timeoutMs ??
|
|
689
|
+
DEFAULT_MACOS_LAUNCH_TIMEOUT_MS,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
629
692
|
let activeExpectDefaults = {};
|
|
630
693
|
function currentExpectDefaults() {
|
|
631
694
|
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.21",
|
|
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.21"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"typescript": "^5.9.2",
|