See how Stencil fits into the entire Ionic Ecosystem ->
Stencil is part of the Ionic Ecosystem ->

Unit Testing

Stencil makes it easy to unit test components and app utility functions using Jest. Unit tests validate the code in isolation. Well written tests are fast, repeatable, and easy to reason about.

To run unit tests, run stencil test --spec. Files ending in .spec.ts will be executed.

newSpecPage()

In order to unit test a component as rendered HTML, tests can use newSpecPage() imported from @stencil/core/testing. This testing utility method is similar to newE2EPage(), however, newSpecPage() is much faster since it does not require a full Puppeteer instance to be running. Please see the newE2EPage() docs on more information about complete End-to-end testing with Puppeteer.

Below is a simple example where newSpecPage() is given one component class which was imported, and the initial HTML to use for the test. In this example, when the component MyCmp renders it sets its text content as "Success!". The matcher toEqualHtml() is then used to ensure the component renders as expected.

import { newSpecPage } from '@stencil/core/testing';
import { MyCmp } from '../my-cmp';

it('should render my component', async () => {
  const page = await newSpecPage({
    components: [MyCmp],
    html: `<my-cmp></my-cmp>`,
  });
  expect(page.root).toEqualHtml(`
    <my-cmp>Success!</my-cmp>
  `);
});

The example below uses the template option to test the component

// mycmp.spec.tsx
// Since the 'template' argument to `newSpecPage` is using jsx syntax, this should be in a .tsx file.
import { h } from '@stencil/core';
import { newSpecPage } from '@stencil/core/testing';
import { MyCmp } from '../my-cmp';

it('should render my component', async () => {
  const greeting = 'Hello World';
  const page = await newSpecPage({
    components: [MyCmp],
    template: () => (<my-cmp greeting={greeting}></my-cmp>),
  });
  expect(page.root).toEqualHtml(`
    <my-cmp>Hello World</my-cmp>
  `);
});

Spec Page Options

The newSpecPage(options) method takes an options argument to help write tests:

Option Description
components An array of components to test. Component classes can be imported into the spec file, then their reference should be added to the component array in order to be used throughout the test. Required
html The initial HTML used to generate the test. This can be useful to construct a collection of components working together, and assign HTML attributes. This value sets the mocked document.body.innerHTML.
template The initial JSX used to generate the test. Use template when you want to initialize a component using their properties, instead of their HTML attributes. It will render the specified template (JSX) into document.body.
autoApplyChanges By default, any changes to component properties and attributes must call page.waitForChanges() in order to test the updates. As an option, autoApplyChanges continuously flushes the queue in the background. Defaults to false
cookie Sets the mocked document.cookie.
direction Sets the mocked dir attribute on <html>.
language Sets the mocked lang attribute on <html>.
referrer Sets the mocked document.referrer.
supportsShadowDom Manually set if the mocked document supports Shadow DOM or not. Defaults to true
userAgent Sets the mocked navigator.userAgent.
url Sets the mocked browser's location.href.

Spec Page Results

The returned "page" object from newSpecPage() contains the initial results from the first render. It's also important to note that the returned page result is a Promise, so for convenience it's recommended to use async/await.

The most useful property on the page results would be root, which is for convenience to find the first root component in the document. For example, if a component is nested in many <div> elements, the root property goes directly to the component being tested in order to skip the query selector boilerplate code.

Result Description
body Mocked testing document.body.
doc Mocked testing document.
root The first component found within the mocked document.body. If a component isn't found, then it'll return document.body.firstElementChild.
rootInstance Similar to root, except returns the component instance. If a root component was not found it'll return null.
setContent(html) Convenience function to set document.body.innerHTML and waitForChanges(). Function argument should be an html string.
waitForChanges() After changes have been made to a component, such as a update to a property or attribute, the test page does not automatically apply the changes. In order to wait for, and apply the update, call await page.waitForChanges().
win Mocked testing window.

Testing Component Class Logic

For simple logic only testing, unit tests can instantiate a component by importing the class and constructing it manually. Since Stencil components are plain JavaScript objects, you can create a new component and execute its methods directly.

import { MyToggle } from '../my-toggle.tsx';

it('should toggle the checked property', () => {
  const toggle = new MyToggle();

  expect(toggle.checked).toBe(false);

  toggle.someMethod();

  expect(toggle.checked).toBe(true);
});
BackNext
Contributors