• Stars
    star
    198
  • Rank 196,898 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 4 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

unplugin-vue-router

Next Generation file based typed routing for Vue Router
TypeScript
1,643
star
3

vim-vue

Syntax Highlight for Vue.js components
Vim Script
1,286
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,188
star
7

pinia-colada

๐Ÿน The smart data fetching layer for Pinia
TypeScript
764
star
8

vuexfire

Check
JavaScript
559
star
9

vite-tailwind-starter

Starter using Vite + Tailwind for super fast prototyping
Vue
459
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
204
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
160
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-use-spring

๐Ÿ’ซ Naturally fluid animations for Vue
TypeScript
89
star
19

vue-compose-promise

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

vue-coerce-props

Coerce props to whatever you want
JavaScript
75
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
65
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

event-emitter

<200 bytes type safe extendable event emitter / pubsub class
TypeScript
39
star
28

vuefire-nuxt-example

Example project using VueFire with Nuxt
Vue
33
star
29

vuefire-emoji-panel

Nuxt + VueFire Demo code
TypeScript
32
star
30

vue-prop-data-fallback

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

size-check-action

A custom size action
TypeScript
28
star
32

nuxt--vuefire-example-spark-plan

๐Ÿ”ฅ Nuxt + VueFire template to bootstrap your Firebase App
Vue
26
star
33

2021-amsterdam-demos

Vue
25
star
34

rollit

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

unplugin-vue-router-demo

Demo for the talk "Stop writing your routes"
TypeScript
23
star
36

vuefire-vite-example

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

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

Talk Vue.js and Typescript, a complicated relationship
22
star
38

vue-recomputed

Recomputable computed properties
JavaScript
21
star
39

talk-data-loaders

Slides and demo code for Vue.js Live talk
TypeScript
20
star
40

onlysponsors

Tracker for Only Sponsors
20
star
41

nuxt--vuefire-example-blaze-plan

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

p-singleton

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

clipboard-text

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

how2

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

faked-promise

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

lib-boilerplate-ts

personal boilerplate for a lib with ts
JavaScript
11
star
47

esm.dev

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

jest-mock-warn

Mock console.log warn calls and assert their calls
JavaScript
10
star
49

paths.esm.dev

๐Ÿ›ฃ A Vue Router path debugger
Vue
10
star
50

dotfiles

๐Ÿ“ My dotfiles
Vim Script
9
star
51

phaser-webpack-ts

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

mocha-requirejs-boilerplate

JavaScript
7
star
53

mocha-css

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

eslint-config-posva

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

vitesse-unplugin-vue-router

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

vitepress-theme-nuxt-content

Vitepress theme imitating Nuxt Content
Vue
5
star
57

minesweeper.rs

Learning project with Rust: Minesweeper
Rust
5
star
58

free-workshop-pinia-from-scratch

Free online workshop to build Pinia from scratch
TypeScript
5
star
59

renovate-config

Renovate config for Open Source
5
star
60

nuxt--vuefire-demo

Nuxt VueFire Demo
Vue
5
star
61

pinia-ssr-example-cw

TypeScript
4
star
62

OUTDATED_nuxt-vuefire-example

wip
Vue
4
star
63

instacraper

Scrap images from Instagram post
JavaScript
4
star
64

vercel-nuxt-example

Vue
3
star
65

vue-pinia-example

Created with CodeSandbox
JavaScript
3
star
66

vuefire-core

mirror to test something with codecov
JavaScript
3
star
67

vuefire-vitesse-example

Example of using VueFire with SSR
TypeScript
3
star
68

slides

๐Ÿ“ข Talks I have given somewhere, sometime
HTML
2
star
69

store-code-split-demo

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

bug-vue-loader-slot

Vue
2
star
71

bug-report-vca

JavaScript
2
star
72

pinia-colada-example

Example repository for stackblitz
Vue
2
star
73

demo-data-loaders-artwork-gallery

TypeScript
2
star
74

nuxt-composition-api-185

Vue
2
star
75

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
76

.github

Default .github folder
2
star
77

vuefire-examples

Various examples showcasing vuefire/vuexfire
HTML
2
star
78

2d-collisions

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

mille-bornes

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

blog.esm.dev

Vue
1
star
81

awesome-latex-workspace

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

vue-merge-options

Helpers to merge vue custom options
1
star
83

mangare-angular

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

bug-report-nuxt-plugin

TypeScript
1
star
85

bcn-marfeel-demo

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

Rndm

Random number generation for vim
Vim Script
1
star
87

portfolio

1
star
88

planet-noise

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

app-dep-test-renovate

JavaScript
1
star
90

lerna-test

Testing things with lerna
JavaScript
1
star
91

imag-utils

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

literate-couscous

1
star
93

lab-vue-getting-started

tech.io lab
JavaScript
1
star
94

tetris

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

pretty-hrtime.sh

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

nuxt--vuefire-repro-template

Nuxt VueFire template for reproductions
Vue
1
star
97

posva

๐ŸŒฎ๐ŸŒฎ๐ŸŒฎ
1
star
98

app-dep-test

JavaScript
1
star
99

test-pr-lib

JavaScript
1
star
100

MangaDown

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