@itmetsam/samurai-framework 0.21.3 → 0.21.4
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/dist/assert/asymmetric.d.ts +29 -0
- package/dist/assert/asymmetric.js +166 -0
- package/dist/assert/element-probes.d.ts +20 -0
- package/dist/assert/element-probes.js +45 -0
- package/dist/assert/expect.d.ts +20 -9
- package/dist/assert/expect.js +12 -4
- package/dist/assert/locator-assertion-base.d.ts +52 -0
- package/dist/assert/locator-assertion-base.js +78 -0
- package/dist/assert/locator-assertions.d.ts +26 -49
- package/dist/assert/locator-assertions.js +35 -78
- package/dist/assert/more-locator-assertions.d.ts +30 -0
- package/dist/assert/more-locator-assertions.js +86 -0
- package/dist/assert/retry-assertions.d.ts +28 -0
- package/dist/assert/retry-assertions.js +113 -0
- package/dist/assert/text-match.d.ts +2 -0
- package/dist/assert/text-match.js +8 -0
- package/dist/assert/value-assertions.d.ts +29 -1
- package/dist/assert/value-assertions.js +84 -5
- package/dist/assert/value-matchers.d.ts +19 -0
- package/dist/assert/value-matchers.js +53 -0
- package/dist/browser/navigation-error.d.ts +5 -1
- package/dist/browser/navigation-error.js +10 -2
- package/dist/browser/page-content.d.ts +5 -0
- package/dist/browser/page-content.js +43 -0
- package/dist/browser/page-evaluate.d.ts +9 -0
- package/dist/browser/page-evaluate.js +20 -0
- package/dist/browser/page-locators.d.ts +1 -1
- package/dist/browser/page-locators.js +1 -1
- package/dist/browser/page-navigation.d.ts +18 -0
- package/dist/browser/page-navigation.js +52 -2
- package/dist/browser/page.d.ts +48 -1
- package/dist/browser/page.js +58 -1
- package/dist/locator/element-access.d.ts +2 -0
- package/dist/locator/element-reads.d.ts +17 -0
- package/dist/locator/element-reads.js +31 -0
- package/dist/locator/evaluate.d.ts +12 -0
- package/dist/locator/evaluate.js +36 -0
- package/dist/locator/locator.d.ts +23 -0
- package/dist/locator/locator.js +36 -1
- package/dist/script/call-function.d.ts +7 -0
- package/dist/script/call-function.js +21 -3
- package/dist/wait/wait-until.d.ts +3 -1
- package/dist/wait/wait-until.js +7 -2
- package/package.json +1 -1
package/dist/locator/locator.js
CHANGED
|
@@ -4,7 +4,8 @@ import { setChecked } from "./check-actions.js";
|
|
|
4
4
|
import { ChainResolver } from "./chain-resolver.js";
|
|
5
5
|
import { callInPage, noElementError, requireElement, } from "./element-access.js";
|
|
6
6
|
import { clickElement, fillElement, focusElement, pressOnElement, screenshotElement, } from "./element-actions.js";
|
|
7
|
-
import { readAccessibleDescription, readAccessibleName, readAttribute, readBoundingClientRect, readClassAttribute, readCssValue, readEnabledState, readInputValue, readIsChecked, readIsEditable, readIsEnabled, readIsVisible, readTextContent, } from "./element-reads.js";
|
|
7
|
+
import { readAccessibleDescription, readAccessibleName, readAllInnerTexts, readAllTextContents, readAttribute, readBoundingBox, readBoundingClientRect, readClassAttribute, readCssValue, readEnabledState, readInnerHTML, readInnerText, readInputValue, readIsChecked, readIsEditable, readIsEnabled, readIsVisible, readTextContent, } from "./element-reads.js";
|
|
8
|
+
import { evaluateOnAll, evaluateOnElement } from "./evaluate.js";
|
|
8
9
|
import { dropFiles, setInputFiles } from "./file-actions.js";
|
|
9
10
|
import { DEFAULT_PAUSE_MS, pause } from "./input-actions.js";
|
|
10
11
|
import { NOT_STRICT, strictViolation, } from "./strict-mode.js";
|
|
@@ -44,6 +45,7 @@ export default class Locator {
|
|
|
44
45
|
return locator.selector;
|
|
45
46
|
},
|
|
46
47
|
resolveOne: (method) => this.resolveOne(method),
|
|
48
|
+
resolveAll: () => this.resolve(),
|
|
47
49
|
call: (fn, args, sandbox) => callInPage(this.access, fn, args, sandbox),
|
|
48
50
|
waitForActionable: (action, checks, probe, options) => this.waitForActionable(action, checks, probe, options),
|
|
49
51
|
requireElement: () => requireElement(this.access),
|
|
@@ -338,6 +340,39 @@ export default class Locator {
|
|
|
338
340
|
async textContent() {
|
|
339
341
|
return readTextContent(this.access);
|
|
340
342
|
}
|
|
343
|
+
/** Rendered text of the element (as a person would copy it, hidden text left out), untrimmed, or null when the element is missing */
|
|
344
|
+
async innerText() {
|
|
345
|
+
return readInnerText(this.access);
|
|
346
|
+
}
|
|
347
|
+
/** The markup inside the element, or null when the element is missing */
|
|
348
|
+
async innerHTML() {
|
|
349
|
+
return readInnerHTML(this.access);
|
|
350
|
+
}
|
|
351
|
+
/** `textContent` of every match, as the page has it (untrimmed, unlike `textContent()`); `[]` when none match. Does not wait */
|
|
352
|
+
async allTextContents() {
|
|
353
|
+
return readAllTextContents(this.access);
|
|
354
|
+
}
|
|
355
|
+
/** `innerText` of every match; `[]` when none match. Does not wait */
|
|
356
|
+
async allInnerTexts() {
|
|
357
|
+
return readAllInnerTexts(this.access);
|
|
358
|
+
}
|
|
359
|
+
/** The element's box in CSS pixels from the viewport's top left, or null when it is missing or not rendered (`display: none`). Does not wait or scroll */
|
|
360
|
+
async boundingBox() {
|
|
361
|
+
return readBoundingBox(this.access);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Waits until the element is attached (hidden is fine), then calls `fn(element, arg)` in the page and returns the result
|
|
365
|
+
* (see `page.evaluate` for what comes back). `fn` is a function or the source of one; a strict locator throws when several match.
|
|
366
|
+
* @example
|
|
367
|
+
* const id = await page.getByTestId("row").evaluate((el) => el.dataset.id);
|
|
368
|
+
*/
|
|
369
|
+
async evaluate(fn, arg, options) {
|
|
370
|
+
return evaluateOnElement(this.access, fn, arg, options);
|
|
371
|
+
}
|
|
372
|
+
/** Calls `fn(elements, arg)` in the page with an array of every match (empty when none; does not wait) and returns the result */
|
|
373
|
+
async evaluateAll(fn, arg) {
|
|
374
|
+
return evaluateOnAll(this.access, fn, arg);
|
|
375
|
+
}
|
|
341
376
|
/** Value of an input/textarea/select, or null when missing */
|
|
342
377
|
async inputValue() {
|
|
343
378
|
return readInputValue(this.access);
|
|
@@ -20,7 +20,14 @@ export declare class ScriptError extends Error {
|
|
|
20
20
|
export declare class ScriptSerializationError extends Error {
|
|
21
21
|
constructor(message: string);
|
|
22
22
|
}
|
|
23
|
+
/** A function to run in the page, or its source (a string is used as written) */
|
|
24
|
+
export type PageFunction<A extends unknown[], R> = string | ((...args: A) => R | Promise<R>);
|
|
23
25
|
/** The source to send for `fn`; a function object must not depend on transpiler helpers */
|
|
24
26
|
export declare function toFunctionDeclaration(fn: string | ((...args: any[]) => unknown)): string;
|
|
25
27
|
/** Calls `fn` in the page with serialized arguments and returns its deserialized result */
|
|
26
28
|
export declare function callFunction<T = unknown>(connector: BiDiConnector, context: string, fn: string | ((...args: any[]) => unknown), args?: Arg[], options?: CallOptions): Promise<T>;
|
|
29
|
+
/**
|
|
30
|
+
* Evaluates `expression` in the page and returns its deserialized result; a promise is awaited.
|
|
31
|
+
* Throws `ScriptError` with the page's message when it throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function evaluateExpression<T = unknown>(connector: BiDiConnector, context: string, expression: string): Promise<T>;
|
|
@@ -26,10 +26,12 @@ export function toFunctionDeclaration(fn) {
|
|
|
26
26
|
if (typeof fn === "string")
|
|
27
27
|
return fn;
|
|
28
28
|
const source = fn.toString();
|
|
29
|
-
// tsx/esbuild wrap named functions in a __name() helper that does not exist in the page
|
|
29
|
+
// tsx/esbuild (keepNames) wrap named functions in a __name() helper that does not exist in the page
|
|
30
30
|
if (source.includes("__name(")) {
|
|
31
|
-
throw new ScriptSerializationError("The function's source uses
|
|
32
|
-
"
|
|
31
|
+
throw new ScriptSerializationError("The function's source uses __name(), a helper that tsx and esbuild add around named functions " +
|
|
32
|
+
"(also an arrow function assigned to a variable) and that does not exist in the page. " +
|
|
33
|
+
"Write the function without inner named functions (pass callbacks inline as anonymous arrow functions), " +
|
|
34
|
+
"or pass it as a string.");
|
|
33
35
|
}
|
|
34
36
|
return source;
|
|
35
37
|
}
|
|
@@ -52,3 +54,19 @@ export async function callFunction(connector, context, fn, args = [], options =
|
|
|
52
54
|
}
|
|
53
55
|
return fromRemoteValue(result.result);
|
|
54
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Evaluates `expression` in the page and returns its deserialized result; a promise is awaited.
|
|
59
|
+
* Throws `ScriptError` with the page's message when it throws.
|
|
60
|
+
*/
|
|
61
|
+
export async function evaluateExpression(connector, context, expression) {
|
|
62
|
+
const result = await connector.send("script.evaluate", {
|
|
63
|
+
expression,
|
|
64
|
+
awaitPromise: true,
|
|
65
|
+
target: { context },
|
|
66
|
+
resultOwnership: "none",
|
|
67
|
+
});
|
|
68
|
+
if (result.type === "exception") {
|
|
69
|
+
throw new ScriptError(result.exceptionDetails.text, expression, result.exceptionDetails.stackTrace);
|
|
70
|
+
}
|
|
71
|
+
return fromRemoteValue(result.result);
|
|
72
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export interface WaitOptions {
|
|
2
2
|
/** Total time (ms) to keep probing; 0 probes exactly once */
|
|
3
3
|
timeout: number;
|
|
4
|
+
/** Pauses (ms) after the first, second, ... probe; the last one repeats. Default: 100 every time */
|
|
5
|
+
intervals?: readonly number[];
|
|
4
6
|
}
|
|
5
7
|
export declare class WaitTimeoutError<T> extends Error {
|
|
6
8
|
readonly timeout: number;
|
|
@@ -13,4 +15,4 @@ export declare class WaitTimeoutError<T> extends Error {
|
|
|
13
15
|
* Always probes at least once; with `timeout > 0` every probe races the time left.
|
|
14
16
|
* Probe errors are rethrown immediately. Throws WaitTimeoutError at the deadline.
|
|
15
17
|
*/
|
|
16
|
-
export declare function waitUntil<T>(probe: () => Promise<T>, isDone: (current: T, previous: T | undefined) => boolean, { timeout }: WaitOptions): Promise<T>;
|
|
18
|
+
export declare function waitUntil<T>(probe: () => Promise<T>, isDone: (current: T, previous: T | undefined) => boolean, { timeout, intervals }: WaitOptions): Promise<T>;
|
package/dist/wait/wait-until.js
CHANGED
|
@@ -29,9 +29,10 @@ function probeBefore(probe, remaining) {
|
|
|
29
29
|
* Always probes at least once; with `timeout > 0` every probe races the time left.
|
|
30
30
|
* Probe errors are rethrown immediately. Throws WaitTimeoutError at the deadline.
|
|
31
31
|
*/
|
|
32
|
-
export async function waitUntil(probe, isDone, { timeout }) {
|
|
32
|
+
export async function waitUntil(probe, isDone, { timeout, intervals }) {
|
|
33
33
|
const deadline = Date.now() + timeout;
|
|
34
34
|
let previous;
|
|
35
|
+
let probes = 0;
|
|
35
36
|
for (let first = true;; first = false) {
|
|
36
37
|
const remaining = deadline - Date.now();
|
|
37
38
|
// Only start a probe while time remains; a later one could only lose the race
|
|
@@ -49,6 +50,10 @@ export async function waitUntil(probe, isDone, { timeout }) {
|
|
|
49
50
|
const left = deadline - Date.now();
|
|
50
51
|
if (left <= 0)
|
|
51
52
|
throw new WaitTimeoutError(timeout, previous);
|
|
52
|
-
|
|
53
|
+
const pause = intervals?.length
|
|
54
|
+
? intervals[Math.min(probes, intervals.length - 1)]
|
|
55
|
+
: POLL_INTERVAL;
|
|
56
|
+
probes++;
|
|
57
|
+
await sleep(Math.min(pause, left));
|
|
53
58
|
}
|
|
54
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itmetsam/samurai-framework",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.4",
|
|
4
4
|
"description": "Browser test framework over WebDriver BiDi: auto-waiting locators, environments and secrets, a recorder, and a command line.",
|
|
5
5
|
"main": "dist/api.js",
|
|
6
6
|
"exports": {
|