@jbrowse/capture 5.0.0-beta.1 → 5.0.0-beta.10

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.
@@ -0,0 +1 @@
1
+ export declare const version = "5.0.0-beta.10";
package/esm/version.js ADDED
@@ -0,0 +1 @@
1
+ export const version = '5.0.0-beta.10';
package/esm/waits.d.ts CHANGED
@@ -1,214 +1,35 @@
1
1
  import type { ElementHandle, Page } from 'puppeteer';
2
- export declare const delay: (ms: number) => Promise<void>;
3
- export declare const LOADING_OVERLAY = "[data-testid=\"loading-overlay\"]";
4
- /**
5
- * The whole readiness contract, in one selector.
6
- *
7
- * `AppReadyMarker` renders it from the session: it reads `ready` when no view
8
- * is resolving an assembly and no display is fetching, and `loading` whenever
9
- * one is. Waiting for it is the entire job — everything else in this module is
10
- * either a narrower question (has THIS display painted) or a fallback for a
11
- * deployment too old to publish it.
12
- *
13
- * It is POSITIVE, which is the property that matters. Every other signal here
14
- * is an absence, and an absence is equally true of an app that has not started:
15
- * measured on a two-track session, the gap between "the session holds the
16
- * tracks" and "the first loading indicator appears" is about a second, and a
17
- * capture taken in it is a picture of an empty browser.
18
- */
19
- export declare const APP_READY = "[data-app-phase=\"ready\"]";
20
- export declare function waitForLoadingComplete(page: Page, { timeout, waitForDownloads, }?: {
21
- timeout?: number;
22
- waitForDownloads?: boolean;
23
- }): Promise<boolean>;
24
- /**
25
- * Wait until nothing on the page is in flight.
26
- *
27
- * Every signal it reads is one the app publishes deliberately — the loading
28
- * overlay, `data-busy`, the display and view phases, and each display's own
29
- * status message on the session model. See `isPageBusyInPage`.
30
- *
31
- * It used to scan rendered text for /^(loading|rendering|computing)/ and resolve
32
- * `getComputedStyle` on each match to decide whether it was on screen. That is a
33
- * heuristic over a rendering: it broke on a reworded or translated message, it
34
- * needed the visibility check only because the loading overlay keeps the word
35
- * "Loading" in the DOM at `opacity: 0`, and an unset opacity parses to zero
36
- * outside a full layout engine, which reads every ordinary element as hidden. A
37
- * component that wants to be waited for now says so with an attribute.
38
- *
39
- * Best-effort: a view genuinely stuck loading would otherwise burn the whole
40
- * timeout, so this reports false rather than throwing and the caller decides.
41
- */
42
- export declare function waitForQuiescent(page: Page, { timeout }?: {
2
+ interface WaitOptions {
43
3
  timeout?: number;
44
- }): Promise<boolean>;
4
+ }
5
+ /** The app's own verdict: no view is resolving an assembly, no display is fetching. */
6
+ export declare const APP_READY = "[data-app-phase=\"ready\"]";
7
+ /** Displays that have not yet drawn anything. */
45
8
  export declare const PENDING_DISPLAYS = "[data-display-drawn=\"false\"]";
46
- /**
47
- * `page.waitForSelector`, with the display census in the timeout.
48
- *
49
- * The waits below are best-effort and hand their outcome back as a boolean, so
50
- * a caller can say what was still unsettled. A *selector* wait is the opposite
51
- * shape — it throws, and it runs FIRST, before any of them: a capture whose
52
- * display never paints dies here on puppeteer's `TimeoutError`, which names the
53
- * selector and nothing else, and the census that would have named the display
54
- * runs later or not at all.
55
- *
56
- * So the census runs on the way out. It is re-read from the DOM here rather
57
- * than taken off a handle the wait held: a handle to an element that has since
58
- * re-rendered throws `Node is detached from document`, which is how the first
59
- * attempt at this turned four diagnosable timeouts into nine opaque puppeteer
60
- * errors (reverted in 28c6ee6d90).
61
- *
62
- * What it reports is the phase, and that is the part a longer timeout cannot
63
- * substitute for: `loading` is a slow fetch, `error` is a display that has
64
- * finished badly and is showing a banner, and `ready` is a display claiming it
65
- * finished without drawing — a bug in the display rather than in the wait.
66
- *
67
- * An EMPTY census is the other answer, and `tooLarge` / `renderError` are why it
68
- * is not good news. Those two replace the display's subtree outright, so they
69
- * publish neither attribute and appear here as nothing at all: a wait on such a
70
- * display can never resolve and can never be reported. Nothing pending means
71
- * either that, or a selector that was never a display's.
72
- */
73
- export declare function waitForSelectorAttributed(page: Page, selector: string, timeoutMs: number): Promise<ElementHandle>;
74
- /**
75
- * The census as one clause, for a message. Best-effort in its own right: a page
76
- * whose execution context is gone cannot be asked, and saying so is the answer.
77
- */
78
- export declare function describePendingDisplaysNow(page: Page): Promise<string>;
9
+ /** A display of this type that has drawn something, possibly mid-fetch. */
79
10
  export declare const displayPainted: (testid: string) => string;
80
- /**
81
- * The stronger one. `drawn` flips on FIRST paint — an empty canvas with the
82
- * fetch still in flight satisfies it — so a figure that must show *data* waits
83
- * on the phase instead.
84
- */
11
+ /** A display of this type whose fetch has finished. */
85
12
  export declare const displaySettled: (testid: string) => string;
86
- /** One display, by its config's `displayId` rather than by type. */
87
- export declare const displayById: (displayId: string) => string;
88
- export declare function waitForDisplaysDone(page: Page, timeoutMs: number): Promise<boolean>;
89
- export declare function waitForDisplayPhases(page: Page, timeoutMs: number): Promise<boolean>;
90
- export declare function waitForViewPhases(page: Page, timeoutMs: number): Promise<import("puppeteer").JSHandle<false> | import("puppeteer").JSHandle<true>>;
91
- /**
92
- * Everything the app publishes to say it is working, as one selector.
93
- *
94
- * All four are attributes a component sets deliberately, which is the whole
95
- * point: the alternative — scanning rendered text for /^loading/ and resolving
96
- * `getComputedStyle` to decide whether each match is on screen — makes a
97
- * reworded message, a translation or an opacity animation change the answer.
98
- *
99
- * `loading-overlay` the view-level scrim, present in every build
100
- * `data-busy` LoadingEllipses, which is what the app renders
101
- * wherever it tells a user it is working
102
- * `data-display-phase` one display's own fetch, newer builds
103
- * `data-view-phase` a view still resolving its assembly, newer builds
104
- */
105
- export declare const BUSY_SELECTOR: string;
106
13
  /**
107
- * Is the app doing anything right now?
108
- *
109
- * Serialized into the page, so it declares everything it uses. Two sources: the
110
- * selector above, and the live session model's own per-display status, which is
111
- * the only PER-DISPLAY signal a build with no readiness attributes has left.
112
- * Both are contracts rather than renderings — a model field and a set of data
113
- * attributes — so neither moves when the UI is restyled.
114
- *
115
- * Exported so a test can call the real function rather than a copy of it.
14
+ * `page.waitForSelector`, whose timeout names each display that had not
15
+ * painted and the phase it was in.
116
16
  */
117
- export declare function isPageBusyInPage(): boolean;
118
- /**
119
- * Wait until the app has been idle for an unbroken stretch.
120
- *
121
- * The gate for a build that publishes no readiness attributes, where every
122
- * other wait in this module is an assertion about an absent selector and so
123
- * cannot fail. Absence answers "is it working NOW"; a capture needs "has it
124
- * finished", and the two differ in both directions:
125
- *
126
- * BEFORE the work starts. Measured on jbrowse.org/code/jb2/latest with two
127
- * remote tracks: the session reports both tracks open at ~2.5s and the
128
- * loading overlay does not go up until ~3.5s. Every absence-based gate passes
129
- * during that second, over an app that has drawn nothing.
130
- *
131
- * BETWEEN two pieces of work. A track that finishes one fetch and starts the
132
- * next is momentarily idle, and a single-sample gate takes it.
133
- *
134
- * Requiring the idle to HOLD closes both without needing to know which signals
135
- * a given build has. Polled from node rather than in-page: chrome throttles
136
- * in-page timers and rAF once the tab is not visible, which is the state a
137
- * headless capture sits in.
138
- *
139
- * Returns false on timeout rather than throwing, like its neighbours — the
140
- * caller decides whether a page that never went quiet is a failure or a slow
141
- * page worth capturing anyway.
142
- */
143
- export declare function waitForQuietPeriod(page: Page, { quietMs, timeout, pollMs, busyWindowMs, }?: {
144
- quietMs?: number;
145
- timeout?: number;
17
+ export declare function waitForSelectorAttributed(page: Page, selector: string, { timeout }?: WaitOptions): Promise<ElementHandle>;
18
+ type SettleOptions = WaitOptions & {
19
+ holdMs?: number;
146
20
  pollMs?: number;
147
- /**
148
- * Wait for the app to be seen BUSY before any idle counts, giving up on
149
- * that after this long. Zero (the default) accepts idle immediately.
150
- *
151
- * This is what turns the wait positive. Idle is still an absence, so an app
152
- * that has not begun looks exactly like one that has finished — measured on
153
- * jbrowse.org/code/jb2/latest, where a chain starting at the session gate
154
- * saw an idle page at 1.6s and the tracks did not draw until past 10s.
155
- * Seeing the transition INTO work and back out of it is an observation of
156
- * the work itself.
157
- *
158
- * The window is bounded because a page with nothing to fetch never goes
159
- * busy at all, and hanging on that would be worse than the race it closes.
160
- * Size it above the gap between the session gate passing and the first
161
- * indicator appearing, measured at ~1s on that instance.
162
- */
163
- busyWindowMs?: number;
164
- }): Promise<boolean>;
21
+ };
165
22
  /**
166
- * Wait for the app to say it has finished.
167
- *
168
- * One selector, no chain: `[data-app-phase="ready"]` is rendered by the session
169
- * itself, so it cannot be satisfied before the app exists. Returns false if the
170
- * page never publishes it, which is how a caller tells "not ready yet" from "a
171
- * build too old to have the marker" and falls back.
23
+ * `waitForAppSettled`, answering with what was still blocking at the timeout,
24
+ * or undefined once the hold passed.
172
25
  */
173
- export declare function waitForAppReady(page: Page, { timeout }?: {
174
- timeout?: number;
175
- }): Promise<boolean>;
176
- /** Whether this build publishes the app-level readiness marker at all. */
177
- export declare function hasAppReadyMarker(page: Page): Promise<boolean>;
26
+ export declare function appSettledBlocker(page: Page, { timeout, holdMs, pollMs, }?: SettleOptions): Promise<string | undefined>;
178
27
  /**
179
- * Wait out work an INTERACTION started: `ready`, and still ready a beat later.
180
- *
181
- * The gate for after a click, a keystroke or a resize, where `waitForAppReady`
182
- * alone is not one. A page that is still LOADING starts at `loading` and the
183
- * transition into `ready` is the app finishing, so one read of the selector
184
- * answers it. After an interaction the app is already `ready` — it was finished a
185
- * moment ago — and stays that way until the click's work registers, so the same
186
- * read returns instantly, on the pre-click frame.
187
- *
188
- * What it replaces is a fixed sleep, which is wrong in both directions and only
189
- * ever caught in one: too short captures the work in progress, and the figure it
190
- * produces looks finished, while too long is dead time on every run.
191
- *
192
- * **Not "seen busy, then ready"**, which is the obvious shape and was built and
193
- * measured first. Waiting for `loading` to appear before accepting `ready` needs
194
- * a cap, since an interaction that only opened a menu never makes the app busy at
195
- * all — and on the figure spec it was measured against
196
- * (`search_feature_highlight`) the app was never seen busy either, because that
197
- * spec's own selector wait had already outlasted the redraw. The busy window then
198
- * ran to its 2s cap having watched nothing, costing more than the 1.2s sleep it
199
- * replaced. Requiring the idle to HOLD costs the hold and no more, and catches
200
- * the same late-starting work.
201
- *
202
- * Polled from Node rather than by `page.waitForSelector`, for the reason
203
- * `waitForQuietPeriod` is: chrome throttles in-page timers and rAF once the tab
204
- * is not visible, which is exactly the state a headless capture sits in.
205
- *
206
- * Falls back to the quiet period on a build too old for the marker, rather than
207
- * passing instantly. A no-op that reports success is how a spec that dropped its
208
- * sleep for this ends up capturing the frame the sleep was there to avoid.
28
+ * Wait until every app on the page has read ready, with nothing loading or
29
+ * animating, for an unbroken `holdMs`. False on timeout. Right after a
30
+ * navigation it first waits for the marker to mount; a page that never
31
+ * publishes `[data-app-phase]` throws, since nothing positive exists to wait
32
+ * for.
209
33
  */
210
- export declare function waitForAppSettled(page: Page, { timeout, holdMs, pollMs, }?: {
211
- timeout?: number;
212
- holdMs?: number;
213
- pollMs?: number;
214
- }): Promise<boolean>;
34
+ export declare function waitForAppSettled(page: Page, options?: SettleOptions): Promise<boolean>;
35
+ export {};