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+

})