Exploring Component Testing in Vue with Playwright
Tags: testing, vue, playwright, tutorial
Published: 2024-01-30 11:35:56

---
title: "Exploring Component Testing in Vue with Playwright"
published: true
description: "A step-by-step guide on how to test a component with the preview Playwright's component testing feature"
cover_image: "https://res.cloudinary.com/mayashavin/image/upload/v1706614013/articles/playwright/component_testing.png"
publishedAt: "2024-01-30T07:48:27.409Z"
tags: ['testing', 'Vue', 'Playwright', 'tutorial']
series: Testing with Playwright in Vue
canonical_url: https://mayashavin.com/articles/component-testing-with-playwright-basics
---

_In this post we will dive into using Playwright component testing for Vue applications. By demonstrating a component with search capability, we will walkthrough a step-by-step guide on how to test a component with the preview Playwright's component testing feature._

## Table of content

- [Table of content](#table-of-content)
- [Getting started with Playwright](#getting-started-with-playwright)
  - [Setting up the component testing](#setting-up-the-component-testing)
  - [Modifying the configuration file](#modifying-the-configuration-file)
- [Implementing ItemsView with search](#implementing-itemsview-with-search)
- [Component testing ItemsView](#component-testing-itemsview)
- [Configuring initial search term as prop](#configuring-initial-search-term-as-prop)
- [Testing initial search term props](#testing-initial-search-term-props)
- [Wrapping up](#wrapping-up)

## Getting started with Playwright

[PlaywrightJS](https://playwright.dev/) is an open-source E2E testing framework that is cross-browser, cross-platform and cross-language, making it a great choice for any modern applications. Whether you're working on a small project or a large-scale app, Playwright ensures your tests are reliable and comprehensive.

### Setting up the component testing

Run the following command to install Playwright with component testing for your Vue project:

```bash
npm init playwright@latest -- --ct
```

<img src="https://res.cloudinary.com/mayashavin/image/upload/q_auto,f_auto/v1706609794/articles/playwright/component%20testing%20install" loading="lazy" alt="Install Playwright component testing" class="mx-auto"/>

The above command will perform the following:

* Install `@playwright/experimental-ct-vue`, the experimental component testing package tailored for Vue.js.
* Brings in the necessary browsers for your test runner.
* Add a script command `test-ct` to your `package.json`.
* Add `playwright-ct.config.js`, a dedicated config file for component testing.
* Add `playwright` folder for **runtime** configuration, such as adding routing.
* And finally, adds an e2e folder with test suites ready to go.

### Modifying the configuration file

Once installed, we need a tiny bit of tweakingin the `playwright-ct.config.js` file to get everything running smoothly in a Vite and ES6 module environment:

* Replace `require()` in line 2 to using ES6 `import`
* Replace `module.export` in line 7 to `export default`.
* Change the `testDir` to `./e2e` instead, to avoid Playwright picking up the unit tests by accident.

And our Vue project is now Playwright-ready for component testing. Let's write our first component and test.

## Implementing ItemsView with search

We will implement component `ItemsView` that contains the following features:

* An input field that binds to a `searchTerm` variable
* The component uses `useSearch()`, a custom composable, that accepts an initial list of `items` and returns the reactive `searchTerm` and the filtered `searchResults`.
* A list of items based on the search term.

Below is the implementation for `template` section of `ItemsView`:

```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 { items } = useItems();

const { search, searchResults } = useSearch({
  items: items,
});
```

Launch the app, the browser will display the view with a search input and the 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/itemsview" alt="ItemsView component" class="mx-auto" loading="lazy" />

And with that, it's time to add our first test to `ItemsView`, focusing on the search.

## Component testing ItemsView

Within `e2e` folder, we create a new `ItemsView.spec.js` with the following code:

```javascript
import { test, expect } from '@playwright/experimental-ct-vue';
import ItemsView from "../src/components/ItemsView.vue";

test("", async ({ mount, page }) => {
})
```

Our first test will do the following:

1. Mounting the component using `mount`
2. Verify the initial value of the search input:

```javascript
test("should display component with empty input", async ({ mount, page }) => {
    //1. Mount the component
    const component = await mount(ItemsView);

    //2. Locate the search input 
    const elem = await component.getByTestId('search-input');

    //3. Verify the label and the initial value
    await expect(elem).toHaveValue('')
})
```

Next up, we'll test if the component updates when you type in the search box. We will simulate the user's input by using `elem.fill()` function:

```javascript
test("should update the search term", async ({ mount }) => {
    //1. Mount the component 
    //2. Locate the input
    //...

    //3. Fill in the input's value
    await elem.fill('hello')

    //4. Verify
    await expect(elem).toHaveValue('hello')
})
```

When we run `yarn test-ct`, Playwright will trigger the test on different browsers defined in `playwright-ct.config.js`. If something's amiss, you'll get a detailed report, both in your terminal and a UI report in the browser, while waiting for the test to be fixed.

You can view the final result any time with `yarn playwright show-report`:

<img src="https://res.cloudinary.com/mayashavin/image/upload/q_auto,f_auto/v1706607077/articles/playwright/test_report" loading="lazy" alt="Show report per component test" class="mx-auto"/>

And there you have it! Our `ItemsView` is now equipped with its first set of search tests.

Next, let's empower `ItemsView` to accept an `initialSearchTerm` prop as the initial search value for the input.

## Configuring initial search term as prop

First, we'll declare the `initialSearchTerm` as one of the component's props using `defineProps`:

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

Next, we pass it as the `defaultSearch` for `useSearch`:

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

With that setup, if we pass a value to `intialSearchTerm` prop, the search input will take it as its initial value. 

```html
<ItemsView initial-search-term="hawaii"/>
```

<img src="https://res.cloudinary.com/mayashavin/image/upload/q_auto,f_auto/v1706607290/articles/playwright/with_initial_value" loading="lazy" alt="Component rendered with initial search value" class="mx-auto"/>

Next, we will cover it with tests.

## Testing initial search term props

Unlike [Vue Test Utils](https://test-utils.vuejs.org/) or [Testing Library](https://testing-library.com/docs/vue-testing-library/intro/), the `mount()` in Playwright does not work the same way. It does not accept a second parameter as additional Vue component options. To pass a prop upon mounting, we will use JSX syntax, as follows:

```javascript
test("should get the search term from outside", async ({ mount }) => {

    const component = await mount(<ItemsView initialSearchTerm="hello" />);
});
```

Playwright renders this beautifully and from there we can validate our search input's initial value:

```javascript
const elem = await component.getByTestId('search-input');
await expect(elem).toHaveValue('hello')
```

And just like that, run the tests again, and watch as everything passed as expected.

<img src="https://res.cloudinary.com/mayashavin/image/upload/q_auto,f_auto/v1706607290/articles/playwright/with_initial_value" loading="lazy" alt="Test on initial value as prop" class="mx-auto"/>

As an extra tip, you can debug the test 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"/>

## Wrapping up

While Playwright's component testing capabilities sounds promising, it's important to remember they're still in the experimental phase. This means you might encounter some limitations or bugs along the way. Also, the tests we performed in our post today can easily be done using Vitest + Vue Test Utils, just without the actual UI render.

So, the question here is: are there scenarios where using an E2E framework like Playwright for component testing offers a clear advantage over traditional unit testing frameworks? We will explore that in our next post. Until then, it's time to dive into some test writing! 😉🧪💻

👉 _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 👇🏼 😉