Skip to main content

Component testing

Testing our MonsterJS components can help us check that our components are working properly. MonsterJS provides a testing tools found in @monster-js/tester package. These tools can help us validate that all our components are performing as expected.

The componentTester function

import { componentTester } from '@monster-js/tester'

The componentTester function helps us to create a tester instance based on the provided component.

Example.

import { greeting } from './greeting.component';
import { componentTester } from '@monster-js/tester';

const tester = componentTester(greeting);

The componentTester function has two arguments. First is the component that we want to create a tester instance and second is an optional argument which is an object that has the following properties.

PropertyTypeDescription
componentsArrayArray of components we want to define.
externalComponentsArrayArray of component selectors which we want our test to treat as external components.

Example.

import { greeting } from './greeting.component';
import { greetingChild } from './greeting-child.component';
import { componentTester } from '@monster-js/tester';

const tester = componentTester(greeting, {
components: [greetingChild],
externalComponents: ['app-external-component']
});

Child components that are not needed to be tested can be registered as external component.

The tester.createComponent function

After creating a tester instance, we can now call the createComponent method to build the component and return an object that contains the following properties.

PropertyTypeDescription
hostHTMLElementThe host element of the component. Can be converted to component using parseComponent function.
elementHTMLElementThe DOM element version of the component's template.
componentObjectThe component instance.
shadowRootObjectThe shadow root of a shadow dom component.

Example.

import { greeting } from './greeting.component';
import { componentTester } from '@monster-js/tester';

const tester = componentTester(greeting);

it('should create a component', function() {
const { host, element, shadowRoot } = tester.createComponent();
expect(host).toBeTruthy();
expect(element).toBeTruthy();
expect(shadowRoot).toBeTruthy();
});

The parseComponent function

import { parseComponent } from '@monster-js/tester'

This will convert an element to component and return an object that has the same structure as the one returned by the tester.createComponent method. If the element is not a component, it will throw an error.

Example.

import { greeting } from './greeting.component';
import { greetingChild } from './greeting-child.component';
import { componentTester, parseComponent } from '@monster-js/tester';

const tester = componentTester(greeting, {
components: [greetingChild]
});

it('should have the child component', function() {
const greeting = tester.createComponent();
const childElement = greeting.element.querySelector('app-greeting-child');
const { host, element, shadowRoot } = parseComponent(childElement);
expect(host).toBeTruthy();
expect(element).toBeTruthy();
expect(shadowRoot).toBeTruthy();
});

The render function

import { render } from '@monster-js/tester'

This will render the component that is already defined using customElement.define and return an object that has the same structure as the one returned by the tester.createComponent method.

Example.

import { greeting } from './greeting.component';
import { greetingChild } from './greeting-child.component';
import { componentTester, render } from '@monster-js/tester';

const tester = componentTester(greeting, {
components: [greetingChild]
});

it('should be able to render child component', function() {
const { host, element, shadowRoot } = render(greetingChild);
expect(host).toBeTruthy();
expect(element).toBeTruthy();
expect(shadowRoot).toBeTruthy();
});

The fireEvent function

import { fireEvent } from '@monster-js/tester'

This will fire an event of an an element like click, dblclick, input and other events.

Example.

import { fireEvent, componentTester } from '@monster-js/tester';
import { counter } from './counter.component';

const tester = componentTester(counter);

it('should increment the counter when button is clicked', function() {
const { element } = tester.createComponent();
const btn = element.querySelector('button');
const span = element.querySelector('.count-holder');
fireEvent(btn, 'click')
expect(span.textContent).toBe('1');
});

The fireEvent function has the following arguments.

ParameterTypeDescription
elementElementThat target html element of the event we want to fire.
eventTypeElementThat target html element of the event we want to fire.

The inputText function

import { inputText } from '@monster-js/tester'

The inputText function allows us to emulate a user typing into an input box.

Example.

import { inputText, componentTester } from '@monster-js/tester';
import { counter } from './counter.component';

const tester = componentTester(counter);

it('should display the inputted text to text holder', function() {
const { element } = tester.createComponent();
const input = element.querySelector('input');
const span = element.querySelector('.text-holder');
inputText(input, 'Hello World');
expect(span.textContent).toBe('Hello World');
});

If it has only two arguments the function is synchronous and asynchronous if it has a third argument which is the input delay in milliseconds.

Example.

import { inputText, componentTester } from '@monster-js/tester';
import { counter } from './counter.component';

const tester = componentTester(counter);

it('should display the inputted text to text holder', async function() {
const { element } = tester.createComponent();
const input = element.querySelector('input');
const span = element.querySelector('.text-holder');
await inputText(input, 'Hello World', 100);
expect(span.textContent).toBe('Hello World');
});

The arguments of inputText(element, text, delay) are the following.

ArgumentTypeDescription
elementElementThe element where the text should be inputted.
textstringThe text that will be inputted in the element.
delaynumberThe delay of the input event for the next character when typing.