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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +276 -0
  3. package/bin/walkwright.js +3 -0
  4. package/build/aria.d.ts +92 -0
  5. package/build/aria.js +215 -0
  6. package/build/aria.js.map +1 -0
  7. package/build/browser.d.ts +3 -0
  8. package/build/browser.js +18 -0
  9. package/build/browser.js.map +1 -0
  10. package/build/chunk-5CHKYNP7.js +507 -0
  11. package/build/chunk-5CHKYNP7.js.map +1 -0
  12. package/build/chunk-6YRKPGUO.js +1197 -0
  13. package/build/chunk-6YRKPGUO.js.map +1 -0
  14. package/build/chunk-A452S7R3.js +35 -0
  15. package/build/chunk-A452S7R3.js.map +1 -0
  16. package/build/chunk-BODO6HIH.js +60 -0
  17. package/build/chunk-BODO6HIH.js.map +1 -0
  18. package/build/chunk-FJI2CMCE.js +439 -0
  19. package/build/chunk-FJI2CMCE.js.map +1 -0
  20. package/build/chunk-JYHZVRB2.js +80 -0
  21. package/build/chunk-JYHZVRB2.js.map +1 -0
  22. package/build/chunk-KQN5IYN6.js +97 -0
  23. package/build/chunk-KQN5IYN6.js.map +1 -0
  24. package/build/chunk-KTXNERHT.js +72 -0
  25. package/build/chunk-KTXNERHT.js.map +1 -0
  26. package/build/chunk-MFTC7XL2.js +141 -0
  27. package/build/chunk-MFTC7XL2.js.map +1 -0
  28. package/build/chunk-N4SSLHMP.js +108 -0
  29. package/build/chunk-N4SSLHMP.js.map +1 -0
  30. package/build/chunk-RNNW7OW2.js +270 -0
  31. package/build/chunk-RNNW7OW2.js.map +1 -0
  32. package/build/chunk-UAWBPTDW.js +51 -0
  33. package/build/chunk-UAWBPTDW.js.map +1 -0
  34. package/build/chunk-Z7CW5CAY.js +64 -0
  35. package/build/chunk-Z7CW5CAY.js.map +1 -0
  36. package/build/cli.d.ts +1 -0
  37. package/build/cli.js +253 -0
  38. package/build/cli.js.map +1 -0
  39. package/build/config.d.ts +13 -0
  40. package/build/config.js +15 -0
  41. package/build/config.js.map +1 -0
  42. package/build/descriptor.d.ts +96 -0
  43. package/build/descriptor.js +27 -0
  44. package/build/descriptor.js.map +1 -0
  45. package/build/device-auth.d.ts +6 -0
  46. package/build/device-auth.js +11 -0
  47. package/build/device-auth.js.map +1 -0
  48. package/build/locator.d.ts +140 -0
  49. package/build/locator.js +92 -0
  50. package/build/locator.js.map +1 -0
  51. package/build/paths.d.ts +11 -0
  52. package/build/paths.js +22 -0
  53. package/build/paths.js.map +1 -0
  54. package/build/pom-kcSMxwX2.d.ts +349 -0
  55. package/build/pom.d.ts +6 -0
  56. package/build/pom.js +37 -0
  57. package/build/pom.js.map +1 -0
  58. package/build/project.d.ts +13 -0
  59. package/build/project.js +19 -0
  60. package/build/project.js.map +1 -0
  61. package/build/provisioner.d.ts +34 -0
  62. package/build/provisioner.js +14 -0
  63. package/build/provisioner.js.map +1 -0
  64. package/build/recorder.d.ts +6 -0
  65. package/build/recorder.js +15 -0
  66. package/build/recorder.js.map +1 -0
  67. package/build/reporter.d.ts +16 -0
  68. package/build/reporter.js +426 -0
  69. package/build/reporter.js.map +1 -0
  70. package/build/schema.d.ts +49 -0
  71. package/build/schema.js +16 -0
  72. package/build/schema.js.map +1 -0
  73. package/build/storage-state.d.ts +22 -0
  74. package/build/storage-state.js +42 -0
  75. package/build/storage-state.js.map +1 -0
  76. package/build/store.d.ts +17 -0
  77. package/build/store.js +9 -0
  78. package/build/store.js.map +1 -0
  79. package/build/ui.d.ts +49 -0
  80. package/build/ui.js +56 -0
  81. package/build/ui.js.map +1 -0
  82. package/build/upload.d.ts +10 -0
  83. package/build/upload.js +8 -0
  84. package/build/upload.js.map +1 -0
  85. package/build/wait.d.ts +14 -0
  86. package/build/wait.js +50 -0
  87. package/build/wait.js.map +1 -0
  88. package/package.json +52 -0
  89. package/src/aria.ts +326 -0
  90. package/src/browser.ts +15 -0
  91. package/src/cli.ts +295 -0
  92. package/src/config.ts +16 -0
  93. package/src/descriptor.ts +179 -0
  94. package/src/device-auth.ts +188 -0
  95. package/src/locator.ts +683 -0
  96. package/src/paths.ts +70 -0
  97. package/src/pom.ts +2363 -0
  98. package/src/project.ts +77 -0
  99. package/src/provisioner.ts +183 -0
  100. package/src/recorder.ts +877 -0
  101. package/src/reporter.ts +561 -0
  102. package/src/schema.ts +37 -0
  103. package/src/storage-state.ts +71 -0
  104. package/src/store.ts +96 -0
  105. package/src/ui.ts +333 -0
  106. package/src/upload.ts +116 -0
  107. 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.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ // the bin is checked in so it can be linked before the package is built
3
+ import "../build/cli.js";
@@ -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"]}
@@ -0,0 +1,3 @@
1
+ declare function hideStyle(selectors: string[]): string | undefined;
2
+
3
+ export { hideStyle };
@@ -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":[]}