Skip to main content

Stencil

Stencil is a library for building reusable, scalable component libraries. You can test Stencil components directly in a real browser using WebdriverIO and its browser runner.

Setup

To set up WebdriverIO within your Stencil project, follow the instructions in our component testing docs. Make sure to select stencil as preset within your runner options, e.g.:

// wdio.conf.js
export const config = {
// ...
runner: ['browser', {
preset: 'stencil'
}],
// ...
}
info

In case you use Stencil with a framework like React or Vue, you should keep the preset for these frameworks.

You can then start the tests by running:

npx wdio run ./wdio.conf.ts

Writing Tests

Given you have the following Stencil components:

./components/Component.tsx
import { Component, Prop, h } from '@stencil/core'

@Component({
tag: 'my-name',
shadow: true
})
export class MyName {
@Prop() name: string

normalize(name: string): string {
if (name) {
return name.slice(0, 1).toUpperCase() + name.slice(1).toLowerCase()
}
return ''
}

render() {
return (
<div class="text">
<p>Hello! My name is {this.normalize(this.name)}.</p>
</div>
)
}
}

render

In your test use the render method from @wdio/browser-runner/stencil to attach the component to the test page. To interact with the component we recommend using WebdriverIO commands as they behave closer to actual user interactions, e.g.:

app.test.tsx
import { expect } from '@wdio/globals'
import { render } from '@wdio/browser-runner/stencil'

import MyNameComponent from './components/Component.tsx'

describe('Stencil Component Testing', () => {
it('should render component correctly', async () => {
await render({
components: [MyNameComponent],
template: () => (
<my-name name={'stencil'}></my-name>
)
})
await expect($('.text')).toHaveText('Hello! My name is Stencil.')
})
})

Render Options

The render method provides the following options:

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 to be used throughout the test.

Type: CustomElementConstructor[]
Default: []

flushQueue

If false, do not flush the render queue on the initial test setup.

Type: boolean
Default: true

template

The initial JSX that is 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.

Type: JSX.Template

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.

Type: string

language

Sets the mocked lang attribute on <html>.

Type: string

autoApplyChanges

By default, any changes to component properties and attributes must env.waitForChanges() to test the updates. As an option, autoApplyChanges continuously flushes the queue in the background.

Type: boolean
Default: false

attachStyles

By default, styles are not attached to the DOM and they are not reflected in the serialized HTML. Setting this option to true will include the component's styles in the serializable output.

Type: boolean
Default: false

Render Environment

The render method returns an environment object that provides certain utility helpers to manage the component's environment.

flushAll

After changes have been made to a component, such as an update to a property or attribute, the test page does not automatically apply the changes. To wait for, and apply the update, call await flushAll()

Type: () => void

unmount

Removes the container element from the DOM.

Type: () => void

styles

All styles defined by components.

Type: Record<string, string>

container

Container element in which the template is being rendered.

Type: HTMLElement

$container

The container element as a WebdriverIO element.

Type: WebdriverIO.Element

root

The root component of the template.

Type: HTMLElement

$root

The root component as a WebdriverIO element.

Type: WebdriverIO.Element

waitForChanges

Helper method to wait for the component to be ready.

import { render, waitForChanges } from '@wdio/browser-runner/stencil'
import { MyComponent } from './component.tsx'

const page = render({
components: [MyComponent],
html: '<my-component></my-component>'
})

expect(page.root.querySelector('div')).not.toBeDefined()
await waitForChanges()
expect(page.root.querySelector('div')).toBeDefined()

Element Updates

If you define properties or states in your Stencil component you have to manage when these changes should be applied to the component to be re-rendered.

Examples

You can find a full example of a WebdriverIO component test suite for Stencil in our example repository.

Welcome! How can I help?

WebdriverIO AI Copilot