@unotest/web 0.46.0 → 0.47.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/CHANGELOG.md +49 -3
- package/README.md +5 -0
- package/dist/config/schema.d.ts +106 -106
- package/dist/config/schema.js +1 -1
- package/dist/driver/index.d.ts +7 -2
- package/dist/driver/index.js +1 -1
- package/dist/dsl/index.d.ts +7 -2
- package/dist/dsl/index.js +1 -1
- package/dist/dsl/web-dsl-language-service.js +1 -1
- package/dist/inspection/page-inject.d.ts +10 -2
- package/dist/inspection/page-inject.js +12 -0
- package/dist/{interfaces-CYoL4Taq.d.ts → interfaces-LE6GsJ0c.d.ts} +22 -1
- 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/dsl-reference.md +168 -5
- package/package.json +8 -8
- package/types/unotest-dsl.d.ts +54 -5
package/guides/dsl-reference.md
CHANGED
|
@@ -515,11 +515,16 @@ assertCount(getByRole('listitem'), 5)
|
|
|
515
515
|
|
|
516
516
|
### `assertUrl(pattern, options?)`
|
|
517
517
|
|
|
518
|
-
|
|
518
|
+
A string is a substring match against the active page's URL. A
|
|
519
|
+
`/regex/` is tested against the whole URL, unanchored: add `^` or `$`
|
|
520
|
+
yourself. A failure names the regex as `/source/flags`.
|
|
521
|
+
|
|
522
|
+
**Options:** `timeout?`.
|
|
519
523
|
|
|
520
524
|
```js
|
|
521
525
|
assertUrl('/dashboard')
|
|
522
526
|
assertUrl('https://example.com/checkout')
|
|
527
|
+
assertUrl(/\/cars\/\d+$/)
|
|
523
528
|
```
|
|
524
529
|
|
|
525
530
|
### `assertTrue(value, message)`
|
|
@@ -844,12 +849,16 @@ goto('/dashboard') // relative — resolved against the
|
|
|
844
849
|
|
|
845
850
|
### `waitForUrl(pattern, options?)`
|
|
846
851
|
|
|
847
|
-
Wait until the active page URL contains `pattern
|
|
848
|
-
that triggers
|
|
852
|
+
Wait until the active page URL contains `pattern` (a string) or matches
|
|
853
|
+
it (a `/regex/`, unanchored). Useful after a click that triggers
|
|
854
|
+
navigation.
|
|
855
|
+
|
|
856
|
+
**Options:** `timeout?`.
|
|
849
857
|
|
|
850
858
|
```js
|
|
851
859
|
click(getByRole('link', {name: 'Settings'}));
|
|
852
860
|
waitForUrl('/settings');
|
|
861
|
+
waitForUrl(/\/orders\/\d+/);
|
|
853
862
|
```
|
|
854
863
|
|
|
855
864
|
### `waitForNavigation(options?)`
|
|
@@ -964,6 +973,23 @@ waitForCount(locator('[data-id]'), 3, {timeout: 90000});
|
|
|
964
973
|
waitForText(/\bshipping\b/i, {timeout: 90000});
|
|
965
974
|
```
|
|
966
975
|
|
|
976
|
+
### `waitForAnimations(loc, options?)`
|
|
977
|
+
|
|
978
|
+
Wait until the element and its descendants have no animation still
|
|
979
|
+
running — a dialog done fading in, a card done sliding — before reading
|
|
980
|
+
or screenshotting it. Infinite animations (spinners) and paused ones are
|
|
981
|
+
not waited for: neither ends by itself, so waiting could only time out.
|
|
982
|
+
A static element returns at once. Same rule as `hasAnimation`.
|
|
983
|
+
|
|
984
|
+
Options: `{ timeout? }` (default 5000 ms). A timeout is an error naming
|
|
985
|
+
the element and how many animations were still running.
|
|
986
|
+
|
|
987
|
+
```js
|
|
988
|
+
click(getByRole('button', {name: 'Edit'}));
|
|
989
|
+
waitForAnimations(getByRole('dialog'));
|
|
990
|
+
assertScreenshot(getByRole('dialog'), 'edit-dialog');
|
|
991
|
+
```
|
|
992
|
+
|
|
967
993
|
### `pause(ms)`
|
|
968
994
|
|
|
969
995
|
Hard sleep. **Avoid** — the linter flags it (`lint:pause-explicit`). Use
|
|
@@ -1232,6 +1258,27 @@ would be lost. See [Viewport and scale](#viewport-and-scale).
|
|
|
1232
1258
|
Playwright keeps it, and nothing hands the page back to the window. For
|
|
1233
1259
|
the real window, set `viewport: null` in the config.
|
|
1234
1260
|
|
|
1261
|
+
### `emulateMedia({reducedMotion?, colorScheme?})`
|
|
1262
|
+
|
|
1263
|
+
Change the media features the current tab reports, mid-scenario — what
|
|
1264
|
+
`matchMedia` and CSS `@media` see from that moment, without a reload.
|
|
1265
|
+
`reducedMotion`: `'reduce'` | `'no-preference'`; `colorScheme`:
|
|
1266
|
+
`'light'` | `'dark'` | `'no-preference'`. A feature left out keeps its
|
|
1267
|
+
current value. An unknown key, another value or an empty object is
|
|
1268
|
+
refused on that line.
|
|
1269
|
+
|
|
1270
|
+
```js
|
|
1271
|
+
emulateMedia({reducedMotion: 'reduce'}); // the app's no-animation path
|
|
1272
|
+
click(getByRole('button', {name: 'Edit'}));
|
|
1273
|
+
assertScreenshot(getByRole('dialog'), 'edit-dialog-still');
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
It applies to **this tab only**: a tab or popup opened afterwards — even
|
|
1277
|
+
by the same browser context — starts without it; call `emulateMedia`
|
|
1278
|
+
again after `setPage` / `waitForPage`. An app that reads the color
|
|
1279
|
+
scheme once at load sees the change on its next load (`reload()`), not
|
|
1280
|
+
before.
|
|
1281
|
+
|
|
1235
1282
|
#### Viewport and scale
|
|
1236
1283
|
|
|
1237
1284
|
Where the window's size and scale come from, first match wins:
|
|
@@ -1863,6 +1910,10 @@ mockRoute('**/ads/**', { abort: true });
|
|
|
1863
1910
|
navigation to your site still loads. Only the document: its scripts,
|
|
1864
1911
|
styles, images and API calls are ordinary requests, and an abort mask
|
|
1865
1912
|
that matches them stops them.
|
|
1913
|
+
- A mask reaches web requests only: http(s) and ws(s). An extension's
|
|
1914
|
+
own pages and scripts (`chrome-extension://`) load under `**/*`, so
|
|
1915
|
+
a network allowlist does not leave its UI dead. To mock one of them,
|
|
1916
|
+
start the mask with its scheme: `chrome-extension://<id>/panel.js`.
|
|
1866
1917
|
|
|
1867
1918
|
A network allowlist is two masks — the later one wins where both match.
|
|
1868
1919
|
The second one lets through everything your app loads from its own
|
|
@@ -1957,6 +2008,29 @@ box = boundingBox(getByRole('dialog'));
|
|
|
1957
2008
|
assertTrue(box.width <= 480, json(box));
|
|
1958
2009
|
```
|
|
1959
2010
|
|
|
2011
|
+
### `computedStyle(loc, property)` → `string`
|
|
2012
|
+
|
|
2013
|
+
The element's computed CSS value, as the browser resolved it — what
|
|
2014
|
+
`getComputedStyle(el).getPropertyValue(property)` gives, trimmed.
|
|
2015
|
+
Custom properties read too, inherited ones included; a property that is
|
|
2016
|
+
not set reads `""`. A missing or ambiguous element fails as
|
|
2017
|
+
`getAttribute` does.
|
|
2018
|
+
|
|
2019
|
+
```js
|
|
2020
|
+
assertTrue(computedStyle(getByRole('dialog'), 'opacity') == 1, 'dialog is faded');
|
|
2021
|
+
accent = computedStyle(locator('body'), '--accent');
|
|
2022
|
+
```
|
|
2023
|
+
|
|
2024
|
+
### `hasAnimation(loc)` → `boolean`
|
|
2025
|
+
|
|
2026
|
+
Whether the element or a descendant has an animation still running
|
|
2027
|
+
towards an end. Infinite (spinners) and paused animations do not count —
|
|
2028
|
+
the rule `waitForAnimations` waits by.
|
|
2029
|
+
|
|
2030
|
+
```js
|
|
2031
|
+
assertTrue(hasAnimation(getByRole('dialog')) === false, 'dialog still moving');
|
|
2032
|
+
```
|
|
2033
|
+
|
|
1960
2034
|
### `getTitle()` → `string`
|
|
1961
2035
|
|
|
1962
2036
|
Active page title.
|
|
@@ -2047,6 +2121,60 @@ src = getAttribute(locator('iframe#chat'), 'src');
|
|
|
2047
2121
|
assertEqual(urlParam(src, 'roomId'), 'r-7');
|
|
2048
2122
|
```
|
|
2049
2123
|
|
|
2124
|
+
### `toNumber(text, options?)` → `number`
|
|
2125
|
+
|
|
2126
|
+
A number as a page writes it, for arithmetic and comparison. What
|
|
2127
|
+
`parseInt`, `parseFloat` and `Number` would be in JS.
|
|
2128
|
+
|
|
2129
|
+
- Spaces group digits, NBSP and the narrow NBSP too: `'1 234 567'`.
|
|
2130
|
+
- A leading sign: `-`, `+` or the typographic minus `−`.
|
|
2131
|
+
- With both `,` and `.`, the last one is the decimal mark:
|
|
2132
|
+
`'1,234.56'` and `'1.234,56'` are both 1234.56. One mark used twice
|
|
2133
|
+
groups: `'1,234,567'`. One mark used once is the decimal mark:
|
|
2134
|
+
`'12,5'`, `'0.125'`.
|
|
2135
|
+
- `'1,234'` and `'1.234'` read both ways (1234 or 1.234), so they fail
|
|
2136
|
+
the step unless `{decimal: ','}` or `{decimal: '.'}` says which. With
|
|
2137
|
+
`{decimal}` the other mark may only group digits left of it.
|
|
2138
|
+
- Anything else fails the step and quotes the input: units and
|
|
2139
|
+
currency (`'440px'`, `'€12'`), exponents, an empty string. Cut the
|
|
2140
|
+
number out first with `textMatches`.
|
|
2141
|
+
- A number passes through unchanged.
|
|
2142
|
+
|
|
2143
|
+
```js
|
|
2144
|
+
total = toNumber(getInnerText(getByTestId('total'))); // "1 234,50"
|
|
2145
|
+
assertTrue(total > 1000, 'total: ' + total);
|
|
2146
|
+
width = toNumber(textMatches(computedStyle(phone, '--phone-w'), /(\d+)px/)[1]);
|
|
2147
|
+
```
|
|
2148
|
+
|
|
2149
|
+
### `round(n, digits?)` → `number`
|
|
2150
|
+
|
|
2151
|
+
Round to `digits` decimals, 0 to 10, default 0. Half goes away from
|
|
2152
|
+
zero, on the decimal as written: `round(2.5)` is 3, `round(-2.5)` is
|
|
2153
|
+
-3, `round(1.005, 2)` is 1.01. A string fails: read it with
|
|
2154
|
+
`toNumber` first.
|
|
2155
|
+
|
|
2156
|
+
```js
|
|
2157
|
+
payout = round(stake * odds, 2);
|
|
2158
|
+
```
|
|
2159
|
+
|
|
2160
|
+
### `formatNumber(n, options?)` → `string`
|
|
2161
|
+
|
|
2162
|
+
A number as text, with digit grouping, through `Intl.NumberFormat`.
|
|
2163
|
+
|
|
2164
|
+
**Options:** `locale?` (default `'en-US'`), `minFractionDigits?`,
|
|
2165
|
+
`maxFractionDigits?` (0 to 20; without them, up to 3 decimals).
|
|
2166
|
+
|
|
2167
|
+
- Without a locale the answer is the same on every machine, whatever
|
|
2168
|
+
its system language: `formatNumber(1234.5)` is `'1,234.5'`.
|
|
2169
|
+
- With another locale the text comes from the ICU data of the Node
|
|
2170
|
+
that runs the scenario, spaces included (`fr-FR` puts a narrow NBSP
|
|
2171
|
+
between thousands). Compare it with what the page shows rather than
|
|
2172
|
+
with a string typed in the scenario.
|
|
2173
|
+
|
|
2174
|
+
```js
|
|
2175
|
+
assertText(getByTestId('payout'), formatNumber(payout, {minFractionDigits: 2, maxFractionDigits: 2}));
|
|
2176
|
+
```
|
|
2177
|
+
|
|
2050
2178
|
### `json(value)` → `string`
|
|
2051
2179
|
|
|
2052
2180
|
Serialize any value to a JSON string. The debug tool for API and data
|
|
@@ -2115,10 +2243,20 @@ The body gets the element first, then the extras by the same rule: one
|
|
|
2115
2243
|
→ the value itself, two or more → one array.
|
|
2116
2244
|
|
|
2117
2245
|
```js
|
|
2118
|
-
color = evaluateOnLocator(getByRole('alert'), `(el) => getComputedStyle(el).color`);
|
|
2119
2246
|
ok = evaluateOnLocator(getByRole('main'), `(el, [a, b]) => el.children.length > a + b`, 1, 2);
|
|
2120
2247
|
```
|
|
2121
2248
|
|
|
2249
|
+
Reach for it only for what no typed call reads — a style is
|
|
2250
|
+
`computedStyle`, a box is `boundingBox`. Overflow is one such case: is
|
|
2251
|
+
the text cut off? There is no getter for `scrollWidth`, so the line says
|
|
2252
|
+
why it uses the hatch, and the linter takes the reason:
|
|
2253
|
+
|
|
2254
|
+
```js
|
|
2255
|
+
// Truncated with an ellipsis: the content is wider than the cell.
|
|
2256
|
+
overflows = evaluateOnLocator(getByRole('cell', {name: /^R-00001/}), `(el) => el.scrollWidth > el.clientWidth`); // lint-ok: no typed getter reads scrollWidth
|
|
2257
|
+
assertTrue(overflows === false, 'the id is cut off');
|
|
2258
|
+
```
|
|
2259
|
+
|
|
2122
2260
|
---
|
|
2123
2261
|
|
|
2124
2262
|
## Diagnostics
|
|
@@ -2315,7 +2453,8 @@ The DSL is JavaScript-shaped but parsed by a small AST engine
|
|
|
2315
2453
|
parse).
|
|
2316
2454
|
- **Method chains** — `getByRole('row').filter({hasText:'X'}).click()`.
|
|
2317
2455
|
- **Backticks** — multi-line raw strings, no `${}` interpolation.
|
|
2318
|
-
- **Booleans, numbers, strings, `null
|
|
2456
|
+
- **Booleans, numbers, strings, `null`** — escapes in strings: see
|
|
2457
|
+
[Escape rules](#escape-rules).
|
|
2319
2458
|
- **Comparison operators** — `==` / `!=` (loose: `"1" == 1` is true,
|
|
2320
2459
|
numeric strings coerce), `===` / `!==` (strict: type AND value must
|
|
2321
2460
|
match, `1 === "1"` is false), `<` `<=` `>` `>=`, logical `&&` / `||`.
|
|
@@ -2336,6 +2475,30 @@ inspection.
|
|
|
2336
2475
|
See `vendor/dsl/EXTENSIONS.md` for the
|
|
2337
2476
|
exact grammar deltas from the upstream parser.
|
|
2338
2477
|
|
|
2478
|
+
### Escape rules
|
|
2479
|
+
|
|
2480
|
+
In a quoted string (`'…'` or `"…"`):
|
|
2481
|
+
|
|
2482
|
+
| Escape | Gives |
|
|
2483
|
+
|---|---|
|
|
2484
|
+
| `\n` `\t` `\r` `\f` `\v` | the control character |
|
|
2485
|
+
| `\\` | one backslash |
|
|
2486
|
+
| `\'` in `'…'`, `\"` in `"…"` | the quote |
|
|
2487
|
+
| `\0` (no digit after it) | the NUL character |
|
|
2488
|
+
| `\xHH` | the character with that hex code: `"\xA0"` is a non-breaking space |
|
|
2489
|
+
| `\uXXXX` | the same with four hex digits: `'\u00A0'` |
|
|
2490
|
+
|
|
2491
|
+
A malformed `\x` / `\u` (`'\u12'`, `'\xG1'`) is a parse error at the
|
|
2492
|
+
backslash. Any other backslash pair stays **as written** — `'\d+'` is
|
|
2493
|
+
three characters, which is what a regex built from a string needs. The
|
|
2494
|
+
same goes for `\b`: a word boundary there, never a backspace. `\01` and
|
|
2495
|
+
the other quote (`"\'"`) are kept as written too. Backtick strings are raw: no
|
|
2496
|
+
escape decodes inside `` `…` ``.
|
|
2497
|
+
|
|
2498
|
+
```js
|
|
2499
|
+
assertText(getByRole('cell', {name: /^Total/}), '1\u00A0250'); // NBSP between digit groups
|
|
2500
|
+
```
|
|
2501
|
+
|
|
2339
2502
|
### Strings, objects, indexes
|
|
2340
2503
|
|
|
2341
2504
|
Since 0.44.0.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unotest/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "AI-native E2E testing for web applications. MCP server (run_test / step / resume / inspect_runtime / agent_fix) + CLI runner + JavaScript DSL scenarios on a sandboxed AST engine + semantic DOM snapshots.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -85,18 +85,18 @@
|
|
|
85
85
|
"tsx": "^4.19.2",
|
|
86
86
|
"yaml": "^2.6.0",
|
|
87
87
|
"zod": "^3.23.8",
|
|
88
|
-
"@unotest/
|
|
89
|
-
"@unotest/dsl": "^0.
|
|
90
|
-
"@unotest/
|
|
91
|
-
"@unotest/
|
|
92
|
-
"@unotest/
|
|
88
|
+
"@unotest/grounder-client": "^0.47.0",
|
|
89
|
+
"@unotest/dsl": "^0.47.0",
|
|
90
|
+
"@unotest/core": "^0.47.0",
|
|
91
|
+
"@unotest/protocol": "^0.47.0",
|
|
92
|
+
"@unotest/viewer": "^0.47.0"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@types/node": "^22.10.0",
|
|
96
96
|
"javascript-obfuscator": "^4.1.1",
|
|
97
97
|
"tsup": "^8.5.1",
|
|
98
98
|
"typescript": "^5.7.2",
|
|
99
|
-
"@unotest/
|
|
100
|
-
"@unotest/
|
|
99
|
+
"@unotest/grounder": "^0.47.0",
|
|
100
|
+
"@unotest/judge": "^0.47.0"
|
|
101
101
|
}
|
|
102
102
|
}
|
package/types/unotest-dsl.d.ts
CHANGED
|
@@ -234,9 +234,9 @@ declare function assertCount(locator: Locator, count: number): void;
|
|
|
234
234
|
/**
|
|
235
235
|
* assertUrl(pattern, { timeout? })
|
|
236
236
|
*
|
|
237
|
-
* Current URL contains `pattern
|
|
237
|
+
* Current URL contains `pattern` (a string) or matches it (a /regex/, unanchored). A failure names the pattern as /source/flags.
|
|
238
238
|
*/
|
|
239
|
-
declare function assertUrl(pattern: string): void;
|
|
239
|
+
declare function assertUrl(pattern: string | RegExp, options?: any): void;
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
242
|
* assertJudge(locator, rubric)
|
|
@@ -413,6 +413,13 @@ declare function closePage(index?: number): void;
|
|
|
413
413
|
*/
|
|
414
414
|
declare function setViewport(size: any): void;
|
|
415
415
|
|
|
416
|
+
/**
|
|
417
|
+
* emulateMedia({ reducedMotion?, colorScheme? })
|
|
418
|
+
*
|
|
419
|
+
* Change the media features the current tab reports from now on — what matchMedia and CSS @media see: reducedMotion 'reduce' | 'no-preference', colorScheme 'light' | 'dark' | 'no-preference'. This tab only: a tab or popup opened later starts without it.
|
|
420
|
+
*/
|
|
421
|
+
declare function emulateMedia(media: any): void;
|
|
422
|
+
|
|
416
423
|
/**
|
|
417
424
|
* newContext() → number
|
|
418
425
|
*
|
|
@@ -472,9 +479,9 @@ declare function goForward(): void;
|
|
|
472
479
|
/**
|
|
473
480
|
* waitForUrl(pattern, { timeout? })
|
|
474
481
|
*
|
|
475
|
-
* Wait until the URL contains `pattern` (substring match).
|
|
482
|
+
* Wait until the URL contains `pattern` (a string, substring match) or matches it (a /regex/, unanchored).
|
|
476
483
|
*/
|
|
477
|
-
declare function waitForUrl(pattern: string): void;
|
|
484
|
+
declare function waitForUrl(pattern: string | RegExp, options?: any): void;
|
|
478
485
|
|
|
479
486
|
/**
|
|
480
487
|
* waitForNavigation({ timeout? })
|
|
@@ -532,6 +539,20 @@ declare function isEnabled(locator: Locator): boolean;
|
|
|
532
539
|
*/
|
|
533
540
|
declare function hasAttribute(locator: Locator, name: string): boolean;
|
|
534
541
|
|
|
542
|
+
/**
|
|
543
|
+
* computedStyle(locator, property) → string
|
|
544
|
+
*
|
|
545
|
+
* The element's computed CSS value, as the browser resolved it: computedStyle(card, "opacity") → "0.5", custom properties too ("--accent"). "" when the property is not set.
|
|
546
|
+
*/
|
|
547
|
+
declare function computedStyle(locator: Locator, property: string): string;
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* hasAnimation(locator) → bool
|
|
551
|
+
*
|
|
552
|
+
* Whether the element or a descendant has an animation still running towards an end. Infinite (spinners) and paused ones do not count — the same rule waitForAnimations waits by.
|
|
553
|
+
*/
|
|
554
|
+
declare function hasAnimation(locator: Locator): boolean;
|
|
555
|
+
|
|
535
556
|
/**
|
|
536
557
|
* randomFirstName() → string
|
|
537
558
|
*
|
|
@@ -630,6 +651,27 @@ declare function parseJson(text: string): any;
|
|
|
630
651
|
*/
|
|
631
652
|
declare function urlParam(url: string, key: string): any;
|
|
632
653
|
|
|
654
|
+
/**
|
|
655
|
+
* toNumber(text, { decimal? }) → number
|
|
656
|
+
*
|
|
657
|
+
* A number as a page writes it: '1 234,5', '1,234.56', '−12'. Spaces (NBSP too) group digits; with both ',' and '.' the last one is the decimal mark; one mark used twice groups. '1,234' and '1.234' read both ways and FAIL unless {decimal: ',' | '.'} says which. Units and currency ('440px', '€12') FAIL, quoting the input — cut the number out with textMatches first. A number passes through.
|
|
658
|
+
*/
|
|
659
|
+
declare function toNumber(text: any, options?: any): number;
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* round(n, digits?) → number
|
|
663
|
+
*
|
|
664
|
+
* Round to `digits` decimals (0..10, default 0), half away from zero on the decimal as written: round(2.5) → 3, round(-2.5) → -3, round(1.005, 2) → 1.01.
|
|
665
|
+
*/
|
|
666
|
+
declare function round(n: number, digits?: number): number;
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* formatNumber(n, { locale?, minFractionDigits?, maxFractionDigits? }) → string
|
|
670
|
+
*
|
|
671
|
+
* A number as text, via Intl.NumberFormat with digit grouping. Without a locale it is en-US on every machine: formatNumber(1234.5) → '1,234.5'. Another locale's output (its spaces and marks) comes from the ICU of the Node that runs it.
|
|
672
|
+
*/
|
|
673
|
+
declare function formatNumber(n: number, options?: any): string;
|
|
674
|
+
|
|
633
675
|
/**
|
|
634
676
|
* env(name) → string | null
|
|
635
677
|
*
|
|
@@ -903,6 +945,13 @@ declare function waitForText(text: string | RegExp, options?: any): void;
|
|
|
903
945
|
*/
|
|
904
946
|
declare function waitForCount(locator: Locator, count: number, options?: any): void;
|
|
905
947
|
|
|
948
|
+
/**
|
|
949
|
+
* waitForAnimations(locator, { timeout? })
|
|
950
|
+
*
|
|
951
|
+
* Wait until the element and its descendants have no animation still running — a dialog done fading in, a card done sliding. Infinite ones (spinners) and paused ones are not waited for. Default timeout 5000 ms; a timeout names the element and how many were left.
|
|
952
|
+
*/
|
|
953
|
+
declare function waitForAnimations(locator: Locator, options?: any): void;
|
|
954
|
+
|
|
906
955
|
/**
|
|
907
956
|
* pause(ms)
|
|
908
957
|
*
|
|
@@ -941,7 +990,7 @@ declare function clockRun(): void;
|
|
|
941
990
|
/**
|
|
942
991
|
* mockRoute(glob, response)
|
|
943
992
|
*
|
|
944
|
-
* From now on, requests matching `glob` (a Playwright URL glob: `**\/api/items*`) get a fixed answer: `{status?, body?, headers?, contentType?}` (an object body goes as JSON), `{abort: true, record?}` or `{continue: true}` (to the network). Where several masks match, the one mocked last answers; mocking a mask again replaces its answer. A response to `**\/*` is refused; the site's own page is never aborted. Mocks last until the scenario ends.
|
|
993
|
+
* From now on, requests matching `glob` (a Playwright URL glob: `**\/api/items*`) get a fixed answer: `{status?, body?, headers?, contentType?}` (an object body goes as JSON), `{abort: true, record?}` or `{continue: true}` (to the network). Where several masks match, the one mocked last answers; mocking a mask again replaces its answer. A response to `**\/*` is refused; the site's own page is never aborted. A mask reaches http(s) and ws(s) only, so an extension's own pages and scripts load under `**\/*`; to mock them, start the mask with their scheme (`chrome-extension://<id>/x.js`). Mocks last until the scenario ends.
|
|
945
994
|
*/
|
|
946
995
|
declare function mockRoute(glob: string, response: any): void;
|
|
947
996
|
|