[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

test: cover more use cases

Vladimir Sheremet (Jul 25, 2026, 1:08 PM +0200) 804a57b8 204c4206

+175
+175
test/e2e/test/vm-threads.test.ts
··· 327 327 expect(exitCode).toBe(0) 328 328 }, 329 329 ) 330 + 331 + // error handling, cache interplay with import(), and edges that cannot be 332 + // loaded synchronously. esm-scope/cjs-scope are externalized so that both 333 + // require() and import() of the same files go through the vm executors. 334 + test.skipIf(!supportsRequireEsm).for(['vmThreads', 'vmForks'] as const)( 335 + '%s handles require(esm) edge cases', 336 + async (pool) => { 337 + const { stderr, exitCode } = await runInlineTests({ 338 + 'package.json': '{}', 339 + 'esm-scope/package.json': JSON.stringify({ type: 'module' }), 340 + 'esm-scope/throws.mjs': 'throw new Error("boom")', 341 + 'esm-scope/tla.mjs': 'export const value = await Promise.resolve("tla")', 342 + 'esm-scope/tla-imported.mjs': 'export const done = await Promise.resolve(true)', 343 + 'esm-scope/shared.mjs': 'export const state = { name: "shared" }', 344 + 'esm-scope/uses-shared.mjs': 'export { state } from "./shared.mjs"', 345 + 'esm-scope/dynamic.mjs': 'export function load() { return import("./shared.mjs") }', 346 + 'esm-scope/meta.mjs': [ 347 + 'export const url = import.meta.url', 348 + 'export const filename = import.meta.filename', 349 + 'export const resolved = import.meta.resolve("./shared.mjs")', 350 + ].join('\n'), 351 + 'esm-scope/imports-data.mjs': [ 352 + 'import { fromData } from "data:text/javascript,export%20const%20fromData%20=%20%22data-js%22"', 353 + 'import json from "data:application/json,%7B%22a%22:1%7D" with { type: "json" }', 354 + 'export const combined = fromData + ":" + json.a', 355 + ].join('\n'), 356 + 'esm-scope/imports-data-wasm.mjs': 'import "data:application/wasm;base64,AGFzbQEAAAA="', 357 + 'esm-scope/imports-wasm.mjs': 'import "./empty.wasm"', 358 + 'esm-scope/empty.wasm': '', 359 + 'esm-scope/imports-css.mjs': 'import "./style.css"\nexport const x = 1', 360 + 'esm-scope/style.css': 'body {}', 361 + 'esm-scope/imports-missing.mjs': 'import { x } from "./missing.mjs"\nexport const y = x', 362 + 'esm-scope/plain-cjs.js': 'module.exports = { value: "stays-cjs" }', 363 + 'esm-scope/leaf.mjs': 'export const leaf = "leaf"', 364 + 'esm-scope/bridge.cjs': 'module.exports = require("./leaf.mjs")', 365 + 'esm-scope/host.mjs': [ 366 + 'import bridge from "./bridge.cjs"', 367 + 'export const value = bridge.leaf', 368 + ].join('\n'), 369 + 'cjs-scope/package.json': '{}', 370 + 'cjs-scope/broken.js': 'const x = {', 371 + 'cjs-scope/esm-tla.js': 'export const x = await Promise.resolve(1)', 372 + 'cjs-scope/wrong.cjs': 'export const x = 1', 373 + 'cjs-scope/esm-syntax.js': 'export const value = "detected"', 374 + 'require-esm-edge.test.js': ` 375 + import { createRequire } from 'node:module' 376 + import { expect, test } from 'vitest' 377 + 378 + const require = createRequire(import.meta.url) 379 + 380 + function requireError(id) { 381 + try { 382 + require(id) 383 + } 384 + catch (error) { 385 + return error 386 + } 387 + throw new Error('expected require to throw for ' + id) 388 + } 389 + 390 + test('an evaluation error is thrown and cached', async () => { 391 + expect(() => require('./esm-scope/throws.mjs')).toThrow('boom') 392 + // second require rethrows from the errored cache entry 393 + expect(() => require('./esm-scope/throws.mjs')).toThrow('boom') 394 + // import() shares the same errored module 395 + await expect(import('./esm-scope/throws.mjs')).rejects.toThrow('boom') 396 + }) 397 + 398 + test('require() of a TLA module already evaluated by import() still throws', async () => { 399 + const ns = await import('./esm-scope/tla-imported.mjs') 400 + expect(ns.done).toBe(true) 401 + // a settled async graph is still not require()-able (Node parity) 402 + const error = requireError('./esm-scope/tla-imported.mjs') 403 + expect(error.code).toBe('ERR_REQUIRE_ASYNC_MODULE') 404 + }) 405 + 406 + test('a failed require() does not poison the import() cache', async () => { 407 + expect(requireError('./esm-scope/tla.mjs').code).toBe('ERR_REQUIRE_ASYNC_MODULE') 408 + const ns = await import('./esm-scope/tla.mjs') 409 + expect(ns.value).toBe('tla') 410 + }) 411 + 412 + test('require() reuses modules already evaluated by import()', async () => { 413 + const imported = await import('./esm-scope/shared.mjs') 414 + const required = require('./esm-scope/uses-shared.mjs') 415 + expect(required.state).toBe(imported.state) 416 + }) 417 + 418 + test('data: javascript and json dependencies load synchronously', () => { 419 + expect(require('./esm-scope/imports-data.mjs').combined).toBe('data-js:1') 420 + }) 421 + 422 + test('data: wasm dependencies throw ERR_REQUIRE_ASYNC_MODULE', () => { 423 + const error = requireError('./esm-scope/imports-data-wasm.mjs') 424 + expect(error.code).toBe('ERR_REQUIRE_ASYNC_MODULE') 425 + expect(error.message).toContain('WebAssembly') 426 + }) 427 + 428 + test('wasm file dependencies throw ERR_REQUIRE_ASYNC_MODULE', () => { 429 + const error = requireError('./esm-scope/imports-wasm.mjs') 430 + expect(error.code).toBe('ERR_REQUIRE_ASYNC_MODULE') 431 + expect(error.message).toContain('WebAssembly') 432 + }) 433 + 434 + test('vite-transformed dependencies throw ERR_REQUIRE_ASYNC_MODULE', () => { 435 + const error = requireError('./esm-scope/imports-css.mjs') 436 + expect(error.code).toBe('ERR_REQUIRE_ASYNC_MODULE') 437 + expect(error.message).toContain('Vite') 438 + }) 439 + 440 + test('a missing dependency throws ERR_MODULE_NOT_FOUND', () => { 441 + const error = requireError('./esm-scope/imports-missing.mjs') 442 + expect(error.code).toBe('ERR_MODULE_NOT_FOUND') 443 + }) 444 + 445 + test('a .js file without ESM syntax keeps loading as CJS in an ESM scope', () => { 446 + const exports = require('./esm-scope/plain-cjs.js') 447 + expect(exports.value).toBe('stays-cjs') 448 + expect('default' in exports).toBe(false) 449 + }) 450 + 451 + test('a CJS dependency can require() ES modules during the graph walk', () => { 452 + expect(require('./esm-scope/host.mjs').value).toBe('leaf') 453 + }) 454 + 455 + test('import.meta is populated inside required ES modules', () => { 456 + const ns = require('./esm-scope/meta.mjs') 457 + expect(ns.url.startsWith('file://')).toBe(true) 458 + expect(ns.url.endsWith('meta.mjs')).toBe(true) 459 + expect(ns.filename.endsWith('meta.mjs')).toBe(true) 460 + expect(ns.resolved.endsWith('shared.mjs')).toBe(true) 461 + }) 462 + 463 + test('dynamic import() works inside a required ES module', async () => { 464 + const ns = require('./esm-scope/dynamic.mjs') 465 + const dep = await ns.load() 466 + const imported = await import('./esm-scope/shared.mjs') 467 + expect(dep.state).toBe(imported.state) 468 + }) 469 + 470 + test('a syntax error in a CJS-scope .js file surfaces the original error', () => { 471 + const error = requireError('./cjs-scope/broken.js') 472 + expect(error.name).toBe('SyntaxError') 473 + expect(error.code).toBeUndefined() 474 + }) 475 + 476 + test('the ESM-syntax fallback surfaces non-syntax ESM errors', () => { 477 + const error = requireError('./cjs-scope/esm-tla.js') 478 + expect(error.code).toBe('ERR_REQUIRE_ASYNC_MODULE') 479 + }) 480 + 481 + test('.cjs files never fall back to ESM', () => { 482 + const error = requireError('./cjs-scope/wrong.cjs') 483 + expect(error.name).toBe('SyntaxError') 484 + expect(error.code).toBeUndefined() 485 + }) 486 + 487 + test('import() of a CJS-scope .js file with ESM syntax works', async () => { 488 + const ns = await import('./cjs-scope/esm-syntax.js') 489 + expect(ns.value).toBe('detected') 490 + }) 491 + `, 492 + }, { 493 + pool, 494 + server: { 495 + deps: { 496 + external: [/esm-scope/, /cjs-scope/], 497 + }, 498 + }, 499 + }) 500 + 501 + expect(stderr).toBe('') 502 + expect(exitCode).toBe(0) 503 + }, 504 + )