Exploring Component Testing in Vue with Playwright: The 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
- Getting started with Playwright
- Implementing ItemsView with search
- Component testing ItemsView
- Configuring initial search term as prop
- Testing initial search term props
- Wrapping up
Getting started with Playwright
PlaywrightJS 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:
npm init playwright@latest -- --ct
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 yourpackage.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 ES6import
- Replace
module.export
in line 7 toexport 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 ofitems
and returns the reactivesearchTerm
and the filteredsearchResults
. - A list of items based on the search term.
Below is the implementation for template
section of ItemsView
:
<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:
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:
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:
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:
- Mounting the component using
mount
- Verify the initial value of the search input:
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:
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
:
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
:
const props = defineProps({
intialSearchTerm: {
type: String,
default: "",
},
});
Next, we pass it as the defaultSearch
for useSearch
:
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.
<ItemsView initial-search-term="hawaii"/>
Next, we will cover it with tests.
Testing initial search term props
Unlike Vue Test Utils or Testing Library, 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:
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:
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.
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.
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!
๐ If you'd like to catch up with me sometimes, follow me on X | LinkedIn.
Like this post or find it helpful? Share it ๐๐ผ ๐