4

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: {},
    },
  },
})
Andrew C.
  • 421
  • 5
  • 15
  • `useRouter` is not a plugin, so that should not be in `global.plugins`. Show more context of your `useRouter()` usage in the component. – tony19 Aug 13 '21 at 00:34
  • @tony19 The `useRouter()` is completely unused in my component for this example. It's declaration breaks within the component breaks only when Jest mounts it. It works as expected in the component if I add back usage of it within the component (which doesn't effect Jest's current outcome). – Andrew C. Aug 13 '21 at 13:05
  • There's not enough context to reproduce the problem. Can you share a link to a reproduction? – tony19 Aug 13 '21 at 13:40

2 Answers2

9

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)
  ...
Andrew C.
  • 421
  • 5
  • 15
  • 6
    Very important thing to notice for people like me, who fought it for a 3 hours, is that you can't put jest.mock() inside of describe() or test(), it wouldn't work this way. It seems like jest.mock() should be in the root of a spec file. – Igor Nikiforov Aug 19 '21 at 14:37
  • 1
    It appears that writing "jest.mock" is also very important for some reason. Putting "import mock = jest.mock" then "mock('vue-router', ...)" doesn't work for me. I need to specifically call "jest.mock('vue-router', ...)". – Guillaume Voiron Jan 08 '22 at 09:03
  • 2
    thanks, @IgorNikiforov, it is very helpful comment. Although I read your comment after spending 2 hours :P – Ashish S Mar 20 '22 at 19:40
  • 1
    If you receive a `The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables` error try changing the name of the mock you create, such as `routerPushMock` to something that begins with the word `mock` like `mockRouterPush`. Got that from this answer: https://stackoverflow.com/questions/44649699/service-mocked-with-jest-causes-the-module-factory-of-jest-mock-is-not-allowe – Leo Jun 21 '22 at 03:03
8

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.

uke5tar
  • 399
  • 3
  • 8