• Stars
    star
    187
  • Rank 200,249 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 3 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐Ÿงช Easily mock routing interactions in your Vue apps

vue-router-mock test npm package coverage thanks

Easily mock routing interactions in your Vue 3 apps

โš ๏ธ This library intends to be a collaboration of people writing tests to create a better experience writing tests that involve the use of routing with Vue. Your feedback and experience is welcomed in issues and discussions to give the API shape and create a library that eases unit testing components that deal with the router.

Installation

yarn add vue-router-mock
# or
npm install vue-router-mock

Requirements

This library

  • vue test utils next
  • vue 3 and vue router 4

Goal

The goal of Vue Router Mock is to enable users to unit and integration test navigation scenarios. This means tests that are isolated enough to not be end to end tests (e.g. using Cypress) or are edge cases (e.g. network failures). Because of this, some scenarios are more interesting as end to end tests, using the real vue router.

Introduction

Vue Router Mock exposes a few functions to be used individually and they are all documented through TS. But most of the time you want to globally inject the router in a setupFilesAfterEnv file. Create a jest.setup.js file at the root of your project (it can be named differently):

const {
  VueRouterMock,
  createRouterMock,
  injectRouterMock,
} = require('vue-router-mock')
const { config } = require('@vue/test-utils')

// create one router per test file
const router = createRouterMock()
beforeEach(() => {
  injectRouterMock(router)
})

// Add properties to the wrapper
config.plugins.VueWrapper.install(VueRouterMock)

Then add this line to your jest.config.js:

  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],

This will inject a router in all your tests. If for specific tests, you need to inject a different version of the router, you can do so:

import { createRouterMock, injectRouterMock } from 'vue-router-mock'

describe('SearchUsers', () => {
  // create one mock instance, pass options
  const router = createRouterMock({
    // ...
  })
  beforeEach(() => {
    // inject it globally to ensure `useRoute()`, `$route`, etc work
    // properly and give you access to test specific functions
    injectRouterMock(router)
  })

  it('should paginate', async () => {
    const wrapper = mount(SearchUsers)

    expect(wrapper.router).toBe(router)

    // go to the next page
    // this will internally trigger `router.push({ query: { page: 2 }})`
    wrapper.find('button.next-page').click()

    expect(wrapper.router.push).toHaveBeenCalledWith(
      expect.objectContaining({ query: { page: 2 } })
    )
    expect(wrapper.router.push).toHaveBeenCalledTimes(1)

    // if we had a navigation guard fetching the search results,
    // waiting for it to be done will allow us to wait until it's done.
    // Note you need to mock the fetch and to activate navigation
    // guards as explained below
    await router.getPendingNavigation()
    // wait for the component to render again if we want to check
    await wrapper.vm.nextTick()

    expect(wrapper.find('#user-results .user').text()).toMatchSnapshot()
  })
})

If you need to create a specific version of the router for one single test (or a nested suite of them), you should call the same functions:

it('should paginate', async () => {
  const router = createRouterMock()
  injectRouterMock(router)
  const wrapper = mount(SearchUsers)
})

Guide

Accessing the Router Mock instance

You can access the instance of the router mock in multiple ways:

  • Access wrapper.router:

    it('tests something', async () => {
      const wrapper = mount(MyComponent)
      await wrapper.router.push('/new-location')
    })
  • Access it through wrapper.vm:

    it('tests something', async () => {
      const wrapper = mount(MyComponent)
      await wrapper.vm.$router.push('/new-location')
      expect(wrapper.vm.$route.name).toBe('NewLocation')
    })
  • Call getRouter() inside of a test:

    it('tests something', async () => {
      // can be called before creating the wrapper
      const router = getRouter()
      const wrapper = mount(MyComponent)
      await router.push('/new-location')
    })

Setting parameters

setParams allows you to change route params without triggering a navigation:

it('should display the user details', async () => {
  const wrapper = mount(UserDetails)
  getRouter().setParams({ userId: 12 })

  // test...
})

It can be awaited if you need to wait for Vue to render again:

it('should display the user details', async () => {
  const wrapper = mount(UserDetails)
  await getRouter().setParams({ userId: 12 })

  // test...
})

setQuery and setHash are very similar. They can be used to set the route query or hash without triggering a navigation, and can be awaited too.

Setting the initial location

By default the router mock starts on START_LOCATION. In some scenarios this might need to be adjusted by pushing a new location and awaiting it before testing:

it('should paginate', async () => {
  await router.push('/users?q=haruno')
  const wrapper = mount(SearchUsers)

  // test...
})

You can also set the initial location for all your tests by passing an initialLocation:

const router = createRouterMock({
  initialLocation: '/users?q=jolyne',
})

initialLocation accepts anything that can be passed to router.push().

Simulating navigation failures

You can simulate the failure of the next navigation

Simulating a navigation guard

By default, all navigation guards are ignored so that you can simulate the return of the next guard by using setNextGuardReturn() without depending on existing ones:

// simulate a navigation guard that returns false
router.setNextGuardReturn(false)
// simulate a redirection
router.setNextGuardReturn('/login')

If you want to still run existing navigation guards inside component, you can active them when creating your router mock:

const router = createRouterMock({
  // run `onBeforeRouteLeave()`, `onBeforeRouteUpdate()`, `beforeRouteEnter()`, `beforeRouteUpdate()`, and `beforeRouteLeave()`
  runInComponentGuards: true,
  // run `beforeEnter` of added routes. Note that you must manually add these routes with `router.addRoutes()`
  runPerRouteGuards: true,
})

Stubs

By default, both <router-link> and <router-view> are stubbed but you can override them locally. This is specially useful when you have nested <router-view> and you rely on them for a test:

const wrapper = mount(MyComponent, {
  global: {
    stubs: { RouterView: MyNestedComponent },
  },
})

You need to manually specify the component that is supposed to be displayed because the mock won't be able to know the level of nesting.

NOTE: this might change to become automatic if the necessary routes are provided.

Testing libraries

Vue Router Mock automatically detects if you are using Sinon.js, Jest, or Vitest and use their spying methods. You can of course configure Vue Router Mock to use any spying library you want.

For example, if you use Vitest with globals: false, then you need to manually configure the spy option and pass vi.fn() to it:

const router = createRouterMock({
  spy: {
    create: fn => vi.fn(fn),
    reset: spy => spy.mockReset(),
  },
})

Caveats

Nested Routes

By default, the router mock comes with one single catch all route. You can add routes calling the router.addRoute() function but if you add nested routes and you are relying on running navigation guards, you must manually set the depth of the route you are displaying. This is because the router has no way to know which level of nesting you are trying to display. e.g. Imagine the following routes:

const routes = [
  {
    path: '/users',
    // we are not testing this one so it doesn't matter
    component: UserView,
    children: [
      // UserDetail must be the same component we are unit testing
      { path: ':id', component: UserDetail },
    ],
  },
]
// 0 would be if we were testing UserView at /users
router.depth.value = 1
const wrapper = mount(UserDetail)

Remember, this is not necessary if you are not adding routes or if they are not nested.

Related

License

MIT

This project was created using the Vue Library template by posva

More Repositories

1

vue-promised

๐Ÿ’ Composable Promises & Promises as components
TypeScript
1,792
star
2

vim-vue

Syntax Highlight for Vue.js components
Vim Script
1,285
star
3

unplugin-vue-router

Next Generation file based typed routing for Vue Router
TypeScript
1,279
star
4

catimg

๐Ÿฆฆ Insanely fast image printing in your terminal
C
1,239
star
5

vue-mdc

Material web components for Vue.js
JavaScript
1,201
star
6

mande

<700 bytes convenient and modern wrapper around fetch with smart extensible defaults
TypeScript
1,105
star
7

vuexfire

Check
JavaScript
559
star
8

pinia-colada

๐Ÿน The smart data fetching layer for Pinia
TypeScript
453
star
9

vite-tailwind-starter

Starter using Vite + Tailwind for super fast prototyping
Vue
452
star
10

vuex-mock-store

โœ…Simple and straightforward Vuex Store mock for vue-test-utils
JavaScript
273
star
11

focus-trap-vue

Vue component to trap the focus within a DOM element
JavaScript
201
star
12

vue-plugin-template

๐Ÿš€ Solid foundation to start a Vue plugin with the best developer experience and a focus on performance
JavaScript
192
star
13

vue-local-scope

๐Ÿ–‡ Generate local scopes in templates to compute data from other scoped slots or simply to have variables in templates
JavaScript
168
star
14

vue-reactive-refs

Make $refs reactive so they can be used in computed properties and watchers
TypeScript
160
star
15

vue-ts-lib

Vue 3 library starter in TS with lint, auto release, changelog and tests
JavaScript
156
star
16

sounds-webpack-plugin

๐Ÿ”ŠNotify or errors, warnings, etc with sounds
JavaScript
124
star
17

vue-tweezing

๐Ÿ’ƒ Easy, customizable and automatic tweening nicely served in scoped slots
JavaScript
100
star
18

vue-compose-promise

๐Ÿ’ Promises using vue composition api
TypeScript
76
star
19

vue-coerce-props

Coerce props to whatever you want
JavaScript
75
star
20

vue-use-spring

๐Ÿ’ซ Naturally fluid animations for Vue
TypeScript
72
star
21

shapify

๐ŸŒ€Easily transform objects/rename keys with full TypeScript support
JavaScript
67
star
22

pinia-plugin-debounce

Config-based action debouncing made easy
TypeScript
64
star
23

markdown-it-custom-block

Handle custom blocks transformations for markdown-it
JavaScript
53
star
24

state-animation-demos

Demos for Vue.js amsterdam/roadtrip talk: State animations, getting them right
Vue
43
star
25

task-logger.sh

๐ŸŽจ shell library to log tasks with nice output. Supports zsh and bash
Shell
43
star
26

vue-router-view-transition

Properly time out-in transitions with scrollBehavior
JavaScript
40
star
27

vuefire-nuxt-example

Example project using VueFire with Nuxt
Vue
31
star
28

vue-prop-data-fallback

Vue mixin to support an optional prop by falling back to a local data
JavaScript
31
star
29

vuefire-emoji-panel

Nuxt + VueFire Demo code
TypeScript
30
star
30

size-check-action

A custom size action
TypeScript
28
star
31

2021-amsterdam-demos

Vue
25
star
32

rollit

๐ŸŒฏ Zero config js library bundling using rollup with support for Vue
JavaScript
24
star
33

talk-vuejs-and-typescript-a-complicated-relationship

Talk Vue.js and Typescript, a complicated relationship
21
star
34

unplugin-vue-router-demo

Demo for the talk "Stop writing your routes"
TypeScript
21
star
35

vue-recomputed

Recomputable computed properties
JavaScript
21
star
36

vuefire-vite-example

Example project using VueFire in a vite project
Vue
21
star
37

onlysponsors

Tracker for Only Sponsors
20
star
38

nuxt--vuefire-example-spark-plan

๐Ÿ”ฅ Nuxt + VueFire template to bootstrap your Firebase App
Vue
19
star
39

p-singleton

Ensure only one instance of a promise is created until rejected or resolved
JavaScript
19
star
40

clipboard-text

Simple and small copy-text-to-the-clipboard-utility with IE11 support
TypeScript
13
star
41

how2

Exercise building a scalable web app like how2 cli using Vue
JavaScript
12
star
42

nuxt--vuefire-example-blaze-plan

๐Ÿ”ฅ Nuxt + VueFire template to bootstrap your Firebase App with the Blaze plan
Vue
12
star
43

faked-promise

Create a fake promise that can be resolve and rejected programatically
JavaScript
11
star
44

jest-mock-warn

Mock console.log warn calls and assert their calls
JavaScript
11
star
45

lib-boilerplate-ts

personal boilerplate for a lib with ts
JavaScript
11
star
46

esm.dev

๐Ÿ‘จโ€๐Ÿ’ป my personal website
TypeScript
10
star
47

dotfiles

๐Ÿ“ My dotfiles
Vim Script
9
star
48

phaser-webpack-ts

Starter for Phaser 3 with Typescript, webpack and weback DLLPlugin
JavaScript
8
star
49

mocha-requirejs-boilerplate

JavaScript
7
star
50

paths.esm.dev

๐Ÿ›ฃ A Vue Router path debugger
Vue
7
star
51

mocha-css

A mocha stylesheet for the HTML reporter that let you append visual tests
CSS
7
star
52

eslint-config-posva

๐Ÿคบ Opinionated eslint set of rules with support for Vue
JavaScript
7
star
53

vitesse-unplugin-vue-router

Test repo for unplugin-vue-router + vitesse
TypeScript
6
star
54

minesweeper.rs

Learning project with Rust: Minesweeper
Rust
5
star
55

OUTDATED_nuxt-vuefire-example

wip
Vue
5
star
56

renovate-config

Renovate config for Open Source
5
star
57

vitepress-theme-nuxt-content

Vitepress theme imitating Nuxt Content
Vue
4
star
58

pinia-ssr-example-cw

TypeScript
4
star
59

instacraper

Scrap images from Instagram post
JavaScript
4
star
60

nuxt--vuefire-demo

Nuxt VueFire Demo
Vue
4
star
61

vercel-nuxt-example

Vue
3
star
62

vue-pinia-example

Created with CodeSandbox
JavaScript
3
star
63

vuefire-vitesse-example

Example of using VueFire with SSR
TypeScript
3
star
64

vuefire-core

mirror to test something with codecov
JavaScript
3
star
65

bug-vue-loader-slot

Vue
2
star
66

store-code-split-demo

demo to showcase ideal codesplit for a store like Vuex
JavaScript
2
star
67

bug-report-vca

JavaScript
2
star
68

nuxt-composition-api-185

Vue
2
star
69

configure-script

โšก Simple script to generate Makefiles for your project. It's mainly aimed for C/C++ but can be adapted to other languages
Shell
2
star
70

vuefire-examples

Various examples showcasing vuefire/vuexfire
HTML
2
star
71

.github

Default .github folder
2
star
72

2d-collisions

Collision for 2D using the SAT theorem with Rectangles
C++
2
star
73

mangare-angular

๐Ÿ™ Download Manga in convenient formats!
JavaScript
1
star
74

mille-bornes

mille bornes card game for 2 players only with AI and online
CoffeeScript
1
star
75

slides

๐Ÿ“ข Talks I have given somewhere, sometime
HTML
1
star
76

blog.esm.dev

Vue
1
star
77

awesome-latex-workspace

๐Ÿ“‘ Watcher + commit based diff generator
Shell
1
star
78

vue-merge-options

Helpers to merge vue custom options
1
star
79

bcn-marfeel-demo

Demo for the meetup @marfeel the 19/07/2018
Vue
1
star
80

bug-report-nuxt-plugin

TypeScript
1
star
81

lerna-test

Testing things with lerna
JavaScript
1
star
82

imag-utils

Scripts ou autres infos utiles ร  l'Ensimag
JavaScript
1
star
83

Rndm

Random number generation for vim
Vim Script
1
star
84

portfolio

1
star
85

planet-noise

Test to generate planet terrain using libnoise. SFML to render the image
C++
1
star
86

app-dep-test-renovate

JavaScript
1
star
87

vue-mdc.js.org

Documentation for vue-mdc
JavaScript
1
star
88

literate-couscous

1
star
89

lab-vue-getting-started

tech.io lab
JavaScript
1
star
90

tetris

โฌ› A simple engine of tetris that can be used along with another printing system
C
1
star
91

pretty-hrtime.sh

๐Ÿ•’ Pretty High Resolution Time in shell
Shell
1
star
92

nuxt--vuefire-repro-template

Nuxt VueFire template for reproductions
Vue
1
star
93

posva

๐ŸŒฎ๐ŸŒฎ๐ŸŒฎ
1
star
94

app-dep-test

JavaScript
1
star
95

test-pr-lib

JavaScript
1
star
96

MangaDown

Allow to download mangas from websites using a parsing file
C++
1
star
97

vite-plugin-voie

File system-based routing plugin for Vite
TypeScript
1
star
98

gotta-go-fast-vim

๐ŸŽ Language agnostic starter kit for vim
Shell
1
star
99

pinia.esm.dev-redirect

Redirect site from pinia.esm.dev to pinia.vuejs.org
1
star
100

hydrogen

iGam4ER
JavaScript
1
star