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
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.