walkwright 0.0.1
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/LICENSE +21 -0
- package/README.md +276 -0
- package/bin/walkwright.js +3 -0
- package/build/aria.d.ts +92 -0
- package/build/aria.js +215 -0
- package/build/aria.js.map +1 -0
- package/build/browser.d.ts +3 -0
- package/build/browser.js +18 -0
- package/build/browser.js.map +1 -0
- package/build/chunk-5CHKYNP7.js +507 -0
- package/build/chunk-5CHKYNP7.js.map +1 -0
- package/build/chunk-6YRKPGUO.js +1197 -0
- package/build/chunk-6YRKPGUO.js.map +1 -0
- package/build/chunk-A452S7R3.js +35 -0
- package/build/chunk-A452S7R3.js.map +1 -0
- package/build/chunk-BODO6HIH.js +60 -0
- package/build/chunk-BODO6HIH.js.map +1 -0
- package/build/chunk-FJI2CMCE.js +439 -0
- package/build/chunk-FJI2CMCE.js.map +1 -0
- package/build/chunk-JYHZVRB2.js +80 -0
- package/build/chunk-JYHZVRB2.js.map +1 -0
- package/build/chunk-KQN5IYN6.js +97 -0
- package/build/chunk-KQN5IYN6.js.map +1 -0
- package/build/chunk-KTXNERHT.js +72 -0
- package/build/chunk-KTXNERHT.js.map +1 -0
- package/build/chunk-MFTC7XL2.js +141 -0
- package/build/chunk-MFTC7XL2.js.map +1 -0
- package/build/chunk-N4SSLHMP.js +108 -0
- package/build/chunk-N4SSLHMP.js.map +1 -0
- package/build/chunk-RNNW7OW2.js +270 -0
- package/build/chunk-RNNW7OW2.js.map +1 -0
- package/build/chunk-UAWBPTDW.js +51 -0
- package/build/chunk-UAWBPTDW.js.map +1 -0
- package/build/chunk-Z7CW5CAY.js +64 -0
- package/build/chunk-Z7CW5CAY.js.map +1 -0
- package/build/cli.d.ts +1 -0
- package/build/cli.js +253 -0
- package/build/cli.js.map +1 -0
- package/build/config.d.ts +13 -0
- package/build/config.js +15 -0
- package/build/config.js.map +1 -0
- package/build/descriptor.d.ts +96 -0
- package/build/descriptor.js +27 -0
- package/build/descriptor.js.map +1 -0
- package/build/device-auth.d.ts +6 -0
- package/build/device-auth.js +11 -0
- package/build/device-auth.js.map +1 -0
- package/build/locator.d.ts +140 -0
- package/build/locator.js +92 -0
- package/build/locator.js.map +1 -0
- package/build/paths.d.ts +11 -0
- package/build/paths.js +22 -0
- package/build/paths.js.map +1 -0
- package/build/pom-kcSMxwX2.d.ts +349 -0
- package/build/pom.d.ts +6 -0
- package/build/pom.js +37 -0
- package/build/pom.js.map +1 -0
- package/build/project.d.ts +13 -0
- package/build/project.js +19 -0
- package/build/project.js.map +1 -0
- package/build/provisioner.d.ts +34 -0
- package/build/provisioner.js +14 -0
- package/build/provisioner.js.map +1 -0
- package/build/recorder.d.ts +6 -0
- package/build/recorder.js +15 -0
- package/build/recorder.js.map +1 -0
- package/build/reporter.d.ts +16 -0
- package/build/reporter.js +426 -0
- package/build/reporter.js.map +1 -0
- package/build/schema.d.ts +49 -0
- package/build/schema.js +16 -0
- package/build/schema.js.map +1 -0
- package/build/storage-state.d.ts +22 -0
- package/build/storage-state.js +42 -0
- package/build/storage-state.js.map +1 -0
- package/build/store.d.ts +17 -0
- package/build/store.js +9 -0
- package/build/store.js.map +1 -0
- package/build/ui.d.ts +49 -0
- package/build/ui.js +56 -0
- package/build/ui.js.map +1 -0
- package/build/upload.d.ts +10 -0
- package/build/upload.js +8 -0
- package/build/upload.js.map +1 -0
- package/build/wait.d.ts +14 -0
- package/build/wait.js +50 -0
- package/build/wait.js.map +1 -0
- package/package.json +52 -0
- package/src/aria.ts +326 -0
- package/src/browser.ts +15 -0
- package/src/cli.ts +295 -0
- package/src/config.ts +16 -0
- package/src/descriptor.ts +179 -0
- package/src/device-auth.ts +188 -0
- package/src/locator.ts +683 -0
- package/src/paths.ts +70 -0
- package/src/pom.ts +2363 -0
- package/src/project.ts +77 -0
- package/src/provisioner.ts +183 -0
- package/src/recorder.ts +877 -0
- package/src/reporter.ts +561 -0
- package/src/schema.ts +37 -0
- package/src/storage-state.ts +71 -0
- package/src/store.ts +96 -0
- package/src/ui.ts +333 -0
- package/src/upload.ts +116 -0
- package/src/wait.ts +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hasan Ayan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# walkwright
|
|
2
|
+
|
|
3
|
+
The app-agnostic half of the walk: the recorder, the reporter that describes and
|
|
4
|
+
uploads a run, the provisioner mechanism, the account cache and the `walkwright`
|
|
5
|
+
command. Nothing in here knows about any particular app — the app supplies its
|
|
6
|
+
own config, tests and resources through the seams below.
|
|
7
|
+
|
|
8
|
+
## The walk
|
|
9
|
+
|
|
10
|
+
A walk is Playwright: spec files under a `walk` project, and this package's
|
|
11
|
+
reporter. `walkwright walk` is a thin wrapper around `playwright test` — there is no
|
|
12
|
+
separate runner.
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
walkwright walk
|
|
16
|
+
walkwright walk --workers 4 --headed
|
|
17
|
+
walkwright walk --upload-on-fail
|
|
18
|
+
walkwright walk --no-upload
|
|
19
|
+
walkwright walk --branch main
|
|
20
|
+
playwright test --project=walk # the same lanes as a smoke run: no shots
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| Flag | Meaning |
|
|
24
|
+
| ------------------- | ----------------------------------------------------- |
|
|
25
|
+
| `--upload-on-fail` | upload the passing lanes' shots even though it failed |
|
|
26
|
+
| `--no-upload` | skip the upload entirely |
|
|
27
|
+
| `--branch <name>` | report under this branch instead of git's |
|
|
28
|
+
| `--project <name>` | the Playwright project to run (default `walk`) |
|
|
29
|
+
| `--version` | the banner |
|
|
30
|
+
| `--help`, `-h`, `?` | keys and flags |
|
|
31
|
+
| everything else | forwarded to `playwright test` verbatim |
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// playwright.config.ts
|
|
35
|
+
import { walk } from "walkwright/config";
|
|
36
|
+
|
|
37
|
+
reporter: [["list"], ...walk.reporter({ appUrl })],
|
|
38
|
+
|
|
39
|
+
projects: [{ name: "walk", use: { ...use, ...walk.use } }],
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The helper reads `WALK_RECORDING` — set by `walkwright walk`, unset for a plain
|
|
43
|
+
`playwright test` — and does the wiring above either way: on, it returns the
|
|
44
|
+
reporter and `recording: true`; off, an empty reporter list and
|
|
45
|
+
`recording: false`, so the same lanes double as smoke tests in an ordinary
|
|
46
|
+
`playwright test` run with no shots taken. `walk.recording` is the boolean on
|
|
47
|
+
its own, for anything else that needs to branch on it.
|
|
48
|
+
|
|
49
|
+
The reporter names the run's directory — `.walkwright/reports/run-<timestamp>` —
|
|
50
|
+
before the first worker is spawned, and hands it to them in `WALKWRIGHT_RUN_DIR`.
|
|
51
|
+
Every recording test shoots into that one directory.
|
|
52
|
+
|
|
53
|
+
A run always writes its directory and `manifest.json` locally, failed or not.
|
|
54
|
+
A failed run uploads nothing unless `--upload-on-fail` — with the override,
|
|
55
|
+
only the passing lanes' shots go up; the failing ones never made it into the
|
|
56
|
+
manifest. `--no-upload` skips the upload outright, pass or fail.
|
|
57
|
+
|
|
58
|
+
| Option | Meaning |
|
|
59
|
+
| ------------ | ------------------------------------------------------------- |
|
|
60
|
+
| `appUrl` | the app the run walked, as the report viewer names it |
|
|
61
|
+
| `reportsDir` | where run directories are made (default `.walkwright/reports`) |
|
|
62
|
+
|
|
63
|
+
See `docs/run-manifest.md` for the manifest's shape.
|
|
64
|
+
|
|
65
|
+
What the CLI sets for the child process:
|
|
66
|
+
|
|
67
|
+
| Variable | Set by | Meaning |
|
|
68
|
+
| -------------------------- | ------------------ | ----------------------------------------- |
|
|
69
|
+
| `WALK_RECORDING` | `walkwright walk` | on for every run through the bin |
|
|
70
|
+
| `WALKWRIGHT_UPLOAD_ON_FAIL` | `--upload-on-fail` | upload a failed run's passing shots |
|
|
71
|
+
| `WALKWRIGHT_NO_UPLOAD` | `--no-upload` | skip the upload |
|
|
72
|
+
| `WALKWRIGHT_BRANCH` | `--branch <name>` | report under this branch instead of git's |
|
|
73
|
+
| `WALKWRIGHT_RUN_DIR` | the reporter | internal — hands each worker its run dir |
|
|
74
|
+
| `WALKWRIGHT_THEME` | you | `light` or `dark`; otherwise `COLORFGBG` |
|
|
75
|
+
|
|
76
|
+
Invoking Playwright directly instead of through `walkwright walk`, set the first four
|
|
77
|
+
yourself; `WALKWRIGHT_RUN_DIR` is the reporter's business.
|
|
78
|
+
|
|
79
|
+
## Recording
|
|
80
|
+
|
|
81
|
+
`walkwright/recorder` is a pair of Playwright fixtures the app extends its own
|
|
82
|
+
`test` with:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import type { RecorderFixtures } from "walkwright/recorder";
|
|
86
|
+
import { createRecorderFixtures } from "walkwright/recorder";
|
|
87
|
+
|
|
88
|
+
const walkTest = test.extend<RecorderFixtures>(createRecorderFixtures(app));
|
|
89
|
+
|
|
90
|
+
walkTest("items", async ({ page, record, runDir }) => {
|
|
91
|
+
await record(itemsPage, {}, "empty");
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`record` shoots into `runDir` and hands the reporter what it shot when the test
|
|
96
|
+
passes — when `recording` is on; off, `runDir` is empty and nothing is shot. A shot recorded with a page object is named after it; anything else is
|
|
97
|
+
attributed by the URL, matched against the pages `definePage` registered, and
|
|
98
|
+
`ShotOptions` (`category`, `page`, `state`) overrides any part of that.
|
|
99
|
+
|
|
100
|
+
`runDir` is also where a test writes artifacts that belong beside its shots.
|
|
101
|
+
|
|
102
|
+
## Logging in
|
|
103
|
+
|
|
104
|
+
`walkwright login [--force] [--url <server>]` sets a project's upload token up on its
|
|
105
|
+
own — the same device-authorization login and implicit project creation the
|
|
106
|
+
reporter's first upload needs. It writes `.walkwright/config.json`; without one,
|
|
107
|
+
a green run writes its manifest and skips the upload. `--url` picks the reports
|
|
108
|
+
server (default `https://app.walkwright.dev`) and is written into the config
|
|
109
|
+
next to the project id and token, so the reporter uploads to the same server
|
|
110
|
+
the login happened on. `--force --url` repoints a project.
|
|
111
|
+
|
|
112
|
+
`WALKWRIGHT_BRANCH` names the branch a run is reported under when git cannot
|
|
113
|
+
(a detached CI checkout).
|
|
114
|
+
|
|
115
|
+
## Files
|
|
116
|
+
|
|
117
|
+
Everything walkwright writes into a project lives under one folder:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
.walkwright/
|
|
121
|
+
config.json walkwright login — project id, token, server; commit it
|
|
122
|
+
reports/run-<ts>/ the reporter — shots and manifest.json
|
|
123
|
+
store/worker-<n>/ walkwright/store — worker-scoped caches
|
|
124
|
+
store/shared/ walkwright/store — project-scoped caches
|
|
125
|
+
.gitignore written by walkwright — ignores all but config.json
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The project is the package the walk runs from: the nearest ancestor of the
|
|
129
|
+
cwd with a `package.json` (or an existing `.walkwright/`), never the git
|
|
130
|
+
toplevel — in a monorepo the e2e package is its own project. The folder's
|
|
131
|
+
`.gitignore` keeps everything but the config out of git, and is itself ignored,
|
|
132
|
+
so nothing under `.walkwright/` but the config ever shows up in a status.
|
|
133
|
+
walkwright only writes that file when it is missing: a project that must not
|
|
134
|
+
commit its token (a public repo) keeps a local `*`-only one.
|
|
135
|
+
|
|
136
|
+
## Stores
|
|
137
|
+
|
|
138
|
+
`walkwright/store` keeps a JSON value across runs so the app never touches the
|
|
139
|
+
file system itself:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { createStore } from "walkwright/store";
|
|
143
|
+
|
|
144
|
+
const accounts = createStore("account", { schema: accountSchema });
|
|
145
|
+
|
|
146
|
+
const account = accounts.read() ?? (await signUp());
|
|
147
|
+
accounts.persist(account);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
| Option | Meaning |
|
|
151
|
+
| -------- | ------------------------------------------------------------------------------------------- |
|
|
152
|
+
| `scope` | `worker` (default) — one file per parallel worker; `project` — one file for all |
|
|
153
|
+
| `schema` | a zod schema: `read` decodes through it and ignores a file that does not, `persist` encodes |
|
|
154
|
+
|
|
155
|
+
A worker-scoped store lives under `store/worker-<n>/`, keyed by Playwright's
|
|
156
|
+
`TEST_PARALLEL_INDEX`; a project-scoped one under `store/shared/`. Writes go
|
|
157
|
+
through a temporary file and a rename, so a killed worker never leaves half a
|
|
158
|
+
file, and a project-scoped store that several workers save at once ends up with
|
|
159
|
+
whichever finished last, intact. A file that is missing, not JSON or fails its
|
|
160
|
+
schema reads as `undefined` and is reported, never thrown: the caller makes a
|
|
161
|
+
fresh value instead. `clear` removes the file; `path` is where it lives.
|
|
162
|
+
|
|
163
|
+
`walkwright/storage-state` is the same for a browser session:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import {
|
|
167
|
+
createStorageStateStore,
|
|
168
|
+
storageStateOf,
|
|
169
|
+
} from "walkwright/storage-state";
|
|
170
|
+
|
|
171
|
+
const session = createStorageStateStore("session");
|
|
172
|
+
const services = createStorageStateStore("services", { scope: "project" });
|
|
173
|
+
const github = createStorageStateStore("github", {
|
|
174
|
+
scope: "project",
|
|
175
|
+
cookies: (cookie) => cookie.domain.endsWith("github.com"),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test.extend({ storageState: storageStateOf(session, services) });
|
|
179
|
+
|
|
180
|
+
await session.save(page.context());
|
|
181
|
+
await github.restore(page.context());
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`save` writes the context's storage state; with a `cookies` filter it keeps the
|
|
185
|
+
matching cookies only and no origins. `restore` adds the saved cookies to a
|
|
186
|
+
context that already exists, for a session picked up part-way through a test.
|
|
187
|
+
`storageStateOf` is for Playwright's `storageState` option: the path of the
|
|
188
|
+
first store that has a file, or `emptyStorageState` when none does.
|
|
189
|
+
|
|
190
|
+
## Modules
|
|
191
|
+
|
|
192
|
+
| Import | Role |
|
|
193
|
+
| ------------------------- | ---------------------------------------------------------- |
|
|
194
|
+
| `walkwright/reporter` | the run directory, `manifest.json`, the upload |
|
|
195
|
+
| `walkwright/recorder` | the recorder, and the fixtures that bind it to a test |
|
|
196
|
+
| `walkwright/pom` | `definePage`: page objects, dialogs, fragments |
|
|
197
|
+
| `walkwright/browser` | `hideStyle`: an init script hiding chrome that would move |
|
|
198
|
+
| `walkwright/provisioner` | resources created through the app, disposed in reverse |
|
|
199
|
+
| `walkwright/store` | a JSON value cached across runs, per worker or per project |
|
|
200
|
+
| `walkwright/storage-state` | a browser session cached across runs, for `storageState` |
|
|
201
|
+
|
|
202
|
+
## Page objects
|
|
203
|
+
|
|
204
|
+
`walkwright/pom` has one grammar for every definer:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
defineX(definition).withActions(map); // a literal
|
|
208
|
+
defineX((...params) => definition).withActions(map); // a builder, params-first
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
| Definer | Definition | Instance |
|
|
212
|
+
| ----------------- | ----------------------------------------------------- | ---------------------------------------------- |
|
|
213
|
+
| `defineComponent` | `{ root?, elements? }` — `root` present: rooted | `{ root?, ...elements, ...actions }` |
|
|
214
|
+
| `defineDialog` | `{ name, role?, trigger?, dismiss?, elements? }` | `{ root, open, close, waitFor, ... }` |
|
|
215
|
+
| `definePage` | `{ path, name, header?, fragments?, elements?, ... }` | `{ goto, url, waitFor, elements, ...actions }` |
|
|
216
|
+
| `defineLayout` | `{ path, group?, chrome?, parent? }` — literal only | shared by its pages |
|
|
217
|
+
|
|
218
|
+
Element entries take the context first, own params after; the annotation is
|
|
219
|
+
inferred:
|
|
220
|
+
|
|
221
|
+
| Entry | Instantiates to |
|
|
222
|
+
| ----------------------------------------------- | ---------------------------------- |
|
|
223
|
+
| `back: link("Back")` | a value — a leaf, called |
|
|
224
|
+
| `deployment: link` | a method — a leaf, mounted bare |
|
|
225
|
+
| `email: ({ scope }) => scope.getByLabel(...)` | a value — ≤ 1 parameter |
|
|
226
|
+
| `member: ({ scope }, email: string) => ...` | a method — ≥ 2 parameters |
|
|
227
|
+
| `first(): Locator { return this.rows.first() }` | a value — `this` is the siblings |
|
|
228
|
+
| `row: defineComponent((name) => ...)` | a method — a builder, mounted bare |
|
|
229
|
+
|
|
230
|
+
The builder form comes back branded (`parameterized: true`): mounted under a
|
|
231
|
+
key it is a method, `elements.row("a")`, and its params reach the actions
|
|
232
|
+
context as `params`. `parameterized()` brands hand-written leaves the same
|
|
233
|
+
way; nothing else needs it.
|
|
234
|
+
|
|
235
|
+
`defineComponent`, `defineOverlay`, `defineDialog`, `definePage`, page
|
|
236
|
+
presets and `defineApp` all take a `capture: { rules }` option — declarative
|
|
237
|
+
rules that rewrite dynamic text (counters, relative times, ids, user names)
|
|
238
|
+
in the live DOM right before a screenshot and restore it right after, so
|
|
239
|
+
walks stay stable. See `docs/descriptor-schema.md#capture-rules`.
|
|
240
|
+
|
|
241
|
+
Actions (`withActions`) receive the context — `scope`, `page`, `elements`,
|
|
242
|
+
plus `root` for rooted components and dialogs, `params` for builders — then
|
|
243
|
+
their own params, and see sibling actions as `this`. Actions never mint
|
|
244
|
+
locators: locating is for `elements` and `root`. A page's actions orchestrate
|
|
245
|
+
its elements, including those its fragments spread in; a fragment's actions
|
|
246
|
+
are for callers.
|
|
247
|
+
|
|
248
|
+
Every `withActions` member and every top-level factory names its return type
|
|
249
|
+
(`explicit-function-return-type`); nothing else needs an annotation — a
|
|
250
|
+
`ReturnType<typeof page>` alias, or an explicit interface for a page that
|
|
251
|
+
navigates in a cycle with another, is the exception.
|
|
252
|
+
|
|
253
|
+
## Seams
|
|
254
|
+
|
|
255
|
+
| Seam | The app supplies |
|
|
256
|
+
| ------------------------------------------ | ----------------------------------------------------------------- |
|
|
257
|
+
| the `walk` project | the walks themselves, and the session they run as |
|
|
258
|
+
| `["walkwright/reporter", { appUrl }]` | the app the report is of |
|
|
259
|
+
| `test.extend(createRecorderFixtures(app))` | the test the recorder shoots through, and the page inventory |
|
|
260
|
+
| `definePage({ afterGoto })` | the readiness a page object's `goto` waits out |
|
|
261
|
+
| `createProvisioner(page, kinds)` | the resource kinds, how each is made, and how it is disposed |
|
|
262
|
+
| `createStore(name, { scope, schema })` | the value cached across runs, its shape, and how far it is shared |
|
|
263
|
+
|
|
264
|
+
## Building
|
|
265
|
+
|
|
266
|
+
Consumed as a built package — the reporter and the `walkwright` bin both run under
|
|
267
|
+
plain `node`, which resolves `walkwright` through `node_modules` to `build/`.
|
|
268
|
+
The bin is `bin/walkwright.js`, a checked-in launcher for `build/cli.js`, so it links
|
|
269
|
+
whether or not the package has been built yet. After changing anything here:
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
pnpm build
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Consumers install it from the filesystem (`"walkwright": "link:…/packages/sdk"`)
|
|
276
|
+
and build it before they run, so a fresh build is automatic.
|
package/build/aria.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { O as Overlay, C as Component, S as Surface, a as SurfaceInstance, R as Rooted, b as OverlayFactory, c as RootedComponent, P as Parameterized, I as Instantiated, d as OverlayHandle } from './pom-kcSMxwX2.js';
|
|
2
|
+
import { Locator, Page } from '@playwright/test';
|
|
3
|
+
import { LazyLocator, Mount } from './locator.js';
|
|
4
|
+
import './descriptor.js';
|
|
5
|
+
import 'zod';
|
|
6
|
+
import './provisioner.js';
|
|
7
|
+
|
|
8
|
+
interface Menu<Action extends string> extends Overlay<{
|
|
9
|
+
item: (action: Action) => Locator;
|
|
10
|
+
}> {
|
|
11
|
+
choose: (action: Action) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
interface MenuFactory {
|
|
14
|
+
<Action extends string>(name: string | RegExp, options?: {
|
|
15
|
+
label?: string;
|
|
16
|
+
}): OverlayFactory<Menu<Action>>;
|
|
17
|
+
parameterized: true;
|
|
18
|
+
}
|
|
19
|
+
declare const menu: MenuFactory;
|
|
20
|
+
interface TabsElements<N extends string> {
|
|
21
|
+
names: () => readonly N[];
|
|
22
|
+
tab: (n: N) => LazyLocator;
|
|
23
|
+
tabPanel: (n: N) => LazyLocator;
|
|
24
|
+
select: (n: N) => (scope: Mount) => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
declare const tabs: <const N extends string>(names: readonly N[]) => TabsElements<N>;
|
|
27
|
+
type RadioGroup<Option extends string> = RootedComponent<{
|
|
28
|
+
radio: (option: Option) => Locator;
|
|
29
|
+
}, {
|
|
30
|
+
select: (option: Option) => Promise<void>;
|
|
31
|
+
}>;
|
|
32
|
+
interface RadioGroupFactory {
|
|
33
|
+
<Option extends string>(name: string): Surface<RadioGroup<Option>>;
|
|
34
|
+
parameterized: true;
|
|
35
|
+
}
|
|
36
|
+
declare const radioGroup: RadioGroupFactory;
|
|
37
|
+
type ComboboxOptions<Value extends string> = Overlay<{
|
|
38
|
+
option: (value: Value) => Locator;
|
|
39
|
+
}>;
|
|
40
|
+
type SelectCombobox<Value extends string> = RootedComponent<{
|
|
41
|
+
options: ComboboxOptions<Value>;
|
|
42
|
+
}, {
|
|
43
|
+
ensureSelected: (value: Value) => Promise<void>;
|
|
44
|
+
}>;
|
|
45
|
+
type SelectComboboxFactory = <Value extends string>(scope: LazyLocator) => Surface<SelectCombobox<Value>>;
|
|
46
|
+
declare const selectCombobox: SelectComboboxFactory;
|
|
47
|
+
type MultiCombobox<Value extends string> = RootedComponent<{
|
|
48
|
+
options: ComboboxOptions<Value>;
|
|
49
|
+
selectedTag: (value: Value) => Locator;
|
|
50
|
+
}, {
|
|
51
|
+
ensureSelected: (values: readonly Value[], allValues?: readonly Value[]) => Promise<void>;
|
|
52
|
+
}>;
|
|
53
|
+
interface MultiComboboxFactory {
|
|
54
|
+
<Value extends string>(selectedTag: (value: Value) => LazyLocator): (scope: LazyLocator) => Surface<MultiCombobox<Value>>;
|
|
55
|
+
parameterized: true;
|
|
56
|
+
}
|
|
57
|
+
declare const multiCombobox: MultiComboboxFactory;
|
|
58
|
+
declare const freeCombobox: Surface<Component<Instantiated<Record<never, never>>, {
|
|
59
|
+
ensureSelected(values: readonly string[]): Promise<void>;
|
|
60
|
+
}>>;
|
|
61
|
+
type Disclosure<Panel = Locator> = Component<{
|
|
62
|
+
trigger: Locator;
|
|
63
|
+
panel: Panel;
|
|
64
|
+
}, {
|
|
65
|
+
expand: () => Promise<void>;
|
|
66
|
+
collapse: () => Promise<void>;
|
|
67
|
+
}>;
|
|
68
|
+
interface DisclosureFactory {
|
|
69
|
+
(trigger: LazyLocator, panel: LazyLocator): Surface<Disclosure>;
|
|
70
|
+
<I extends SurfaceInstance>(trigger: LazyLocator, panel: LazyLocator, contents: Surface<I>): Surface<Disclosure<I & Rooted>>;
|
|
71
|
+
}
|
|
72
|
+
declare const disclosure: DisclosureFactory;
|
|
73
|
+
declare const confirmDelete: Parameterized<[def: {
|
|
74
|
+
name: string;
|
|
75
|
+
confirmLabel: string;
|
|
76
|
+
cancelLabel: string;
|
|
77
|
+
confirmed?: (page: Page) => Promise<void>;
|
|
78
|
+
}], OverlayFactory<{
|
|
79
|
+
page: Page;
|
|
80
|
+
elements: Instantiated<{
|
|
81
|
+
confirmTextbox: LazyLocator;
|
|
82
|
+
deleteButton: LazyLocator;
|
|
83
|
+
cancelButton: LazyLocator;
|
|
84
|
+
}>;
|
|
85
|
+
label: string;
|
|
86
|
+
} & Rooted & OverlayHandle & {
|
|
87
|
+
name: string | RegExp;
|
|
88
|
+
} & {
|
|
89
|
+
confirm(name: string): Promise<void>;
|
|
90
|
+
}>>;
|
|
91
|
+
|
|
92
|
+
export { type ComboboxOptions, type Disclosure, type DisclosureFactory, type Menu, type MenuFactory, type MultiCombobox, type MultiComboboxFactory, type RadioGroup, type RadioGroupFactory, type SelectCombobox, type SelectComboboxFactory, type TabsElements, confirmDelete, disclosure, freeCombobox, menu, multiCombobox, radioGroup, selectCombobox, tabs };
|
package/build/aria.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineComponent,
|
|
3
|
+
defineDialog,
|
|
4
|
+
defineOverlay,
|
|
5
|
+
rootOf
|
|
6
|
+
} from "./chunk-6YRKPGUO.js";
|
|
7
|
+
import "./chunk-KQN5IYN6.js";
|
|
8
|
+
import "./chunk-5CHKYNP7.js";
|
|
9
|
+
import "./chunk-KTXNERHT.js";
|
|
10
|
+
import "./chunk-N4SSLHMP.js";
|
|
11
|
+
import {
|
|
12
|
+
button,
|
|
13
|
+
listbox,
|
|
14
|
+
menu,
|
|
15
|
+
menuitem,
|
|
16
|
+
option,
|
|
17
|
+
radio,
|
|
18
|
+
radiogroup,
|
|
19
|
+
resolveLocator,
|
|
20
|
+
tab,
|
|
21
|
+
tabpanel,
|
|
22
|
+
textbox
|
|
23
|
+
} from "./chunk-FJI2CMCE.js";
|
|
24
|
+
import "./chunk-BODO6HIH.js";
|
|
25
|
+
import "./chunk-UAWBPTDW.js";
|
|
26
|
+
|
|
27
|
+
// src/aria.ts
|
|
28
|
+
function labelOf(name, label) {
|
|
29
|
+
if (label !== void 0) {
|
|
30
|
+
return label;
|
|
31
|
+
}
|
|
32
|
+
if (typeof name === "string") {
|
|
33
|
+
return name;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(
|
|
36
|
+
`the ${name.source} menu needs a label: its name is a pattern`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
var menu2 = defineOverlay(
|
|
40
|
+
(name, options) => ({
|
|
41
|
+
root: menu(name),
|
|
42
|
+
recorder: { label: labelOf(name, options?.label) },
|
|
43
|
+
elements: {
|
|
44
|
+
item: (action) => menuitem(action)
|
|
45
|
+
},
|
|
46
|
+
actions: {
|
|
47
|
+
async choose(action) {
|
|
48
|
+
await this.open();
|
|
49
|
+
await this.elements.item(action).click();
|
|
50
|
+
await this.waitFor("hidden");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
async function selectTab(tab2) {
|
|
56
|
+
if (await tab2.getAttribute("aria-selected") !== "true") {
|
|
57
|
+
await tab2.click();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
var tabs = (names) => ({
|
|
61
|
+
names: () => names,
|
|
62
|
+
tab: (n) => tab(n),
|
|
63
|
+
tabPanel: (n) => tabpanel(n),
|
|
64
|
+
select: (n) => async (scope) => {
|
|
65
|
+
await selectTab(resolveLocator(scope, tab(n).chain));
|
|
66
|
+
await resolveLocator(scope, tabpanel(n).chain).waitFor();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
var radioGroup = defineComponent((name) => ({
|
|
70
|
+
root: radiogroup(name),
|
|
71
|
+
elements: {
|
|
72
|
+
radio: (option2) => radio(option2)
|
|
73
|
+
},
|
|
74
|
+
actions: {
|
|
75
|
+
async select(option2) {
|
|
76
|
+
await this.elements.radio(option2).check();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
80
|
+
var comboboxOptions = defineOverlay({
|
|
81
|
+
root: listbox(),
|
|
82
|
+
recorder: { label: "Options" },
|
|
83
|
+
elements: {
|
|
84
|
+
option: (name) => option(name)
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
var selectCombobox = defineComponent({
|
|
88
|
+
elements: {
|
|
89
|
+
options: comboboxOptions
|
|
90
|
+
},
|
|
91
|
+
actions: {
|
|
92
|
+
async ensureSelected(value) {
|
|
93
|
+
await rootOf(this).click();
|
|
94
|
+
await this.elements.options.elements.option(value).click();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
var multiCombobox = defineComponent(
|
|
99
|
+
(selectedTag) => ({
|
|
100
|
+
elements: {
|
|
101
|
+
options: comboboxOptions,
|
|
102
|
+
selectedTag
|
|
103
|
+
},
|
|
104
|
+
actions: {
|
|
105
|
+
async ensureSelected(values, allValues = []) {
|
|
106
|
+
const root = rootOf(this);
|
|
107
|
+
const { options, selectedTag: selectedTag2 } = this.elements;
|
|
108
|
+
await root.click();
|
|
109
|
+
for (const value of values) {
|
|
110
|
+
const option2 = options.elements.option(value);
|
|
111
|
+
if (await option2.getAttribute("aria-selected") !== "true") {
|
|
112
|
+
await option2.click();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
await root.press("Escape");
|
|
116
|
+
for (const value of values) {
|
|
117
|
+
await selectedTag2(value).waitFor();
|
|
118
|
+
}
|
|
119
|
+
for (const value of allValues.filter((it) => !values.includes(it))) {
|
|
120
|
+
const tag = selectedTag2(value);
|
|
121
|
+
if (!await tag.isVisible()) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
await root.click();
|
|
125
|
+
await options.elements.option(value).click();
|
|
126
|
+
await root.press("Escape");
|
|
127
|
+
await tag.waitFor({ state: "hidden" });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
var freeCombobox = defineComponent({
|
|
134
|
+
actions: {
|
|
135
|
+
async ensureSelected(values) {
|
|
136
|
+
const root = rootOf(this);
|
|
137
|
+
for (const value of values) {
|
|
138
|
+
await root.fill(value);
|
|
139
|
+
await root.press("Enter");
|
|
140
|
+
}
|
|
141
|
+
await root.press("Escape");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
var disclosure = ((trigger, panel, contents) => {
|
|
146
|
+
const within = panel.within(trigger);
|
|
147
|
+
return defineComponent({
|
|
148
|
+
elements: {
|
|
149
|
+
trigger,
|
|
150
|
+
panel: contents === void 0 ? within : contents(within)
|
|
151
|
+
},
|
|
152
|
+
actions: {
|
|
153
|
+
async expand() {
|
|
154
|
+
const { trigger: trigger2 } = this.elements;
|
|
155
|
+
const expanded = trigger2.and(
|
|
156
|
+
this.page.locator('[aria-expanded="true"]')
|
|
157
|
+
);
|
|
158
|
+
const collapsed = trigger2.and(
|
|
159
|
+
this.page.locator('[aria-expanded="false"]')
|
|
160
|
+
);
|
|
161
|
+
await expanded.or(collapsed).waitFor();
|
|
162
|
+
if (await expanded.count() > 0) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
await trigger2.click();
|
|
166
|
+
await expanded.waitFor();
|
|
167
|
+
},
|
|
168
|
+
async collapse() {
|
|
169
|
+
const { trigger: trigger2 } = this.elements;
|
|
170
|
+
const expanded = trigger2.and(
|
|
171
|
+
this.page.locator('[aria-expanded="true"]')
|
|
172
|
+
);
|
|
173
|
+
const collapsed = trigger2.and(
|
|
174
|
+
this.page.locator('[aria-expanded="false"]')
|
|
175
|
+
);
|
|
176
|
+
await expanded.or(collapsed).waitFor();
|
|
177
|
+
if (await collapsed.count() > 0) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
await trigger2.click();
|
|
181
|
+
await collapsed.waitFor();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
var confirmDelete = defineDialog(
|
|
187
|
+
(def) => ({
|
|
188
|
+
name: def.name,
|
|
189
|
+
close: { button: button(def.cancelLabel) },
|
|
190
|
+
elements: {
|
|
191
|
+
confirmTextbox: textbox(def.confirmLabel),
|
|
192
|
+
deleteButton: button(def.name),
|
|
193
|
+
cancelButton: button(def.cancelLabel)
|
|
194
|
+
},
|
|
195
|
+
actions: {
|
|
196
|
+
async confirm(name) {
|
|
197
|
+
await this.elements.confirmTextbox.fill(name);
|
|
198
|
+
await this.elements.deleteButton.click();
|
|
199
|
+
await this.root.waitFor({ state: "hidden", timeout: 15e3 });
|
|
200
|
+
await def.confirmed?.(this.page);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
);
|
|
205
|
+
export {
|
|
206
|
+
confirmDelete,
|
|
207
|
+
disclosure,
|
|
208
|
+
freeCombobox,
|
|
209
|
+
menu2 as menu,
|
|
210
|
+
multiCombobox,
|
|
211
|
+
radioGroup,
|
|
212
|
+
selectCombobox,
|
|
213
|
+
tabs
|
|
214
|
+
};
|
|
215
|
+
//# sourceMappingURL=aria.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/aria.ts"],"sourcesContent":["import type { Locator, Page } from \"@playwright/test\";\n\nimport type { LazyLocator, Mount } from \"./locator.js\";\nimport {\n button,\n listbox,\n menu as menuRole,\n menuitem,\n option as optionLeaf,\n radio as radioLeaf,\n radiogroup,\n resolveLocator,\n tab as tabLeaf,\n tabpanel as tabpanelLeaf,\n textbox,\n} from \"./locator.js\";\nimport type {\n AnySurface,\n Component,\n Overlay,\n OverlayFactory,\n Rooted,\n RootedComponent,\n Surface,\n SurfaceInstance,\n} from \"./pom.js\";\nimport { defineComponent, defineDialog, defineOverlay, rootOf } from \"./pom.js\";\n\nexport interface Menu<Action extends string> extends Overlay<{\n item: (action: Action) => Locator;\n}> {\n choose: (action: Action) => Promise<void>;\n}\n\nexport interface MenuFactory {\n <Action extends string>(\n name: string | RegExp,\n options?: { label?: string },\n ): OverlayFactory<Menu<Action>>;\n parameterized: true;\n}\n\nfunction labelOf(name: string | RegExp, label: string | undefined): string {\n if (label !== undefined) {\n return label;\n }\n\n if (typeof name === \"string\") {\n return name;\n }\n\n throw new Error(\n `the ${name.source} menu needs a label: its name is a pattern`,\n );\n}\n\nexport const menu = defineOverlay(\n (name: string | RegExp, options?: { label?: string }) => ({\n root: menuRole(name),\n recorder: { label: labelOf(name, options?.label) },\n elements: {\n item: (action: string): LazyLocator => menuitem(action),\n },\n actions: {\n async choose(action: string): Promise<void> {\n await this.open();\n await this.elements.item(action).click();\n await this.waitFor(\"hidden\");\n },\n },\n }),\n) as unknown as MenuFactory;\n\nasync function selectTab(tab: Locator): Promise<void> {\n if ((await tab.getAttribute(\"aria-selected\")) !== \"true\") {\n await tab.click();\n }\n}\n\nexport interface TabsElements<N extends string> {\n names: () => readonly N[];\n tab: (n: N) => LazyLocator;\n tabPanel: (n: N) => LazyLocator;\n select: (n: N) => (scope: Mount) => Promise<void>;\n}\n\nexport const tabs = <const N extends string>(\n names: readonly N[],\n): TabsElements<N> => ({\n names: (): readonly N[] => names,\n tab: (n: N): LazyLocator => tabLeaf(n),\n tabPanel: (n: N): LazyLocator => tabpanelLeaf(n),\n select:\n (n: N) =>\n async (scope: Mount): Promise<void> => {\n await selectTab(resolveLocator(scope, tabLeaf(n).chain));\n await resolveLocator(scope, tabpanelLeaf(n).chain).waitFor();\n },\n});\n\nexport type RadioGroup<Option extends string> = RootedComponent<\n { radio: (option: Option) => Locator },\n { select: (option: Option) => Promise<void> }\n>;\n\nexport interface RadioGroupFactory {\n <Option extends string>(name: string): Surface<RadioGroup<Option>>;\n parameterized: true;\n}\n\nexport const radioGroup = defineComponent((name: string) => ({\n root: radiogroup(name),\n elements: {\n radio: (option: string): LazyLocator => radioLeaf(option),\n },\n actions: {\n async select(option: string): Promise<void> {\n await this.elements.radio(option).check();\n },\n },\n})) as unknown as RadioGroupFactory;\n\nconst comboboxOptions = defineOverlay({\n root: listbox(),\n recorder: { label: \"Options\" },\n elements: {\n option: (name: string): LazyLocator => optionLeaf(name),\n },\n});\n\nexport type ComboboxOptions<Value extends string> = Overlay<{\n option: (value: Value) => Locator;\n}>;\n\nexport type SelectCombobox<Value extends string> = RootedComponent<\n { options: ComboboxOptions<Value> },\n { ensureSelected: (value: Value) => Promise<void> }\n>;\n\nexport type SelectComboboxFactory = <Value extends string>(\n scope: LazyLocator,\n) => Surface<SelectCombobox<Value>>;\n\nexport const selectCombobox = defineComponent({\n elements: {\n options: comboboxOptions,\n },\n actions: {\n async ensureSelected(value: string): Promise<void> {\n await rootOf(this).click();\n await this.elements.options.elements.option(value).click();\n },\n },\n}) as unknown as SelectComboboxFactory;\n\nexport type MultiCombobox<Value extends string> = RootedComponent<\n {\n options: ComboboxOptions<Value>;\n selectedTag: (value: Value) => Locator;\n },\n {\n ensureSelected: (\n values: readonly Value[],\n allValues?: readonly Value[],\n ) => Promise<void>;\n }\n>;\n\nexport interface MultiComboboxFactory {\n <Value extends string>(\n selectedTag: (value: Value) => LazyLocator,\n ): (scope: LazyLocator) => Surface<MultiCombobox<Value>>;\n parameterized: true;\n}\n\nexport const multiCombobox = defineComponent(\n (selectedTag: (value: string) => LazyLocator) => ({\n elements: {\n options: comboboxOptions,\n selectedTag,\n },\n actions: {\n async ensureSelected(\n values: readonly string[],\n allValues: readonly string[] = [],\n ): Promise<void> {\n const root = rootOf(this);\n const { options, selectedTag } = this.elements;\n\n await root.click();\n\n for (const value of values) {\n const option = options.elements.option(value);\n if ((await option.getAttribute(\"aria-selected\")) !== \"true\") {\n await option.click();\n }\n }\n\n await root.press(\"Escape\");\n\n for (const value of values) {\n await selectedTag(value).waitFor();\n }\n\n for (const value of allValues.filter((it) => !values.includes(it))) {\n const tag = selectedTag(value);\n if (!(await tag.isVisible())) {\n continue;\n }\n\n await root.click();\n await options.elements.option(value).click();\n await root.press(\"Escape\");\n await tag.waitFor({ state: \"hidden\" });\n }\n },\n },\n }),\n) as unknown as MultiComboboxFactory;\n\nexport const freeCombobox = defineComponent({\n actions: {\n async ensureSelected(values: readonly string[]): Promise<void> {\n const root = rootOf(this);\n\n for (const value of values) {\n await root.fill(value);\n await root.press(\"Enter\");\n }\n\n await root.press(\"Escape\");\n },\n },\n});\n\nexport type Disclosure<Panel = Locator> = Component<\n { trigger: Locator; panel: Panel },\n { expand: () => Promise<void>; collapse: () => Promise<void> }\n>;\n\nexport interface DisclosureFactory {\n (trigger: LazyLocator, panel: LazyLocator): Surface<Disclosure>;\n <I extends SurfaceInstance>(\n trigger: LazyLocator,\n panel: LazyLocator,\n contents: Surface<I>,\n ): Surface<Disclosure<I & Rooted>>;\n}\n\nexport const disclosure = ((\n trigger: LazyLocator,\n panel: LazyLocator,\n contents?: AnySurface,\n): AnySurface => {\n const within = panel.within(trigger);\n\n return defineComponent({\n elements: {\n trigger,\n panel: contents === undefined ? within : contents(within),\n },\n actions: {\n async expand(): Promise<void> {\n const { trigger } = this.elements;\n const expanded = trigger.and(\n this.page.locator('[aria-expanded=\"true\"]'),\n );\n const collapsed = trigger.and(\n this.page.locator('[aria-expanded=\"false\"]'),\n );\n\n await expanded.or(collapsed).waitFor();\n\n if ((await expanded.count()) > 0) {\n return;\n }\n\n await trigger.click();\n await expanded.waitFor();\n },\n async collapse(): Promise<void> {\n const { trigger } = this.elements;\n const expanded = trigger.and(\n this.page.locator('[aria-expanded=\"true\"]'),\n );\n const collapsed = trigger.and(\n this.page.locator('[aria-expanded=\"false\"]'),\n );\n\n await expanded.or(collapsed).waitFor();\n\n if ((await collapsed.count()) > 0) {\n return;\n }\n\n await trigger.click();\n await collapsed.waitFor();\n },\n },\n });\n}) as unknown as DisclosureFactory;\n\nexport const confirmDelete = defineDialog(\n (def: {\n name: string;\n confirmLabel: string;\n cancelLabel: string;\n confirmed?: (page: Page) => Promise<void>;\n }) => ({\n name: def.name,\n close: { button: button(def.cancelLabel) },\n elements: {\n confirmTextbox: textbox(def.confirmLabel),\n deleteButton: button(def.name),\n cancelButton: button(def.cancelLabel),\n },\n actions: {\n async confirm(name: string): Promise<void> {\n await this.elements.confirmTextbox.fill(name);\n await this.elements.deleteButton.click();\n await this.root.waitFor({ state: \"hidden\", timeout: 15_000 });\n await def.confirmed?.(this.page);\n },\n },\n }),\n);\n"],"mappings":"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","names":["menu","tab","option","selectedTag","trigger"]}
|
package/build/browser.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./chunk-UAWBPTDW.js";
|
|
2
|
+
|
|
3
|
+
// src/browser.ts
|
|
4
|
+
function hideStyle(selectors) {
|
|
5
|
+
if (selectors.length === 0) {
|
|
6
|
+
return void 0;
|
|
7
|
+
}
|
|
8
|
+
const css = selectors.map((selector) => `${selector}{display:none;}`).join("");
|
|
9
|
+
return `document.addEventListener("DOMContentLoaded", () => {
|
|
10
|
+
const style = document.createElement("style");
|
|
11
|
+
style.textContent = ${JSON.stringify(css)};
|
|
12
|
+
document.head.append(style);
|
|
13
|
+
});`;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
hideStyle
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/browser.ts"],"sourcesContent":["export function hideStyle(selectors: string[]): string | undefined {\n if (selectors.length === 0) {\n return undefined;\n }\n\n const css = selectors\n .map((selector) => `${selector}{display:none;}`)\n .join(\"\");\n\n return `document.addEventListener(\"DOMContentLoaded\", () => {\n const style = document.createElement(\"style\");\n style.textContent = ${JSON.stringify(css)};\n document.head.append(style);\n});`;\n}\n"],"mappings":";;;AAAO,SAAS,UAAU,WAAyC;AACjE,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,UACT,IAAI,CAAC,aAAa,GAAG,QAAQ,iBAAiB,EAC9C,KAAK,EAAE;AAEV,SAAO;AAAA;AAAA,wBAEe,KAAK,UAAU,GAAG,CAAC;AAAA;AAAA;AAG3C;","names":[]}
|