@unotest/web 0.9.1 → 0.11.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.
@@ -45,11 +45,17 @@ type LocatorStep = {
45
45
  } | {
46
46
  kind: 'nth';
47
47
  index: number;
48
+ } | {
49
+ kind: 'randomNth';
48
50
  } | {
49
51
  kind: 'contentFrame';
50
52
  } | {
51
53
  kind: 'ref';
52
54
  ref: string;
55
+ } | {
56
+ kind: 'intent';
57
+ intent: string;
58
+ ordinal?: 'first' | 'last' | number;
53
59
  };
54
60
  interface LocatorValue {
55
61
  readonly kind: 'locator';
@@ -163,6 +169,18 @@ type WaitState = "attached" | "detached" | "visible" | "hidden";
163
169
  interface WaitOptions extends ActionTimeout {
164
170
  state?: WaitState;
165
171
  }
172
+ interface WaitForTextOptions extends WaitOptions {
173
+ /** @deprecated No-op: "first visible occurrence" is the default now.
174
+ * Chat feeds and repeated labels made the old whole-list strict-mode
175
+ * wait a footgun — ≥1 visible match is what "the text is on screen"
176
+ * means. Kept so recorded scenarios with {first: true} stay valid. */
177
+ first?: boolean;
178
+ /** Match the full text exactly (Playwright getByText semantics).
179
+ * Default: substring, which also matches INSIDE a word ("hi" hits
180
+ * "anything") — pass a regex with \b anchors via the DSL for
181
+ * word-boundary matching. */
182
+ exact?: boolean;
183
+ }
166
184
  interface NavigationOptions extends ActionTimeout {
167
185
  /**
168
186
  * When to consider navigation done. Default: 'load'.
@@ -328,20 +346,39 @@ interface DriverPage {
328
346
  scrollIntoView(loc: LocatorValue): Promise<void>;
329
347
  /** Drag the source element onto the target. */
330
348
  dragAndDrop(from: LocatorValue, to: LocatorValue, opts?: ClickOptions): Promise<void>;
331
- /** Set the input element's selected files. Accepts one or many paths. */
332
- uploadFile(loc: LocatorValue, files: string | ReadonlyArray<string>): Promise<void>;
349
+ /** Set the input element's selected files. Accepts a path, path[], or an in-memory file buffer. */
350
+ uploadFile(loc: LocatorValue, files: string | ReadonlyArray<string> | {
351
+ name: string;
352
+ mimeType: string;
353
+ buffer: Buffer;
354
+ }): Promise<void>;
333
355
  /** Focus the locator then dispatch a paste-like input with `text`. */
334
356
  clipboardPaste(loc: LocatorValue, text: string): Promise<void>;
335
357
  count(loc: LocatorValue): Promise<number>;
336
358
  textContent(loc: LocatorValue): Promise<string | null>;
337
359
  inputValue(loc: LocatorValue): Promise<string>;
360
+ /** Checked state of a checkbox / radio / switch, `null` when the element
361
+ * is none of those. Separate from `inputValue` on purpose: a checkbox's
362
+ * `value` is the submitted payload ("on" by default), never its state. */
363
+ checkedState(loc: LocatorValue): Promise<boolean | null>;
338
364
  isVisible(loc: LocatorValue): Promise<boolean>;
339
365
  /** Read a DOM attribute on the matched element. Returns null if absent. */
340
366
  getAttribute(loc: LocatorValue, name: string): Promise<string | null>;
341
367
  waitFor(loc: LocatorValue, opts?: WaitOptions): Promise<void>;
342
368
  waitForUrl(pattern: string | RegExp, opts?: NavigationOptions): Promise<void>;
343
- waitForText(text: string, opts?: WaitOptions): Promise<void>;
369
+ /** Wait until ≥1 VISIBLE occurrence of `text` matches (or none, with
370
+ * `state: 'hidden' | 'detached'`). Accepts a regex matcher in the
371
+ * JSON-safe `Matcher` shape. */
372
+ waitForText(text: Matcher, opts?: WaitForTextOptions): Promise<void>;
344
373
  waitForNavigation(opts?: NavigationOptions): Promise<void>;
374
+ /** Wait for a page-level lifecycle state on the CURRENT document (no
375
+ * navigation required). Diagnostics-only — it backs the pre-capture
376
+ * settle for screenshots, never a DSL action: a test that waits on
377
+ * "the network went quiet" instead of on visible app state is exactly
378
+ * the flaky pattern the linter rejects. */
379
+ waitForLoadState(state: "load" | "domcontentloaded" | "networkidle", opts?: {
380
+ timeout?: number;
381
+ }): Promise<void>;
345
382
  goto(url: string, opts?: GotoOptions): Promise<void>;
346
383
  reload(opts?: ReloadOptions): Promise<void>;
347
384
  goBack(opts?: NavigationOptions): Promise<void>;
@@ -392,6 +429,16 @@ interface ElementHint {
392
429
  /** textContent (trimmed, clipped). Last-resort semantic fallback
393
430
  * before the CSS escape hatch. */
394
431
  text?: string;
432
+ /** Descendant text of a STRUCTURAL container (record row / card /
433
+ * tree-item / `<li>` / `<tr>`) that carries no accessible name of its
434
+ * own — its identifying text lives in children, so it has no `name`/
435
+ * `text` signal. Captured ONLY when short enough to name a single
436
+ * record (not a whole table/section). The resolver turns it into
437
+ * `getByRole(role).filter({hasText})` — the sole semantic handle on
438
+ * containers materialised from unit-grounded asserts (assert_visible on
439
+ * a record). Kept separate from `text` so ARIA name semantics (a
440
+ * container takes its name only from aria-label/labelledby) hold. */
441
+ containerText?: string;
395
442
  /** href attribute for `<a>` elements lacking any of the above.
396
443
  * Resolver emits `locator('a[href="..."]')`. */
397
444
  href?: string;