vitest-dev / vitest-dev/vitest

DoMock doUnmock resetModules does not work as expected in browser mode.

Open
#7,712 7 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

documentation feat: browser p2-edge-case
Dominant language
TypeScript
Stars
17.1k
Forks
2k
Avg merge
1d 22h
Merged PRs (30d)
94

Description

Describe the bug
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { RoutePath } from "../constants";
import type {
  NavigationGuardNext,
  RouteLocationNormalized,
  RouteLocationNormalizedLoaded,
} from "vue-router";

describe("Router Guards", () => {
  let mockTo: RouteLocationNormalized;
  let mockNext: NavigationGuardNext;
  let mockFrom: RouteLocationNormalizedLoaded;

  beforeEach(() => {
    mockTo = {
      meta: {
        requiresAuth: true,
      },
      path: "/test",
      fullPath: "/test",
    } as RouteLocationNormalized;
    mockNext = vi.fn();
    mockFrom = {
      meta: {},
      path: "/test",
      fullPath: "/test",
    } as RouteLocationNormalizedLoaded;
    vi.resetModules();
    vi.doUnmock("../../stores/userStore");
  });

  describe("authGuard", () => {
    it("未登录用户访问需要认证的页面时应该重定向到登录页面", async () => {
      vi.doMock("../../stores/userStore", () => ({
        useUserStore: () => ({
          user: undefined,
          login: vi.fn(),
          logout: vi.fn(),
          roleCodes: undefined,
          permissionCodes: undefined,
        }),
      }));

      const { authGuard } = await import("../guards");
      const result = authGuard(mockTo, mockFrom, mockNext);
      expect(result).toEqual({
        path: RoutePath.LOGIN,
        query: { redirect: mockTo.fullPath },
      });
      const useUserStore1 = await import("../../stores/userStore");
      console.log(useUserStore1.useUserStore());
    });

    it("已登录用户访问登录页面时应该重定向到后台页面", async () => {
      const userInfo = {
        id: 1,
        name: "testUser",
      };
      vi.doMock("../../stores/userStore", () => ({
        useUserStore: () => ({
          user: userInfo,
          login: vi.fn(),
          logout: vi.fn(),
          roleCodes: ["admin"],
          permissionCodes: ["read"],
        }),
      }));
      const { authGuard } = await import("../guards");
      const useUserStore2 = await import("../../stores/userStore");
      console.log(useUserStore2.useUserStore());
      mockTo.path = RoutePath.LOGIN;
      mockTo.meta.requiresAuth = false;

      const result = authGuard(mockTo, mockFrom, mockNext);
      expect(result).toEqual({
        path: RoutePath.DASHBOARD,
      });
    });
  });
});


During actual execution, the value of the second useUserStore2 is always the content of the first useUserStore1.

To my knowledge, even without using doUnmock or resetModules, doMock should be able to override the previous mock content. However, regardless of whether I use vi.resetModules(); vi.doUnmock("../../stores/userStore"); in beforeEach, the doMock in the second test cannot effectively override the content of the doMock in the first test.

Reproduction

Running guards.test.ts from this code reproduces this result
mjga-dashboard.zip

System Info
"devDependencies": {
    "@playwright/test": "^1.51.0",
    "@tsconfig/node22": "^22.0.0",
    "@types/node": "^22.13.9",
    "@vitejs/plugin-vue": "^5.2.1",
    "@vitest/browser": "^3.0.9",
    "@vue/tsconfig": "^0.7.0",
    "npm-run-all2": "^7.0.2",
    "playwright": "^1.51.1",
    "typescript": "~5.8.0",
    "vite": "^6.2.1",
    "vite-plugin-vue-devtools": "^7.7.2",
    "vitest": "^3.0.8",
    "vitest-browser-vue": "^0.2.0",
    "vue-tsc": "^2.2.8"
  }
Used Package Manager

npm

Validations

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running guards.test.ts from the linked reproduction in Vitest browser mode and compare the module state in the two tests. Trace the doMock, doUnmock, and resetModules calls around the imports of ../../stores/userStore; done means the second test can observe its own mock rather than the first test's value.

Written by the indexing model from the issue text.

Assessment

Tech stack
playwright, typescript, vite
Domain
testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.