Skip to content

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

@ccmjga

Description

@ccmjga

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationfeat: browserIssues and PRs related to the browser runnerp2-edge-caseBug, but has workaround or limited in scope (priority)

    Type

    Projects

    Status

    Approved

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions