@ultimat3/scraping 20.1.6 → 20.2.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.
- package/package.json +5 -5
- package/src/cdp-a11y.ts +125 -0
- package/src/cdp-arm.ts +173 -0
- package/src/cdp-fake.ts +131 -2
- package/src/cdp-port.ts +46 -0
- package/src/cdp-snapshot.ts +11 -0
- package/src/cdp-target.ts +99 -166
- package/src/error-throws.ts +14 -0
- package/src/errors.ts +6 -0
- package/src/html-target.ts +49 -0
- package/src/index.ts +15 -1
- package/src/key-chord.ts +60 -0
- package/src/page-over-target.ts +30 -1
- package/src/page.ts +42 -1
- package/src/target.ts +51 -0
package/src/page.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { CaptureFraming } from './capture-clip';
|
|
|
13
13
|
import type { ColorScheme } from './color-scheme';
|
|
14
14
|
import type { ConsoleLine, NetworkEntry, PageError } from './rings';
|
|
15
15
|
import type { SessionSnapshot } from './session-state';
|
|
16
|
-
import type { ElementSnapshot, ScrapeCookie, ScrapeDownloadFile } from './target';
|
|
16
|
+
import type { AxNode, ElementSnapshot, ScrapeCookie, ScrapeDownloadFile } from './target';
|
|
17
17
|
|
|
18
18
|
export interface WaitOptions {
|
|
19
19
|
readonly state?: ActionabilityState | undefined;
|
|
@@ -21,6 +21,13 @@ export interface WaitOptions {
|
|
|
21
21
|
readonly timeout?: number | undefined;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/** How many matches `accessibility()` describes. A bound, because each match is a round trip. */
|
|
25
|
+
export interface AccessibilityOptions {
|
|
26
|
+
readonly max?: number | undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const DEFAULT_ACCESSIBILITY_MAX = 25;
|
|
30
|
+
|
|
24
31
|
export interface ElementValue {
|
|
25
32
|
readonly tag: string;
|
|
26
33
|
readonly text: string;
|
|
@@ -49,6 +56,28 @@ export interface ScrapeFrame {
|
|
|
49
56
|
/** Clears first, then types — the spelling a login form wants. */
|
|
50
57
|
fill(selector: string, text: string | Secret, options?: WaitOptions): Promise<void>;
|
|
51
58
|
select(selector: string, values: readonly string[], options?: WaitOptions): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Waits for the element to be actionable, then moves focus to it — the setup for a `press()`,
|
|
61
|
+
* and the half of keyboard navigation a click cannot stand in for.
|
|
62
|
+
*/
|
|
63
|
+
focus(selector: string, options?: WaitOptions): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* A key chord on whatever holds focus: `'Meta+K'`, `'Escape'`, `'Shift+Tab'`, `'Enter'`.
|
|
66
|
+
* Modifiers are `Meta`, `Control`, `Alt`, `Shift`, in the browser's own spelling — `'Ctrl+K'`
|
|
67
|
+
* is `X_SCRAPE_KEY_INVALID` on every driver, offline included, because the parse is the one
|
|
68
|
+
* thing an offline driver can be wrong about. The browser has ONE keyboard, so a chord pressed
|
|
69
|
+
* through a frame handle reaches whichever element that frame's `focus()` put focus on.
|
|
70
|
+
*/
|
|
71
|
+
press(chord: string): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* What a screen reader is told about each match — the browser's computed role and name, after
|
|
74
|
+
* ARIA and label association, which `query()` cannot answer from attributes. At most
|
|
75
|
+
* `options.max` (default `DEFAULT_ACCESSIBILITY_MAX`) nodes, in document order. Refused with
|
|
76
|
+
* `X_NOT_IMPLEMENTED` on a driver with no accessibility engine — an offline driver, or a frame
|
|
77
|
+
* of the real one — never answered from the markup: a `<div onclick>` computing no role IS the
|
|
78
|
+
* finding, and a fake reading `role=` off the tag would hide it.
|
|
79
|
+
*/
|
|
80
|
+
accessibility(selector: string, options?: AccessibilityOptions): Promise<readonly AxNode[]>;
|
|
52
81
|
/**
|
|
53
82
|
* Every match, as SNAPSHOTS — `visible`, `enabled` and (on a driver with a layout engine) the
|
|
54
83
|
* box and hit-target, which `values()` projects away.
|
|
@@ -125,6 +154,18 @@ export interface ScrapePage extends ScrapeFrame {
|
|
|
125
154
|
* method, which is a fact about the build rather than about the driver.
|
|
126
155
|
*/
|
|
127
156
|
colorScheme(scheme: ColorScheme): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* A script the browser runs in EVERY document this page navigates to, BEFORE the document's
|
|
159
|
+
* own scripts — the one moment that beats an inlined boot script. Call it before `goto()`: what
|
|
160
|
+
* it seeds (a `localStorage` key a boot reads, a flag a component checks) is then in place for
|
|
161
|
+
* the first script the page executes, where an `evaluate()` after navigation is one boot too
|
|
162
|
+
* late. Same string discipline as `evaluate()`: an expression, never a closure.
|
|
163
|
+
*
|
|
164
|
+
* ACCEPTED on every driver, for `colorScheme()`'s reason: the offline drivers run no scripts,
|
|
165
|
+
* so nothing there could be wrong about it. `X_NOT_IMPLEMENTED` is reserved for a LAUNCHER
|
|
166
|
+
* that lacks the method, which is a fact about the build rather than about the driver.
|
|
167
|
+
*/
|
|
168
|
+
prepare(expression: string): Promise<void>;
|
|
128
169
|
/**
|
|
129
170
|
* The handoff, made explicit: what the HTTP leg will send, as a value an author can inspect and
|
|
130
171
|
* a fixture can assert on. `http` uses it automatically — this is for seeing what carried over.
|
package/src/target.ts
CHANGED
|
@@ -47,6 +47,24 @@ export interface ElementSnapshot {
|
|
|
47
47
|
readonly hitTarget?: boolean | undefined;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* One node of the browser's accessibility tree, as of one observation — what a screen reader is
|
|
52
|
+
* told about an element, which is a different fact from what `ElementSnapshot` says about its
|
|
53
|
+
* markup. `role` and `name` are always answered, `''` when the browser computed nothing: absent is
|
|
54
|
+
* a real answer for a `<div>`, and a fabricated `generic` would hide the elements a reader cannot
|
|
55
|
+
* name. A VALUE, like `ElementSnapshot`: it cannot go stale behind the caller's back, only old.
|
|
56
|
+
*/
|
|
57
|
+
export interface AxNode {
|
|
58
|
+
readonly role: string;
|
|
59
|
+
readonly name: string;
|
|
60
|
+
readonly description?: string | undefined;
|
|
61
|
+
readonly value?: string | undefined;
|
|
62
|
+
readonly focused?: boolean | undefined;
|
|
63
|
+
readonly disabled?: boolean | undefined;
|
|
64
|
+
/** Pruned from the tree a reader walks — `aria-hidden`, or a wrapper with nothing to say. */
|
|
65
|
+
readonly ignored: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
50
68
|
export interface ScrapeCookie {
|
|
51
69
|
readonly name: string;
|
|
52
70
|
readonly value: string;
|
|
@@ -133,6 +151,25 @@ export interface ScrapeTarget {
|
|
|
133
151
|
select(selector: string, values: readonly string[]): Promise<void>;
|
|
134
152
|
/** The expression runs in the page. The result is `unknown` and is parsed by the caller. */
|
|
135
153
|
evaluate(expression: string): Promise<unknown>;
|
|
154
|
+
/**
|
|
155
|
+
* A key chord — `'Meta+K'`, `'Escape'`, `'Shift+Tab'` — pressed on whatever holds focus. The
|
|
156
|
+
* PAGE's keyboard, on a frame target too: a browser has one keyboard, and the focused element
|
|
157
|
+
* is what decides which document hears it. REQUIRED here where `CdpPageLike.keyboard` is
|
|
158
|
+
* optional, for `setOfflineMode`'s reason: the asymmetry is the enforcement. A driver with no
|
|
159
|
+
* keyboard still PARSES the chord (`key-chord.ts`) and then resolves — the refusal an offline
|
|
160
|
+
* driver can give is the one it does give.
|
|
161
|
+
*/
|
|
162
|
+
press(chord: string): Promise<void>;
|
|
163
|
+
/** Moves focus to the first match. Refused when nothing matches. */
|
|
164
|
+
focus(selector: string): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* The accessibility node of every match, bounded by `max` — the browser's own computed role and
|
|
167
|
+
* name, which no HTML parse can reproduce. REQUIRED for `press`'s reason, and a driver with no
|
|
168
|
+
* accessibility engine answers `X_NOT_IMPLEMENTED`, never an invented role: a fake that read
|
|
169
|
+
* `role="button"` off the markup would pass a test against a `<div onclick>` a reader cannot
|
|
170
|
+
* reach, which is the exact defect this read exists to catch.
|
|
171
|
+
*/
|
|
172
|
+
accessibility(selector: string, max: number): Promise<readonly AxNode[]>;
|
|
136
173
|
/**
|
|
137
174
|
* The browser goes offline, or comes back. REQUIRED on this port where it is optional on
|
|
138
175
|
* `CdpPageLike`, and the asymmetry is the enforcement: a driver author gets a type error naming
|
|
@@ -164,6 +201,20 @@ export interface ScrapeTarget {
|
|
|
164
201
|
* so a driver that dropped the preference fails a test rather than passing every one.
|
|
165
202
|
*/
|
|
166
203
|
setColorScheme(scheme: ColorScheme): Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* A script every document this target navigates to runs BEFORE its own — the browser's
|
|
206
|
+
* `evaluateOnNewDocument`. REQUIRED here where `CdpPageLike.evaluateOnNewDocument` is optional,
|
|
207
|
+
* for `setOfflineMode`'s reason: the asymmetry is the enforcement, and a launcher without the
|
|
208
|
+
* method is `X_NOT_IMPLEMENTED`.
|
|
209
|
+
*
|
|
210
|
+
* A DRIVER WITH NO JS ENGINE ACCEPTS IT, for `setColorScheme`'s reason and not
|
|
211
|
+
* `setOfflineMode`'s: the offline drivers execute nothing, so there is no document script for
|
|
212
|
+
* the expression to run ahead of and no assertion a resolved promise could let through — a
|
|
213
|
+
* seeded `localStorage` key is the INPUT to a boot script this driver never runs. Refusing
|
|
214
|
+
* would make `x shot` and every `ui.*` tool untestable on a machine with no Chrome, and the
|
|
215
|
+
* outcome it would protect does not exist here. The call is still checked for a closed target.
|
|
216
|
+
*/
|
|
217
|
+
prepare(expression: string): Promise<void>;
|
|
167
218
|
screenshot(options: CaptureOptions): Promise<Uint8Array>;
|
|
168
219
|
pdf(options: CaptureOptions): Promise<Uint8Array>;
|
|
169
220
|
cookies(): Promise<readonly ScrapeCookie[]>;
|