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.tswith content