Vivid Test Utils
A library that makes it easier to interact with Vivid components in tests. It works with any frontend library and with common testing frameworks.
Since Vivid is a Web Components library, writing tests can be more challenging. Depending on the testing framework and how you set up your tests, there can be various pitfalls that slow down test development.
The library provides a unified and reliable way to select components, perform actions on them, and assert their state.
Since the version of the library is kept in sync with the Vivid version, these operations will continue to work in the future, even when the implementation of the components changes.
The library supports the following testing frameworks:
- Playwright
- Cypress
- DOM: Can be used with a simulated DOM like JSDOM, e.g. in combination with Vue Test Utils or React Testing Library
The usage is the same across all testing frameworks. The only differences are the initialization and whether certain operations are asynchronous.
The library is provided as the @vonage/vivid-test-utils package. The version number is kept in sync with the version of Vivid that it supports.
npm install --save-dev @vonage/vivid-test-utils
yarn add -D @vonage/vivid-test-utils
pnpm add -D @vonage/vivid-test-utils
Playwright
import { vividPlaywright } from '@vonage/vivid-test-utils/playwright';
// Create the vvd object using the Playwright page object and Playwright's expect function:
const vvd = vividPlaywright(page, expect);
Cypress
import { vividCypress } from '@vonage/vivid-test-utils/cypress';
// Create the vvd object using the cy object:
const vvd = vividCypress(cy);
DOM
import { vividDOM } from '@vonage/vivid-test-utils/dom';
// Create the vvd object using a Jest/Vitest or other Jasmine-style expect function and a root DOM node:
const vvd = vividDOM(expect, document.body);
JSDOM
If you run your tests in a simulated DOM environment, it may not provide all the features that Vivid needs.
The library comes with a polyfill for JSDOM that fills these gaps. You can load it as follows, e.g. in a global test setup file:
import '@vonage/vivid-test-utils/jsdom-polyfill';
Vue Test Utils
By default, Vue Test Utils does not attach the rendered component to the document. However, Web Components need to be attached to initialize, and the Vivid Test Utils need them to be in the document to find them.
Use the attachTo option to render components into the document.
import { mount } from '@vue/test-utils';
const wrapper = mount(Component, { attachTo: document.body });
Components that you attach to the document stay there after the test ends.
Use enableAutoUnmount to unmount components after each test automatically, for example in a global test setup file:
import { enableAutoUnmount } from '@vue/test-utils';
import { afterEach } from 'vitest';
enableAutoUnmount(afterEach);
Alternatively, call wrapper.unmount() at the end of each test.
// Select with a component-specific selector:
vvd.textField.byLabel('Email');
// Or by test ID, which will work for all components:
vvd.textField.byTestId('email');
This returns a locator that you can perform further operations with.
Locators are lazy, they resolve against the DOM every time when they are used, not when they are created.
Wrapping and Unwrapping Locators
Each Vivid locator wraps a locator of your testing framework. You can convert between the two, for example to select a component with a query the library doesn't support, or to use a feature of your testing framework on a component.
The type of the wrapped locator depends on the testing framework:
- Playwright: A
Locator. - Cypress: A function that returns a Cypress chainable, for example
() => cy.get('#email'). - DOM: A function that returns the element, for example
() => screen.getByTestId('email'). The function should throw if it can't find the element, so that actions and expectations retry until the element is rendered.
const locator = vvd.textField.byLabel('Email').unwrap();
vvd.textField.wrap(locator).fill('Hello');
After selecting a component, you can perform component-specific actions:
vvd.textField.byLabel('Email').fill('user@example.com');
When using Playwright or DOM, you need to await actions.
To make assertions against a component, use the vvd.expect method instead of your testing framework's assertion method.
vvd.expect provides only the expectations that are available for the given component, with types specific to that component.
vvd.expect(vvd.textField.byLabel('Email')).toHaveValue('user@example.com');
When using Playwright or DOM, you need to await expectations.
The all() selector creates a locator for a collection of components.
vvd.textField.all();
Collections support the following API:
// Locate the nth component
vvd.textField.all().nth(0).fill('user@example.com');
// Assert specific component count
vvd.expect(vvd.textField.all()).toHaveCount(2);
Like other locators, collections are lazy. A collection reflects the components that are rendered at the time you use it, not at the time you created it.
Actions wait for the component to be rendered, and expectations retry until they pass. If this takes longer than the timeout, the action or expectation fails.
The library uses the timeouts of your testing framework where possible:
| Testing framework | Actions | Expectations |
|---|---|---|
| Playwright | Action timeout (no limit by default) | Expect timeout (5 seconds by default) |
| Cypress | Default command timeout (4 seconds by default) | Default command timeout (4 seconds by default) |
| DOM | timeout option (1 second by default) |
timeout option (1 second by default) |
DOM
Pass the timeout option (in milliseconds) to vividDOM:
const vvd = vividDOM(expect, document.body, { timeout: 2000 });
You can find the supported methods for each component in the Testing section of its API reference.