When it comes to testing Vue components, Vue Test Utils is the official testing library that provides a rich set of utilities for interacting with and asserting on components in a Vue application. However, just like any library, there are always opportunities for enhancements and additions to further improve the testing experience.
If you've used other testing libraries like testing-library, Cypress etc, one pattern that you might have found useful is to select elements based on their text content (e.g getByText
, cy.contains
etc).
Although Vue Test Utils supports finding elements using CSS selectors via the find
and findAll
methods, it doesn't provide a method for getting elements by text.
Thankfully, Vue Test Utils includes a Plugin
API that lets us extend its capabilities with custom logic, methods, or functionality, so we can create our own findByText
method 🎉.
Let's get right to it then!
Create and register the extends file
Create a file for your Vue Test Utils extends, e.g. vue-test-utils.extends.js
and save it to your preffered location.
You'll need to register that file in your test runner's configuration so that it runs before each test.
For Jest, that would be inside jest.config.js
setupFilesAfterEnv
array
jest.config.js
module.exports = {
...
setupFilesAfterEnv: ['./tests/jest.extends.js'],
}
For Vitest that would be inside vite.config.js
test
setupFiles
vite.config.js
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
...
test: {
...
setupFiles: './tests/jest.extends.js',
},
});
With that out of the way it's time to add our findByText
function.
findByText
function
jest.extends.js
import { config, createWrapperError } from '@vue/test-utils';
const Plugin = (wrapper) => {
function findByText(str, selector = '*') {
const items = wrapper.findAll(selector);
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.text().trim() === str.trim()) {
return item;
}
}
return createWrapperError('DOMWrapper');
}
return {
findByText,
};
};
config.plugins.VueWrapper.install(Plugin);
Details
The findByText
function uses the findAll
method of Vue Test Utils under the hood in order to find elements and then loops over them to find the text that matches the string
passed as an argument. Optionally, we can also pass a selector
as a second argument if we want to narrow down the results to a specific container.
Things to note:
The function performs a case-sensitive text match so ensure that the text parameter exactly matches the casing of the desired text content. It also trims both the text and the actual text content of the elements being searched to remove leading and trailing whitespace, allowing for more flexible matching.
Feel free to change the code that does the matching part to your own liking.
Parameters
text
(string): The text content to search for within the component's wrapper.
selector
(string): (Optional) CSS selector used to narrow down the search scope. Defaults to '*', which matches all elements within the wrapper.
Return Value
element
(DOMWrapper): A DOMWrapper
object representing the first element that matches the given text within the wrapper. If no matching element is found, an error is thrown.
Example
import { mount } from '@vue/test-utils';
const Component = {
template: `
<div>
<span class="test1">Foo</span>
<span class="test2">Bar</span>
</div>
`,
};
const wrapper = mount(Component);
const span = wrapper.findByText('Foo');
expect(span.classes()).toContain('test1');
Final notes
We saw how you can use Vue Test Utils Plugin
API to extend its functionality. Using the same format we can create other query functions to use in our tests without the need to install another 3rd party testing library.
Happy component testing!
Top comments (1)
Thank you! Thank you and once more thank you! This is the definitively missing piece of Vue Test Utils.
The only improvement to it could be to get rid of TypeScript unknown method error by creating
vue-test-utils.d.ts
with content