@noego/wood 0.4.0 → 0.4.2
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/main/index.cjs +16 -2
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.js +16 -2
- package/dist/main/index.js.map +1 -1
- package/dist/runtime/runtime.cjs +4 -4
- package/dist/runtime/runtime.cjs.map +1 -1
- package/dist/runtime/runtime.d.cts +2 -1
- package/dist/runtime/runtime.d.ts +2 -1
- package/dist/runtime/runtime.js +8 -5
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/testing/browser.cjs +224 -32
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +18 -1
- package/dist/testing/browser.d.ts +18 -1
- package/dist/testing/browser.js +226 -32
- 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 +6 -4
- package/dist/testing/index.d.ts +6 -4
- package/dist/testing/index.js +2 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/trace-testing/index.cjs +39 -0
- package/dist/trace-testing/index.cjs.map +1 -0
- package/dist/trace-testing/index.d.cts +6 -0
- package/dist/trace-testing/index.d.ts +6 -0
- package/dist/trace-testing/index.js +19 -0
- package/dist/trace-testing/index.js.map +1 -0
- package/dist/trace-testing/trace_assertions.cjs +29 -0
- package/dist/trace-testing/trace_assertions.cjs.map +1 -0
- package/dist/trace-testing/trace_assertions.d.cts +1 -0
- package/dist/trace-testing/trace_assertions.d.ts +1 -0
- package/dist/trace-testing/trace_assertions.js +7 -0
- package/dist/trace-testing/trace_assertions.js.map +1 -0
- package/dist/trace-testing/trace_query.cjs +33 -0
- package/dist/trace-testing/trace_query.cjs.map +1 -0
- package/dist/trace-testing/trace_query.d.cts +1 -0
- package/dist/trace-testing/trace_query.d.ts +1 -0
- package/dist/trace-testing/trace_query.js +11 -0
- package/dist/trace-testing/trace_query.js.map +1 -0
- 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 +19 -86
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +11 -16
- package/dist/tracing/trace_hub.d.ts +11 -16
- package/dist/tracing/trace_hub.js +19 -74
- 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 +8 -1
package/dist/testing/browser.js
CHANGED
|
@@ -2,10 +2,18 @@ import fs from "node:fs";
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
|
+
import {
|
|
6
|
+
dispatchRendererTracePayload
|
|
7
|
+
} from "../tracing/index.js";
|
|
8
|
+
import { TraceRecorder } from "../trace-testing/index.js";
|
|
5
9
|
const DEFAULT_VIEWPORT = {
|
|
6
10
|
width: 1280,
|
|
7
11
|
height: 800
|
|
8
12
|
};
|
|
13
|
+
const DEFAULT_EXPECT_TIMEOUT_MS = 1e4;
|
|
14
|
+
const DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS = 5e3;
|
|
15
|
+
const WORKER_RUNTIME_IDLE_CLOSE_MS = 5e3;
|
|
16
|
+
const browserWorkerRuntimes = /* @__PURE__ */ new Map();
|
|
9
17
|
function normalizeRoot(rootDir) {
|
|
10
18
|
return path.resolve(rootDir ?? process.cwd());
|
|
11
19
|
}
|
|
@@ -28,6 +36,18 @@ function mergeBridge(base, override) {
|
|
|
28
36
|
record: override?.record ?? base?.record
|
|
29
37
|
};
|
|
30
38
|
}
|
|
39
|
+
async function waitForBoundedClose(promise, timeoutMs = DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS) {
|
|
40
|
+
let timeout;
|
|
41
|
+
await Promise.race([
|
|
42
|
+
promise.catch(() => void 0),
|
|
43
|
+
new Promise((resolve) => {
|
|
44
|
+
timeout = setTimeout(resolve, timeoutMs);
|
|
45
|
+
})
|
|
46
|
+
]);
|
|
47
|
+
if (timeout) {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
31
51
|
function channelToManifestEntry(channel, handler) {
|
|
32
52
|
const pathSegments = channel.split(".").filter(Boolean);
|
|
33
53
|
const action = pathSegments.length > 0 ? pathSegments[pathSegments.length - 1] : channel;
|
|
@@ -58,24 +78,32 @@ function createBridgeState(input) {
|
|
|
58
78
|
};
|
|
59
79
|
}
|
|
60
80
|
function createBrowserBridgeFixture(input) {
|
|
81
|
+
return createBrowserBridgeFixtureWithTrace(input, void 0);
|
|
82
|
+
}
|
|
83
|
+
function createBrowserBridgeFixtureWithTrace(input, traceConfig) {
|
|
61
84
|
const state = createBridgeState(input);
|
|
62
85
|
const manifest = Array.from(state.operations.entries()).map(([channel, handler]) => channelToManifestEntry(channel, handler));
|
|
63
86
|
return {
|
|
64
87
|
state,
|
|
65
88
|
manifest,
|
|
66
|
-
bridgeInit: buildBridgeInitScript(manifest)
|
|
89
|
+
bridgeInit: buildBridgeInitScript(manifest, traceConfig)
|
|
67
90
|
};
|
|
68
91
|
}
|
|
69
|
-
function buildBridgeInitScript(manifest) {
|
|
92
|
+
function buildBridgeInitScript(manifest, traceConfig) {
|
|
93
|
+
const traceEnabled = traceConfig?.enabled === true;
|
|
94
|
+
const traceMinLevel = traceConfig?.minLevel ?? "debug";
|
|
70
95
|
return `
|
|
71
96
|
(() => {
|
|
72
97
|
const manifest = ${JSON.stringify(manifest)};
|
|
73
98
|
const listeners = new Map();
|
|
74
99
|
const bridge = {
|
|
75
100
|
__rpcManifest: manifest,
|
|
76
|
-
__woodConfig: async () => ({
|
|
101
|
+
__woodConfig: async () => ({
|
|
102
|
+
rendererTraceEnabled: ${JSON.stringify(traceEnabled)},
|
|
103
|
+
rendererTraceMinLevel: ${JSON.stringify(traceMinLevel)}
|
|
104
|
+
}),
|
|
77
105
|
__log: () => {},
|
|
78
|
-
__trace: () =>
|
|
106
|
+
__trace: (payload) => window.__woodBrowserTrace?.(payload),
|
|
79
107
|
__window: {
|
|
80
108
|
current: async () => ({ ok: true, windowId: 'wood-browser-harness', defaultRoute: window.__WOOD_BROWSER_DEFAULT_ROUTE__ }),
|
|
81
109
|
open: async () => ({}),
|
|
@@ -151,12 +179,13 @@ async function loadViews(viewsPath) {
|
|
|
151
179
|
const parser = await import("../parser/views_parser.js");
|
|
152
180
|
return parser.parseViewsFile(viewsPath);
|
|
153
181
|
}
|
|
154
|
-
async function createViteServer(rootDir) {
|
|
182
|
+
async function createViteServer(rootDir, cacheDir) {
|
|
155
183
|
const vite = await loadVite();
|
|
156
184
|
const svelte = await loadSveltePlugin(rootDir);
|
|
157
185
|
const plugins = svelte ? [svelte()] : [];
|
|
158
186
|
const server = await vite.createServer({
|
|
159
187
|
root: rootDir,
|
|
188
|
+
cacheDir,
|
|
160
189
|
logLevel: process.env.WOOD_BROWSER_TEST_DEBUG ? "info" : "silent",
|
|
161
190
|
plugins,
|
|
162
191
|
resolve: {
|
|
@@ -167,6 +196,92 @@ async function createViteServer(rootDir) {
|
|
|
167
196
|
await server.listen();
|
|
168
197
|
return server;
|
|
169
198
|
}
|
|
199
|
+
function workerRuntimeKey(input) {
|
|
200
|
+
return [
|
|
201
|
+
input.rootDir,
|
|
202
|
+
input.browserName,
|
|
203
|
+
input.headless ? "headless" : "headed"
|
|
204
|
+
].join("::");
|
|
205
|
+
}
|
|
206
|
+
async function createBrowserWorkerRuntime(input) {
|
|
207
|
+
const cacheRoot = fs.mkdtempSync(path.join(input.rootDir, ".wood-browser-vite-"));
|
|
208
|
+
let browser2 = null;
|
|
209
|
+
try {
|
|
210
|
+
const playwrightBrowser = await loadPlaywright(input.browserName);
|
|
211
|
+
browser2 = await playwrightBrowser.launch({ headless: input.headless });
|
|
212
|
+
const server = await createViteServer(input.rootDir, path.join(cacheRoot, ".vite"));
|
|
213
|
+
return {
|
|
214
|
+
browser: browser2,
|
|
215
|
+
server,
|
|
216
|
+
cacheDir: cacheRoot,
|
|
217
|
+
rootDir: input.rootDir,
|
|
218
|
+
key: input.key,
|
|
219
|
+
activeHarnesses: 0,
|
|
220
|
+
closing: false,
|
|
221
|
+
idleCloseTimer: null
|
|
222
|
+
};
|
|
223
|
+
} catch (error) {
|
|
224
|
+
await browser2?.close().catch(() => void 0);
|
|
225
|
+
fs.rmSync(cacheRoot, { recursive: true, force: true });
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function acquireBrowserWorkerRuntime(input) {
|
|
230
|
+
const key = workerRuntimeKey(input);
|
|
231
|
+
let entry = browserWorkerRuntimes.get(key);
|
|
232
|
+
if (!entry) {
|
|
233
|
+
entry = {
|
|
234
|
+
promise: createBrowserWorkerRuntime({ ...input, key })
|
|
235
|
+
};
|
|
236
|
+
browserWorkerRuntimes.set(key, entry);
|
|
237
|
+
}
|
|
238
|
+
const runtime = await entry.promise;
|
|
239
|
+
if (runtime.closing) {
|
|
240
|
+
browserWorkerRuntimes.delete(key);
|
|
241
|
+
return await acquireBrowserWorkerRuntime(input);
|
|
242
|
+
}
|
|
243
|
+
if (runtime.idleCloseTimer) {
|
|
244
|
+
clearTimeout(runtime.idleCloseTimer);
|
|
245
|
+
runtime.idleCloseTimer = null;
|
|
246
|
+
}
|
|
247
|
+
runtime.activeHarnesses += 1;
|
|
248
|
+
return runtime;
|
|
249
|
+
}
|
|
250
|
+
async function closeBrowserWorkerRuntime(runtime) {
|
|
251
|
+
if (runtime.closing) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
runtime.closing = true;
|
|
255
|
+
try {
|
|
256
|
+
await Promise.all([
|
|
257
|
+
waitForBoundedClose(runtime.server.close()),
|
|
258
|
+
waitForBoundedClose(runtime.browser.close())
|
|
259
|
+
]);
|
|
260
|
+
} finally {
|
|
261
|
+
fs.rmSync(runtime.cacheDir, { recursive: true, force: true });
|
|
262
|
+
const entry = browserWorkerRuntimes.get(runtime.key);
|
|
263
|
+
const current = entry ? await entry.promise.catch(() => null) : null;
|
|
264
|
+
if (current === runtime) {
|
|
265
|
+
browserWorkerRuntimes.delete(runtime.key);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function scheduleBrowserWorkerRuntimeClose(runtime) {
|
|
270
|
+
if (runtime.closing || runtime.activeHarnesses > 0 || runtime.idleCloseTimer) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
runtime.idleCloseTimer = setTimeout(() => {
|
|
274
|
+
runtime.idleCloseTimer = null;
|
|
275
|
+
if (runtime.activeHarnesses === 0) {
|
|
276
|
+
void closeBrowserWorkerRuntime(runtime);
|
|
277
|
+
}
|
|
278
|
+
}, WORKER_RUNTIME_IDLE_CLOSE_MS);
|
|
279
|
+
runtime.idleCloseTimer.unref?.();
|
|
280
|
+
}
|
|
281
|
+
function releaseBrowserWorkerRuntime(runtime) {
|
|
282
|
+
runtime.activeHarnesses = Math.max(0, runtime.activeHarnesses - 1);
|
|
283
|
+
scheduleBrowserWorkerRuntimeClose(runtime);
|
|
284
|
+
}
|
|
170
285
|
function serverBaseUrl(server) {
|
|
171
286
|
return server.resolvedUrls?.local?.[0] ?? "http://127.0.0.1:5173";
|
|
172
287
|
}
|
|
@@ -373,6 +488,14 @@ async function installBridge(page, bridgeState, manifest, bridgeInit) {
|
|
|
373
488
|
window.__WOOD_BROWSER_BRIDGE_MANIFEST__ = entries;
|
|
374
489
|
}, manifest);
|
|
375
490
|
}
|
|
491
|
+
async function installTraceBinding(page, traceRecorder, context) {
|
|
492
|
+
if (!traceRecorder) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
await page.exposeBinding("__woodBrowserTrace", async (_source, payload) => {
|
|
496
|
+
dispatchRendererTracePayload(payload, context);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
376
499
|
function createMountedBridge(page, state) {
|
|
377
500
|
return {
|
|
378
501
|
async emit(channel, payload) {
|
|
@@ -449,20 +572,35 @@ async function elementRect(page, selector) {
|
|
|
449
572
|
}).catch(() => null);
|
|
450
573
|
}
|
|
451
574
|
function createExpect(page, outputDir) {
|
|
575
|
+
async function waitForVisible(selector) {
|
|
576
|
+
const locator = page.locator(selector).first();
|
|
577
|
+
try {
|
|
578
|
+
await locator.waitFor({ state: "attached", timeout: DEFAULT_EXPECT_TIMEOUT_MS });
|
|
579
|
+
} catch {
|
|
580
|
+
throw new Error(`Expected "${selector}" to exist.`);
|
|
581
|
+
}
|
|
582
|
+
try {
|
|
583
|
+
await locator.waitFor({ state: "visible", timeout: DEFAULT_EXPECT_TIMEOUT_MS });
|
|
584
|
+
} catch {
|
|
585
|
+
throw new Error(`Expected "${selector}" to be visible.`);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
452
588
|
return {
|
|
453
589
|
async visible(selector) {
|
|
454
|
-
|
|
455
|
-
if (count < 1) throw new Error(`Expected "${selector}" to exist.`);
|
|
456
|
-
const visible = await page.locator(selector).first().isVisible();
|
|
457
|
-
if (!visible) throw new Error(`Expected "${selector}" to be visible.`);
|
|
590
|
+
await waitForVisible(selector);
|
|
458
591
|
},
|
|
459
592
|
async hidden(selector) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
593
|
+
try {
|
|
594
|
+
await page.locator(selector).first().waitFor({
|
|
595
|
+
state: "hidden",
|
|
596
|
+
timeout: DEFAULT_EXPECT_TIMEOUT_MS
|
|
597
|
+
});
|
|
598
|
+
} catch {
|
|
599
|
+
throw new Error(`Expected "${selector}" to be hidden.`);
|
|
600
|
+
}
|
|
464
601
|
},
|
|
465
602
|
async insideViewport(selector, options = {}) {
|
|
603
|
+
await waitForVisible(selector);
|
|
466
604
|
const margin = options.margin ?? 0;
|
|
467
605
|
const rect = await elementRect(page, selector);
|
|
468
606
|
if (!rect) throw new Error(`Expected "${selector}" to exist.`);
|
|
@@ -473,6 +611,7 @@ function createExpect(page, outputDir) {
|
|
|
473
611
|
}
|
|
474
612
|
},
|
|
475
613
|
async notClipped(selector) {
|
|
614
|
+
await waitForVisible(selector);
|
|
476
615
|
const result = await page.locator(selector).first().evaluate((element) => {
|
|
477
616
|
const rect = element.getBoundingClientRect();
|
|
478
617
|
let parent = element.parentElement;
|
|
@@ -494,6 +633,8 @@ function createExpect(page, outputDir) {
|
|
|
494
633
|
}
|
|
495
634
|
},
|
|
496
635
|
async notOverlapping(firstSelector, secondSelector) {
|
|
636
|
+
await waitForVisible(firstSelector);
|
|
637
|
+
await waitForVisible(secondSelector);
|
|
497
638
|
const first = await elementRect(page, firstSelector);
|
|
498
639
|
const second = await elementRect(page, secondSelector);
|
|
499
640
|
if (!first || !second) throw new Error(`Expected both "${firstSelector}" and "${secondSelector}" to exist.`);
|
|
@@ -503,6 +644,8 @@ function createExpect(page, outputDir) {
|
|
|
503
644
|
}
|
|
504
645
|
},
|
|
505
646
|
async zIndexAbove(topSelector, lowerSelector) {
|
|
647
|
+
await waitForVisible(topSelector);
|
|
648
|
+
await waitForVisible(lowerSelector);
|
|
506
649
|
const values = await page.evaluate((payload) => {
|
|
507
650
|
const { topSelector: top, lowerSelector: lower } = payload;
|
|
508
651
|
const topElement = document.querySelector(top);
|
|
@@ -576,6 +719,7 @@ async function openMountPage(input) {
|
|
|
576
719
|
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
|
577
720
|
const entryPath = writeEntry(input.runtime.tempDir, input.name, input.entrySource);
|
|
578
721
|
const htmlPath = writeHtml(input.runtime.tempDir, input.name, entryPath, input.css);
|
|
722
|
+
await installTraceBinding(input.runtime.page, input.traceRecorder, input.traceContext ?? {});
|
|
579
723
|
await installBridge(page, input.bridge.state, input.bridge.manifest, input.bridge.bridgeInit);
|
|
580
724
|
const mountedBridge = createMountedBridge(page, input.bridge.state);
|
|
581
725
|
const context = {
|
|
@@ -608,22 +752,47 @@ async function openMountPage(input) {
|
|
|
608
752
|
async function createHarness(config = {}) {
|
|
609
753
|
const rootDir = normalizeRoot(config.rootDir);
|
|
610
754
|
const browserName = config.browser?.browserName ?? "chromium";
|
|
611
|
-
const
|
|
612
|
-
const
|
|
613
|
-
|
|
755
|
+
const headless = config.browser?.headless ?? true;
|
|
756
|
+
const workerRuntime = await acquireBrowserWorkerRuntime({
|
|
757
|
+
rootDir,
|
|
758
|
+
browserName,
|
|
759
|
+
headless
|
|
614
760
|
});
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
761
|
+
let released = false;
|
|
762
|
+
let destroyed = false;
|
|
763
|
+
let tempDir = null;
|
|
764
|
+
let context = null;
|
|
765
|
+
let page = null;
|
|
766
|
+
let traceRecorder;
|
|
767
|
+
function releaseRuntimeOnce() {
|
|
768
|
+
if (released) {
|
|
769
|
+
return;
|
|
621
770
|
}
|
|
622
|
-
|
|
623
|
-
|
|
771
|
+
released = true;
|
|
772
|
+
releaseBrowserWorkerRuntime(workerRuntime);
|
|
773
|
+
}
|
|
774
|
+
try {
|
|
775
|
+
tempDir = fs.mkdtempSync(path.join(rootDir, ".wood-browser-harness-"));
|
|
776
|
+
context = await workerRuntime.browser.newContext({
|
|
777
|
+
viewport: {
|
|
778
|
+
width: config.viewport?.width ?? DEFAULT_VIEWPORT.width,
|
|
779
|
+
height: config.viewport?.height ?? DEFAULT_VIEWPORT.height,
|
|
780
|
+
deviceScaleFactor: config.viewport?.deviceScaleFactor
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
page = await context.newPage();
|
|
784
|
+
traceRecorder = config.trace?.enabled === true ? new TraceRecorder() : void 0;
|
|
785
|
+
traceRecorder?.enable({ maxEvents: config.trace?.maxEvents });
|
|
786
|
+
} catch (error) {
|
|
787
|
+
if (page) await waitForBoundedClose(page.close());
|
|
788
|
+
if (context) await waitForBoundedClose(context.close());
|
|
789
|
+
if (tempDir) fs.rmSync(tempDir, { recursive: true, force: true });
|
|
790
|
+
releaseRuntimeOnce();
|
|
791
|
+
throw error;
|
|
792
|
+
}
|
|
624
793
|
const runtime = {
|
|
625
|
-
|
|
626
|
-
server,
|
|
794
|
+
context,
|
|
795
|
+
server: workerRuntime.server,
|
|
627
796
|
page,
|
|
628
797
|
tempDir,
|
|
629
798
|
rootDir
|
|
@@ -635,8 +804,9 @@ async function createHarness(config = {}) {
|
|
|
635
804
|
});
|
|
636
805
|
return {
|
|
637
806
|
page,
|
|
807
|
+
...traceRecorder ? { traceRecorder } : {},
|
|
638
808
|
async mountRoute(routeKey, options = {}) {
|
|
639
|
-
const bridge =
|
|
809
|
+
const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);
|
|
640
810
|
const route = {
|
|
641
811
|
params: options.route?.params ?? {},
|
|
642
812
|
query: options.route?.query ?? {}
|
|
@@ -667,6 +837,12 @@ async function createHarness(config = {}) {
|
|
|
667
837
|
css,
|
|
668
838
|
viewport: options.viewport ?? config.viewport,
|
|
669
839
|
bridge,
|
|
840
|
+
traceRecorder,
|
|
841
|
+
traceContext: {
|
|
842
|
+
windowId: config.trace?.windowId ?? routeKey.split(".")[0],
|
|
843
|
+
routeKey,
|
|
844
|
+
harnessId: config.trace?.harnessId
|
|
845
|
+
},
|
|
670
846
|
context: {
|
|
671
847
|
route: {
|
|
672
848
|
key: routeKey,
|
|
@@ -687,7 +863,7 @@ async function createHarness(config = {}) {
|
|
|
687
863
|
async mountComponent(component, options = {}) {
|
|
688
864
|
const componentPath = resolveFromRoot(rootDir, component);
|
|
689
865
|
assertFileExists(componentPath, "Component");
|
|
690
|
-
const bridge =
|
|
866
|
+
const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, options.bridge), config.trace);
|
|
691
867
|
return await openMountPage({
|
|
692
868
|
runtime,
|
|
693
869
|
entrySource: buildComponentEntrySource({
|
|
@@ -698,6 +874,11 @@ async function createHarness(config = {}) {
|
|
|
698
874
|
css,
|
|
699
875
|
viewport: options.viewport ?? config.viewport,
|
|
700
876
|
bridge,
|
|
877
|
+
traceRecorder,
|
|
878
|
+
traceContext: {
|
|
879
|
+
windowId: config.trace?.windowId ?? "wood-browser-harness",
|
|
880
|
+
harnessId: config.trace?.harnessId
|
|
881
|
+
},
|
|
701
882
|
context: {},
|
|
702
883
|
hooks: {
|
|
703
884
|
beforeMount: options.page?.beforeMount ?? config.page?.beforeMount,
|
|
@@ -706,7 +887,7 @@ async function createHarness(config = {}) {
|
|
|
706
887
|
});
|
|
707
888
|
},
|
|
708
889
|
async mountTree(tree) {
|
|
709
|
-
const bridge =
|
|
890
|
+
const bridge = createBrowserBridgeFixtureWithTrace(mergeBridge(config.bridge, tree.bridge), config.trace);
|
|
710
891
|
const layouts = (tree.layouts ?? []).map((layout) => ({
|
|
711
892
|
component: resolveFromRoot(rootDir, layout.component),
|
|
712
893
|
props: layout.props
|
|
@@ -726,6 +907,12 @@ async function createHarness(config = {}) {
|
|
|
726
907
|
css,
|
|
727
908
|
viewport: tree.viewport ?? config.viewport,
|
|
728
909
|
bridge,
|
|
910
|
+
traceRecorder,
|
|
911
|
+
traceContext: {
|
|
912
|
+
windowId: config.trace?.windowId ?? tree.page?.key?.split(".")[0] ?? "wood-browser-harness",
|
|
913
|
+
routeKey: tree.page?.key,
|
|
914
|
+
harnessId: config.trace?.harnessId
|
|
915
|
+
},
|
|
729
916
|
context: tree.page?.key ? {
|
|
730
917
|
route: {
|
|
731
918
|
key: tree.page.key,
|
|
@@ -737,10 +924,17 @@ async function createHarness(config = {}) {
|
|
|
737
924
|
});
|
|
738
925
|
},
|
|
739
926
|
async destroy() {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
927
|
+
if (destroyed) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
destroyed = true;
|
|
931
|
+
await Promise.all([
|
|
932
|
+
waitForBoundedClose(page.close()),
|
|
933
|
+
waitForBoundedClose(context.close())
|
|
934
|
+
]);
|
|
935
|
+
traceRecorder?.disable();
|
|
743
936
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
937
|
+
releaseRuntimeOnce();
|
|
744
938
|
}
|
|
745
939
|
};
|
|
746
940
|
}
|