Categories
Vue 3 Testing

Testing Vue 3 Apps — Testing with a Mocked Router

Spread the love

With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.

In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.

Test Apps with Vue Router

We can test apps that use the Vue Router with a mock router.

This way, we can test our component in isolation without worrying about the router.

src/views/Edit.vue

<template>
  <button @click="redirect">Click to Edit</button>
</template>

<script>
export default {
  props: ["authenticated"],
  methods: {
    redirect() {
      if (this.authenticated) {
        this.$router.push(`/posts/${this.$route.params.id}/edit`);
      } else {
        this.$router.push("/404");
      }
    },
  },
};
</script>

src/views/Edit.vue

<template>
  <div>Post {{$route.params.id}}</div>
</template>

src/views/NotFound.vue

<template>
  <div>404</div>
</template>

index.js

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Edit from '../views/Edit.vue'
import Post from '../views/Post.vue'
import NotFound from '../views/NotFound.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/edit/:id',
    name: 'Edit',
    component: Edit
  },
  {
    path: '/posts/:id',
    name: 'post',
    component: Post
  },
  {
    path: '/404',
    name: 'not-found',
    component: NotFound
  },
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

tests/unit/example.spec.js

import { mount } from '@vue/test-utils'
import Edit from '@/views/Edit'

describe('component handles routing correctly', () => {
  it('allows authenticated user to edit a post', async () => {
    const mockRoute = {
      params: {
        id: 1
      }
    }
    const mockRouter = {
      push: jest.fn()
    }
    const wrapper = mount(Edit, {
      props: {
        authenticated: true
      },
      global: {
        mocks: {
          $route: mockRoute,
          $router: mockRouter
        }
      }
    })
    await wrapper.find('button').trigger('click')
    expect(mockRouter.push).toHaveBeenCalledWith('/posts/1/edit')
  })

  it('redirect an unauthenticated user to 404', async () => {
    const mockRoute = {
      params: {
        id: 1
      }
    }
    const mockRouter = {
      push: jest.fn()
    }
    const wrapper = mount(Edit, {
      props: {
        authenticated: false
      },
      global: {
        mocks: {
          $route: mockRoute,
          $router: mockRouter
        }
      }
    })
    await wrapper.find('button').trigger('click')
    expect(mockRouter.push).toHaveBeenCalledWith('/404')
  })
})

The Vue app has several routes and we map them to routes.

Also, we added a group of tests that uses the mock router to test the components.

We add the mockRoute to add a mock route object.

And we create the mockRouter by adding the push method to it.

Its value is a mocked function.

Also, when we mount the component, we pass in the props and global properties.

The mocks have the $route and $router properties that we want to mock.

In the first test, we get the button in the Edit component and click it.

And we check that the mockRouter.push method goes to /posts/1/edit .

In the 2nd test, we do the same thing but with the the authenticated prop set to false .

And we check that we’re redirected to the /404 route when we click on the button.

Conclusion

We can test our components with a mocked version of Vue Router in our Vue 3 app tests.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *