@norskvideo/ctl-dev-kit 0.2.23 → 0.2.24

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.
@@ -62,6 +62,19 @@ export declare function livePictureFailure(selector: string, phase: string | nul
62
62
  export declare function awaitLivePicture(page: Page, selector: string, opts?: {
63
63
  timeoutMs?: number;
64
64
  }): Promise<void>;
65
+ /** How long a capture waits for web fonts before shooting anyway. */
66
+ export declare const FONTS_READY_TIMEOUT_MS = 10000;
67
+ /** `document.fonts.ready`, bounded. True when the fonts settled in time.
68
+ *
69
+ * Unbounded, this hung commentary's composition guide for its whole 360s test
70
+ * budget on 2026-10-03 (CI only, after the Take, with the page about to render
71
+ * the advanced compositor): `fonts.ready` resolves only once every pending font
72
+ * load has finished, a request that never answers never finishes, and
73
+ * `page.evaluate` has no timeout of its own. The test then timed out, its
74
+ * teardown with it, and the instance ran on for hours. A capture in a fallback
75
+ * font is a far smaller failure than that, so bound the wait inside the page
76
+ * AND around the call -- a wedged renderer never answers the call at all. */
77
+ export declare function awaitFontsReady(page: Pick<Page, "evaluate">, timeoutMs?: number): Promise<boolean>;
65
78
  /** Produce the screenshot bytes for a capture, applying its treatment. Split out
66
79
  * from `DocGuide.capture` (which also gates on DOCS_GENERATE and writes the file)
67
80
  * so the treatment geometry is testable on its own. */
@@ -79,14 +79,47 @@ async function spotlightOn(page, selector, pad) {
79
79
  async function spotlightOff(page) {
80
80
  await page.evaluate((id) => document.getElementById(id)?.remove(), SPOTLIGHT_ID);
81
81
  }
82
+ /** How long a capture waits for web fonts before shooting anyway. */
83
+ export const FONTS_READY_TIMEOUT_MS = 10_000;
84
+ /** `document.fonts.ready`, bounded. True when the fonts settled in time.
85
+ *
86
+ * Unbounded, this hung commentary's composition guide for its whole 360s test
87
+ * budget on 2026-10-03 (CI only, after the Take, with the page about to render
88
+ * the advanced compositor): `fonts.ready` resolves only once every pending font
89
+ * load has finished, a request that never answers never finishes, and
90
+ * `page.evaluate` has no timeout of its own. The test then timed out, its
91
+ * teardown with it, and the instance ran on for hours. A capture in a fallback
92
+ * font is a far smaller failure than that, so bound the wait inside the page
93
+ * AND around the call -- a wedged renderer never answers the call at all. */
94
+ export async function awaitFontsReady(page, timeoutMs = FONTS_READY_TIMEOUT_MS) {
95
+ let timer;
96
+ const late = new Promise((resolve) => {
97
+ timer = setTimeout(() => resolve(false), timeoutMs);
98
+ });
99
+ const ready = page
100
+ .evaluate((ms) => Promise.race([
101
+ document.fonts.ready.then(() => true),
102
+ new Promise((resolve) => setTimeout(() => resolve(false), ms)),
103
+ ]), timeoutMs)
104
+ .catch(() => false);
105
+ try {
106
+ return await Promise.race([ready, late]);
107
+ }
108
+ finally {
109
+ clearTimeout(timer);
110
+ }
111
+ }
82
112
  /** Produce the screenshot bytes for a capture, applying its treatment. Split out
83
113
  * from `DocGuide.capture` (which also gates on DOCS_GENERATE and writes the file)
84
114
  * so the treatment geometry is testable on its own. */
85
115
  export async function screenshotFor(page, treat) {
86
116
  if (treat?.livePicture)
87
117
  await awaitLivePicture(page, treat.livePicture, { timeoutMs: treat.livePictureTimeoutMs });
88
- // Wait for web fonts, else the snapshot catches a fallback font mid-swap.
89
- await page.evaluate(() => document.fonts.ready);
118
+ // Wait for web fonts, else the snapshot catches a fallback font mid-swap --
119
+ // but not forever (see awaitFontsReady).
120
+ if (!(await awaitFontsReady(page))) {
121
+ console.warn(`[doc-guide] web fonts not ready after ${FONTS_READY_TIMEOUT_MS}ms; capturing with what has loaded`);
122
+ }
90
123
  if (treat?.crop)
91
124
  return page.locator(treat.crop).first().screenshot();
92
125
  if (treat?.spotlight) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.2.23",
3
+ "version": "0.2.24",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./create-product": "./create-product/create-product.ts",