Vue Router Mock
vue-router-mock is a testing utility designed for Vue 3 applications, specifically to facilitate unit and integration testing of components that interact with the official `vue-router`. Currently stable at version 2.0.2, the library maintains an active release cadence, providing minor updates for bug fixes and compatibility, such as the recent addition of `vue-router` v5 support. Its core purpose is to provide a mock `vue-router` instance that can be injected into components, enabling developers to spy on navigation calls (e.g., `push`, `replace`), simulate route changes, and assert router state without requiring a full browser environment or actual navigation. It differentiates itself from end-to-end testing tools by focusing on isolated scenarios, leading to more granular and faster test execution. The library integrates seamlessly with `@vue/test-utils` and offers flexible setup options for test environments like Jest or Vitest through functions such as `createRouterMock` and `injectRouterMock`.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'push') or TypeError: this.$router is undefined
cause The mock router has not been correctly injected into the component under test or its wrapper.fixEnsure `injectRouterMock(router)` is called before mounting the component in your test, and that `config.plugins.VueWrapper.install(VueRouterMock)` is set up globally if accessing via `wrapper.router`. -
Error: [vue-router]: Injection "VueRouter" not found.
cause The Vue application instance or component hierarchy does not have the mock router provided.fixVerify that `injectRouterMock(router)` is being called in your test setup (e.g., `beforeEach`) to ensure the mock router is provided to the components within the test scope. -
TypeError: Cannot read properties of undefined (reading 'install') or Cannot access 'config' before initialization
cause The `@vue/test-utils` `config` object or `VueWrapper` is not correctly imported or available when attempting to install the `VueRouterMock` plugin.fixMake sure to `import { config } from '@vue/test-utils'` and that the `config.plugins.VueWrapper.install(VueRouterMock)` line is executed after `config` is properly defined.
Warnings
- breaking Version 2.0.0 introduced significant changes. While the specific breaking changes are detailed in the `CHANGELOG.md` file on GitHub, users upgrading from v1.x should consult it for migration steps, as API surface and integration methods may have changed.
- gotcha This library is explicitly designed for unit and integration testing and is not suitable for end-to-end (E2E) testing scenarios. For E2E tests, it's recommended to use the real `vue-router` setup within a browser environment.
- gotcha To enable `wrapper.router` access in `@vue/test-utils` wrappers, you must explicitly install the `VueRouterMock` plugin via `config.plugins.VueWrapper.install(VueRouterMock)` in your test setup file.
- gotcha When using Jest, your test setup file (e.g., in `setupFilesAfterEnv`) might need to be written in CommonJS syntax if Jest's environment does not fully support ESM, leading to import errors. Vitest typically handles ESM better.
Install
-
npm install vue-router-mock -
yarn add vue-router-mock -
pnpm add vue-router-mock
Imports
- createRouterMock
const createRouterMock = require('vue-router-mock')import { createRouterMock } from 'vue-router-mock' - injectRouterMock
import injectRouterMock from 'vue-router-mock'
import { injectRouterMock } from 'vue-router-mock' - VueRouterMock
import { VueRouterMock } from 'vue-router-mock'
Quickstart
import { VueRouterMock, createRouterMock, injectRouterMock } from 'vue-router-mock';
import { config } from '@vue/test-utils';
import { mount } from '@vue/test-utils';
import { defineComponent } from 'vue';
// Create a simple component to test
const MyComponent = defineComponent({
template: `
<div>
<p>Current path: {{ $route.path }}</p>
<button @click="$router.push('/about')">Go to About</button>
</div>
`
});
// Create one router per test file/suite setup
const router = createRouterMock();
beforeEach(() => {
router.reset(); // Reset the router state before each test
injectRouterMock(router); // Inject the mock router globally for the test
});
// Add properties to the @vue/test-utils wrapper (required for `wrapper.router`)
config.plugins.VueWrapper.install(VueRouterMock);
describe('MyComponent with vue-router-mock', () => {
it('should display the current path and navigate', async () => {
const wrapper = mount(MyComponent);
// Initial state
expect(wrapper.find('p').text()).toContain('/');
expect(wrapper.router.path).toBe('/');
// Simulate navigation
await wrapper.find('button').trigger('click');
// Assertions on the mock router
expect(wrapper.router.push).toHaveBeenCalledTimes(1);
expect(wrapper.router.push).toHaveBeenCalledWith('/about');
// Assertions on component state after navigation (if it reacts to route change)
// Note: for reactive updates, you might need await wrapper.vm.$nextTick()
// depending on how the component consumes the route changes
expect(wrapper.find('p').text()).toContain('/about');
});
});