Component Testing in Vue: Using routing for states
Tags: testing, vue, playwright, tutorial
Published: 2024-02-06 07:13:45

---
title: "Component Testing in Vue: Using routing for states"
description: "A step-by-step guide on how to test a component using routing with Playwright"
published: true
tags: ['Testing', 'Vue', 'Playwright', 'tutorial']
cover_image: https://res.cloudinary.com/mayashavin/image/upload/v1707082421/articles/playwright/component_testing_2.png
series: Testing with Playwright in Vue
canonical_url: https://mayashavin.com/articles/component-testing-router-playwright
---

_In the [previous post](https://dev.to/mayashavin/exploring-component-testing-in-vue-with-playwright-27mi) we explored how to set up Playwright with component testing in a Vue application, as well as wrote our first few component tests. In this post, we will expand further in testing the components that use Vue Router to synchronize their states with the URL params_

## Table of content

- [Table of content](#table-of-content)
- [Pre-requisites](#pre-requisites)
- [Create and map ItemsView with the right route](#create-and-map-itemsview-with-the-right-route)
- [Save search term with Route URL query params](#save-search-term-with-route-url-query-params)
- [Test the sync between search term and URL query](#test-the-sync-between-search-term-and-url-query)
- [Debugging Playwright tests](#debugging-playwright-tests)
- [Summary](#summary)

## Pre-requisites

This post assumes you have a Vue project set up wit [Vue Router](https://router.vuejs.org/) and [Playwright](https://playwright.dev) component testing. If you haven't done so, please refer to the [previous post](https://dev.to/mayashavin/exploring-component-testing-in-vue-with-playwright-27mi) to set up Playwright with component testing for your Vue project.

## Create and map ItemsView with the right route

We will create a new component `ItemsView` that contains a search input and a list of items. The search input will filter the items based on the search term, with the following code:

```html
<template>
  <div class="items-view--container">
    <div>
        <input 
            v-model="searchTerm" placeholder="Search for an item" data-testid="search-input" id="searchbox" 
        />
    </div>
    <ul>
      <li v-for="item in searchResults" :key="item.id">
        <h2>{{item}}</h2>
      </li>
    </ul>
  </div>
</template>
```

And our `script setup` is as follows:

```js
import { useItems } from "../composables/useItems";
import PizzaCard from "../components/PizzaCard.vue";
import { useSearch } from "../composables/useSearch";

const props = defineProps({
  intialSearchTerm: {
    type: String,
    default: "",
  },
});

const { items } = useItems();

const { search, searchResults } = useSearch({
  items: items,
  defaultSearch: props.intialSearchTerm,
});
```

We will map the `ItemsView` to the path `/items`, by editing the `routes` inside `router/index.js` file:

```javascript
export const routes = [
//...
    {
        path: "/items",  
        component: ItemsView,
        name: 'items',
    }
];
//...
```

Upon running and redirecting to `/items`, the browser will display the view with a search input and the initial list of items, as seen in the below screenshot.

<img src="https://res.cloudinary.com/mayashavin/image/upload/q_auto/f_auto/v1706606204/articles/playwright/items_view_with_route" alt="ItemsView component" class="mx-auto" loading="lazy" />

Next we will save the search term to the URL and test this functionality.

## Save search term with Route URL query params

Within `ItemsView.vue`, we will import `useRouter()` from the `vue-router` package, and update the URL query params whenever the search term changes using `watch()`:

```javascript
/**ItemsView.vue */
import { watch } from "vue";
import { useRouter } from "vue-router";

const router = useRouter();

watch(search, (value, prevValue) => {
  if (value === prevValue) return;
  router.replace({ query: { search: value } });
});
```

We also receive the component's initial search state from the URL, by adding the following code to the `router/index.js` and map the route's query params with the props of the `ItemsView` component:

```js
export const routes = [
//...
    {
        path: "/items",  
        //...
        props: (route) => ({
          intialSearchTerm: route.query?.search || "",
        }), 
    }
];
```

At this point whenever the user changes the search term and refreshes the browser, the component will remain in the same state, and won't reset the results to the default list.

Let's test it next.

## Test the sync between search term and URL query

For this test scenario, we need to enable and wrap the component with routing, **before** mounting it. To do so, we add the following code in `/playwright/index.js`:

```javascript
import { beforeMount } from '@playwright/experimental-ct-vue/hooks';
import router from '../src/router'

beforeMount(async ({ app }) => {
    app.use(router);
 });
```

Playwright provides an `app` instance that we can hook a mock router to it. In our demo, for simplicity we will use the same router instance from `router/index.js`.

**Note**: _This set up with `beforeMount()` will apply to all E2E tests in the project. At the time of writing this post, Playwright team hasn't provided the option to configure `beforeMount` per test yet._

Once done, we can add the check for the URL reflects the new search term to our `should update the search term` test case:

```javascript
test("should update the search term", async ({ mount, page }) => {
    //...
    await expect(page.url()).toContain('/?search=hello')
})
```

That's it! We have successfully tested the sync between the search term and the URL query params.

## Debugging Playwright tests

You can debug your tests by add the `--debug` flag the test command (`yarn test-ct --debug`). With this flag, Playwright will open the browser's DevTools, pause the tests, and allow you to inspect the component's DOM while running the tests.

<img src="https://res.cloudinary.com/mayashavin/image/upload/q_auto,f_auto/v1706608008/articles/playwright/debug%20mode" loading="lazy" alt="Playwright test run in debug mode" class="mx-auto"/>

## Summary

At this point, you should have a basic understanding of how to test a component that uses Vue Router to synchronize its states with the URL params, using Playwright. It will be more challenging to validate the query params synchronization in the same test scenario with Vue Test Utils, due to the limitation non browser's environment.

So when should you use Playwright for component testing? And when should you use traditional unit testing frameworks like Vue Test Utils or Testing Library? That depends on the complexity of your codebase, each component's nature and your test goals!

👉 _Learn about Vue 3 and TypeScript with my new book [Learning Vue](https://www.oreilly.com/library/view/learning-vue/9781492098812/)!_

👉 _If you'd like to catch up with me sometimes, follow me on [X](https://x.com/MayaShavin) | [LinkedIn](https://www.linkedin.com/in/mayashavin)._

Like this post or find it helpful? Share it 👇🏼 😉