DEV Community

Cover image for Extend Vue Test Utils - findByText
Giannis Koutsaftakis
Giannis Koutsaftakis

Posted on • Edited on

Extend Vue Test Utils - findByText

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'],
}
Enter fullscreen mode Exit fullscreen mode

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',
  },
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
liborjelinek profile image
Libor Jelinek

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

import { DOMWrapper } from '@vue/test-utils';

declare module '@vue/test-utils' {
  export class VueWrapper {
    findByText(text: string, selector = '*'): DOMWrapper[];
  }
}
Enter fullscreen mode Exit fullscreen mode