I am trying to test a Vue component with Vitest but in order to do that I need to mock auth0
Below is my Navbar.test.ts file, however when I run the test I keep getting the following error Cannot read properties of undefined (reading 'mockReturnValue'
as useAuth0
seems to be undefined even though I am imported it at the top of the page. Maybe I'm just not understanding the mocking side of it very well but any help would be appreciated.
import { vi } from 'vitest'
import { ref } from "vue";
import { shallowMount } from '@vue/test-utils'
import { useAuth0 } from '@auth0/auth0-vue';
import NavBar from "@/components/NavBar.vue";
const user = {
email: "user@test.com",
email_verified: true,
sub: ""
};
vi.mock("@auth0/auth0-vue");
const mockedUseAuth0 = vi.mocked(useAuth0, true);
describe("NavBar.vue", () => {
beforeEach(() => {
mockedUseAuth0.mockReturnValue({
isAuthenticated: ref(true),
user: ref(user),
logout: vi.fn(),
loginWithRedirect: vi.fn(),
...
isLoading: ref(false),
});
});
it("mounts", () => {
const wrapper = shallowMount(NavBar, {
props: { },
});
expect(wrapper).toBeTruthy();
});
afterEach(() => vi.clearAllMocks());
});
auth0.useAuth0
To access the mocked module, import the whole module with a wildcard import, and avoid named imports. Also, vi.mocked()
is just a helper for TypeScript support. It doesn't mock anything.
So instead of this:
import { useAuth0 } from '@auth0/auth0-vue' ❌
vi.mock('@auth0/auth0-vue')
const mockedUseAuth0 = vi.mocked(useAuth0, true) ❌
...do this:
import * as auth0 from '@auth0/auth0-vue' ✅
vi.mock('@auth0/auth0-vue')
Then, mock useAuth0
by attaching a property directly to the mocked auth0
import:
describe('NavBar.vue', () => {
it('does something', async () => {
👇
(auth0 as any).useAuth0 = vi.fn().mockReturnValue({
// relevant fields for test
});
})
})
The value of useAuth0
should be a mock function ( vi.fn()
) that returns the fields relevant to the test. Assuming the component under test is NavBar.vue
from Auth0's sample app , one could write a test to verify the login button calls loginWithRedirect
. That button is only available when isAuthenticated
and isLoading
are false . Note the fields do not need to be Vue ref
s.
So such a test could look like this:
describe('NavBar.vue', () => {
it('login button invokes useAuth.loginWithRedirect', async () => {
const loginWithRedirect = vi.fn();
(auth0 as any).useAuth0 = vi.fn().mockReturnValue({
isAuthenticated: false,
isLoading: false,
loginWithRedirect,
});
const wrapper = shallowMount(NavBar);
await wrapper.find('button#qsLoginBtn').trigger('click');
expect(auth0.useAuth0).toHaveBeenCalled();
expect(loginWithRedirect).toHaveBeenCalled();
})
})
useAuth().user
One could also write a test to verify the authenticated user's details are shown in the component. Specifically, the user's name is shown in .user-info
, and the user's picture is shown in .user-info img
when isAuthenticated
is true. The mocked useAuth0
should thus return isAuthenticated
and user
as follows:
describe('NavBar', () => {
it('authenticated user details are shown', async () => {
const user = {
name: 'john@gmail.com',
picture: 'https://s.gravatar.com/avatar/1f9d9a9efc2f523b2f09629444632b5c?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjo.png',
};
(auth0 as any).useAuth0 = vi.fn().mockReturnValue({
isAuthenticated: true,
user,
});
const wrapper = shallowMount(NavBar);
expect(wrapper.find('.user-info').text()).toBe(user.name);
expect(wrapper.find('.user-info img').attributes('src')).toBe(user.picture);
})
})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.