@unotest/web 0.43.2 → 0.45.0
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/.claude/skills/write-e2e-test/SKILL.md +7 -6
- package/.claude/skills/write-e2e-test-ground/SKILL.md +7 -6
- package/CHANGELOG.md +127 -3
- package/dist/config/schema.d.ts +260 -62
- package/dist/config/schema.js +1 -1
- package/dist/driver/index.d.ts +12 -3
- package/dist/driver/index.js +1 -1
- package/dist/dsl/index.d.ts +241 -6
- package/dist/dsl/index.js +1 -1
- package/dist/dsl/web-dsl-language-service.js +1 -1
- package/dist/inspection/page-inject.d.ts +1 -1
- package/dist/{interfaces-ClW2IRgY.d.ts → interfaces-OvnJKELk.d.ts} +232 -9
- package/dist/mcp/server.js +1 -1
- package/dist/runner/cli.js +1 -1
- package/dist/runner/init/chrome-probe.js +1 -1
- package/dist/runner/init.js +1 -1
- package/dist/runner/install-chromium.js +1 -1
- package/dist/runner/prepare-fix.js +1 -1
- package/dist/runner/scaffold-workspace.js +1 -1
- package/dist/runner/serve-fixture.js +1 -1
- package/dist/runner/web-runner-adapter.js +1 -1
- package/guides/agent-integration.md +8 -0
- package/guides/dsl-reference.md +846 -10
- package/package.json +9 -8
- package/types/unotest-dsl.d.ts +199 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InjectedDomHelpers } from '@unotest/grounder-client/dom-walker';
|
|
2
2
|
import { PickerMode } from '@unotest/protocol';
|
|
3
|
-
import { E as ElementHint } from '../interfaces-
|
|
3
|
+
import { E as ElementHint } from '../interfaces-OvnJKELk.js';
|
|
4
4
|
import '../config/schema.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
|
@@ -91,13 +91,28 @@ interface LaunchOptions {
|
|
|
91
91
|
/** Extra browser command-line arguments (`config.launch.args`). */
|
|
92
92
|
args?: string[];
|
|
93
93
|
}
|
|
94
|
-
interface
|
|
94
|
+
interface ViewportSize {
|
|
95
95
|
width: number;
|
|
96
96
|
height: number;
|
|
97
97
|
}
|
|
98
|
+
/** What a context is asked to look like. Each field left out comes from
|
|
99
|
+
* the device preset, or from DEFAULT_VIEWPORT when there is none. */
|
|
100
|
+
interface Viewport extends Partial<ViewportSize> {
|
|
101
|
+
/** Device pixels per CSS pixel. Fixed for the life of a context. */
|
|
102
|
+
deviceScaleFactor?: number;
|
|
103
|
+
}
|
|
98
104
|
interface ContextOptions {
|
|
99
105
|
baseUrl?: string;
|
|
100
|
-
|
|
106
|
+
/** A device preset by name — the driver owns the list and refuses a
|
|
107
|
+
* name it does not know. Applied before `viewport`, which overrides the
|
|
108
|
+
* preset's size and scale field by field. */
|
|
109
|
+
device?: string;
|
|
110
|
+
/** `null` — the real browser window, no size emulation. */
|
|
111
|
+
viewport?: Viewport | null;
|
|
112
|
+
/** Put a fake clock on the context before its first page loads, so that
|
|
113
|
+
* every timer the pages set is under `DriverContext.clock()`. Off by
|
|
114
|
+
* default: time on the page is the real one. */
|
|
115
|
+
clock?: boolean;
|
|
101
116
|
/** Path to storageState JSON (D-23 caching, optional). */
|
|
102
117
|
storageState?: string;
|
|
103
118
|
/** Per-context override for dialog policy. Defaults to config.dialogPolicy. */
|
|
@@ -231,11 +246,34 @@ interface ScreenshotOptions {
|
|
|
231
246
|
* as `png`. `webp` needs Playwright 1.62+, which is why the package
|
|
232
247
|
* pins that floor. */
|
|
233
248
|
type?: "png" | "jpeg" | "webp";
|
|
249
|
+
/** `"disabled"` — CSS animations and transitions are finished first, so
|
|
250
|
+
* two captures of the same page are the same picture (the visual
|
|
251
|
+
* assert). Default: as Playwright, animations run. */
|
|
252
|
+
animations?: "disabled" | "allow";
|
|
253
|
+
/** `"hide"` — the text caret is not drawn (it blinks). Default `"initial"`. */
|
|
254
|
+
caret?: "hide" | "initial";
|
|
234
255
|
}
|
|
235
256
|
/** Encoding options for an element capture — `ScreenshotOptions` minus
|
|
236
257
|
* the page-geometry fields (`fullPage`, `clip`) that have no meaning for a
|
|
237
258
|
* single element. */
|
|
238
|
-
type ElementScreenshotOptions = Pick<ScreenshotOptions, "type" | "quality">;
|
|
259
|
+
type ElementScreenshotOptions = Pick<ScreenshotOptions, "type" | "quality" | "animations" | "caret">;
|
|
260
|
+
/** A rectangle in the PIXELS of a capture (device pixels, the capture's own
|
|
261
|
+
* origin) — where an element lies in a screenshot. */
|
|
262
|
+
interface CaptureRect {
|
|
263
|
+
x: number;
|
|
264
|
+
y: number;
|
|
265
|
+
width: number;
|
|
266
|
+
height: number;
|
|
267
|
+
}
|
|
268
|
+
/** Which capture a `CaptureRect` is measured in. */
|
|
269
|
+
type CaptureFrame = {
|
|
270
|
+
kind: "viewport";
|
|
271
|
+
} | {
|
|
272
|
+
kind: "fullPage";
|
|
273
|
+
} | {
|
|
274
|
+
kind: "element";
|
|
275
|
+
loc: LocatorValue;
|
|
276
|
+
};
|
|
239
277
|
interface CookieOptions {
|
|
240
278
|
domain?: string;
|
|
241
279
|
path?: string;
|
|
@@ -250,7 +288,12 @@ interface CookieOptions {
|
|
|
250
288
|
* dismisses every dialog on behalf of the client that has none — and a
|
|
251
289
|
* second client watching the run's page would answer `confirm()` with
|
|
252
290
|
* "no" before the run's own accept lands. */
|
|
253
|
-
|
|
291
|
+
interface AttachOptions extends Pick<ContextOptions, "dialogPolicy"> {
|
|
292
|
+
/** The browser's id of the context to attach to (CDP `browserContextId`,
|
|
293
|
+
* as the run publishes it). Unset, or not found → the first context
|
|
294
|
+
* with an open page, as before. */
|
|
295
|
+
contextId?: string;
|
|
296
|
+
}
|
|
254
297
|
|
|
255
298
|
interface WebDriver {
|
|
256
299
|
/**
|
|
@@ -280,7 +323,7 @@ interface WebDriver {
|
|
|
280
323
|
*/
|
|
281
324
|
wsEndpoint(): string | undefined;
|
|
282
325
|
connectShared(wsEndpoint: string, browser: LaunchOptions["browser"]): Promise<void>;
|
|
283
|
-
attachExisting(opts?: AttachOptions): DriverContext
|
|
326
|
+
attachExisting(opts?: AttachOptions): Promise<DriverContext>;
|
|
284
327
|
}
|
|
285
328
|
/** One captured network request/response, recorded only under
|
|
286
329
|
* `UNOTEST_NETWORK`. `status`/`ok` come from the response; `failureText`
|
|
@@ -298,6 +341,100 @@ interface NetworkEntry {
|
|
|
298
341
|
/** Total request→response-end time (ms), from Playwright request timing. */
|
|
299
342
|
durationMs?: number;
|
|
300
343
|
timestamp: string;
|
|
344
|
+
/** The request never reached the network: a `mockRoute` answered or
|
|
345
|
+
* aborted it. Absent for requests a mock let through. */
|
|
346
|
+
mocked?: true;
|
|
347
|
+
}
|
|
348
|
+
/** A file a page of the context downloaded. The bytes stay with the
|
|
349
|
+
* browser until `saveAs` copies them out. */
|
|
350
|
+
interface DriverDownload {
|
|
351
|
+
/** The name the site suggested (`Content-Disposition`, `download`). */
|
|
352
|
+
readonly name: string;
|
|
353
|
+
/** Copy the file to `path` (absolute); resolves once it is written. */
|
|
354
|
+
saveAs(path: string): Promise<void>;
|
|
355
|
+
}
|
|
356
|
+
/** Which downloads `waitForDownload` accepts, by suggested name. `describe`
|
|
357
|
+
* is an infinitive for the timeout message ("contain \"report\""). */
|
|
358
|
+
interface DownloadNameFilter {
|
|
359
|
+
matches(name: string): boolean;
|
|
360
|
+
describe(): string;
|
|
361
|
+
}
|
|
362
|
+
/** A fake clock shared by every page of a context. Time runs by itself
|
|
363
|
+
* until `freeze`, and again after `run`. */
|
|
364
|
+
interface DriverClock {
|
|
365
|
+
/** Stop time at `at`: `Date` reads it, and no timer fires until `tick`
|
|
366
|
+
* or `run`. Any instant, past or future — no timer fires on the way. */
|
|
367
|
+
freeze(at: Date): Promise<void>;
|
|
368
|
+
/** Advance frozen time by `ms`, firing every timer due in it. */
|
|
369
|
+
tick(ms: number): Promise<void>;
|
|
370
|
+
/** Let time run again from where it stands. */
|
|
371
|
+
run(): Promise<void>;
|
|
372
|
+
/** Whether time stands still now (after `freeze`, before `run`). While
|
|
373
|
+
* it does, `requestAnimationFrame` does not fire either — a wait for a
|
|
374
|
+
* painted frame would wait for nothing. */
|
|
375
|
+
frozen(): boolean;
|
|
376
|
+
}
|
|
377
|
+
/** What a mocked route does with a request it catches. */
|
|
378
|
+
type RouteResponse = {
|
|
379
|
+
kind: "fulfill";
|
|
380
|
+
status: number;
|
|
381
|
+
body: string;
|
|
382
|
+
contentType?: string;
|
|
383
|
+
headers: Readonly<Record<string, string>>;
|
|
384
|
+
}
|
|
385
|
+
/** `record` keeps every aborted request, for `blocked` to report. */
|
|
386
|
+
| {
|
|
387
|
+
kind: "abort";
|
|
388
|
+
record: boolean;
|
|
389
|
+
} | {
|
|
390
|
+
kind: "continue";
|
|
391
|
+
};
|
|
392
|
+
/** A request as the page sent it. */
|
|
393
|
+
interface CapturedRequest {
|
|
394
|
+
url: string;
|
|
395
|
+
method: string;
|
|
396
|
+
headers: Readonly<Record<string, string>>;
|
|
397
|
+
/** The body as sent, or null when there is none. */
|
|
398
|
+
postData: string | null;
|
|
399
|
+
/** The body parsed as JSON, or null when it is absent or not JSON. */
|
|
400
|
+
postDataJson: unknown;
|
|
401
|
+
}
|
|
402
|
+
/** A service worker of the context — an MV3 extension's background. MV3
|
|
403
|
+
* puts an idle worker to sleep, so a handle is good for the call at hand:
|
|
404
|
+
* ask the context for the worker again next time. */
|
|
405
|
+
interface DriverWorker {
|
|
406
|
+
url(): string;
|
|
407
|
+
/** Like `DriverPage.evaluate`, in the worker: a function source is
|
|
408
|
+
* CALLED with `arg`. */
|
|
409
|
+
evaluate<T = unknown>(js: string, arg?: unknown): Promise<T>;
|
|
410
|
+
}
|
|
411
|
+
/** A request a recording abort stopped, with when it was stopped. */
|
|
412
|
+
interface BlockedRequest {
|
|
413
|
+
url: string;
|
|
414
|
+
method: string;
|
|
415
|
+
/** Epoch milliseconds. */
|
|
416
|
+
at: number;
|
|
417
|
+
}
|
|
418
|
+
/** The context's route mocks. Masks use Playwright's URL glob syntax;
|
|
419
|
+
* where several match one request, the one mocked last answers it, and
|
|
420
|
+
* mocking a mask again replaces its answer and makes it the latest.
|
|
421
|
+
* Mocks last as long as the context. */
|
|
422
|
+
interface DriverNetwork {
|
|
423
|
+
mock(glob: string, response: RouteResponse): Promise<void>;
|
|
424
|
+
/** Take off the mock at `glob`, or every mock when it is omitted.
|
|
425
|
+
* What a recording abort kept stays readable through `blocked`. */
|
|
426
|
+
unmock(glob?: string): Promise<void>;
|
|
427
|
+
/** The next request matching `glob` not yet returned by an earlier
|
|
428
|
+
* wait. A mocked mask keeps its requests from the moment it was
|
|
429
|
+
* mocked, so one sent before the wait is still found; any other mask
|
|
430
|
+
* sees requests from the call on. Throws TimeoutError after `timeoutMs`. */
|
|
431
|
+
waitForRequest(glob: string, opts: {
|
|
432
|
+
timeoutMs: number;
|
|
433
|
+
}): Promise<CapturedRequest>;
|
|
434
|
+
/** The requests stopped by the recording abort at `glob`. Throws when
|
|
435
|
+
* `glob` was never mocked with a recording abort: an empty answer
|
|
436
|
+
* would then mean "nothing was watched", not "nothing left". */
|
|
437
|
+
blocked(glob: string): ReadonlyArray<BlockedRequest>;
|
|
301
438
|
}
|
|
302
439
|
interface DriverContext {
|
|
303
440
|
/** Currently-open tabs/windows in this context. Index 0 = first opened. */
|
|
@@ -306,8 +443,26 @@ interface DriverContext {
|
|
|
306
443
|
activePage(): DriverPage;
|
|
307
444
|
/** Switch the active page index (D-4 setPage). 0 = first opened, etc.
|
|
308
445
|
* Implementations MUST also reset the frame stack — a frame scope
|
|
309
|
-
* established on tab A is not valid on tab B.
|
|
310
|
-
|
|
446
|
+
* established on tab A is not valid on tab B. `activate: false` moves
|
|
447
|
+
* only the runner's target and leaves the browser's front tab as is
|
|
448
|
+
* (default `true`: the tab is brought to front too). */
|
|
449
|
+
setActivePage(index: number, opts?: {
|
|
450
|
+
activate?: boolean;
|
|
451
|
+
}): Promise<void>;
|
|
452
|
+
/** Bring a tab to front — the browser's visible tab, not the runner's
|
|
453
|
+
* target. Absent index → the active page. Throws `DriverError` on an
|
|
454
|
+
* index no open tab has. */
|
|
455
|
+
bringToFront(index?: number): Promise<void>;
|
|
456
|
+
/** Open a blank tab in this context and make it the active page (brought
|
|
457
|
+
* to front, frame stack reset). It counts as handed: `waitForNewPage`
|
|
458
|
+
* never returns it. Resolves with its index. */
|
|
459
|
+
newPage(): Promise<number>;
|
|
460
|
+
/** Close a tab. Absent index → the active page. Closing the active page
|
|
461
|
+
* makes the page that was active before it active again (the one at the
|
|
462
|
+
* index below when that one is gone); closing another tab keeps the
|
|
463
|
+
* active page. Throws `DriverError` on an index no open tab has, and on
|
|
464
|
+
* the only open tab — nothing would be left to drive. */
|
|
465
|
+
closePage(index?: number): Promise<void>;
|
|
311
466
|
/**
|
|
312
467
|
* Subscribe to new-page events. Listener fires when a tab/window opens
|
|
313
468
|
* in this context (`target="_blank"`, `window.open`, etc.). Returns an
|
|
@@ -322,6 +477,17 @@ interface DriverContext {
|
|
|
322
477
|
index: number;
|
|
323
478
|
url: string;
|
|
324
479
|
}) => void): () => void;
|
|
480
|
+
/**
|
|
481
|
+
* Resolve with the index of the first open tab the scenario has not been
|
|
482
|
+
* handed yet, waiting up to `timeoutMs` (default: the navigation budget)
|
|
483
|
+
* for one to open. "Handed" = open when the context started, switched to
|
|
484
|
+
* by `setActivePage`, or returned here before — so a tab opened by a click
|
|
485
|
+
* a step earlier still counts, and no tab is returned twice. Throws
|
|
486
|
+
* `TimeoutError` naming how many tabs are open. Does not switch to it.
|
|
487
|
+
*/
|
|
488
|
+
waitForNewPage(opts?: {
|
|
489
|
+
timeoutMs?: number;
|
|
490
|
+
}): Promise<number>;
|
|
325
491
|
/**
|
|
326
492
|
* Enter a frame scope (D-4 stateful pair). All subsequent locators
|
|
327
493
|
* resolve inside this frame until `exitFrame()` is called. Stacks (calling
|
|
@@ -334,6 +500,32 @@ interface DriverContext {
|
|
|
334
500
|
* before auto-switching to a popup (frame scope does not survive tab
|
|
335
501
|
* changes). */
|
|
336
502
|
frameDepth(): number;
|
|
503
|
+
/**
|
|
504
|
+
* Resize every open page of this context, and every page it opens after
|
|
505
|
+
* this call. Width and height only: the device scale factor is fixed when
|
|
506
|
+
* the context is created — changing it would mean a new context and the
|
|
507
|
+
* loss of the page, which a resize must never cost.
|
|
508
|
+
*/
|
|
509
|
+
setViewport(size: ViewportSize): Promise<void>;
|
|
510
|
+
/** The browser's own id of this context (CDP `browserContextId`), the
|
|
511
|
+
* same in every process connected to the browser — or null where the
|
|
512
|
+
* engine has no such id to give (Firefox, WebKit) or no page is open. */
|
|
513
|
+
browserContextId(): Promise<string | null>;
|
|
514
|
+
/** The page clock. Works only on a context opened with `clock: true`
|
|
515
|
+
* (the fake clock must be in place before the first page loads, or the
|
|
516
|
+
* page's own timers stay real) — otherwise every call throws
|
|
517
|
+
* ClockNotInstalledError. */
|
|
518
|
+
clock(): DriverClock;
|
|
519
|
+
/** Route mocks of this context: every page, tab and frame of it. */
|
|
520
|
+
network(): DriverNetwork;
|
|
521
|
+
/** A running service worker whose URL matches `url` (substring or
|
|
522
|
+
* regex; any when omitted), or the first to start within `timeoutMs`
|
|
523
|
+
* (default: the context's navigation timeout). Throws at once on a
|
|
524
|
+
* context without a browser profile — extensions never load there. */
|
|
525
|
+
waitForServiceWorker(opts?: {
|
|
526
|
+
timeoutMs?: number;
|
|
527
|
+
url?: Matcher;
|
|
528
|
+
}): Promise<DriverWorker>;
|
|
337
529
|
/** Typed storage shortcuts (D-6). */
|
|
338
530
|
setLocalStorage(key: string, value: string): Promise<void>;
|
|
339
531
|
getLocalStorage(key: string): Promise<string | null>;
|
|
@@ -364,6 +556,18 @@ interface DriverContext {
|
|
|
364
556
|
* `network.json` for the viewer's Network tab.
|
|
365
557
|
*/
|
|
366
558
|
networkEntries(): ReadonlyArray<NetworkEntry>;
|
|
559
|
+
/**
|
|
560
|
+
* The first download of this context the scenario has not taken yet,
|
|
561
|
+
* waiting up to `timeoutMs` (default: the navigation budget) for one.
|
|
562
|
+
* Downloads are recorded from the moment the context opens, on every
|
|
563
|
+
* page, so one a click started before this call is not lost. `name`
|
|
564
|
+
* narrows to downloads whose suggested file name it accepts. Each
|
|
565
|
+
* download is handed out once. Throws `TimeoutError` when none comes.
|
|
566
|
+
*/
|
|
567
|
+
waitForDownload(opts?: {
|
|
568
|
+
timeoutMs?: number;
|
|
569
|
+
name?: DownloadNameFilter;
|
|
570
|
+
}): Promise<DriverDownload>;
|
|
367
571
|
/** Close all pages in this context. Idempotent. */
|
|
368
572
|
close(): Promise<void>;
|
|
369
573
|
}
|
|
@@ -404,6 +608,9 @@ interface DriverPage {
|
|
|
404
608
|
* `value` is the submitted payload ("on" by default), never its state. */
|
|
405
609
|
checkedState(loc: LocatorValue): Promise<boolean | null>;
|
|
406
610
|
isVisible(loc: LocatorValue): Promise<boolean>;
|
|
611
|
+
/** Where the matched element lies in the viewport, CSS pixels; `null`
|
|
612
|
+
* when it is not rendered (display:none, detached). No scrolling. */
|
|
613
|
+
boundingBox(loc: LocatorValue): Promise<BoundingBox | null>;
|
|
407
614
|
/** Disabled state of the matched element: native `:disabled` (covers
|
|
408
615
|
* fieldset inheritance) OR `aria-disabled="true"`. Boolean attributes
|
|
409
616
|
* are invisible through `getAttribute` (`""` present vs `null` absent
|
|
@@ -437,12 +644,21 @@ interface DriverPage {
|
|
|
437
644
|
* CALLED with `arg` — that is the documented multi-arg escape hatch
|
|
438
645
|
* (`evaluate('function([a, b]) { … }', 1, 2)`). */
|
|
439
646
|
evaluate<T = unknown>(js: string, arg?: unknown): Promise<T>;
|
|
440
|
-
|
|
647
|
+
/** `evaluate` on the matched element: a function body is called with
|
|
648
|
+
* the element and `arg`. */
|
|
649
|
+
evaluateOnLocator<T = unknown>(loc: LocatorValue, js: string, arg?: unknown): Promise<T>;
|
|
441
650
|
screenshot(opts?: ScreenshotOptions): Promise<Buffer>;
|
|
442
651
|
/** Capture ONE element (first match, scrolled into view) instead of the
|
|
443
652
|
* viewport — the evidence shot of a card / row / dialog. Same encoding
|
|
444
653
|
* options as `screenshot`; `fullPage` / `clip` don't apply. */
|
|
445
654
|
screenshotElement(loc: LocatorValue, opts?: ElementScreenshotOptions): Promise<Buffer>;
|
|
655
|
+
/** Where each element lies in a capture of `frame`, in that capture's
|
|
656
|
+
* pixels (device pixel ratio, page scroll and the element's own box
|
|
657
|
+
* applied) — the masks of the visual assert. Each locator must match
|
|
658
|
+
* exactly one element (a locator that matches none is an error, not a
|
|
659
|
+
* skipped mask); an element that is not rendered has no box and is
|
|
660
|
+
* left out. */
|
|
661
|
+
boxesInCapture(locs: readonly LocatorValue[], frame: CaptureFrame): Promise<CaptureRect[]>;
|
|
446
662
|
inspectElement(loc: LocatorValue, opts?: InspectElementOptions): Promise<ElementHint | null>;
|
|
447
663
|
/** HTML of the element the locator matches (first match), redacted like
|
|
448
664
|
* page.html — secret and hidden field values and script content become
|
|
@@ -458,6 +674,13 @@ interface DriverPage {
|
|
|
458
674
|
* optional — an element might have only a role+name, or only a testId,
|
|
459
675
|
* or nothing stable at all (in which case the resolver throws).
|
|
460
676
|
*/
|
|
677
|
+
/** An element's box in the viewport, CSS pixels — Playwright's shape. */
|
|
678
|
+
interface BoundingBox {
|
|
679
|
+
x: number;
|
|
680
|
+
y: number;
|
|
681
|
+
width: number;
|
|
682
|
+
height: number;
|
|
683
|
+
}
|
|
461
684
|
/** How `inspectElement` reads the element's `readable` text. By default
|
|
462
685
|
* whitespace folded and clipped to 200 — a hint. `whole` keeps the text as
|
|
463
686
|
* it is, up to `limit` characters, for a refusal that quotes it (#256). */
|
|
@@ -565,4 +788,4 @@ interface AncestorHint {
|
|
|
565
788
|
className?: string;
|
|
566
789
|
}
|
|
567
790
|
|
|
568
|
-
export { type AttachOptions as A, type
|
|
791
|
+
export { type AttachOptions as A, type BoundingBox as B, type CaptureFrame as C, type DriverContext as D, type ElementHint as E, type FillOptions as F, type GotoOptions as G, type HoverOptions as H, type LocatorValue as L, type NetworkEntry as N, type PressOptions as P, type ReloadOptions as R, type ScreenshotOptions as S, type Viewport as V, type WebDriver as W, type CaptureRect as a, type LaunchOptions as b, type ContextOptions as c, type ActionTimeout as d, type CheckOptions as e, type ClickOptions as f, type CookieOptions as g, type DriverPage as h, type NavigationOptions as i, type SelectOptions as j, type ViewportSize as k, type WaitOptions as l, type WaitState as m, type DriverDownload as n, type LocatorStep as o, appendStep as p, describeLocator as q, isLocatorValue as r, rootedAt as s };
|