( cwd: string, config: RuntimeTest, variant: 'dom' | 'hydrate' | 'ssr' | 'async-ssr', compileOptions: CompileOptions, runes: boolean )
| 270 | } |
| 271 | |
| 272 | async function run_test_variant( |
| 273 | cwd: string, |
| 274 | config: RuntimeTest, |
| 275 | variant: 'dom' | 'hydrate' | 'ssr' | 'async-ssr', |
| 276 | compileOptions: CompileOptions, |
| 277 | runes: boolean |
| 278 | ) { |
| 279 | let unintended_error = false; |
| 280 | |
| 281 | let logs: string[] = []; |
| 282 | let warnings: string[] = []; |
| 283 | let errors: string[] = []; |
| 284 | let manual_hydrate = false; |
| 285 | let intercept_errors = false; |
| 286 | |
| 287 | // Capture phase so we still see the error if a test installs its own |
| 288 | // `stopImmediatePropagation` listener (e.g. event-handler-*). Named so we |
| 289 | // can remove it in `finally` — otherwise listeners from earlier tests leak |
| 290 | // and keep writing to module-level `unhandled_rejection`. When the test |
| 291 | // intercepts `errors`, mirror jsdom's `Uncaught [...]` format into the |
| 292 | // array — vitest 4's jsdom env no longer routes `jsdomError` to vitest's |
| 293 | // wrapped console reliably (works locally but not in CI's forks pool). |
| 294 | const window_error_listener = (e: ErrorEvent) => { |
| 295 | if (intercept_errors) { |
| 296 | const detail = e.error; |
| 297 | const is_error = detail && detail.name && detail.message !== undefined && detail.stack; |
| 298 | const error_string = is_error ? `[${detail.name}: ${detail.message}]` : String(detail); |
| 299 | errors.push(`Error: Uncaught ${error_string}\n${detail?.stack ?? ''}`, detail); |
| 300 | } else { |
| 301 | unhandled_rejection = e.error; |
| 302 | } |
| 303 | e.preventDefault(); |
| 304 | }; |
| 305 | |
| 306 | { |
| 307 | // use some crude static analysis to determine if logs/warnings are intercepted. |
| 308 | // we do this instead of using getters on the `test` parameters so that we can |
| 309 | // squelch logs in SSR tests while printing temporary logs in other cases |
| 310 | let str = config.test?.toString() ?? ''; |
| 311 | let n = 0; |
| 312 | let i = 0; |
| 313 | while (i < str.length) { |
| 314 | if (str[i] === '(') n++; |
| 315 | if (str[i] === ')' && --n === 0) break; |
| 316 | i++; |
| 317 | } |
| 318 | |
| 319 | let ssr_str = config.test_ssr?.toString() ?? ''; |
| 320 | let sn = 0; |
| 321 | let si = 0; |
| 322 | while (si < ssr_str.length) { |
| 323 | if (ssr_str[si] === '(') sn++; |
| 324 | if (ssr_str[si] === ')' && --sn === 0) break; |
| 325 | si++; |
| 326 | } |
| 327 | |
| 328 | if (str.slice(0, i).includes('logs') || ssr_str.slice(0, si).includes('logs')) { |
| 329 | // eslint-disable-next-line no-console |
no test coverage detected