@allwright.dev/vitest 0.1.23 → 0.1.25
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 +51 -10
- package/dist/expectations.d.ts +20 -8
- package/dist/expectations.js +83 -18
- package/dist/index.d.ts +10 -1
- package/dist/index.js +87 -0
- 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, iOS, and
|
|
4
|
+
injection, plus Android, iOS, macOS, and Windows 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
|
|
|
@@ -44,10 +44,19 @@ test("opens an iOS app", async ({ iosApp }) => {
|
|
|
44
44
|
test("opens a macOS app", async ({ macosApp }) => {
|
|
45
45
|
await macosApp.getByRole("button", { name: "New Document", exact: true }).click();
|
|
46
46
|
});
|
|
47
|
+
|
|
48
|
+
test("opens a Windows app", async ({ windowsApp }) => {
|
|
49
|
+
await windowsApp.getByRole("textbox").fill("Hello from Allwright");
|
|
50
|
+
});
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
Checked-in example specs
|
|
50
|
-
|
|
53
|
+
Checked-in example specs cover every implemented surface:
|
|
54
|
+
[Web](./examples/basic.spec.ts), [Android](./examples/android-flights.spec.ts),
|
|
55
|
+
[iOS](./examples/ios-flights.spec.ts),
|
|
56
|
+
[macOS](./examples/macos-calculator.spec.ts), and
|
|
57
|
+
[Windows](./examples/windows-notepad.spec.ts). Native specs use the app target
|
|
58
|
+
configured for their surface in `allwright.config.yaml` or
|
|
59
|
+
`allwright.config.json`.
|
|
51
60
|
|
|
52
61
|
The fixture package reads the shared stack-agnostic config format through `@allwright.dev/core`.
|
|
53
62
|
Use `allwright.config.yaml` by default, or `allwright.config.json` if you prefer. Both follow the same root schema in `allwright.schema.json`.
|
|
@@ -167,11 +176,35 @@ test("opens a document window", async ({ macosApp }) => {
|
|
|
167
176
|
Use `ALLWRIGHT_MAC_AGENT_ENDPOINT` for an external agent or
|
|
168
177
|
`ALLWRIGHT_MAC_APP_ID` to override the configured bundle identifier.
|
|
169
178
|
|
|
179
|
+
Windows apps use an executable path, command name, or packaged-app AUMID. The
|
|
180
|
+
fixture starts the bundled FlaUI UIA3 agent and launches the app lazily:
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
# allwright.config.yaml
|
|
184
|
+
desktop:
|
|
185
|
+
windows:
|
|
186
|
+
app:
|
|
187
|
+
id: notepad.exe
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { expect, test } from "@allwright.dev/vitest";
|
|
192
|
+
|
|
193
|
+
test("edits a document", async ({ windowsApp }) => {
|
|
194
|
+
await windowsApp.getByRole("textbox").fill("Hello from Allwright");
|
|
195
|
+
await expect(windowsApp.getByRole("textbox")).toContainText("Hello");
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Use `ALLWRIGHT_WINDOWS_AGENT_ENDPOINT` for an external agent or
|
|
200
|
+
`ALLWRIGHT_WINDOWS_APP_ID` to override the configured application identifier.
|
|
201
|
+
|
|
170
202
|
Fixtures are lazy on first use. Injecting `browser`, `page`, `android`,
|
|
171
|
-
`androidApp`, `ios`, `iosApp`, `macos`,
|
|
172
|
-
immediately; the underlying session is created only
|
|
173
|
-
performs an action through that fixture. Sync metadata
|
|
174
|
-
available after the lazy fixture has been realized by a
|
|
203
|
+
`androidApp`, `ios`, `iosApp`, `macos`, `macosApp`, `windows`, or `windowsApp`
|
|
204
|
+
does not launch or connect immediately; the underlying session is created only
|
|
205
|
+
when the test first performs an action through that fixture. Sync metadata
|
|
206
|
+
properties are only available after the lazy fixture has been realized by a
|
|
207
|
+
prior awaited call.
|
|
175
208
|
|
|
176
209
|
Available fixtures:
|
|
177
210
|
|
|
@@ -183,13 +216,16 @@ Available fixtures:
|
|
|
183
216
|
- `iosApp`: launched iOS app page
|
|
184
217
|
- `macos`: connected macOS desktop session
|
|
185
218
|
- `macosApp`: launched macOS app page
|
|
219
|
+
- `windows`: connected Windows desktop session
|
|
220
|
+
- `windowsApp`: launched Windows app page
|
|
186
221
|
|
|
187
222
|
`androidApp` launches using `allwright.android.launchOptions` first, then falls back to `config.mobile.android`.
|
|
188
223
|
`iosApp` does the same with `allwright.ios.launchOptions` and `config.mobile.ios`.
|
|
189
224
|
`macosApp` does the same with `allwright.macos.launchOptions` and `config.desktop.mac`.
|
|
225
|
+
`windowsApp` does the same with `allwright.windows.launchOptions` and `config.desktop.windows`.
|
|
190
226
|
|
|
191
|
-
Android, iOS, and
|
|
192
|
-
subset: `click`, `count`, `focus`, `fill`, `press`, `textContent`, `innerText`,
|
|
227
|
+
Android, iOS, macOS, and Windows apps and locators support the native action and
|
|
228
|
+
expectation subset: `click`, `count`, `focus`, `fill`, `press`, `textContent`, `innerText`,
|
|
193
229
|
`waitForSelector`, and `screenshot`. Mobile expectations provide `toHaveText`,
|
|
194
230
|
`toContainText`, `toHaveCount`, and `toBeVisible` with the same retry controls
|
|
195
231
|
as web fixtures. Hover and highlight remain web-only.
|
|
@@ -253,13 +289,18 @@ await expect(page.locator('select')).toHaveSelectedOptions(['a', 'b']);
|
|
|
253
289
|
await expect(page.locator('select')).toHaveSelectedOptions([{ value: 'a', label: /Alpha/ }]);
|
|
254
290
|
await expect(page.locator('textarea')).toHaveSelectedText('selected words');
|
|
255
291
|
await expect(page.locator('input[type=checkbox]')).toBeChecked();
|
|
292
|
+
await expect(page.locator('button[type=submit]')).toBeEnabled();
|
|
293
|
+
await expect(page.locator('input')).toBeEditable();
|
|
294
|
+
await expect(page.locator('input')).toBeFocused();
|
|
295
|
+
await expect(page.locator('.spinner')).toBeHidden();
|
|
296
|
+
await expect(page.locator('main')).toBeAttached();
|
|
256
297
|
await expect(page.locator('h1')).toHaveText('Welcome');
|
|
257
298
|
await expect(page.locator('a')).toHaveAttribute('href', /dashboard/);
|
|
258
299
|
await expect(page.locator('button')).toHaveBoundingBox({ width: 100, height: 40 });
|
|
259
300
|
await expect(page.locator('input[type=radio]')).not().toBeChecked();
|
|
260
301
|
```
|
|
261
302
|
|
|
262
|
-
Every element matcher also has a page form, such as `expect(page).toHaveValue('#name', 'Alice')` or `expect(
|
|
303
|
+
Every element matcher also has a page/app form, such as `expect(page).toHaveValue('#name', 'Alice')` or `expect(androidApp).toBeEnabled('text="Continue"')`. Value, checked-state, attribute, bounding-box, attached/hidden, enabled/disabled, focused, and editable matchers work across web, Android, iOS, macOS, and Windows. URL, selected-option, and selected-text matchers remain web-only.
|
|
263
304
|
|
|
264
305
|
All Allwright page/app/locator expectations retry until they match or the timeout expires, including `.not` and `.not()`. Defaults come from the shared assertion configuration, falling back to 5 seconds and a 100 ms interval. Override these with `{ timeoutMs, intervalMs }`. In-flight reads and nested command timeout hints are bounded by the remaining assertion budget; `timeoutMs: 0` makes one observation without polling. Ordinary assertions on already captured values, such as `expect(await page.url()).toBe(...)`, use standard Vitest behavior and do not re-read the page.
|
|
265
306
|
|
package/dist/expectations.d.ts
CHANGED
|
@@ -15,6 +15,16 @@ export interface MobilePageExpectMatchers {
|
|
|
15
15
|
toContainText(selector: string, expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
16
16
|
toHaveCount(selector: string, expected: number, options?: RetryExpectationOptions): Promise<void>;
|
|
17
17
|
toBeVisible(selector: string, options?: VisibleExpectationOptions): Promise<void>;
|
|
18
|
+
toBeHidden(selector: string, options?: VisibleExpectationOptions): Promise<void>;
|
|
19
|
+
toBeAttached(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
20
|
+
toBeEnabled(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
21
|
+
toBeDisabled(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
22
|
+
toBeFocused(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
23
|
+
toBeEditable(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
24
|
+
toHaveValue(selector: string, expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
25
|
+
toBeChecked(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
26
|
+
toHaveAttribute(selector: string, name: string, expected: string | RegExp | null, options?: TextExpectationOptions): Promise<void>;
|
|
27
|
+
toHaveBoundingBox(selector: string, expected: Partial<BoundingBox> | null, options?: TextExpectationOptions): Promise<void>;
|
|
18
28
|
}
|
|
19
29
|
export interface MobileLocatorExpectMatchers {
|
|
20
30
|
readonly not: MobileLocatorExpectMatchers & (() => MobileLocatorExpectMatchers);
|
|
@@ -22,6 +32,16 @@ export interface MobileLocatorExpectMatchers {
|
|
|
22
32
|
toContainText(expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
23
33
|
toHaveCount(expected: number, options?: RetryExpectationOptions): Promise<void>;
|
|
24
34
|
toBeVisible(options?: VisibleExpectationOptions): Promise<void>;
|
|
35
|
+
toBeHidden(options?: VisibleExpectationOptions): Promise<void>;
|
|
36
|
+
toBeAttached(options?: TextExpectationOptions): Promise<void>;
|
|
37
|
+
toBeEnabled(options?: TextExpectationOptions): Promise<void>;
|
|
38
|
+
toBeDisabled(options?: TextExpectationOptions): Promise<void>;
|
|
39
|
+
toBeFocused(options?: TextExpectationOptions): Promise<void>;
|
|
40
|
+
toBeEditable(options?: TextExpectationOptions): Promise<void>;
|
|
41
|
+
toHaveValue(expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
42
|
+
toBeChecked(options?: TextExpectationOptions): Promise<void>;
|
|
43
|
+
toHaveAttribute(name: string, expected: string | RegExp | null, options?: TextExpectationOptions): Promise<void>;
|
|
44
|
+
toHaveBoundingBox(expected: Partial<BoundingBox> | null, options?: TextExpectationOptions): Promise<void>;
|
|
25
45
|
}
|
|
26
46
|
export type SelectedOptionExpectation = string | RegExp | {
|
|
27
47
|
value?: string | RegExp;
|
|
@@ -30,22 +50,14 @@ export type SelectedOptionExpectation = string | RegExp | {
|
|
|
30
50
|
};
|
|
31
51
|
export interface LocatorExpectMatchers extends MobileLocatorExpectMatchers {
|
|
32
52
|
readonly not: LocatorExpectMatchers & (() => LocatorExpectMatchers);
|
|
33
|
-
toHaveValue(expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
34
53
|
toHaveSelectedOptions(expected: SelectedOptionExpectation[], options?: TextExpectationOptions): Promise<void>;
|
|
35
54
|
toHaveSelectedText(expected: string | RegExp | null, options?: TextExpectationOptions): Promise<void>;
|
|
36
|
-
toBeChecked(options?: TextExpectationOptions): Promise<void>;
|
|
37
|
-
toHaveAttribute(name: string, expected: string | RegExp | null, options?: TextExpectationOptions): Promise<void>;
|
|
38
|
-
toHaveBoundingBox(expected: Partial<BoundingBox> | null, options?: TextExpectationOptions): Promise<void>;
|
|
39
55
|
}
|
|
40
56
|
export interface PageExpectMatchers extends MobilePageExpectMatchers {
|
|
41
57
|
readonly not: PageExpectMatchers & (() => PageExpectMatchers);
|
|
42
58
|
toHaveURL(expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
43
|
-
toHaveValue(selector: string, expected: string | RegExp, options?: TextExpectationOptions): Promise<void>;
|
|
44
59
|
toHaveSelectedOptions(selector: string, expected: SelectedOptionExpectation[], options?: TextExpectationOptions): Promise<void>;
|
|
45
60
|
toHaveSelectedText(selector: string, expected: string | RegExp | null, options?: TextExpectationOptions): Promise<void>;
|
|
46
|
-
toBeChecked(selector: string, options?: TextExpectationOptions): Promise<void>;
|
|
47
|
-
toHaveAttribute(selector: string, name: string, expected: string | RegExp | null, options?: TextExpectationOptions): Promise<void>;
|
|
48
|
-
toHaveBoundingBox(selector: string, expected: Partial<BoundingBox> | null, options?: TextExpectationOptions): Promise<void>;
|
|
49
61
|
}
|
|
50
62
|
type Defaults = () => RetryExpectationOptions;
|
|
51
63
|
type AnyLocator = Locator | NativeAppLocator;
|
package/dist/expectations.js
CHANGED
|
@@ -57,11 +57,20 @@ async function isVisible(locator, command) {
|
|
|
57
57
|
return true;
|
|
58
58
|
}
|
|
59
59
|
catch (error) {
|
|
60
|
-
if (error instanceof Error && error.message.startsWith("selector found but not visible: ")
|
|
60
|
+
if (error instanceof Error && (error.message.startsWith("selector found but not visible: ")
|
|
61
|
+
|| error.message.includes("did not become visible")))
|
|
61
62
|
return false;
|
|
62
63
|
throw error;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
async function nativeOrWebState(locator, state, command) {
|
|
67
|
+
const attribute = "filter" in locator ? `__allwright_state_${state}` : state;
|
|
68
|
+
const value = await locator.getAttribute(attribute, command);
|
|
69
|
+
if (value !== "true" && value !== "false") {
|
|
70
|
+
throw new Error(`Element did not expose a ${state} state`);
|
|
71
|
+
}
|
|
72
|
+
return value === "true";
|
|
73
|
+
}
|
|
65
74
|
export function createLocatorExpect(locator, defaults, negated = false) {
|
|
66
75
|
const assertion = (value) => negated ? vitestExpect(value).not : vitestExpect(value);
|
|
67
76
|
const common = {
|
|
@@ -94,18 +103,64 @@ export function createLocatorExpect(locator, defaults, negated = false) {
|
|
|
94
103
|
assertion(await isVisible(locator, command)).toBe(true);
|
|
95
104
|
}, options, defaults());
|
|
96
105
|
},
|
|
106
|
+
async toBeHidden(options = {}) {
|
|
107
|
+
await retryExpectation(async (command) => {
|
|
108
|
+
assertion(await isVisible(locator, command)).toBe(false);
|
|
109
|
+
}, options, defaults());
|
|
110
|
+
},
|
|
111
|
+
async toBeAttached(options = {}) {
|
|
112
|
+
await retryExpectation(async (command) => {
|
|
113
|
+
assertion((await locator.count(command)) > 0).toBe(true);
|
|
114
|
+
}, options, defaults());
|
|
115
|
+
},
|
|
116
|
+
async toBeEnabled(options = {}) {
|
|
117
|
+
await retryExpectation(async (command) => {
|
|
118
|
+
assertion(await nativeOrWebState(locator, "enabled", command)).toBe(true);
|
|
119
|
+
}, options, defaults());
|
|
120
|
+
},
|
|
121
|
+
async toBeDisabled(options = {}) {
|
|
122
|
+
await retryExpectation(async (command) => {
|
|
123
|
+
assertion(await nativeOrWebState(locator, "enabled", command)).toBe(false);
|
|
124
|
+
}, options, defaults());
|
|
125
|
+
},
|
|
126
|
+
async toBeFocused(options = {}) {
|
|
127
|
+
await retryExpectation(async (command) => {
|
|
128
|
+
assertion(await nativeOrWebState(locator, "focused", command)).toBe(true);
|
|
129
|
+
}, options, defaults());
|
|
130
|
+
},
|
|
131
|
+
async toBeEditable(options = {}) {
|
|
132
|
+
await retryExpectation(async (command) => {
|
|
133
|
+
assertion(await nativeOrWebState(locator, "editable", command)).toBe(true);
|
|
134
|
+
}, options, defaults());
|
|
135
|
+
},
|
|
136
|
+
async toHaveValue(expected, options = {}) {
|
|
137
|
+
await retryExpectation(async (command) => assertion(await locator.inputValue(command)).toEqual(expectedText(expected)), options, defaults());
|
|
138
|
+
},
|
|
139
|
+
async toBeChecked(options = {}) {
|
|
140
|
+
await retryExpectation(async (command) => assertion(await locator.isChecked(command)).toBe(true), options, defaults());
|
|
141
|
+
},
|
|
142
|
+
async toHaveAttribute(name, expected, options = {}) {
|
|
143
|
+
await retryExpectation(async (command) => assertion(await locator.getAttribute(name, command)).toEqual(expectedText(expected)), options, defaults());
|
|
144
|
+
},
|
|
145
|
+
async toHaveBoundingBox(expected, options = {}) {
|
|
146
|
+
await retryExpectation(async (command) => assertion(await locator.boundingBox(command)).toEqual(expected === null ? null : vitestExpect.objectContaining(expected)), options, defaults());
|
|
147
|
+
},
|
|
97
148
|
};
|
|
98
|
-
if (!("
|
|
149
|
+
if (!("selectedOptions" in locator))
|
|
99
150
|
return common;
|
|
100
151
|
const web = {
|
|
101
152
|
toHaveText: common.toHaveText,
|
|
102
153
|
toContainText: common.toContainText,
|
|
103
154
|
toHaveCount: common.toHaveCount,
|
|
104
155
|
toBeVisible: common.toBeVisible,
|
|
156
|
+
toBeHidden: common.toBeHidden,
|
|
157
|
+
toBeAttached: common.toBeAttached,
|
|
158
|
+
toBeEnabled: common.toBeEnabled,
|
|
159
|
+
toBeDisabled: common.toBeDisabled,
|
|
160
|
+
toBeFocused: common.toBeFocused,
|
|
161
|
+
toBeEditable: common.toBeEditable,
|
|
105
162
|
get not() { return callableMatchers(createLocatorExpect(locator, defaults, !negated)); },
|
|
106
|
-
|
|
107
|
-
await retryExpectation(async (command) => assertion(await locator.inputValue(command)).toEqual(expectedText(expected)), options, defaults());
|
|
108
|
-
},
|
|
163
|
+
toHaveValue: common.toHaveValue,
|
|
109
164
|
async toHaveSelectedOptions(expected, options = {}) {
|
|
110
165
|
await retryExpectation(async (command) => {
|
|
111
166
|
const wanted = expected.map(option => {
|
|
@@ -123,15 +178,9 @@ export function createLocatorExpect(locator, defaults, negated = false) {
|
|
|
123
178
|
async toHaveSelectedText(expected, options = {}) {
|
|
124
179
|
await retryExpectation(async (command) => assertion(await locator.selectedText(command)).toEqual(expectedText(expected)), options, defaults());
|
|
125
180
|
},
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
async toHaveAttribute(name, expected, options = {}) {
|
|
130
|
-
await retryExpectation(async (command) => assertion(await locator.getAttribute(name, command)).toEqual(expectedText(expected)), options, defaults());
|
|
131
|
-
},
|
|
132
|
-
async toHaveBoundingBox(expected, options = {}) {
|
|
133
|
-
await retryExpectation(async (command) => assertion(await locator.boundingBox(command)).toEqual(expected === null ? null : vitestExpect.objectContaining(expected)), options, defaults());
|
|
134
|
-
},
|
|
181
|
+
toBeChecked: common.toBeChecked,
|
|
182
|
+
toHaveAttribute: common.toHaveAttribute,
|
|
183
|
+
toHaveBoundingBox: common.toHaveBoundingBox,
|
|
135
184
|
};
|
|
136
185
|
return web;
|
|
137
186
|
}
|
|
@@ -143,6 +192,16 @@ export function createPageExpect(page, defaults, negated = false) {
|
|
|
143
192
|
toContainText: (selector, expected, options) => matcher(selector).toContainText(expected, options),
|
|
144
193
|
toHaveCount: (selector, expected, options) => matcher(selector).toHaveCount(expected, options),
|
|
145
194
|
toBeVisible: (selector, options) => matcher(selector).toBeVisible(options),
|
|
195
|
+
toBeHidden: (selector, options) => matcher(selector).toBeHidden(options),
|
|
196
|
+
toBeAttached: (selector, options) => matcher(selector).toBeAttached(options),
|
|
197
|
+
toBeEnabled: (selector, options) => matcher(selector).toBeEnabled(options),
|
|
198
|
+
toBeDisabled: (selector, options) => matcher(selector).toBeDisabled(options),
|
|
199
|
+
toBeFocused: (selector, options) => matcher(selector).toBeFocused(options),
|
|
200
|
+
toBeEditable: (selector, options) => matcher(selector).toBeEditable(options),
|
|
201
|
+
toHaveValue: (selector, expected, options) => matcher(selector).toHaveValue(expected, options),
|
|
202
|
+
toBeChecked: (selector, options) => matcher(selector).toBeChecked(options),
|
|
203
|
+
toHaveAttribute: (selector, name, expected, options) => matcher(selector).toHaveAttribute(name, expected, options),
|
|
204
|
+
toHaveBoundingBox: (selector, expected, options) => matcher(selector).toHaveBoundingBox(expected, options),
|
|
146
205
|
};
|
|
147
206
|
if (!("url" in page))
|
|
148
207
|
return common;
|
|
@@ -152,6 +211,12 @@ export function createPageExpect(page, defaults, negated = false) {
|
|
|
152
211
|
toContainText: common.toContainText,
|
|
153
212
|
toHaveCount: common.toHaveCount,
|
|
154
213
|
toBeVisible: common.toBeVisible,
|
|
214
|
+
toBeHidden: common.toBeHidden,
|
|
215
|
+
toBeAttached: common.toBeAttached,
|
|
216
|
+
toBeEnabled: common.toBeEnabled,
|
|
217
|
+
toBeDisabled: common.toBeDisabled,
|
|
218
|
+
toBeFocused: common.toBeFocused,
|
|
219
|
+
toBeEditable: common.toBeEditable,
|
|
155
220
|
get not() { return callableMatchers(createPageExpect(page, defaults, !negated)); },
|
|
156
221
|
async toHaveURL(expected, options = {}) {
|
|
157
222
|
await retryExpectation(async (command) => {
|
|
@@ -159,12 +224,12 @@ export function createPageExpect(page, defaults, negated = false) {
|
|
|
159
224
|
(negated ? vitestExpect(url).not : vitestExpect(url)).toEqual(expectedText(expected));
|
|
160
225
|
}, options, defaults());
|
|
161
226
|
},
|
|
162
|
-
toHaveValue:
|
|
227
|
+
toHaveValue: common.toHaveValue,
|
|
163
228
|
toHaveSelectedOptions: (selector, expected, options) => webMatcher(selector).toHaveSelectedOptions(expected, options),
|
|
164
229
|
toHaveSelectedText: (selector, expected, options) => webMatcher(selector).toHaveSelectedText(expected, options),
|
|
165
|
-
toBeChecked:
|
|
166
|
-
toHaveAttribute:
|
|
167
|
-
toHaveBoundingBox:
|
|
230
|
+
toBeChecked: common.toBeChecked,
|
|
231
|
+
toHaveAttribute: common.toHaveAttribute,
|
|
232
|
+
toHaveBoundingBox: common.toHaveBoundingBox,
|
|
168
233
|
};
|
|
169
234
|
return web;
|
|
170
235
|
}
|
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 NativeApp, type NativeAppLocator, 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 Page } from "@allwright.dev/core";
|
|
3
|
+
import { type MobileAndroidConnectOptions, type MobileAndroidDevice, type MobileAndroidLaunchOptions, type MobileAndroidApp, type NativeApp, type NativeAppLocator, type MobileIosConnectOptions, type MobileIosDevice, type MobileIosLaunchOptions, type MobileIosApp, type DesktopMacApp, type DesktopMacConnectOptions, type DesktopMacDesktop, type DesktopMacLaunchOptions, type DesktopWindowsApp, type DesktopWindowsConnectOptions, type DesktopWindowsDesktop, type DesktopWindowsLaunchOptions, type Browser, type BrowserKind, type LaunchOptions, type Locator, 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;
|
|
@@ -19,6 +19,10 @@ export interface AllwrightVitestOptions {
|
|
|
19
19
|
connectOptions?: DesktopMacConnectOptions;
|
|
20
20
|
launchOptions?: DesktopMacLaunchOptions;
|
|
21
21
|
};
|
|
22
|
+
windows?: {
|
|
23
|
+
connectOptions?: DesktopWindowsConnectOptions;
|
|
24
|
+
launchOptions?: DesktopWindowsLaunchOptions;
|
|
25
|
+
};
|
|
22
26
|
configFile?: string;
|
|
23
27
|
suite?: string;
|
|
24
28
|
}
|
|
@@ -31,6 +35,8 @@ export interface AllwrightVitestFixtures {
|
|
|
31
35
|
iosApp: MobileIosApp;
|
|
32
36
|
macos: DesktopMacDesktop;
|
|
33
37
|
macosApp: DesktopMacApp;
|
|
38
|
+
windows: DesktopWindowsDesktop;
|
|
39
|
+
windowsApp: DesktopWindowsApp;
|
|
34
40
|
}
|
|
35
41
|
interface LazyResource<T> {
|
|
36
42
|
peek(): T | null;
|
|
@@ -46,11 +52,14 @@ export declare const test: import("vitest").TestAPI<{
|
|
|
46
52
|
iosApp: NativeApp;
|
|
47
53
|
macos: DesktopMacDesktop;
|
|
48
54
|
macosApp: NativeApp;
|
|
55
|
+
windows: DesktopWindowsDesktop;
|
|
56
|
+
windowsApp: NativeApp;
|
|
49
57
|
allwright: AllwrightVitestOptions;
|
|
50
58
|
_browserResource: LazyResource<Browser>;
|
|
51
59
|
_androidResource: LazyResource<MobileAndroidDevice>;
|
|
52
60
|
_iosResource: LazyResource<MobileIosDevice>;
|
|
53
61
|
_macosResource: LazyResource<DesktopMacDesktop>;
|
|
62
|
+
_windowsResource: LazyResource<DesktopWindowsDesktop>;
|
|
54
63
|
}>;
|
|
55
64
|
type VitestExpect = typeof vitestExpect;
|
|
56
65
|
interface AllwrightExpect extends VitestExpect {
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,8 @@ const DEFAULT_IOS_CONNECT_TIMEOUT_MS = 30_000;
|
|
|
7
7
|
const DEFAULT_IOS_LAUNCH_TIMEOUT_MS = 60_000;
|
|
8
8
|
const DEFAULT_MACOS_CONNECT_TIMEOUT_MS = 30_000;
|
|
9
9
|
const DEFAULT_MACOS_LAUNCH_TIMEOUT_MS = 60_000;
|
|
10
|
+
const DEFAULT_WINDOWS_CONNECT_TIMEOUT_MS = 30_000;
|
|
11
|
+
const DEFAULT_WINDOWS_LAUNCH_TIMEOUT_MS = 60_000;
|
|
10
12
|
function createLazyResource(factory) {
|
|
11
13
|
let value = null;
|
|
12
14
|
let promise = null;
|
|
@@ -66,6 +68,9 @@ function createLazyLocator(pageResource, selectorFactory) {
|
|
|
66
68
|
async click(options) {
|
|
67
69
|
return (await pageResource.get()).locator(await selectorFactory()).click(options);
|
|
68
70
|
},
|
|
71
|
+
async dblclick(options) {
|
|
72
|
+
return (await pageResource.get()).locator(await selectorFactory()).dblclick(options);
|
|
73
|
+
},
|
|
69
74
|
async count(options) {
|
|
70
75
|
return (await pageResource.get()).locator(await selectorFactory()).count(options);
|
|
71
76
|
},
|
|
@@ -176,6 +181,9 @@ function createLazyPage(pageResource) {
|
|
|
176
181
|
async click(selector, options) {
|
|
177
182
|
return (await pageResource.get()).click(selector, options);
|
|
178
183
|
},
|
|
184
|
+
async dblclick(selector, options) {
|
|
185
|
+
return (await pageResource.get()).dblclick(selector, options);
|
|
186
|
+
},
|
|
179
187
|
async count(selector, options) {
|
|
180
188
|
return (await pageResource.get()).count(selector, options);
|
|
181
189
|
},
|
|
@@ -384,6 +392,18 @@ function createLazyMobileApp(appResource) {
|
|
|
384
392
|
async innerText(selector, options) {
|
|
385
393
|
return (await appResource.get()).innerText(selector, options);
|
|
386
394
|
},
|
|
395
|
+
async inputValue(selector, options) {
|
|
396
|
+
return (await appResource.get()).inputValue(selector, options);
|
|
397
|
+
},
|
|
398
|
+
async isChecked(selector, options) {
|
|
399
|
+
return (await appResource.get()).isChecked(selector, options);
|
|
400
|
+
},
|
|
401
|
+
async getAttribute(selector, name, options) {
|
|
402
|
+
return (await appResource.get()).getAttribute(selector, name, options);
|
|
403
|
+
},
|
|
404
|
+
async boundingBox(selector, options) {
|
|
405
|
+
return (await appResource.get()).boundingBox(selector, options);
|
|
406
|
+
},
|
|
387
407
|
async waitForSelector(selector, options) {
|
|
388
408
|
return (await appResource.get()).waitForSelector(selector, options);
|
|
389
409
|
},
|
|
@@ -425,6 +445,18 @@ function createLazyMobileLocator(appResource, selectorFactory) {
|
|
|
425
445
|
async innerText(options) {
|
|
426
446
|
return (await appResource.get()).locator(await selectorFactory()).innerText(options);
|
|
427
447
|
},
|
|
448
|
+
async inputValue(options) {
|
|
449
|
+
return (await appResource.get()).locator(await selectorFactory()).inputValue(options);
|
|
450
|
+
},
|
|
451
|
+
async isChecked(options) {
|
|
452
|
+
return (await appResource.get()).locator(await selectorFactory()).isChecked(options);
|
|
453
|
+
},
|
|
454
|
+
async getAttribute(name, options) {
|
|
455
|
+
return (await appResource.get()).locator(await selectorFactory()).getAttribute(name, options);
|
|
456
|
+
},
|
|
457
|
+
async boundingBox(options) {
|
|
458
|
+
return (await appResource.get()).locator(await selectorFactory()).boundingBox(options);
|
|
459
|
+
},
|
|
428
460
|
async waitFor(options) {
|
|
429
461
|
return (await appResource.get()).locator(await selectorFactory()).waitFor(options);
|
|
430
462
|
},
|
|
@@ -495,6 +527,20 @@ function createLazyMacosDesktop(desktopResource) {
|
|
|
495
527
|
},
|
|
496
528
|
};
|
|
497
529
|
}
|
|
530
|
+
function createLazyWindowsDesktop(desktopResource) {
|
|
531
|
+
const initialAppResource = createLazyResource(async () => (await desktopResource.get()).app());
|
|
532
|
+
return {
|
|
533
|
+
get sessionId() {
|
|
534
|
+
return getLazySyncProperty(desktopResource, "sessionId");
|
|
535
|
+
},
|
|
536
|
+
app() {
|
|
537
|
+
return createLazyMobileApp(initialAppResource);
|
|
538
|
+
},
|
|
539
|
+
async launch(options) {
|
|
540
|
+
return (await desktopResource.get()).launch(options);
|
|
541
|
+
},
|
|
542
|
+
};
|
|
543
|
+
}
|
|
498
544
|
export const test = base.extend({
|
|
499
545
|
allwright: async ({}, use) => {
|
|
500
546
|
await use({});
|
|
@@ -540,6 +586,14 @@ export const test = base.extend({
|
|
|
540
586
|
const macosResource = createLazyResource(async () => desktop.mac.connect(resolveMacosConnectOptions(config, allwright)));
|
|
541
587
|
await use(macosResource);
|
|
542
588
|
},
|
|
589
|
+
_windowsResource: async ({ allwright }, use) => {
|
|
590
|
+
const config = resolveVitestConfig(allwright);
|
|
591
|
+
if (config.serverAddr) {
|
|
592
|
+
setServerAddr(config.serverAddr);
|
|
593
|
+
}
|
|
594
|
+
const windowsResource = createLazyResource(async () => desktop.windows.connect(resolveWindowsConnectOptions(config, allwright)));
|
|
595
|
+
await use(windowsResource);
|
|
596
|
+
},
|
|
543
597
|
browser: async ({ _browserResource }, use) => {
|
|
544
598
|
try {
|
|
545
599
|
await use(createLazyBrowser(_browserResource));
|
|
@@ -584,6 +638,17 @@ export const test = base.extend({
|
|
|
584
638
|
});
|
|
585
639
|
await use(createLazyMobileApp(appResource));
|
|
586
640
|
},
|
|
641
|
+
windows: async ({ _windowsResource }, use) => {
|
|
642
|
+
await use(createLazyWindowsDesktop(_windowsResource));
|
|
643
|
+
},
|
|
644
|
+
windowsApp: async ({ _windowsResource, allwright }, use) => {
|
|
645
|
+
const appResource = createLazyResource(async () => {
|
|
646
|
+
const config = resolveVitestConfig(allwright);
|
|
647
|
+
const launchOptions = resolveWindowsLaunchOptions(config, allwright);
|
|
648
|
+
return (await _windowsResource.get()).launch(launchOptions);
|
|
649
|
+
});
|
|
650
|
+
await use(createLazyMobileApp(appResource));
|
|
651
|
+
},
|
|
587
652
|
});
|
|
588
653
|
function isPage(value) {
|
|
589
654
|
return !!value && typeof value === "object" && typeof value.locator === "function";
|
|
@@ -689,6 +754,28 @@ function resolveMacosLaunchOptions(config, options) {
|
|
|
689
754
|
DEFAULT_MACOS_LAUNCH_TIMEOUT_MS,
|
|
690
755
|
};
|
|
691
756
|
}
|
|
757
|
+
function resolveWindowsConnectOptions(config, options) {
|
|
758
|
+
return {
|
|
759
|
+
agentEndpoint: options.windows?.connectOptions?.agentEndpoint ??
|
|
760
|
+
process.env.ALLWRIGHT_WINDOWS_AGENT_ENDPOINT,
|
|
761
|
+
timeoutMs: options.windows?.connectOptions?.timeoutMs ??
|
|
762
|
+
DEFAULT_WINDOWS_CONNECT_TIMEOUT_MS,
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function resolveWindowsLaunchOptions(config, options) {
|
|
766
|
+
const appId = options.windows?.launchOptions?.appId ??
|
|
767
|
+
process.env.ALLWRIGHT_WINDOWS_APP_ID ??
|
|
768
|
+
config.desktop.windows?.appId;
|
|
769
|
+
if (!appId) {
|
|
770
|
+
throw new Error("windowsApp fixture requires Windows launch options with `appId`, or config.desktop.windows.app configured");
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
appId,
|
|
774
|
+
terminateRunning: options.windows?.launchOptions?.terminateRunning ?? false,
|
|
775
|
+
timeoutMs: options.windows?.launchOptions?.timeoutMs ??
|
|
776
|
+
DEFAULT_WINDOWS_LAUNCH_TIMEOUT_MS,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
692
779
|
let activeExpectDefaults = {};
|
|
693
780
|
function currentExpectDefaults() {
|
|
694
781
|
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.25",
|
|
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.25"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"typescript": "^5.9.2",
|