Testing Web Components — Complete Guide
DodaTech
Updated 2026-06-28
2 min read
In this tutorial, you will learn about Testing Web Components. We cover key concepts, practical examples, and best practices to help you master this topic.
Testing Web Components involves unit tests with Jest, DOM tests with testing-library, and visual regression tests for Shadow Dom rendered output.
What You'll Learn
- How to unit test custom element classes
- How to test shadow DOM rendering
- How to test custom events
- How to test attribute reactivity
Why It Matters
Web Components are DOM-native, so testing requires a DOM environment. Jest with happy-dom or @web/test-runner with Playwright provides the environment.
flowchart LR A[Test Types] --> B[Unit Tests] A --> C[DOM Tests] A --> D[Visual Tests] B --> E[Jest] C --> F[@open-wc/testing] D --> G[Percy/Chromatic]
Setting Up Tests
// Using @open-wc/testing with Web Test Runner
import { fixture, expect } from '@open-wc/testing';
import '../src/my-component.js';
describe('MyComponent', () => {
it('renders with default content', async () => {
const el = await fixture('<my-component></my-component>');
expect(el.shadowRoot.textContent).to.include('Hello');
});
it('reflects attribute changes', async () => {
const el = await fixture('<my-component name="World"></my-component>');
expect(el.shadowRoot.querySelector('.name').textContent).to.equal('World');
});
it('dispatches event on click', async () => {
const el = await fixture('<my-component></my-component>');
const spy = sinon.spy();
el.addEventListener('custom-event', spy);
el.shadowRoot.querySelector('button').click();
expect(spy).to.have.been.calledOnce;
});
it('updates on property change', async () => {
const el = await fixture('<my-component></my-component>');
el.data = { value: 42 };
await el.updateComplete;
expect(el.shadowRoot.textContent).to.include('42');
});
});
Testing Shadow DOM
import { fixture, expect } from '@open-wc/testing';
describe('Shadow DOM Tests', () => {
it('styles are encapsulated', async () => {
const el = await fixture('<styled-component></styled-component>');
const style = el.shadowRoot.querySelector('style');
expect(style.textContent).to.include(':host');
});
it('slots project content', async () => {
const el = await fixture(`
<slot-component>
<span slot="title">Test Title</span>
</slot-component>
`);
const slot = el.shadowRoot.querySelector('slot[name="title"]');
const assigned = slot.assignedNodes();
expect(assigned[0].textContent).to.equal('Test Title');
});
});
Common Mistakes
- Not awaiting fixture() — custom elements need time to upgrade
- Testing implementation details instead of behavior
- Not cleaning up after tests (memory leaks from custom elements)
Practice Questions
- What tool provides a DOM environment for testing Web Components? @open-wc/testing with Web Test Runner.
- Why must you await fixture()? To allow the browser to upgrade the custom element before testing.
Mini Project
Set up a test suite for a previously built component. Write tests for rendering, attribute changes, event dispatching, and slot projection. Run tests in headless Chrome.
What's Next
Lesson 19: Lit Element
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro