@noego/wood 0.4.1 → 0.4.3
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 +100 -2
- package/dist/client/global_polyfill.d.cts +1 -2
- package/dist/client/global_polyfill.d.ts +1 -2
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/index.cjs +0 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/dist/testing/browser.cjs +253 -36
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +6 -2
- package/dist/testing/browser.d.ts +6 -2
- package/dist/testing/browser.js +253 -37
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.cjs +3 -1
- package/dist/testing/create_controller_harness.cjs.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +4 -2
- package/dist/testing/create_controller_harness.d.ts +4 -2
- package/dist/testing/create_controller_harness.js +3 -1
- package/dist/testing/create_controller_harness.js.map +1 -1
- package/dist/testing/index.cjs +3 -3
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +5 -3
- package/dist/testing/index.d.ts +5 -3
- package/dist/testing/index.js +2 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/trace-testing/index.cjs +3 -3
- package/dist/trace-testing/index.cjs.map +1 -1
- package/dist/trace-testing/index.d.cts +2 -3
- package/dist/trace-testing/index.d.ts +2 -3
- package/dist/trace-testing/index.js +3 -3
- package/dist/trace-testing/index.js.map +1 -1
- package/dist/trace-testing/trace_assertions.cjs +2 -46
- package/dist/trace-testing/trace_assertions.cjs.map +1 -1
- package/dist/trace-testing/trace_assertions.d.cts +1 -15
- package/dist/trace-testing/trace_assertions.d.ts +1 -15
- package/dist/trace-testing/trace_assertions.js +3 -45
- package/dist/trace-testing/trace_assertions.js.map +1 -1
- package/dist/trace-testing/trace_query.cjs +4 -115
- package/dist/trace-testing/trace_query.cjs.map +1 -1
- package/dist/trace-testing/trace_query.d.cts +1 -24
- package/dist/trace-testing/trace_query.d.ts +1 -24
- package/dist/trace-testing/trace_query.js +5 -112
- package/dist/trace-testing/trace_query.js.map +1 -1
- package/dist/trace-testing/trace_recorder.cjs +50 -0
- package/dist/trace-testing/trace_recorder.cjs.map +1 -0
- package/dist/trace-testing/trace_recorder.d.cts +12 -0
- package/dist/trace-testing/trace_recorder.d.ts +12 -0
- package/dist/trace-testing/trace_recorder.js +32 -0
- package/dist/trace-testing/trace_recorder.js.map +1 -0
- package/dist/tracing/index.cjs +0 -4
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.cts +1 -1
- package/dist/tracing/index.d.ts +1 -1
- package/dist/tracing/index.js +1 -5
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/trace_hub.cjs +0 -84
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +1 -16
- package/dist/tracing/trace_hub.d.ts +1 -16
- package/dist/tracing/trace_hub.js +0 -72
- package/dist/tracing/trace_hub.js.map +1 -1
- package/dist/tracing/trace_provider.cjs +0 -6
- package/dist/tracing/trace_provider.cjs.map +1 -1
- package/dist/tracing/trace_provider.d.cts +1 -3
- package/dist/tracing/trace_provider.d.ts +1 -3
- package/dist/tracing/trace_provider.js +0 -7
- package/dist/tracing/trace_provider.js.map +1 -1
- package/docs/browser-testing.md +84 -0
- package/package.json +2 -1
- package/dist/trace-testing/trace_scenario.cjs +0 -61
- package/dist/trace-testing/trace_scenario.cjs.map +0 -1
- package/dist/trace-testing/trace_scenario.d.cts +0 -27
- package/dist/trace-testing/trace_scenario.d.ts +0 -27
- package/dist/trace-testing/trace_scenario.js +0 -37
- package/dist/trace-testing/trace_scenario.js.map +0 -1
package/dist/testing/browser.cjs
CHANGED
|
@@ -33,14 +33,31 @@ __export(browser_exports, {
|
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(browser_exports);
|
|
35
35
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
36
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
36
37
|
var import_node_module = require("node:module");
|
|
37
38
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
38
39
|
var import_node_url = require("node:url");
|
|
39
40
|
var import_tracing = require("../tracing/index.js");
|
|
41
|
+
var import_trace_testing = require("../trace-testing/index.js");
|
|
40
42
|
const DEFAULT_VIEWPORT = {
|
|
41
43
|
width: 1280,
|
|
42
44
|
height: 800
|
|
43
45
|
};
|
|
46
|
+
const DEFAULT_EXPECT_TIMEOUT_MS = 1e4;
|
|
47
|
+
const DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS = 5e3;
|
|
48
|
+
const WORKER_RUNTIME_IDLE_CLOSE_MS = 5e3;
|
|
49
|
+
const browserWorkerRuntimes = /* @__PURE__ */ new Map();
|
|
50
|
+
const browserWorkerCacheDirs = /* @__PURE__ */ new Set();
|
|
51
|
+
process.on("exit", () => {
|
|
52
|
+
for (const cacheDir of browserWorkerCacheDirs) {
|
|
53
|
+
try {
|
|
54
|
+
import_node_fs.default.rmSync(cacheDir, { recursive: true, force: true });
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
browserWorkerCacheDirs.clear();
|
|
59
|
+
browserWorkerRuntimes.clear();
|
|
60
|
+
});
|
|
44
61
|
function normalizeRoot(rootDir) {
|
|
45
62
|
return import_node_path.default.resolve(rootDir ?? process.cwd());
|
|
46
63
|
}
|
|
@@ -63,6 +80,18 @@ function mergeBridge(base, override) {
|
|
|
63
80
|
record: override?.record ?? base?.record
|
|
64
81
|
};
|
|
65
82
|
}
|
|
83
|
+
async function waitForBoundedClose(promise, timeoutMs = DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS) {
|
|
84
|
+
let timeout;
|
|
85
|
+
await Promise.race([
|
|
86
|
+
promise.catch(() => void 0),
|
|
87
|
+
new Promise((resolve) => {
|
|
88
|
+
timeout = setTimeout(resolve, timeoutMs);
|
|
89
|
+
})
|
|
90
|
+
]);
|
|
91
|
+
if (timeout) {
|
|
92
|
+
clearTimeout(timeout);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
66
95
|
function channelToManifestEntry(channel, handler) {
|
|
67
96
|
const pathSegments = channel.split(".").filter(Boolean);
|
|
68
97
|
const action = pathSegments.length > 0 ? pathSegments[pathSegments.length - 1] : channel;
|
|
@@ -164,6 +193,51 @@ async function loadPlaywright(browserName) {
|
|
|
164
193
|
async function loadVite() {
|
|
165
194
|
return await import("vite");
|
|
166
195
|
}
|
|
196
|
+
function createPackageRequire(rootDir) {
|
|
197
|
+
return (0, import_node_module.createRequire)(import_node_path.default.join(rootDir, "package.json"));
|
|
198
|
+
}
|
|
199
|
+
function resolvePackageModule(rootDir, source) {
|
|
200
|
+
const rootRequire = createPackageRequire(rootDir);
|
|
201
|
+
const processRequire = (0, import_node_module.createRequire)(import_node_path.default.join(process.cwd(), "package.json"));
|
|
202
|
+
try {
|
|
203
|
+
return rootRequire.resolve(source);
|
|
204
|
+
} catch {
|
|
205
|
+
try {
|
|
206
|
+
return processRequire.resolve(source);
|
|
207
|
+
} catch {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function resolvePackageDir(rootDir, packageName) {
|
|
213
|
+
const packageJson = resolvePackageModule(rootDir, `${packageName}/package.json`);
|
|
214
|
+
return packageJson ? import_node_path.default.dirname(packageJson) : null;
|
|
215
|
+
}
|
|
216
|
+
function createWoodBrowserResolver(rootDir) {
|
|
217
|
+
const sveltePackageDir = resolvePackageDir(rootDir, "svelte");
|
|
218
|
+
const svelteClientEntry = sveltePackageDir ? import_node_path.default.join(sveltePackageDir, "src", "index-client.js") : null;
|
|
219
|
+
const svelteLegacyClientEntry = sveltePackageDir ? import_node_path.default.join(sveltePackageDir, "src", "legacy", "legacy-client.js") : null;
|
|
220
|
+
const svelteReactivityClientEntry = sveltePackageDir ? import_node_path.default.join(sveltePackageDir, "src", "reactivity", "index-client.js") : null;
|
|
221
|
+
return {
|
|
222
|
+
name: "wood-browser-resolver",
|
|
223
|
+
enforce: "pre",
|
|
224
|
+
resolveId(source) {
|
|
225
|
+
if (source === "svelte") {
|
|
226
|
+
return svelteClientEntry;
|
|
227
|
+
}
|
|
228
|
+
if (source === "svelte/legacy") {
|
|
229
|
+
return svelteLegacyClientEntry;
|
|
230
|
+
}
|
|
231
|
+
if (source === "svelte/reactivity") {
|
|
232
|
+
return svelteReactivityClientEntry;
|
|
233
|
+
}
|
|
234
|
+
if (source.startsWith("svelte/")) {
|
|
235
|
+
return resolvePackageModule(rootDir, source);
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
167
241
|
async function loadSveltePlugin(rootDir) {
|
|
168
242
|
try {
|
|
169
243
|
const rootPluginPath = import_node_path.default.join(
|
|
@@ -194,22 +268,115 @@ async function loadViews(viewsPath) {
|
|
|
194
268
|
const parser = await import("../parser/views_parser.cjs");
|
|
195
269
|
return parser.parseViewsFile(viewsPath);
|
|
196
270
|
}
|
|
197
|
-
async function createViteServer(rootDir) {
|
|
271
|
+
async function createViteServer(rootDir, cacheDir) {
|
|
198
272
|
const vite = await loadVite();
|
|
199
273
|
const svelte = await loadSveltePlugin(rootDir);
|
|
200
|
-
const plugins =
|
|
274
|
+
const plugins = [
|
|
275
|
+
createWoodBrowserResolver(rootDir),
|
|
276
|
+
...svelte ? [svelte()] : []
|
|
277
|
+
];
|
|
201
278
|
const server = await vite.createServer({
|
|
202
279
|
root: rootDir,
|
|
280
|
+
cacheDir,
|
|
203
281
|
logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? "info" : "silent",
|
|
204
282
|
plugins,
|
|
205
283
|
resolve: {
|
|
206
284
|
dedupe: ["svelte"]
|
|
207
285
|
},
|
|
208
|
-
server: { port: 0 }
|
|
286
|
+
server: { port: 0, fs: { allow: [rootDir, import_node_os.default.tmpdir()] } }
|
|
209
287
|
});
|
|
210
288
|
await server.listen();
|
|
211
289
|
return server;
|
|
212
290
|
}
|
|
291
|
+
function workerRuntimeKey(input) {
|
|
292
|
+
return [
|
|
293
|
+
input.rootDir,
|
|
294
|
+
input.browserName,
|
|
295
|
+
input.headless ? "headless" : "headed"
|
|
296
|
+
].join("::");
|
|
297
|
+
}
|
|
298
|
+
async function createBrowserWorkerRuntime(input) {
|
|
299
|
+
const cacheRoot = import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "wood-browser-vite-"));
|
|
300
|
+
browserWorkerCacheDirs.add(cacheRoot);
|
|
301
|
+
let browser2 = null;
|
|
302
|
+
try {
|
|
303
|
+
const playwrightBrowser = await loadPlaywright(input.browserName);
|
|
304
|
+
browser2 = await playwrightBrowser.launch({ headless: input.headless });
|
|
305
|
+
const server = await createViteServer(input.rootDir, import_node_path.default.join(cacheRoot, ".vite"));
|
|
306
|
+
return {
|
|
307
|
+
browser: browser2,
|
|
308
|
+
server,
|
|
309
|
+
cacheDir: cacheRoot,
|
|
310
|
+
rootDir: input.rootDir,
|
|
311
|
+
key: input.key,
|
|
312
|
+
activeHarnesses: 0,
|
|
313
|
+
closing: false,
|
|
314
|
+
idleCloseTimer: null
|
|
315
|
+
};
|
|
316
|
+
} catch (error) {
|
|
317
|
+
await browser2?.close().catch(() => void 0);
|
|
318
|
+
import_node_fs.default.rmSync(cacheRoot, { recursive: true, force: true });
|
|
319
|
+
browserWorkerCacheDirs.delete(cacheRoot);
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function acquireBrowserWorkerRuntime(input) {
|
|
324
|
+
const key = workerRuntimeKey(input);
|
|
325
|
+
let entry = browserWorkerRuntimes.get(key);
|
|
326
|
+
if (!entry) {
|
|
327
|
+
entry = {
|
|
328
|
+
promise: createBrowserWorkerRuntime({ ...input, key })
|
|
329
|
+
};
|
|
330
|
+
browserWorkerRuntimes.set(key, entry);
|
|
331
|
+
}
|
|
332
|
+
const runtime = await entry.promise;
|
|
333
|
+
if (runtime.closing) {
|
|
334
|
+
browserWorkerRuntimes.delete(key);
|
|
335
|
+
return await acquireBrowserWorkerRuntime(input);
|
|
336
|
+
}
|
|
337
|
+
if (runtime.idleCloseTimer) {
|
|
338
|
+
clearTimeout(runtime.idleCloseTimer);
|
|
339
|
+
runtime.idleCloseTimer = null;
|
|
340
|
+
}
|
|
341
|
+
runtime.activeHarnesses += 1;
|
|
342
|
+
return runtime;
|
|
343
|
+
}
|
|
344
|
+
async function closeBrowserWorkerRuntime(runtime) {
|
|
345
|
+
if (runtime.closing) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
runtime.closing = true;
|
|
349
|
+
try {
|
|
350
|
+
await Promise.all([
|
|
351
|
+
waitForBoundedClose(runtime.server.close()),
|
|
352
|
+
waitForBoundedClose(runtime.browser.close())
|
|
353
|
+
]);
|
|
354
|
+
} finally {
|
|
355
|
+
import_node_fs.default.rmSync(runtime.cacheDir, { recursive: true, force: true });
|
|
356
|
+
browserWorkerCacheDirs.delete(runtime.cacheDir);
|
|
357
|
+
const entry = browserWorkerRuntimes.get(runtime.key);
|
|
358
|
+
const current = entry ? await entry.promise.catch(() => null) : null;
|
|
359
|
+
if (current === runtime) {
|
|
360
|
+
browserWorkerRuntimes.delete(runtime.key);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function scheduleBrowserWorkerRuntimeClose(runtime) {
|
|
365
|
+
if (runtime.closing || runtime.activeHarnesses > 0 || runtime.idleCloseTimer) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
runtime.idleCloseTimer = setTimeout(() => {
|
|
369
|
+
runtime.idleCloseTimer = null;
|
|
370
|
+
if (runtime.activeHarnesses === 0) {
|
|
371
|
+
void closeBrowserWorkerRuntime(runtime);
|
|
372
|
+
}
|
|
373
|
+
}, WORKER_RUNTIME_IDLE_CLOSE_MS);
|
|
374
|
+
runtime.idleCloseTimer.unref?.();
|
|
375
|
+
}
|
|
376
|
+
function releaseBrowserWorkerRuntime(runtime) {
|
|
377
|
+
runtime.activeHarnesses = Math.max(0, runtime.activeHarnesses - 1);
|
|
378
|
+
scheduleBrowserWorkerRuntimeClose(runtime);
|
|
379
|
+
}
|
|
213
380
|
function serverBaseUrl(server) {
|
|
214
381
|
return server.resolvedUrls?.local?.[0] ?? "http://127.0.0.1:5173";
|
|
215
382
|
}
|
|
@@ -416,8 +583,8 @@ async function installBridge(page, bridgeState, manifest, bridgeInit) {
|
|
|
416
583
|
window.__WOOD_BROWSER_BRIDGE_MANIFEST__ = entries;
|
|
417
584
|
}, manifest);
|
|
418
585
|
}
|
|
419
|
-
async function installTraceBinding(page,
|
|
420
|
-
if (!
|
|
586
|
+
async function installTraceBinding(page, traceRecorder, context) {
|
|
587
|
+
if (!traceRecorder) {
|
|
421
588
|
return;
|
|
422
589
|
}
|
|
423
590
|
await page.exposeBinding("__woodBrowserTrace", async (_source, payload) => {
|
|
@@ -500,20 +667,35 @@ async function elementRect(page, selector) {
|
|
|
500
667
|
}).catch(() => null);
|
|
501
668
|
}
|
|
502
669
|
function createExpect(page, outputDir) {
|
|
670
|
+
async function waitForVisible(selector) {
|
|
671
|
+
const locator = page.locator(selector).first();
|
|
672
|
+
try {
|
|
673
|
+
await locator.waitFor({ state: "attached", timeout: DEFAULT_EXPECT_TIMEOUT_MS });
|
|
674
|
+
} catch {
|
|
675
|
+
throw new Error(`Expected "${selector}" to exist.`);
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
await locator.waitFor({ state: "visible", timeout: DEFAULT_EXPECT_TIMEOUT_MS });
|
|
679
|
+
} catch {
|
|
680
|
+
throw new Error(`Expected "${selector}" to be visible.`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
503
683
|
return {
|
|
504
684
|
async visible(selector) {
|
|
505
|
-
|
|
506
|
-
if (count < 1) throw new Error(`Expected "${selector}" to exist.`);
|
|
507
|
-
const visible = await page.locator(selector).first().isVisible();
|
|
508
|
-
if (!visible) throw new Error(`Expected "${selector}" to be visible.`);
|
|
685
|
+
await waitForVisible(selector);
|
|
509
686
|
},
|
|
510
687
|
async hidden(selector) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
688
|
+
try {
|
|
689
|
+
await page.locator(selector).first().waitFor({
|
|
690
|
+
state: "hidden",
|
|
691
|
+
timeout: DEFAULT_EXPECT_TIMEOUT_MS
|
|
692
|
+
});
|
|
693
|
+
} catch {
|
|
694
|
+
throw new Error(`Expected "${selector}" to be hidden.`);
|
|
695
|
+
}
|
|
515
696
|
},
|
|
516
697
|
async insideViewport(selector, options = {}) {
|
|
698
|
+
await waitForVisible(selector);
|
|
517
699
|
const margin = options.margin ?? 0;
|
|
518
700
|
const rect = await elementRect(page, selector);
|
|
519
701
|
if (!rect) throw new Error(`Expected "${selector}" to exist.`);
|
|
@@ -524,6 +706,7 @@ function createExpect(page, outputDir) {
|
|
|
524
706
|
}
|
|
525
707
|
},
|
|
526
708
|
async notClipped(selector) {
|
|
709
|
+
await waitForVisible(selector);
|
|
527
710
|
const result = await page.locator(selector).first().evaluate((element) => {
|
|
528
711
|
const rect = element.getBoundingClientRect();
|
|
529
712
|
let parent = element.parentElement;
|
|
@@ -545,6 +728,8 @@ function createExpect(page, outputDir) {
|
|
|
545
728
|
}
|
|
546
729
|
},
|
|
547
730
|
async notOverlapping(firstSelector, secondSelector) {
|
|
731
|
+
await waitForVisible(firstSelector);
|
|
732
|
+
await waitForVisible(secondSelector);
|
|
548
733
|
const first = await elementRect(page, firstSelector);
|
|
549
734
|
const second = await elementRect(page, secondSelector);
|
|
550
735
|
if (!first || !second) throw new Error(`Expected both "${firstSelector}" and "${secondSelector}" to exist.`);
|
|
@@ -554,6 +739,8 @@ function createExpect(page, outputDir) {
|
|
|
554
739
|
}
|
|
555
740
|
},
|
|
556
741
|
async zIndexAbove(topSelector, lowerSelector) {
|
|
742
|
+
await waitForVisible(topSelector);
|
|
743
|
+
await waitForVisible(lowerSelector);
|
|
557
744
|
const values = await page.evaluate((payload) => {
|
|
558
745
|
const { topSelector: top, lowerSelector: lower } = payload;
|
|
559
746
|
const topElement = document.querySelector(top);
|
|
@@ -627,7 +814,7 @@ async function openMountPage(input) {
|
|
|
627
814
|
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
|
628
815
|
const entryPath = writeEntry(input.runtime.tempDir, input.name, input.entrySource);
|
|
629
816
|
const htmlPath = writeHtml(input.runtime.tempDir, input.name, entryPath, input.css);
|
|
630
|
-
await installTraceBinding(input.runtime.page, input.
|
|
817
|
+
await installTraceBinding(input.runtime.page, input.traceRecorder, input.traceContext ?? {});
|
|
631
818
|
await installBridge(page, input.bridge.state, input.bridge.manifest, input.bridge.bridgeInit);
|
|
632
819
|
const mountedBridge = createMountedBridge(page, input.bridge.state);
|
|
633
820
|
const context = {
|
|
@@ -660,23 +847,47 @@ async function openMountPage(input) {
|
|
|
660
847
|
async function createHarness(config = {}) {
|
|
661
848
|
const rootDir = normalizeRoot(config.rootDir);
|
|
662
849
|
const browserName = config.browser?.browserName ?? "chromium";
|
|
663
|
-
const
|
|
664
|
-
const
|
|
665
|
-
|
|
850
|
+
const headless = config.browser?.headless ?? true;
|
|
851
|
+
const workerRuntime = await acquireBrowserWorkerRuntime({
|
|
852
|
+
rootDir,
|
|
853
|
+
browserName,
|
|
854
|
+
headless
|
|
666
855
|
});
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
856
|
+
let released = false;
|
|
857
|
+
let destroyed = false;
|
|
858
|
+
let tempDir = null;
|
|
859
|
+
let context = null;
|
|
860
|
+
let page = null;
|
|
861
|
+
let traceRecorder;
|
|
862
|
+
function releaseRuntimeOnce() {
|
|
863
|
+
if (released) {
|
|
864
|
+
return;
|
|
673
865
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
866
|
+
released = true;
|
|
867
|
+
releaseBrowserWorkerRuntime(workerRuntime);
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
tempDir = import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "wood-browser-harness-"));
|
|
871
|
+
context = await workerRuntime.browser.newContext({
|
|
872
|
+
viewport: {
|
|
873
|
+
width: config.viewport?.width ?? DEFAULT_VIEWPORT.width,
|
|
874
|
+
height: config.viewport?.height ?? DEFAULT_VIEWPORT.height,
|
|
875
|
+
deviceScaleFactor: config.viewport?.deviceScaleFactor
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
page = await context.newPage();
|
|
879
|
+
traceRecorder = config.trace?.enabled === true ? new import_trace_testing.TraceRecorder() : void 0;
|
|
880
|
+
traceRecorder?.enable({ maxEvents: config.trace?.maxEvents });
|
|
881
|
+
} catch (error) {
|
|
882
|
+
if (page) await waitForBoundedClose(page.close());
|
|
883
|
+
if (context) await waitForBoundedClose(context.close());
|
|
884
|
+
if (tempDir) import_node_fs.default.rmSync(tempDir, { recursive: true, force: true });
|
|
885
|
+
releaseRuntimeOnce();
|
|
886
|
+
throw error;
|
|
887
|
+
}
|
|
677
888
|
const runtime = {
|
|
678
|
-
|
|
679
|
-
server,
|
|
889
|
+
context,
|
|
890
|
+
server: workerRuntime.server,
|
|
680
891
|
page,
|
|
681
892
|
tempDir,
|
|
682
893
|
rootDir
|
|
@@ -688,7 +899,7 @@ async function createHarness(config = {}) {
|
|
|
688
899
|
});
|
|
689
900
|
return {
|
|
690
901
|
page,
|
|
691
|
-
...
|
|
902
|
+
...traceRecorder ? { traceRecorder } : {},
|
|
692
903
|
async mountRoute(routeKey, options = {}) {
|
|
693
904
|
const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);
|
|
694
905
|
const route = {
|
|
@@ -721,7 +932,7 @@ async function createHarness(config = {}) {
|
|
|
721
932
|
css,
|
|
722
933
|
viewport: options.viewport ?? config.viewport,
|
|
723
934
|
bridge,
|
|
724
|
-
|
|
935
|
+
traceRecorder,
|
|
725
936
|
traceContext: {
|
|
726
937
|
windowId: config.trace?.windowId ?? routeKey.split(".")[0],
|
|
727
938
|
routeKey,
|
|
@@ -758,7 +969,7 @@ async function createHarness(config = {}) {
|
|
|
758
969
|
css,
|
|
759
970
|
viewport: options.viewport ?? config.viewport,
|
|
760
971
|
bridge,
|
|
761
|
-
|
|
972
|
+
traceRecorder,
|
|
762
973
|
traceContext: {
|
|
763
974
|
windowId: config.trace?.windowId ?? "wood-browser-harness",
|
|
764
975
|
harnessId: config.trace?.harnessId
|
|
@@ -791,7 +1002,7 @@ async function createHarness(config = {}) {
|
|
|
791
1002
|
css,
|
|
792
1003
|
viewport: tree.viewport ?? config.viewport,
|
|
793
1004
|
bridge,
|
|
794
|
-
|
|
1005
|
+
traceRecorder,
|
|
795
1006
|
traceContext: {
|
|
796
1007
|
windowId: config.trace?.windowId ?? tree.page?.key?.split(".")[0] ?? "wood-browser-harness",
|
|
797
1008
|
routeKey: tree.page?.key,
|
|
@@ -808,11 +1019,17 @@ async function createHarness(config = {}) {
|
|
|
808
1019
|
});
|
|
809
1020
|
},
|
|
810
1021
|
async destroy() {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1022
|
+
if (destroyed) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
destroyed = true;
|
|
1026
|
+
await Promise.all([
|
|
1027
|
+
waitForBoundedClose(page.close()),
|
|
1028
|
+
waitForBoundedClose(context.close())
|
|
1029
|
+
]);
|
|
1030
|
+
traceRecorder?.disable();
|
|
815
1031
|
import_node_fs.default.rmSync(tempDir, { recursive: true, force: true });
|
|
1032
|
+
releaseRuntimeOnce();
|
|
816
1033
|
}
|
|
817
1034
|
};
|
|
818
1035
|
}
|