Skip to main content
BEEQ uses Jest for unit (spec) tests and Jest combined with Puppeteer for end-to-end (e2e) tests. Every new component must ship with both.
Puppeteer uses a real Chromium instance to run e2e tests. Make sure you have Google Chrome or Chromium installed, or set the PUPPETEER_EXECUTABLE_PATH environment variable to point to your browser executable:
export PUPPETEER_EXECUTABLE_PATH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

Running tests

Run all tests

pnpm test

Run unit tests and e2e tests separately

# Unit (spec) tests only
pnpm test:spec

# End-to-end tests only
pnpm test:e2e

Run a specific test file

Pass the filename (or part of it) as an argument after --:
# Run spec tests matching "debounce"
pnpm test:spec -- debounce

# Run e2e tests matching "dialog"
pnpm test:e2e -- dialog

Watch mode

Add --watch to re-run tests automatically on file changes — useful during active development:
pnpm test:spec -- debounce --watch
pnpm test:e2e -- dialog --watch

Writing e2e tests

E2e tests live in __tests__/bq-{component}.e2e.ts and use StencilJS’s newE2EPage helper, which launches a real Puppeteer browser:
import { newE2EPage } from '@stencil/core/testing';

describe('bq-button', () => {
  it('should render', async () => {
    const page = await newE2EPage();
    await page.setContent('<bq-button>Button</bq-button>');

    const element = await page.find('bq-button');
    expect(element).toHaveClass('hydrated');
  });

  it('should have shadow root', async () => {
    const page = await newE2EPage();
    await page.setContent('<bq-button>Button</bq-button>');

    const element = await page.find('bq-button');
    expect(element.shadowRoot).not.toBeNull();
  });

  it('should trigger bqClick', async () => {
    const page = await newE2EPage();
    await page.setContent('<bq-button>Button</bq-button>');

    const bqFocus = await page.spyOnEvent('bqFocus');
    const bqClick = await page.spyOnEvent('bqClick');

    const element = await page.find('bq-button >>> [part="button"]');
    await element.click();

    expect(bqFocus).toHaveReceivedEventTimes(1);
    expect(bqClick).toHaveReceivedEventTimes(1);
  });
});

Querying inside shadow DOM

Use the >>> deep-pierce selector to query elements inside a shadow root:
// Find the internal <button> or <a> element via its CSS part
const button = await page.find('bq-button >>> [part="button"]');

What to test

Every new component should cover these scenarios:
  • Renders — the component mounts and has the hydrated class.
  • Shadow root — the shadow DOM is present.
  • Props — changing a prop updates the rendered output.
  • Events — user interactions fire the expected bq-prefixed events.
  • Accessibility — keyboard navigation works (Tab, Enter, Space).
  • Disabled / loading states — interactions are blocked when appropriate.
  • Slots — slot content is rendered correctly.
When adding tests for an existing component, follow the existing test patterns in that component’s __tests__/ directory.

Test configuration

The project-level Jest config delegates to NX’s project configuration:
// jest.config.ts
import { getJestProjectsAsync } from '@nx/jest';

export default async () => ({
  projects: await getJestProjectsAsync(),
});
Each package (e.g., packages/beeq) has its own jest.config.ts that inherits from a shared preset. You generally do not need to modify these files when adding tests for a component.

Build docs developers (and LLMs) love