src/Umbraco.Web.UI.Client/docs/testing.md
← Umbraco Backoffice | ← Monorepo Root
Unit/Component Testing:
@web/test-runner - Fast test runner for web components@open-wc/testing - Testing utilities, includes Chai assertions@types/chai - Assertion library@types/mocha - Test framework (used by @web/test-runner)@web/test-runner-playwright - Browser launcherelement-internals-polyfill - Polyfill for form-associated custom elementsE2E Testing:
@playwright/test - End-to-end testing in real browsersTest Utilities:
@umbraco-cms/internal/test-utils - Shared test utilitiessrc/mocks/data/ - Test datasrc/
├── **/*.test.ts # Unit tests co-located with source
├── mocks/
│ ├── data/ # Mock data & in-memory databases
│ └── handlers/ # MSW request handlers
├── examples/
│ └── **/*.test.ts # Example tests
└── utils/
└── test-utils.ts # Shared test utilities
e2e/
├── **/*.spec.ts # Playwright E2E tests
└── fixtures/ # E2E test fixtures
describe('UmbMyComponent', () => {
describe('initialization', () => {
it('should create element', async () => {
// test
});
it('should set default properties', async () => {
// test
});
});
describe('user interactions', () => {
it('should emit event when button clicked', async () => {
// test
});
});
});
it('should do something', async () => {
// Arrange - Set up test data and conditions
const element = await fixture<UmbMyElement>(html`<umb-my-element></umb-my-element>`);
const spy = sinon.spy();
element.addEventListener('change', spy);
// Act - Perform the action
element.value = 'new value';
await element.updateComplete;
// Assert - Verify the results
expect(spy.calledOnce).to.be.true;
expect(element.value).to.equal('new value');
});
What to Test:
What NOT to Test:
Best Practices:
Web Component Testing:
import { fixture, html, expect } from '@open-wc/testing';
import { UmbMyElement } from './my-element.element';
describe('UmbMyElement', () => {
let element: UmbMyElement;
beforeEach(async () => {
element = await fixture(html`<umb-my-element></umb-my-element>`);
});
it('should render', () => {
expect(element).to.exist;
expect(element.shadowRoot).to.exist;
});
it('should be accessible', async () => {
await expect(element).to.be.accessible();
});
});
Integration tests verify interactions between multiple components/systems:
describe('UmbContentRepository', () => {
let repository: UmbContentRepository;
let mockContext: UmbMockContext;
beforeEach(() => {
mockContext = new UmbMockContext();
repository = new UmbContentRepository(mockContext);
});
it('should fetch and cache content', async () => {
const result = await repository.requestById('content-123');
expect(result.data).to.exist;
// Verify caching behavior
const cached = await repository.requestById('content-123');
expect(cached.data).to.equal(result.data);
});
});
E2E tests with Playwright:
import { test, expect } from '@playwright/test';
test.describe('Content Editor', () => {
test('should create new document', async ({ page }) => {
await page.goto('/');
await page.click('[data-test="create-document"]');
await page.fill('[data-test="document-name"]', 'My New Page');
await page.click('[data-test="save"]');
await expect(page.locator('[data-test="success-notification"]')).toBeVisible();
});
});
MSW (Mock Service Worker) for API mocking:
import { rest } from 'msw';
export const handlers = [
rest.get('/umbraco/management/api/v1/document/:id', (req, res, ctx) => {
const { id } = req.params;
return res(
ctx.json({
id,
name: 'Test Document',
// ... mock data
})
);
}),
];
Context Mocking:
import { UmbMockContext } from '@umbraco-cms/internal/test-utils';
const mockContext = new UmbMockContext();
mockContext.provideContext(UMB_AUTH_CONTEXT, mockAuthContext);
Local Development:
# Run all tests once
npm test
# Run in watch mode
npm run test:watch
# Run with dev config (faster, less strict)
npm run test:dev
# Run in watch mode with dev config
npm run test:dev-watch
# Run specific test file pattern
npm test -- --files "**/my-component.test.ts"
E2E Tests:
# Run E2E tests
npm run test:e2e
# Run in headed mode (see browser)
npx playwright test --headed
# Run specific test
npx playwright test e2e/content-editor.spec.ts
# Debug mode
npx playwright test --debug
CI/CD:
Coverage reporting is currently disabled (see web-test-runner.config.mjs):
/* TODO: fix coverage report
coverageConfig: {
reporters: ['lcovonly', 'text-summary'],
},
*/
What to Exclude from Coverage: