fix: properly re-evaluate actual modules of mocked external (#9898) · vitest-dev/vitest@ae5ec03
@@ -391,3 +391,152 @@ test('mock works without loading original', () => {
391391 }
392392 `)
393393})
394+395+test.for([
396+'node',
397+'playwright',
398+'webdriverio',
399+])('repeating mock, importActual, and resetModules (%s)', async (mode) => {
400+const { stderr, errorTree } = await runInlineTests({
401+// external
402+'./external.test.ts': `
403+import { expect, test, vi } from "vitest"
404+405+test("external", async () => {
406+ vi.doMock(import("test-dep-simple"), async (importActual) => {
407+ const lib = await importActual();
408+ return lib;
409+ })
410+ const lib1: any = await import("test-dep-simple")
411+ expect(lib1.default).toBe("test-dep-simple")
412+413+ vi.resetModules();
414+ vi.doMock(import("test-dep-simple"), async (importActual) => {
415+ const lib = await importActual();
416+ return lib;
417+ })
418+ const lib2: any = await import("test-dep-simple")
419+ expect(lib2.default).toBe("test-dep-simple")
420+ expect.soft(lib1 !== lib2).toBe(true)
421+422+ vi.resetModules();
423+ vi.doMock(import("test-dep-simple"), async () => ({ mocked: true }));
424+ const lib3 = await import("test-dep-simple");
425+ expect(lib3).toMatchObject({ mocked: true })
426+427+ const lib4 = await vi.importActual("test-dep-simple");
428+ expect(lib4.default).toBe("test-dep-simple")
429+ const lib5 = await vi.importActual("test-dep-simple");
430+ expect(lib4).toBe(lib5)
431+});
432+ `,
433+// builtin module
434+'./builtin.test.ts': `
435+import { expect, test, vi } from "vitest"
436+437+test("builtin", async () => {
438+ vi.doMock(import("node:path"), async (importActual) => {
439+ const lib = await importActual();
440+ return lib;
441+ })
442+ const lib1: any = await import("node:path")
443+ expect(lib1).toHaveProperty('join')
444+445+ vi.resetModules();
446+ vi.doMock(import("node:path"), async (importActual) => {
447+ const lib = await importActual();
448+ return lib;
449+ })
450+ const lib2: any = await import("node:path")
451+ expect(lib2).toHaveProperty('join')
452+ expect.soft(lib1 !== lib2).toBe(true)
453+454+ vi.resetModules();
455+ vi.doMock(import("node:path"), async () => ({ mocked: true }));
456+ const lib3 = await import("node:path");
457+ expect(lib3).toMatchObject({ mocked: true })
458+459+ const lib4 = await vi.importActual("node:path");
460+ expect(lib4).toHaveProperty('join')
461+ const lib5 = await vi.importActual("node:path");
462+ expect(lib4).toBe(lib5)
463+});
464+ `,
465+// local module
466+'./local.test.ts': `
467+import { expect, test, vi } from "vitest"
468+469+test("local", async () => {
470+ vi.doMock(import("./local.js"), async (importActual) => {
471+ const lib = await importActual();
472+ return lib;
473+ })
474+ const lib1: any = await import("./local.js")
475+ expect(lib1).toHaveProperty('local')
476+477+ vi.resetModules();
478+ vi.doMock(import("./local.js"), async (importActual) => {
479+ const lib = await importActual();
480+ return lib;
481+ })
482+ const lib2: any = await import("./local.js")
483+ expect(lib2).toHaveProperty('local')
484+ expect.soft(lib1 !== lib2).toBe(true)
485+486+ vi.resetModules();
487+ vi.doMock(import("./local.js"), async () => ({ mocked: true }));
488+ const lib3 = await import("./local.js");
489+ expect(lib3).toMatchObject({ mocked: true })
490+491+ const lib4 = await vi.importActual("./local.js");
492+ expect(lib4).toHaveProperty('local')
493+ const lib5 = await vi.importActual("./local.js");
494+ expect(lib4).toBe(lib5)
495+});
496+ `,
497+'./local.js': `export const local = 'local'`,
498+}, modeToConfig(mode))
499+500+if (mode === 'webdriverio' || mode === 'playwright') {
501+// browser mode doesn't support resetModules nor node builtin
502+expect(errorTree()).toMatchInlineSnapshot(`
503+ {
504+ "builtin.test.ts": {
505+ "builtin": [
506+ "Cannot convert a Symbol value to a string",
507+ ],
508+ },
509+ "external.test.ts": {
510+ "external": [
511+ "expected false to be true // Object.is equality",
512+ "expected { default: 'test-dep-simple', …(1) } to match object { mocked: true }
513+ (1 matching property omitted from actual)",
514+ ],
515+ },
516+ "local.test.ts": {
517+ "local": [
518+ "expected false to be true // Object.is equality",
519+ "expected { local: 'local', …(1) } to match object { mocked: true }
520+ (1 matching property omitted from actual)",
521+ ],
522+ },
523+ }
524+ `)
525+return
526+}
527+528+expect(stderr).toMatchInlineSnapshot(`""`)
529+expect(errorTree()).toMatchInlineSnapshot(`
530+ {
531+ "builtin.test.ts": {
532+ "builtin": "passed",
533+ },
534+ "external.test.ts": {
535+ "external": "passed",
536+ },
537+ "local.test.ts": {
538+ "local": "passed",
539+ },
540+ }
541+ `)
542+})