Skip to content

Commit cb8b250

Browse files
committed
add scripts
1 parent 95afac7 commit cb8b250

5 files changed

Lines changed: 281 additions & 123 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ jobs:
101101
102102
# move this up temporarily to accelerate
103103
- name: test (logs)
104-
run: scripts/wasm-test-with-logs.sh 2>&1
104+
run: CHROMEDRIVER=`which chromedriver` RUSTDOCFLAGS="-D warnings" CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER='wasm-bindgen-test-runner' ./scripts/wasm-test-with-logs.sh --verbose -- cargo +nightly test --target=wasm32-unknown-unknown --lib -- --nocapture
105105

106106
- name: test
107107
run: cd ${{ matrix.cwd }} && ${{ matrix.additional_test_prefix}} RUSTDOCFLAGS="-D warnings" CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER='wasm-bindgen-test-runner' cargo ${{ matrix.channel }} test ${{ steps.args.outputs.features }} ${{ steps.args.outputs.target }} --lib -- --nocapture

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ js-sys = "0.3.77"
2828

2929
[dev-dependencies]
3030
test_executors = "0.3"
31+
portable_async_sleep = "0.1.1"
3132

3233
[target.'cfg(target_arch="wasm32")'.dev-dependencies]
3334
wasm-bindgen-test = "0.3.45"

scripts/capture-logs.js

Lines changed: 144 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,192 @@
1+
#!/usr/bin/env node
2+
//
3+
// capture-logs.js - Capture Chrome DevTools Protocol logs from WASM tests
4+
//
5+
16
const CDP = require('chrome-remote-interface');
27

3-
async function setupLogging(client, label) {
4-
const {Log, Runtime, Network, Page} = client;
8+
const PORT = 9222;
9+
const VERBOSE = process.argv.includes('--verbose');
510

6-
await Log.enable();
7-
await Runtime.enable();
11+
function log(msg) {
12+
console.log(`WASM:CDP: ${msg}`);
13+
}
814

9-
// Try to enable Network and Page (may not be available on all targets)
10-
try { await Network.enable(); } catch (e) { /* ignore */ }
11-
try { await Page.enable(); } catch (e) { /* ignore */ }
15+
function logVerbose(msg) {
16+
if (VERBOSE) {
17+
console.log(`WASM:CDP: ${msg}`);
18+
}
19+
}
1220

13-
Log.entryAdded((params) => {
14-
const {entry} = params;
15-
console.log(`[${label}:LOG:${entry.level}] ${entry.text}`);
16-
});
21+
function outputLog(type, level, text) {
22+
console.log(`WASM:${type}:${level}: ${text}`);
23+
}
24+
25+
async function replayBufferedMessages(Runtime) {
26+
try {
27+
const {result} = await Runtime.evaluate({
28+
expression: `JSON.stringify(window.__cdp_console_buffer__ || [])`,
29+
returnByValue: true
30+
});
31+
if (result.value) {
32+
const buffered = JSON.parse(result.value);
33+
if (buffered.length > 0) {
34+
log(`Replaying ${buffered.length} buffered message(s)`);
35+
for (const msg of buffered) {
36+
outputLog('CONSOLE', msg.type.toUpperCase(), msg.args.join(' '));
37+
}
38+
// Clear buffer
39+
await Runtime.evaluate({ expression: `window.__cdp_console_buffer__ = [];` });
40+
}
41+
}
42+
} catch (e) {
43+
// Ignore - page might not have the buffer
44+
}
45+
}
1746

47+
async function setupRuntimeLogging(Runtime, label) {
1848
Runtime.consoleAPICalled((params) => {
1949
const args = params.args.map(arg => arg.value || arg.description || '').join(' ');
20-
console.log(`[${label}:CONSOLE:${params.type}] ${args}`);
50+
outputLog('CONSOLE', params.type.toUpperCase(), args);
2151
});
2252

23-
// Catch exceptions
24-
Runtime.exceptionThrown((params) => {
25-
const details = params.exceptionDetails;
26-
const text = details.exception?.description || details.text || JSON.stringify(details);
27-
console.log(`[${label}:EXCEPTION] ${text}`);
53+
Runtime.exceptionThrown(({exceptionDetails}) => {
54+
const text = exceptionDetails.exception?.description
55+
|| exceptionDetails.text
56+
|| JSON.stringify(exceptionDetails);
57+
outputLog('EXCEPTION', 'ERROR', text);
2858
});
59+
}
2960

30-
// Network failures
31-
Network.requestFailed && Network.requestFailed((params) => {
32-
console.log(`[${label}:NET:FAILED] ${params.request?.url} - ${params.errorText}`);
33-
});
61+
async function attachToTarget(Target, targetId, targetType) {
62+
try {
63+
const client = await CDP({port: PORT, target: targetId});
64+
const {Runtime, Log, Network} = client;
3465

35-
// Network responses (for 4xx/5xx)
36-
Network.responseReceived && Network.responseReceived((params) => {
37-
const {response} = params;
38-
if (response.status >= 400) {
39-
console.log(`[${label}:NET:${response.status}] ${response.url}`);
40-
}
41-
});
66+
// Enable and set up listeners immediately
67+
await Runtime.enable();
68+
setupRuntimeLogging(Runtime, targetType);
4269

43-
// Page crashes
44-
Page.javascriptDialogOpening && Page.javascriptDialogOpening((params) => {
45-
console.log(`[${label}:DIALOG] ${params.type}: ${params.message}`);
46-
});
70+
// Replay any buffered messages
71+
await replayBufferedMessages(Runtime);
72+
73+
// Optional extras
74+
try {
75+
await Log.enable();
76+
Log.entryAdded(({entry}) => {
77+
if (entry.level === 'verbose' && !VERBOSE) return;
78+
outputLog('LOG', entry.level.toUpperCase(), entry.text);
79+
});
80+
} catch (e) {}
4781

48-
console.error(`CDP: Logging enabled for ${label}`);
82+
try {
83+
await Network.enable();
84+
Network.responseReceived && Network.responseReceived(({response}) => {
85+
if (response.status >= 400 && !response.url.includes('favicon')) {
86+
outputLog('NET', String(response.status), response.url);
87+
}
88+
});
89+
} catch (e) {}
90+
91+
logVerbose(`Attached to ${targetType}`);
92+
} catch (err) {
93+
logVerbose(`Failed to attach to ${targetId}: ${err.message}`);
94+
}
4995
}
5096

5197
async function captureLogs() {
52-
// Retry connection forever - CI timeout will protect us
5398
let browser;
5499
let attempt = 0;
100+
101+
// Retry connection forever
55102
while (!browser) {
56103
try {
57-
browser = await CDP({port: 9222});
104+
browser = await CDP({port: PORT});
58105
} catch (err) {
59106
attempt++;
60-
if (attempt % 10 === 0) {
61-
console.error(`CDP: Waiting for Chrome (attempt ${attempt})...`);
107+
if (attempt % 30 === 0) {
108+
log(`Waiting for Chrome on port ${PORT} (attempt ${attempt})...`);
62109
}
63110
await new Promise(r => setTimeout(r, 1000));
64111
}
65112
}
66113

67-
// Set up logging on browser-level connection too
68-
await setupLogging(browser, 'browser');
114+
log('Connected');
69115

70-
const {Target} = browser;
116+
const {Target, Page, Runtime} = browser;
71117

72-
// Discover all targets
118+
// Set up target discovery FIRST - this is the critical path
73119
await Target.setDiscoverTargets({discover: true});
74120

75-
// Attach to each page target we find
76-
const attachToPage = async (targetId, targetType) => {
77-
try {
78-
// Create a new CDP session for this target
79-
const {sessionId} = await Target.attachToTarget({targetId, flatten: true});
80-
console.error(`CDP: Attached to ${targetType} ${targetId} (session: ${sessionId})`);
81-
82-
// Connect to this specific target
83-
const client = await CDP({port: 9222, target: targetId});
84-
await setupLogging(client, targetType);
85-
} catch (err) {
86-
console.error(`CDP: Failed to attach to ${targetId}: ${err.message}`);
87-
}
121+
const attachedTargets = new Set();
122+
const attachIfNeeded = async (targetId, targetType) => {
123+
if (attachedTargets.has(targetId)) return;
124+
attachedTargets.add(targetId);
125+
await attachToTarget(Target, targetId, targetType);
88126
};
89127

90128
// Listen for new targets
91129
Target.targetCreated(async ({targetInfo}) => {
92-
console.error(`CDP: New target: ${targetInfo.type} - ${targetInfo.url || targetInfo.targetId}`);
93-
if (targetInfo.type === 'page' || targetInfo.type === 'worker' || targetInfo.type === 'iframe') {
94-
await attachToPage(targetInfo.targetId, targetInfo.type);
130+
const {type, targetId} = targetInfo;
131+
if (type === 'page' || type === 'worker' || type === 'iframe') {
132+
await attachIfNeeded(targetId, type);
95133
}
96134
});
97135

98-
// Attach to existing targets
136+
// Attach to existing targets immediately
99137
const {targetInfos} = await Target.getTargets();
100-
for (const info of targetInfos) {
101-
console.error(`CDP: Existing target: ${info.type} - ${info.url || info.targetId}`);
102-
if (info.type === 'page' || info.type === 'worker' || info.type === 'iframe') {
103-
await attachToPage(info.targetId, info.type);
104-
}
138+
const pageTargets = targetInfos.filter(t =>
139+
t.type === 'page' || t.type === 'worker' || t.type === 'iframe'
140+
);
141+
142+
// Attach in parallel for speed
143+
await Promise.all(pageTargets.map(t => attachIfNeeded(t.targetId, t.type)));
144+
145+
// Install early interceptor for future pages
146+
try {
147+
await Page.enable();
148+
await Page.addScriptToEvaluateOnNewDocument({
149+
source: `
150+
if (!window.__cdp_console_injected__) {
151+
window.__cdp_console_buffer__ = [];
152+
window.__cdp_console_injected__ = true;
153+
['log', 'warn', 'error', 'info', 'debug'].forEach(m => {
154+
const orig = console[m].bind(console);
155+
console[m] = function(...args) {
156+
window.__cdp_console_buffer__.push({
157+
type: m,
158+
args: args.map(a => { try { return typeof a === 'object' ? JSON.stringify(a) : String(a); } catch(e) { return String(a); } })
159+
});
160+
return orig(...args);
161+
};
162+
});
163+
}
164+
`
165+
});
166+
} catch (e) {
167+
logVerbose(`Early interceptor failed: ${e.message}`);
105168
}
106169

107-
console.error('CDP: Setup complete, listening for all targets...');
170+
// Also set up browser-level runtime (sometimes catches things)
171+
try {
172+
await Runtime.enable();
173+
setupRuntimeLogging(Runtime, 'browser');
174+
} catch (e) {}
175+
176+
log('Listening');
177+
178+
// Periodically check for buffered messages on known targets
179+
setInterval(async () => {
180+
for (const targetId of attachedTargets) {
181+
try {
182+
const client = await CDP({port: PORT, target: targetId});
183+
await replayBufferedMessages(client.Runtime);
184+
} catch (e) {}
185+
}
186+
}, 2000);
108187
}
109188

110189
captureLogs().catch(err => {
111-
console.error('CDP: Fatal error:', err);
190+
console.error(`WASM:CDP:ERROR: ${err.message}`);
112191
process.exit(1);
113192
});

0 commit comments

Comments
 (0)