@jbrowse/capture 5.0.0-beta.4 → 5.0.0-beta.7
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/README.md +38 -40
- package/esm/args.d.ts +14 -4
- package/esm/args.js +78 -84
- package/esm/bin.js +17 -15
- package/esm/capture.js +21 -7
- package/esm/index.d.ts +2 -2
- package/esm/index.js +1 -1
- package/esm/ready.d.ts +19 -41
- package/esm/ready.js +57 -191
- package/esm/session.js +13 -3
- package/esm/sessionGate.d.ts +20 -66
- package/esm/sessionGate.js +44 -148
- package/esm/waits.d.ts +24 -46
- package/esm/waits.js +39 -62
- package/package.json +2 -2
package/esm/ready.js
CHANGED
|
@@ -1,207 +1,73 @@
|
|
|
1
|
-
import { describePendingDisplays,
|
|
2
|
-
import { delay, hasAppReadyMarker, waitForAppSettled,
|
|
3
|
-
// The whole ready chain, in a module that touches puppeteer only through its
|
|
4
|
-
// types — capture.ts holds the runtime import (launching a browser), which is
|
|
5
|
-
// what keeps the chain callable under jest against a stubbed Page.
|
|
6
|
-
// A build with no per-display paint attributes gives no signal between "the
|
|
7
|
-
// overlay cleared" and "the canvas has pixels on it", so the only thing left is
|
|
8
|
-
// to wait. Sized from the measured gap on jbrowse.org/code/jb2/latest between
|
|
9
|
-
// the overlay clearing and the tracks being fully drawn.
|
|
10
|
-
const LEGACY_PAINT_SETTLE_MS = 1500;
|
|
11
|
-
// ...and the gap at the OTHER end, which is the one that lands a capture on an
|
|
12
|
-
// app that has drawn nothing at all. Measured on the same instance with two
|
|
13
|
-
// remote tracks: the session gate is satisfied at ~2.5s, and the loading overlay
|
|
14
|
-
// — the only remaining signal there — does not go up until ~3.5s. An
|
|
15
|
-
// instrumented build has no such window: `data-display-phase` appears in the
|
|
16
|
-
// same frame as the display it belongs to.
|
|
17
|
-
//
|
|
18
|
-
// So on an uninstrumented build the app has to be seen to START working, and
|
|
19
|
-
// then hold still, before it counts as finished. The window is how long the
|
|
20
|
-
// first indicator gets to appear before "nothing to wait for" is the better
|
|
21
|
-
// reading; the quiet is how long the idle then has to hold.
|
|
22
|
-
const LEGACY_BUSY_WINDOW_MS = 4000;
|
|
23
|
-
const LEGACY_QUIET_MS = 2000;
|
|
1
|
+
import { describePendingDisplays, pendingDisplayStates, waitForSession, } from './sessionGate.js';
|
|
2
|
+
import { delay, hasAppReadyMarker, waitForAppSettled, waitForDisplaysDone, } from './waits.js';
|
|
24
3
|
/**
|
|
25
4
|
* Wait until a JBrowse page has finished loading AND finished drawing.
|
|
26
5
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
6
|
+
* Two gates, both positive, which is the property that matters — every other
|
|
7
|
+
* readiness signal the app publishes is an ABSENCE, and an absence is equally
|
|
8
|
+
* true of an app that has not started.
|
|
9
|
+
*
|
|
10
|
+
* 1. The census says the assembly and trackIds you asked for are open.
|
|
11
|
+
* 2. `[data-app-phase="ready"]` HOLDS: no view is resolving an assembly and no
|
|
12
|
+
* display is fetching, and still not a beat later. A display drops to
|
|
13
|
+
* `ready` in the gap between one fetch finishing and the debounced next one
|
|
14
|
+
* starting, so a single read takes that gap for the end.
|
|
15
|
+
*
|
|
16
|
+
* Then one negative gate that is only meaningful after them, and answers the
|
|
17
|
+
* question the marker does not: the marker is about WORK, and a display whose
|
|
18
|
+
* fetch failed is not working — it reads `ready` over an error banner.
|
|
19
|
+
* `data-display-drawn` is the stricter gate.
|
|
33
20
|
*/
|
|
34
|
-
export async function waitForJBrowseReady(page, { timeout = 60000,
|
|
21
|
+
export async function waitForJBrowseReady(page, { timeout = 60000, settleMs = 0, assembly, trackIds, allowUnsettled = false, } = {}) {
|
|
35
22
|
const unsettled = [];
|
|
36
|
-
const stage = async (name, work) => {
|
|
37
|
-
if (!(await work)) {
|
|
38
|
-
unsettled.push(name);
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
// The post-condition of the paint stage, and on a terminal display the ONLY
|
|
42
|
-
// report of it: `waitForDisplaysDone` returns as soon as every pending display
|
|
43
|
-
// is past `loading`, so an errored canvas that will never paint no longer
|
|
44
|
-
// spends the whole timeout to arrive here. The phase is what a reader needs —
|
|
45
|
-
// `error` is a banner, `ready` is a display claiming it finished without
|
|
46
|
-
// drawing — so the entry carries the census rather than naming the question.
|
|
47
|
-
const reportUnpainted = async () => {
|
|
48
|
-
const pending = await pendingDisplayStates(page);
|
|
49
|
-
if (pending.length > 0) {
|
|
50
|
-
unsettled.push(`display(s) never painted: ${describePendingDisplays(pending)}`);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
// The two hard waits reject with puppeteer's own `Waiting failed: Nms
|
|
54
|
-
// exceeded`, which names neither the stage nor the selector — the whole
|
|
55
|
-
// failure mode this module exists to avoid, arriving as an error message
|
|
56
|
-
// instead of as a blank image. Say which gate it was and what to do.
|
|
57
|
-
const required = async (name, work) => {
|
|
58
|
-
try {
|
|
59
|
-
return await work;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
throw new Error(`gave up waiting after ${timeout}ms: ${name}. Raise the timeout if the ` +
|
|
63
|
-
'page is merely slow; if it never finishes, open the same URL in a ' +
|
|
64
|
-
'browser — this gate has no content to fall through to.');
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
23
|
// 0. the session exists and holds what was asked for. Positive, and throws.
|
|
68
|
-
|
|
69
|
-
|
|
24
|
+
await waitForSession(page, { assembly, trackIds, timeout });
|
|
25
|
+
// 1. and the build publishes the marker at all. Said out loud rather than
|
|
26
|
+
// worked around: a chain built from the remaining signals is satisfied by
|
|
27
|
+
// a page that has not started, so the fallback that used to run here
|
|
28
|
+
// reported success on an empty browser unless it was also given a
|
|
29
|
+
// seen-busy-then-quiet gate to compensate. One positive selector replaces
|
|
30
|
+
// all of it, and a build too old to have it needs a newer --instance, not
|
|
31
|
+
// a wait chain that cannot fail.
|
|
32
|
+
if (!(await hasAppReadyMarker(page))) {
|
|
33
|
+
throw new Error('this page publishes no [data-app-phase], so there is no positive signal ' +
|
|
34
|
+
'that it has finished — every other readiness attribute is an absence ' +
|
|
35
|
+
'an app that has not started also satisfies. Point --instance at a ' +
|
|
36
|
+
'JBrowse build that publishes it.');
|
|
70
37
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// cannot be satisfied by an app that has not started.
|
|
75
|
-
//
|
|
76
|
-
// Held, not read once — the same hold `jb.waitReady` requires, because a
|
|
77
|
-
// display drops to `ready` in the gap between one fetch finishing and the
|
|
78
|
-
// debounced next one starting. The marker is known to exist here, so
|
|
79
|
-
// `waitForAppSettled`'s quiet-period fallback does not come into it.
|
|
80
|
-
//
|
|
81
|
-
// Everything after this point is the fallback for a deployment older than
|
|
82
|
-
// the marker, and can be deleted the day the oldest supported build has
|
|
83
|
-
// it.
|
|
84
|
-
if (await hasAppReadyMarker(page)) {
|
|
85
|
-
const ready = await waitForAppSettled(page, { timeout });
|
|
86
|
-
if (!ready) {
|
|
87
|
-
unsettled.push('the app never held itself ready');
|
|
88
|
-
}
|
|
89
|
-
// One thing the marker does not answer, so this stage stays even here: the
|
|
90
|
-
// marker is about WORK, and a display whose fetch failed is not working. It
|
|
91
|
-
// reads `ready` over an error banner, which is a correct answer to a
|
|
92
|
-
// different question than a capture is asking. `data-display-drawn` is the
|
|
93
|
-
// stricter gate — the two comparative canvases publish it from `settled`,
|
|
94
|
-
// which holds an error open deliberately so a golden regenerated during an
|
|
95
|
-
// outage fails on the census below instead of absorbing the banner as
|
|
96
|
-
// expected output. Ordered after the marker rather than instead of it, which
|
|
97
|
-
// is what makes an absence meaningful (see waitForDisplaysDone), and free on
|
|
98
|
-
// a page that has no such canvas. Skipped when the marker itself timed out:
|
|
99
|
-
// the paint wait would spend a second full timeout on a page already known
|
|
100
|
-
// unsettled, and the census reports the unpainted displays either way.
|
|
101
|
-
if (ready) {
|
|
102
|
-
await stage('a display never reported its first paint', waitForDisplaysDone(page, timeout));
|
|
103
|
-
}
|
|
104
|
-
await reportUnpainted();
|
|
105
|
-
if (settleMs > 0) {
|
|
106
|
-
await delay(settleMs);
|
|
107
|
-
}
|
|
108
|
-
const pendingStates = await pendingDisplayStates(page);
|
|
109
|
-
const report = {
|
|
110
|
-
pending: pendingStates.map(d => d.name),
|
|
111
|
-
pendingStates,
|
|
112
|
-
paintContract: await hasPaintContract(page),
|
|
113
|
-
unsettled,
|
|
114
|
-
instrumentation: await readInstrumentation(page),
|
|
115
|
-
appMarker: true,
|
|
116
|
-
};
|
|
117
|
-
if (!allowUnsettled && unsettled.length > 0) {
|
|
118
|
-
throw new Error(unsettledMessage(timeout, unsettled));
|
|
119
|
-
}
|
|
120
|
-
return report;
|
|
121
|
-
}
|
|
122
|
-
// 1b. what an older build can be asked instead. On one that publishes none of
|
|
123
|
-
// these, the stages below are not gates at all: they are assertions about
|
|
124
|
-
// absent attributes that no page can fail.
|
|
125
|
-
const instrumentation = await readInstrumentation(page);
|
|
126
|
-
const instrumented = instrumentation.displayPhase || instrumentation.displayDrawn;
|
|
127
|
-
// A page with no tracks open has nothing to load, so the quiet gate below
|
|
128
|
-
// would be a fixed sleep for an import form or a menu shot. No summary at all
|
|
129
|
-
// — expectSession: false, where these reads race the boot — is the opposite
|
|
130
|
-
// case: nothing has been ruled out, and reading "unknown" as "no tracks" here
|
|
131
|
-
// is what let the whole chain pass over an app that had not started, since
|
|
132
|
-
// every stage below the gate is an absence an empty page satisfies.
|
|
133
|
-
const summary = await readSessionSummary(page);
|
|
134
|
-
const needsQuietGate = !instrumented && (summary === undefined || summary.trackIds.length > 0);
|
|
135
|
-
// 2. the view has an assembly and its React component has arrived. Also not
|
|
136
|
-
// best-effort: a view stuck here has no content to fall through to.
|
|
137
|
-
await required('a view never left its loading phase (still resolving its assembly, or its ' +
|
|
138
|
-
'lazily-imported component never arrived)', waitForViewPhases(page, timeout));
|
|
139
|
-
// 3. no track is still fetching: an overlay that never clears is a fetch
|
|
140
|
-
// that never finished, with nothing behind it, so this one throws too.
|
|
141
|
-
await required('the loading overlay never cleared (a track fetch never finished)', waitForLoadingComplete(page, { timeout }));
|
|
142
|
-
await stage('a display was still in its loading phase', waitForDisplayPhases(page, timeout));
|
|
143
|
-
// 4. no display is still pending its first paint
|
|
144
|
-
await stage('a display never reported its first paint', waitForDisplaysDone(page, timeout));
|
|
145
|
-
await reportUnpainted();
|
|
146
|
-
// 5. nothing still reports itself busy: adapter "Downloading…" status on the
|
|
147
|
-
// session model, which can outlive the overlay, and the visible
|
|
148
|
-
// "Loading…/Rendering…" labels of the views that publish no phase
|
|
149
|
-
// attribute. One predicate answers both, so it is one stage — it used to
|
|
150
|
-
// run twice, once as waitForLoadingComplete's download half and once
|
|
151
|
-
// under its own name, and a slow page paid the same timeout for each.
|
|
152
|
-
if (waitForDownloads) {
|
|
153
|
-
await stage('a track was still downloading, or a "Loading…/Rendering…" label was ' +
|
|
154
|
-
'still on screen', waitForQuiescent(page, { timeout }));
|
|
38
|
+
const ready = await waitForAppSettled(page, { timeout });
|
|
39
|
+
if (!ready) {
|
|
40
|
+
unsettled.push('the app never held itself ready');
|
|
155
41
|
}
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
'is)', waitForQuietPeriod(page, {
|
|
165
|
-
quietMs: LEGACY_QUIET_MS,
|
|
166
|
-
busyWindowMs: LEGACY_BUSY_WINDOW_MS,
|
|
167
|
-
timeout,
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
const paintContract = await hasPaintContract(page);
|
|
171
|
-
if (!paintContract) {
|
|
172
|
-
await delay(LEGACY_PAINT_SETTLE_MS);
|
|
42
|
+
// Skipped when the marker itself timed out: the paint wait would spend a
|
|
43
|
+
// second full timeout on a page already known unsettled, and the census below
|
|
44
|
+
// reports the unpainted displays either way. Free on a page with no canvas.
|
|
45
|
+
if (ready) {
|
|
46
|
+
const drawn = await waitForDisplaysDone(page, timeout);
|
|
47
|
+
if (!drawn) {
|
|
48
|
+
unsettled.push('a display never reported its first paint');
|
|
49
|
+
}
|
|
173
50
|
}
|
|
174
51
|
if (settleMs > 0) {
|
|
175
52
|
await delay(settleMs);
|
|
176
53
|
}
|
|
54
|
+
// The shutter-time census, taken ONCE and after the settle, so the throw and
|
|
55
|
+
// the report it ships with agree. Taken before it they did not: a display
|
|
56
|
+
// that painted during `settleMs` was absent from `pending` and still failed
|
|
57
|
+
// the run, while the CLI's own warning recommended raising `--settle` to fix
|
|
58
|
+
// exactly that.
|
|
177
59
|
const pendingStates = await pendingDisplayStates(page);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
paintContract,
|
|
182
|
-
unsettled,
|
|
183
|
-
instrumentation,
|
|
184
|
-
appMarker: false,
|
|
185
|
-
};
|
|
60
|
+
if (pendingStates.length > 0) {
|
|
61
|
+
unsettled.push(`display(s) never painted: ${describePendingDisplays(pendingStates)}`);
|
|
62
|
+
}
|
|
186
63
|
if (!allowUnsettled && unsettled.length > 0) {
|
|
187
|
-
// Throwing is the point. Each
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
throw new Error(
|
|
64
|
+
// Throwing is the point. Each stage swallows its own timeout so a slow page
|
|
65
|
+
// is not failed for being slow, which historically meant the run ended with
|
|
66
|
+
// an image and an exit code of 0 whether it had settled or not. A caller
|
|
67
|
+
// that genuinely wants the frame anyway asks for it by name.
|
|
68
|
+
throw new Error(`gave up waiting after ${timeout}ms: ${unsettled.join('; ')}. ` +
|
|
69
|
+
'Raise the timeout, or pass allowUnsettled (--allowUnsettled) to ' +
|
|
70
|
+
'capture the frame as it stands.');
|
|
192
71
|
}
|
|
193
|
-
return
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* What a timed-out wait says. A stage name is the QUESTION rather than the
|
|
197
|
-
* answer — "a display never reported its first paint" reads identically for a
|
|
198
|
-
* slow fetch, a failed one and a display that never had a canvas to paint — so
|
|
199
|
-
* `reportUnpainted` puts the census in the list beside it, and the `ready` case
|
|
200
|
-
* is the one that most changes what a reader does next: a longer timeout is the
|
|
201
|
-
* fix for `loading` and never the fix for that.
|
|
202
|
-
*/
|
|
203
|
-
function unsettledMessage(timeout, unsettled) {
|
|
204
|
-
return (`gave up waiting after ${timeout}ms: ${unsettled.join('; ')}. ` +
|
|
205
|
-
'Raise the timeout, or pass allowUnsettled (--allowUnsettled) to ' +
|
|
206
|
-
'capture the frame as it stands.');
|
|
72
|
+
return { pending: pendingStates.map(d => d.name), pendingStates, unsettled };
|
|
207
73
|
}
|
package/esm/session.js
CHANGED
|
@@ -58,8 +58,18 @@ export function trackIdsFromSession(session) {
|
|
|
58
58
|
]);
|
|
59
59
|
return collect(session.views);
|
|
60
60
|
}
|
|
61
|
-
// Full `?config=…&session=…&sessionName=…` query string
|
|
62
|
-
//
|
|
61
|
+
// Full `?config=…&session=…&sessionName=…` query string, for a caller that has
|
|
62
|
+
// an origin but no JBrowse instance URL to hand `jbrowseUrl`.
|
|
63
|
+
//
|
|
64
|
+
// Built with URLSearchParams, the same encoder and the same rule as
|
|
65
|
+
// `jbrowseUrl`: hand it the DECODED spec, because it encodes once itself. It
|
|
66
|
+
// used to interpolate `config` raw and ask callers to pre-encode it, which none
|
|
67
|
+
// of them did — harmless only for as long as no config URL contained a `?` or
|
|
68
|
+
// an `&`, at which point the link loads a truncated config and reports nothing.
|
|
63
69
|
export function sessionSpecQuery({ config, session, sessionName = 'Screenshot', }) {
|
|
64
|
-
return
|
|
70
|
+
return `?${new URLSearchParams({
|
|
71
|
+
config,
|
|
72
|
+
session: sessionSpecParam(session),
|
|
73
|
+
sessionName,
|
|
74
|
+
})}`;
|
|
65
75
|
}
|
package/esm/sessionGate.d.ts
CHANGED
|
@@ -13,11 +13,15 @@ export interface SessionExpectations {
|
|
|
13
13
|
/**
|
|
14
14
|
* The census the app publishes beside its phase: `AppReadyMarker` renders
|
|
15
15
|
* `data-app-views` (a count), and `data-app-assemblies` / `data-app-tracks`
|
|
16
|
-
* (JSON string arrays of what is open).
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* (JSON string arrays of what is open).
|
|
17
|
+
*
|
|
18
|
+
* One element answers the whole gate. Each view declares what it holds and
|
|
19
|
+
* `openViews`/`openTracks` reduce over those declarations (ADR-103), so nothing
|
|
20
|
+
* here has to know that a synteny view keeps its tracks on levels and its rows
|
|
21
|
+
* on sub-views — the duck-typed walk of `window.JBrowseSession` that used to
|
|
22
|
+
* live here, and drifted against the copy in `isPageBusyInPage`, is gone with
|
|
23
|
+
* the builds that needed it.
|
|
24
|
+
*
|
|
21
25
|
* `scripts/readinessContract.test.ts` pins the attribute names against the
|
|
22
26
|
* marker, since neither package may import the other.
|
|
23
27
|
*/
|
|
@@ -27,12 +31,12 @@ export interface SessionSummary {
|
|
|
27
31
|
assemblies: string[];
|
|
28
32
|
trackIds: string[];
|
|
29
33
|
}
|
|
30
|
-
/** What the page currently has open, or undefined if there is no
|
|
34
|
+
/** What the page currently has open, or undefined if there is no census yet. */
|
|
31
35
|
export declare function readSessionSummary(page: Page): Promise<SessionSummary | undefined>;
|
|
32
36
|
export declare function readSessionSummaryInPage(): SessionSummary | undefined;
|
|
33
37
|
/**
|
|
34
|
-
* Wait until the
|
|
35
|
-
*
|
|
38
|
+
* Wait until the census exists and the assembly and tracks that were asked for
|
|
39
|
+
* are actually open.
|
|
36
40
|
*
|
|
37
41
|
* Throws on timeout rather than proceeding. A config URL that 404s, a trackId
|
|
38
42
|
* that does not exist in the config, and an assembly name that does not match
|
|
@@ -43,58 +47,11 @@ export declare function readSessionSummaryInPage(): SessionSummary | undefined;
|
|
|
43
47
|
export declare function waitForSession(page: Page, { assembly, trackIds, timeout, }?: SessionExpectations & {
|
|
44
48
|
timeout?: number;
|
|
45
49
|
}): Promise<void>;
|
|
46
|
-
export declare const PAINT_CONTRACT_NOTE: string;
|
|
47
|
-
/**
|
|
48
|
-
* Whether every open display's paint state was actually measurable.
|
|
49
|
-
*
|
|
50
|
-
* The per-display paint attributes are not universal. Measured on 2026-08-07:
|
|
51
|
-
* jbrowse.org/code/jb2/main publishes `data-view-phase`, `data-display-phase`
|
|
52
|
-
* and `data-display-drawn`; jbrowse.org/code/jb2/latest — the released build,
|
|
53
|
-
* which is what every genomes.jbrowse.org link and every docs figure link opens
|
|
54
|
-
* — publishes none of them and exposes only the loading overlay. Against that
|
|
55
|
-
* instance the display-level waits are unfalsifiable rather than satisfied, so a
|
|
56
|
-
* caller has to be told which of the two it got instead of reading "0 displays
|
|
57
|
-
* pending" as good news.
|
|
58
|
-
*
|
|
59
|
-
* The absence of the attribute is NOT on its own the answer, which is the trap
|
|
60
|
-
* here: a page with no tracks open — an import form, a menu shot, a bare view —
|
|
61
|
-
* publishes none of it either, and reporting that as "this build cannot measure
|
|
62
|
-
* paint" is both wrong and alarming. So this asks the question only when there
|
|
63
|
-
* is something to measure, and answers true when there is not.
|
|
64
|
-
*
|
|
65
|
-
* Call it AFTER the session gate, so "no tracks open" means the page genuinely
|
|
66
|
-
* has none rather than not having got there yet.
|
|
67
|
-
*/
|
|
68
|
-
export declare function hasPaintContract(page: Page): Promise<boolean>;
|
|
69
|
-
/**
|
|
70
|
-
* Which readiness attributes this build publishes at all.
|
|
71
|
-
*
|
|
72
|
-
* `hasPaintContract` answers the same question for one attribute and folds in
|
|
73
|
-
* "there was nothing to measure"; this is the raw read of all three, so the
|
|
74
|
-
* chain can adapt to the build BEFORE it starts waiting rather than reporting
|
|
75
|
-
* afterwards what it could not see.
|
|
76
|
-
*
|
|
77
|
-
* Every wait keyed on one of these is NEGATIVE — it passes when the selector is
|
|
78
|
-
* absent — so on a build that publishes none of them all three are satisfied by
|
|
79
|
-
* a page that has not begun to draw. Read this after the session gate and treat
|
|
80
|
-
* `false` as "this signal is unavailable", never as "this signal says done".
|
|
81
|
-
*/
|
|
82
|
-
export interface Instrumentation {
|
|
83
|
-
viewPhase: boolean;
|
|
84
|
-
displayPhase: boolean;
|
|
85
|
-
displayDrawn: boolean;
|
|
86
|
-
}
|
|
87
|
-
/** Serialized into the page; exported so a test can call the real function. */
|
|
88
|
-
export declare function readInstrumentationInPage(): Instrumentation;
|
|
89
|
-
export declare function readInstrumentation(page: Page): Promise<Instrumentation>;
|
|
90
50
|
/**
|
|
91
51
|
* Displays that were still reporting unpainted at the moment of the call.
|
|
92
52
|
*
|
|
93
53
|
* Distinct from `unsettled`, which says a wait ran out of time. This says what
|
|
94
|
-
* the page looked like when the shutter fired
|
|
95
|
-
* other: a display can go back to pending after its stage passed. An empty
|
|
96
|
-
* result means nothing at all on a build with no paint contract — check
|
|
97
|
-
* `paintContract` before reading it as good news.
|
|
54
|
+
* the page looked like when the shutter fired.
|
|
98
55
|
*/
|
|
99
56
|
export declare function pendingDisplays(page: Page): Promise<string[]>;
|
|
100
57
|
/** One unpainted display and what it says about itself. */
|
|
@@ -104,10 +61,9 @@ export interface PendingDisplay {
|
|
|
104
61
|
/** which instance, where the display publishes `data-display-id` */
|
|
105
62
|
id?: string;
|
|
106
63
|
/**
|
|
107
|
-
* Its own phase
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* the display rather than a slow page.
|
|
64
|
+
* Its own phase. `loading` is a display still fetching; `ready` is the one
|
|
65
|
+
* that earns this census, since a display that says it has finished while
|
|
66
|
+
* reporting no paint is a bug in the display rather than a slow page.
|
|
111
67
|
*/
|
|
112
68
|
phase?: string;
|
|
113
69
|
}
|
|
@@ -123,14 +79,12 @@ export interface PendingDisplay {
|
|
|
123
79
|
* `ready` it says it is done and reports no paint. That is the display's
|
|
124
80
|
* bug, not the wait's, and it is the one a longer timeout will
|
|
125
81
|
* never fix.
|
|
126
|
-
* absent the element publishes no phase: a build older than the
|
|
127
|
-
* attribute, or a surface that never grew one.
|
|
128
82
|
*
|
|
129
83
|
* Serialized into the page, so a test can call the real function. Read fresh
|
|
130
|
-
* from the DOM at report time rather than from handles the waits held. A handle
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* in 28c6ee6d90).
|
|
84
|
+
* from the DOM at report time rather than from handles the waits held. A handle
|
|
85
|
+
* to an element that has since re-rendered throws `Node is detached from
|
|
86
|
+
* document`, which is how the previous attempt at this turned four diagnosable
|
|
87
|
+
* timeouts into nine opaque puppeteer errors (reverted in 28c6ee6d90).
|
|
134
88
|
*/
|
|
135
89
|
export declare function pendingDisplayStatesInPage(): PendingDisplay[];
|
|
136
90
|
export declare function pendingDisplayStates(page: Page): Promise<PendingDisplay[]>;
|