Skip to content

stenciljs/vitest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@stenciljs/vitest

First-class testing utilities for Stencil components, powered by Vitest.

Quick Start

1. Install

npm i --save-dev @stenciljs/vitest vitest

For browser testing, also install:

npm i -D @vitest/browser-playwright
# or
npm i -D @vitest/browser-webdriverio

2. Create vitest.config.ts

import { defineVitestConfig } from '@stenciljs/vitest/config';
import { playwright } from '@vitest/browser-playwright';

export default defineVitestConfig({
  stencilConfig: './stencil.config.ts',
  test: {
    projects: [
      // Unit tests - node environment for functions / logic
      {
        test: {
          name: 'unit',
          include: ['src/**/*.unit.{ts,tsx}'],
          environment: 'node',
        },
      },
      // Spec tests - via a node DOM of your choice
      {
        test: {
          name: 'spec',
          include: ['src/**/*.spec.{ts,tsx}'],
          environment: 'stencil',
          setupFiles: ['./vitest-setup.ts'],

          // Optional environment options

          // environmentOptions: {
          //   stencil: {
          //     domEnvironment: 'happy-dom' | 'jsdom' | 'mock-doc' (default)
          //                      ^^ Make sure to install relevant packages
          //   },
          // },
        },
      },
      // Browser tests
      {
        test: {
          name: 'browser',
          include: ['src/**/*.test.{ts,tsx}'],
          setupFiles: ['./vitest-setup.ts'],
          browser: {
            enabled: true,
            provider: playwright(),
            headless: true,
            instances: [{ browser: 'chromium' }],
          },
        },
      },
    ],
  },
});

refer Vitest documentation for all configuration options

3. Load your components

// vitest-setup.ts

// Load Stencil components.
// Adjust according to your build output of choice *
await import('./dist/test-components/test-components.esm.js');

export {};
// * Bear in mind, you may need `buildDist: true` (in your stencil.config)
// or `--prod` to use an output other than the browser lazy-loader

4. Write Tests

// src/components/my-button/my-button.spec.tsx

import { describe, it, expect } from 'vitest';
import { render, h } from '@stenciljs/vitest';

describe('my-button', () => {
  it('renders with text', async () => {
    const { root, waitForChanges } = await render(<my-button label="Click me" />);
    root.click();
    await waitForChanges();
    expect(root).toEqualHtml(`
      <my-button class="hydrated">
        <mock:shadow-root>
          <button class="button button--secondary button--small" type="button">
            <slot></slot>
          </button>
        </mock:shadow-root>
        Small
      </my-button>
    `);
  });
});

4. Run tests

// package.json

{
  "scripts": {
    "test": "stencil-test",
    "test:watch": "stencil-test --watch",
    "test:e2e": "stencil-test --project browser",
    "test:spec": "stencil-test --project spec"
  }
}

API

Rendering

render(VNode)

Render a component for testing.

import { render, h } from '@stenciljs/vitest';

const { root, waitForChanges, setProps, unmount } = await render(<my-component name="World" />);

// Access the element
expect(root.textContent).toContain('World');

// Update props
root.name = 'Stencil';
await waitForChanges();
// or
await setProps({ name: 'Stencil' });

// Unmount component
unmount();

Available matchers:

// DOM assertions
expect(element).toHaveClass('active');
expect(element).toHaveClasses(['active', 'primary']);
expect(element).toMatchClasses(['active']); // Partial match
expect(element).toHaveAttribute('aria-label', 'Close');
expect(element).toEqualAttribute('type', 'button');
expect(element).toEqualAttributes({ type: 'button', disabled: true });
expect(element).toHaveProperty('value', 'test');
expect(element).toHaveTextContent('Hello World');
expect(element).toEqualText('Exact text match');
expect(element).toBeVisible();

// Shadow DOM
expect(element).toHaveShadowRoot();
expect(element).toEqualHtml('<div>Expected HTML</div>');
expect(element).toEqualLightHtml('<div>Light DOM only</div>');

Event Testing

Test custom events emitted by your components:

const { root, spyOnEvent, waitForChanges } = await render(<my-button />);

// Spy on events
const clickSpy = spyOnEvent('buttonClick');
const changeSpy = spyOnEvent('valueChange');

// Trigger events
root.click();
await waitForChanges();

// Assert events were emitted
expect(clickSpy).toHaveReceivedEvent();
expect(clickSpy).toHaveReceivedEventTimes(1);
expect(clickSpy).toHaveReceivedEventDetail({ buttonId: 'my-button' });

// Access event data
expect(clickSpy.events).toHaveLength(1);
expect(clickSpy.firstEvent?.detail).toEqual({ buttonId: 'my-button' });
expect(clickSpy.lastEvent?.detail).toEqual({ buttonId: 'my-button' });

Snapshots

The package includes a custom snapshot serializer for Stencil components that properly handles shadow DOM:

import { render, h } from '@stenciljs/vitest';
...
const { root } = await render(<my-component />);
expect(root).toMatchSnapshot();

Snapshot output example:

<my-component>
  <mock:shadow-root>
    <button class="primary">
      <slot />
    </button>
  </mock:shadow-root>
  Click me
</my-component>

Screenshot Testing

Browser tests can include screenshot comparisons using Vitest's screenshot capabilities:

import { render, h } from '@stenciljs/vitest';
...
const { root } = await render(<my-button variant="primary">Primary Button</my-button>);
await expect(root).toMatchScreenshot();

Refer to Vitest's screenshot testing documentation for more details.

CLI

The stencil-test CLI wraps both Stencil builds with Vitest testing.

Add to package.json

{
  "scripts": {
    "test": "stencil-test",
    "test:watch": "stencil-test --watch"
  }
}

Usage

# Build once, test once
stencil-test

# Watch mode (rebuilds on component changes, interactive Vitest)
stencil-test --watch

# Watch mode with dev server
stencil-test --watch --serve

# Production build before testing
stencil-test --prod

# Pass arguments to Vitest
stencil-test --watch --coverage

# Test specific files
stencil-test button.spec.ts

# Test specific project
stencil-test --project browser

CLI Options

The stencil-test CLI supports most of Stencil's CLI options and all of Vitest CLI options

License

MIT

Contributing

See CONTRIBUTING.md for development setup and guidelines.

About

First-class testing utilities for Stencil components with Vitest

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published