Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
6 tasks done
ccmjga opened this issue Mar 21, 2025 · 4 comments
Open
6 tasks done

Comments

@ccmjga
Copy link

ccmjga commented Mar 21, 2025

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

@sheremet-va
Copy link
Member

This doesn't work because resetModules doesn't work in the browser at the moment.

@ccmjga
Copy link
Author

ccmjga commented Mar 21, 2025

This doesn't work because resetModules doesn't work in the browser at the moment.

Thank you. However, is doUnmock currently unavailable as well?
Additionally, as far as I know, even though doMock's default behavior overwrites the previous behavior (as mentioned in this issue), theoretically, this test should still work without using resetModules.

@sheremet-va
Copy link
Member

Browser mocking and Node.js mocking have completely different implementations. At the moment, browser mocking doesn't support subsequent mocks for the same reason it doesn't support resetModules - the cache is not invalidated.

@ccmjga
Copy link
Author

ccmjga commented Mar 23, 2025

Browser mocking and Node.js mocking have completely different implementations. At the moment, browser mocking doesn't support subsequent mocks for the same reason it doesn't support resetModules - the cache is not invalidated.

I see. It looks like there's still a long way to go before I'll be able to use mock in browser mode, so I'm going to hold off on writing unit tests for a while until browser mode has perfected sub-sequent mock.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants