@tybalt/test-utils
The test-utils package is for unit testing web components. It's built specifically for Tybalt, but it works for most web component frameworks -- see our Lit example on GitHub.
A simple test might look like
it('emits a click event when the button is clicked', async () => {
const wrapper = await mountCookieBanner();
const actual = wrapper.find('button');
actual.trigger('click');
expect(wrapper.emitted('click')).toHaveLength(1);
});
See the API section below for more examples.
Installation
npm install --save-dev @tybalt/test-utils
Setup
You'll need to add the setup script to your jest.config.js
.
In commonjs
module.exports = {
setupFilesAfterEnv: ['./node_modules/@tybalt/test-utils/dist/cjs/setup.js'],
};
In esm
export default {
setupFilesAfterEnv: ['./node_modules/@tybalt/test-utils/dist/mjs/setup.js'],
};
Usage
import { mount } from '@tybalt/test-utils';
import MyComponent from './my-component';
describe('component', () => {
it('renders', async () => {
const wrapper = await mount(MyComponent);
expect(wrapper.html()).toBe(`<my-component></my-component>`);
});
});
Api
flushPromises
await flushPromises();
import { flushPromises, mount } from '@tybalt/test-utils';
import MyComponent from './my-component';
describe('component', () => {
it('renders', async () => {
const wrapper = await mount(MyComponent);
// wait for asynchronous action, like a fetch request, that is performed when mounting to be completed
await flushPromises();
expect(wrapper.text()).toBe(`<expected content>`);
});
});
mount
Use mount
to create an instance of a web component.
mount
takes two arguments, the component definition, and an optional options
object that can have
an attributes and slot key on it. The attributes argument is an object in the shape
{ attributeKey: "attributeValue" }
, and the slot is a string of html that should be place inside the
web component.
import { mount } from '@tybalt/test-utils';
import MyComponent from './my-component';
describe('component', () => {
it('renders', async () => {
const attributes = {};
const slot = 'this is slot content';
const wrapper = await mount(MyComponent, { attributes, slot });
expect(wrapper.html()).toBe(`<my-component></my-component>`);
});
});
wrapper
The wrapper is a convenience class for testing DOM elements. Wrapper is an interface that has multiple implemenetations,
and is returned from methods like find
, mount
and findComponentAll
.
attributes
The attributes method is used to get the value of attributes that are passed to an element. It takes a single, optional
parameter, attributeName
, the name of the attribute to get the value for.
const attributeName = 'name';
const attributeValue = 'value';
const wrapper = mount(MyComponent, { [attributeName]: attributeValue });
expect(wrapper.attributes(attributeName)).toBe(attributeValue);
If the optional parameter is not provided, instead an object is returned where the keys are all of the attributes, and their corresponding values are the attribute values.
const attributeName = 'name';
const attributeValue = 'value';
const wrapper = mount(MyComponent, { [attributeName]: attributeValue });
expect(wrapper.attributes()).toBe({ [attributeName]: attributeValue });
classes
The classes method is used to indicate the presence of classes that are present on an element. It takes a single,
optional parameter, className
, the name of the attribute to check for the presence of.
const className = 'my-class';
const MyComponent = defineComponent({
render() {
return html`<div class="${className}"></div>`;
},
});
const wrapper = mount(MyComponent);
expect(wrapper.classes(className)).toBeTruthy();
If the optional parameter is not provided, instead an object is returned where the keys are all of the attributes, and their corresponding values are the attribute values.
const className = 'my-class';
const MyComponent = defineComponent({
render() {
return html`<div class="${className}"></div>`;
},
});
const wrapper = mount(MyComponent);
expect(wrapper.classes()).toBe({ [className]: true });
exists
Indicates whether an element exists or not.
For example, if you call this method on the result of a mount
call, it will return true
because mount
returns
an element.
const wrapper = mount(MyComponent);
expect(wrapper.exists()).toBeTruthy();
If, instead, you query the result for a element that is not present, it will return false
.
const MyComponent = defineComponent({
render() {
return html`<div>Hello World</div>`;
},
});
const wrapper = mount(MyComponent);
const element = wrapper.find('button');
expect(element.exists()).not.toBeTruthy();
find
Finds an element that is a descendant of this wrapper that matches a CSS selector string. Only returns the first element matching the selector.
const MyComponent = defineComponent({
render() {
return html`<div>Hello World</div>`;
},
});
const wrapper = mount(MyComponent);
const element = wrapper.find('div[data-jest="my-selector"]');
expect(element.exists()).toBeTruthy();
findAll
Finds all elements that are descendants of this wrapper that match a CSS selector string. Returns all elements matching the selector.
const MyComponent = defineComponent({
render() {
return html`<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>`;
},
});
const wrapper = mount(MyComponent);
const elements = wrapper.findAll('li');
expect(elements.length).toBe(3);
findComponent
Finds an element that is a descendant of this wrapper that is an instance of the constructor provided as the first argument. Only returns the first element that is an instance of the constructor.
const MyComponent = defineComponent({
render() {
return html`<div><my-other-component></my-other-component></div>`;
},
});
const wrapper = mount(MyComponent);
const element = wrapper.findComponent(MyOtherComponent);
expect(element.exists()).toBeTruthy();
findComponentAll
Finds all elements that are descendants of this wrapper that are an instance of the constructor provided as the first argument. Returns all elements that is an instance of the constructor.
const MyComponent = defineComponent({
render() {
return html` <ul>
<li><my-other-component></my-other-component></li>
<li><my-other-component></my-other-component></li>
<li><my-other-component></my-other-component></li>
</ul>`;
},
});
const wrapper = mount(MyComponent);
const elements = wrapper.findComponentAll(MyOtherComponent);
expect(elements.length).toBe(3);
html
Returns a string of the html of a wrapper.
const template = `<div><span>foo</span><span>bar</span><span>baz</span></div>`;
const MyComponent = defineComponent({ template });
const wrapper = mount(MyComponent);
expect(wrapper.html()).toBe(template);
html
returns the html as it would be seen by a third-party script. For instance, if you use the shadow DOM and you
close it, the shadow DOM will not be returned from html
.
const template = `<div>my secret DOM</div>`;
const MyComponent = defineComponent({ template, shadowMode: 'closed' });
const wrapper = mount(MyComponent);
expect(wrapper.html()).toBe(`<my-component></my-component>`);
If, instead, you have an open shadow DOM, it will be included in the returned html
.
const template = `<div>my open DOM</div>`;
const MyComponent = defineComponent({ template, shadowMode: 'open' });
const wrapper = mount(MyComponent);
expect(wrapper.html()).toBe(`<my-component>${template}</my-component>`);
length
Returns the number of DOM elements that are wrapped by this wrapper.
const wrapper = mount(MyComponent);
expect(wrapper.length).toBe(1);
text
Returns the innerText of an html element.
const template = `<div><span>foo</span><span>bar</span><span>baz</span></div>`;
const MyComponent = defineComponent({ template });
const wrapper = mount(MyComponent);
expect(wrapper.text()).toBe(`foo bar baz`);
trigger
Fires a custom event from the wrapped element.
const eventName = 'click';
const payload = { foo: 'bar' };
const wrapper = mount(MyComponent);
wrapper.trigger(eventName, payload);