Vue router's injection fails during a Jest unit test

Viewed 2425

In a .vue file with Composition API (and Vue 3), set up the router:

const router = useRouter()

Mount the .vue file in a jest test:

const wrapper = mount(Lookup)

On execution, produces:

console.warn
    [Vue warn]: injection "Symbol([vue-router]: router)" not found.
      at <Anonymous ref="VTU_COMPONENT" >
      at <VTUROOT>

Mocking it results in the same output:

useRouter().push = jest.fn()

Setting provide results in same output:

import { useRouter } from 'vue-router'
...
const wrapper = mount(Lookup, {
  global: {
    plugins: [useRouter],
    provide: {
      router: {},
    },
  },
})
2 Answers

This solution allows me to mock useRouter() in Jest. Note that useRouter() is the only way to use vue-router for composition API because this is unavailable:

const routerPushMock = jest.fn();

jest.mock('vue-router', () => ({
  useRouter: () => ({
    push: routerPushMock,
  }),
}));

test('...', async () => {
  const wrapper = mount(vueFile)
  ...

If someone has additionally this error

babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.

I recommend to write it like this

const mockPush = jest.fn();
jest.mock('vue-router', () => ({
  useRouter: () => ({
    push: mockPush,
  }),
}));

It is important to name it mockPush (mockXYZ) because according to: https://github.com/facebook/jest/issues/2567 this specific naming is an escape hatch.

Related