Quick Reference ("How Do I...")
Practical answers to common testing questions in Aurelia 2.
Table of Contents
Getting Started
How do I set up my test environment?
import { BrowserPlatform } from '@aurelia/platform-browser';
import { setPlatform } from '@aurelia/testing';
export function bootstrapTestEnvironment() {
if (!(globalThis as any).__aureliaTestPlatform__) {
const platform = new BrowserPlatform(window);
setPlatform(platform);
BrowserPlatform.set(globalThis, platform);
(globalThis as any).__aureliaTestPlatform__ = platform;
}
}
// Call once globally
bootstrapTestEnvironment();Configure Jest (jest.config.js):
module.exports = {
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
testEnvironment: 'jsdom',
};Configure Mocha (test/setup.ts):
import './test-bootstrap';
// Import this file at the top of each test file or via --requireHow do I create a simple test fixture?
import { createFixture } from '@aurelia/testing';
const { component, startPromise, stop } = createFixture(
'<div>${message}</div>',
class App { message = 'Hello World'; }
);
await startPromise;
// ... assertions
await stop(true);How do I test a component with a template file?
import { createFixture } from '@aurelia/testing';
import { MyComponent } from './my-component';
const { appHost, startPromise, stop } = createFixture(
'<my-component value.bind="testValue"></my-component>',
class App { testValue = 'test'; },
[MyComponent] // Register your component
);
await startPromise;
expect(appHost.textContent).toContain('test');
await stop(true);How do I use the builder pattern for fixtures?
const fixture = await createFixture
.component(class App { items = [1, 2, 3]; })
.html`<div repeat.for="i of items">${i}</div>`
.deps(MyService, MyCustomElement)
.build()
.started;
fixture.assertText('123');
await fixture.stop(true);Basic Component Testing
How do I test that a component renders correctly?
const { assertText } = await createFixture
.html`<div>${message}</div>`
.component(class { message = 'Hello'; })
.build()
.started;
assertText('Hello');How do I test bindable properties?
import { MyComponent } from './my-component';
const { component, getBy } = await createFixture
.html`<my-component value.bind="testValue"></my-component>`
.component(class App { testValue = 'initial'; })
.deps(MyComponent)
.build()
.started;
expect(getBy('my-component').textContent).toContain('initial');
// Change the value
component.testValue = 'updated';
expect(getBy('my-component').textContent).toContain('updated');How do I test computed properties?
const { component, assertText } = await createFixture
.html`<div>\${fullName}</div>`
.component(class {
firstName = 'John';
lastName = 'Doe';
get fullName() { return `\${this.firstName} \${this.lastName}`; }
})
.build()
.started;
assertText('John Doe');
component.firstName = 'Jane';
assertText('Jane Doe');How do I test conditional rendering?
const { component, assertText, assertHtml } = await createFixture
.html`<div if.bind="show">Visible</div>`
.component(class { show = true; })
.build()
.started;
assertText('Visible');
component.show = false;
assertHtml(''); // Empty when hiddenHow do I test repeat.for?
const { component, assertText } = await createFixture
.html`<div repeat.for="item of items">\${item}</div>`
.component(class { items = ['a', 'b', 'c']; })
.build()
.started;
assertText('abc');
// Test array mutation
component.items.push('d');
assertText('abcd');
// Test array replacement
component.items = ['x', 'y'];
assertText('xy');DOM Interaction & Assertions
How do I assert text content?
const { assertText } = fixture;
// Assert text of root element
assertText('Expected text');
// Assert text of specific element
assertText('.my-class', 'Expected text');
// Assert text contains substring
assertTextContain('partial text');How do I assert HTML content?
const { assertHtml } = fixture;
// Assert innerHTML of root
assertHtml('<div>Hello</div>');
// Assert innerHTML of specific element
assertHtml('.container', '<span>Content</span>');
// With options
assertHtml('.container', '<div>Text</div>', { compact: true });How do I query DOM elements?
const { getBy, getAllBy, queryBy } = fixture;
// Get single element (throws if not found or multiple)
const button = getBy('button');
// Get all matching elements
const items = getAllBy('.item');
expect(items.length).toBe(3);
// Query (returns null if not found)
const optional = queryBy('.optional');
expect(optional).toBeNull();How do I assert CSS classes?
const { assertClass, assertClassStrict } = fixture;
// Check element has classes (can have others)
assertClass('.my-element', 'active', 'selected');
// Check element has ONLY these classes
assertClassStrict('.my-element', 'active', 'selected');How do I assert attributes?
const { assertAttr, assertAttrNS } = fixture;
// Assert attribute value
assertAttr('input', 'type', 'text');
assertAttr('a', 'href', '/home');
// Assert namespaced attribute
assertAttrNS('svg', 'http://www.w3.org/2000/svg', 'viewBox', '0 0 100 100');How do I assert computed styles?
const { assertStyles } = fixture;
assertStyles('.my-element', {
display: 'flex',
color: 'rgb(255, 0, 0)',
fontSize: '16px'
});How do I assert form values?
const { assertValue, assertChecked } = fixture;
// Assert input value
assertValue('input[name="username"]', 'john');
// Assert checkbox state
assertChecked('input[type="checkbox"]', true);Testing with Dependencies
How do I inject a service into my test component?
import { resolve } from 'aurelia';
import { MyService } from './my-service';
const { component } = await createFixture
.component(class App {
private service = resolve(MyService);
get data() { return this.service.getData(); }
})
.html`<div>\${data}</div>`
.deps(MyService)
.build()
.started;How do I mock a service?
import { Registration } from '@aurelia/kernel';
class MockMyService {
getData() { return 'mock data'; }
}
const { component } = await createFixture
.component(class App {
private service = resolve(IMyService);
})
.html`<div>\${service.getData()}</div>`
.deps(
Registration.instance(IMyService, new MockMyService())
)
.build()
.started;How do I test with custom elements/attributes?
import { MyButton } from './my-button';
import { HighlightAttribute } from './highlight';
const fixture = await createFixture
.html`
<my-button value="Click">
<div highlight.bind="color">Text</div>
</my-button>
`
.component(class { color = 'yellow'; })
.deps(MyButton, HighlightAttribute)
.build()
.started;How do I test with value converters?
import { UppercaseValueConverter } from './uppercase';
const fixture = await createFixture
.html`<div>\${message | uppercase}</div>`
.component(class { message = 'hello'; })
.deps(UppercaseValueConverter)
.build()
.started;
fixture.assertText('HELLO');How do I register multiple dependencies?
const fixture = await createFixture
.html`...`
.component(class App {})
.deps(
MyComponent,
MyService,
MyValueConverter,
MyAttribute,
Registration.singleton(ILogger, ConsoleLogger)
)
.build()
.started;Async Testing
How do I wait for component initialization?
const fixture = createFixture(
'<my-component></my-component>',
class App {},
[MyComponent]
);
// Wait for startup to complete
await fixture.startPromise;
// OR use .started
const fixture = await createFixture
.html`<my-component></my-component>`
.deps(MyComponent)
.build()
.started;How do I test async lifecycle hooks?
let bindingComplete = false;
const { component } = await createFixture
.component(class {
async binding() {
await new Promise(resolve => setTimeout(resolve, 100));
bindingComplete = true;
}
})
.html`<div>Ready</div>`
.build()
.started;
// By the time .started resolves, binding() has completed
expect(bindingComplete).toBe(true);How do I test data loading?
const { component, assertText } = await createFixture
.component(class {
data = '';
async attached() {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 50));
this.data = 'Loaded';
}
})
.html`<div>\${data}</div>`
.build()
.started;
// After .started, attached() has completed
assertText('Loaded');How do I test task queue operations?
import { IPlatform } from '@aurelia/runtime-html';
const { component, platform, assertText } = await createFixture
.component(class {
message = 'initial';
updateMessage() {
platform.taskQueue.queueTask(() => {
this.message = 'updated';
});
}
})
.html`<div>\${message}</div>`
.build()
.started;
component.updateMessage();
assertText('initial'); // Not updated yet
await platform.taskQueue.yield();
assertText('updated'); // Now updatedEvents & User Interaction
How do I trigger a click event?
const { getBy, trigger, component } = fixture;
let clicked = false;
component.handleClick = () => { clicked = true; };
trigger.click('button');
expect(clicked).toBe(true);
// With event init options
trigger.click('button', { bubbles: true, cancelable: true });How do I type into an input?
const { type, assertValue, component } = fixture;
// Type into input (sets value and triggers 'input' event)
type('input[name="username"]', 'john_doe');
// Verify value was set
assertValue('input[name="username"]', 'john_doe');
// Verify binding updated
expect(component.username).toBe('john_doe');How do I trigger keyboard events?
const { trigger } = fixture;
trigger.keydown('input', { key: 'Enter', code: 'Enter' });
trigger.keydown('input', { key: 'Escape', code: 'Escape' });
trigger.keyup('input', { key: 'a', code: 'KeyA' });How do I trigger form submission?
const { trigger, component } = fixture;
let submitted = false;
component.onSubmit = () => { submitted = true; };
trigger('form', new Event('submit'));
expect(submitted).toBe(true);How do I trigger custom events?
const { trigger, createEvent, component } = fixture;
component.onCustom = (event) => {
component.receivedData = event.detail.data;
};
const customEvent = createEvent('custom-event', {
detail: { data: 'test' }
});
trigger('.my-element', customEvent);
expect(component.receivedData).toBe('test');How do I test two-way binding with events?
const { component, type, assertValue } = await createFixture
.html`<input value.two-way="name">`
.component(class { name = 'initial'; })
.build()
.started;
assertValue('input', 'initial');
// User types
type('input', 'updated');
expect(component.name).toBe('updated');
// Programmatic change
component.name = 'changed';
assertValue('input', 'changed');Router Testing
How do I test router navigation?
import { IRouter } from '@aurelia/router';
import { resolve } from 'aurelia';
const { component } = await createFixture
.component(class {
private router = resolve(IRouter);
async navigateToHome() {
await this.router.load('/home');
}
})
.html`<div>Content</div>`
.build()
.started;
await component.navigateToHome();
expect(component.router.currentRoute?.path).toBe('/home');How do I test route parameters?
import { IRouter } from '@aurelia/router';
// Setup router with routes
const fixture = await createFixture
.component(class App {
static routes = [
{ path: 'users/:id', component: UserDetail }
];
})
.html`<au-viewport></au-viewport>`
.deps(UserDetail)
.build()
.started;
await fixture.component.router.load('users/123');
// Verify route parameter
const userDetail = fixture.getBy('user-detail');
expect(userDetail.userId).toBe('123');How do I test route hooks?
export class MyComponent {
canLoad(params, next, current) {
// Test this hook
return params.id !== 'forbidden';
}
async loading(params, next, current) {
// Test async loading
this.data = await fetchData(params.id);
}
}
// In test
const fixture = await createFixture
.component(MyComponent)
.html`<div>\${data}</div>`
.build()
.started;
// Manually invoke hooks if needed
const canProceed = fixture.component.canLoad({ id: '123' }, null, null);
expect(canProceed).toBe(true);Forms & Input Testing
How do I test text input binding?
const { component, type, assertValue } = await createFixture
.html`<input value.bind="username">`
.component(class { username = ''; })
.build()
.started;
type('input', 'john_doe');
expect(component.username).toBe('john_doe');
assertValue('input', 'john_doe');How do I test checkbox binding?
const { component, getBy, trigger } = await createFixture
.html`<input type="checkbox" checked.bind="accepted">`
.component(class { accepted = false; })
.build()
.started;
expect(component.accepted).toBe(false);
trigger.click('input[type="checkbox"]');
expect(component.accepted).toBe(true);
expect(getBy('input').checked).toBe(true);How do I test radio button binding?
const { component, trigger } = await createFixture
.html`
<input type="radio" value="a" checked.bind="choice">
<input type="radio" value="b" checked.bind="choice">
`
.component(class { choice = 'a'; })
.build()
.started;
expect(component.choice).toBe('a');
trigger.click('input[value="b"]');
expect(component.choice).toBe('b');How do I test select dropdown binding?
const { component, getBy, trigger } = await createFixture
.html`
<select value.bind="selected">
<option value="1">One</option>
<option value="2">Two</option>
</select>
`
.component(class { selected = '1'; })
.build()
.started;
const select = getBy('select') as HTMLSelectElement;
select.value = '2';
trigger('select', new Event('change'));
expect(component.selected).toBe('2');How do I test form validation?
import { ValidationController } from '@aurelia/validation';
const { component } = await createFixture
.component(class {
private controller = resolve(ValidationController);
username = '';
async submit() {
const result = await this.controller.validate();
return result.valid;
}
})
.html`<input value.bind="username & validate">`
.build()
.started;
const isValid = await component.submit();
expect(isValid).toBe(false); // Empty username
component.username = 'john';
const isValidNow = await component.submit();
expect(isValidNow).toBe(true);Lifecycle Testing
How do I test lifecycle hooks?
const calls: string[] = [];
const { component } = await createFixture
.component(class {
binding() { calls.push('binding'); }
bound() { calls.push('bound'); }
attaching() { calls.push('attaching'); }
attached() { calls.push('attached'); }
})
.html`<div>Test</div>`
.build()
.started;
expect(calls).toEqual(['binding', 'bound', 'attaching', 'attached']);How do I test detaching/unbinding?
const calls: string[] = [];
const fixture = await createFixture
.component(class {
detaching() { calls.push('detaching'); }
unbinding() { calls.push('unbinding'); }
})
.html`<div>Test</div>`
.build()
.started;
await fixture.stop(true);
expect(calls).toEqual(['detaching', 'unbinding']);How do I test @observable?
import { observable } from 'aurelia';
const { component } = await createFixture
.component(class {
@observable count = 0;
countChanged(newValue, oldValue) {
this.changeLog = { newValue, oldValue };
}
changeLog = { newValue: 0, oldValue: 0 };
})
.html`<div>\${count}</div>`
.build()
.started;
component.count = 5;
expect(component.changeLog).toEqual({ newValue: 5, oldValue: 0 });How do I test component dispose?
let disposed = false;
const fixture = await createFixture
.component(class {
dispose() {
disposed = true;
}
})
.html`<div>Test</div>`
.build()
.started;
await fixture.stop(true); // true = dispose
expect(disposed).toBe(true);Mocking & Spies
How do I create a spy function?
import { createSpy } from '@aurelia/testing';
const spy = createSpy();
spy('arg1', 'arg2');
spy('arg3');
expect(spy.calls.length).toBe(2);
expect(spy.calls[0].args).toEqual(['arg1', 'arg2']);
expect(spy.calls[1].args).toEqual(['arg3']);How do I spy on a method?
const service = new MyService();
const originalMethod = service.getData;
const calls: any[] = [];
service.getData = (...args) => {
calls.push(args);
return originalMethod.call(service, ...args);
};
service.getData('test');
expect(calls.length).toBe(1);
expect(calls[0]).toEqual(['test']);How do I use mock objects?
import { MockServiceLocator } from '@aurelia/testing';
const mockLocator = new MockServiceLocator();
mockLocator.registerService(IMyService, new MyMockService());
const service = mockLocator.get(IMyService);
expect(service).toBeInstanceOf(MyMockService);How do I verify method calls?
import { recordCalls, stopRecordingCalls } from '@aurelia/testing';
const service = new MyService();
const calls = recordCalls(service, 'getData');
service.getData('param1');
service.getData('param2');
stopRecordingCalls(calls);
expect(calls.length).toBe(2);
expect(calls[0].args).toEqual(['param1']);
expect(calls[1].args).toEqual(['param2']);Common Patterns
How do I test error handling?
const { component } = await createFixture
.component(class {
error = '';
async loadData() {
try {
this.data = await fetchData();
} catch (e) {
this.error = e.message;
}
}
})
.html`<div>\${error}</div>`
.build()
.started;
// Trigger error
await component.loadData();
expect(component.error).toBeTruthy();How do I test conditional display?
const { component, assertText, assertHtml } = await createFixture
.component(class {
loading = true;
data = null;
})
.html`
<div if.bind="loading">Loading...</div>
<div if.bind="data">Data: \${data}</div>
`
.build()
.started;
assertText('Loading...');
component.loading = false;
component.data = 'Ready';
assertText('Data: Ready');How do I test promise templates?
const { assertText } = await createFixture
.component(class {
dataPromise = Promise.resolve('async data');
})
.html`
<div promise.bind="dataPromise">
<span pending>Loading...</span>
<span then.from-view="data">\${data}</span>
</div>
`
.build()
.started;
// Wait for promise resolution
await new Promise(resolve => setTimeout(resolve, 10));
assertText('async data');How do I test dynamic composition?
import { au-compose } from 'aurelia';
const { component } = await createFixture
.component(class {
currentView = MyComponent;
currentModel = { data: 'test' };
})
.html`
<au-compose component.bind="currentView" model.bind="currentModel">
</au-compose>
`
.deps(MyComponent)
.build()
.started;
// Verify composed component
const composed = fixture.getBy('my-component');
expect(composed).toBeTruthy();Troubleshooting
Why is "Platform not set" error appearing?
Problem: Test runs before platform initialization.
Solution: Ensure bootstrapTestEnvironment() is called before createFixture():
// In test setup file
bootstrapTestEnvironment();
// OR in beforeAll
beforeAll(() => {
bootstrapTestEnvironment();
});Why is my component not updating after property change?
Problem: Async task queue hasn't flushed.
Solution: Wait for task queue:
const { component, platform, assertText } = fixture;
component.value = 'new';
// Option 1: Wait for task queue
await platform.taskQueue.yield();
// Option 2: Use platform.domQueue
await platform.domQueue.yield();
assertText('new');Why is "window is not defined" error appearing?
Problem: Test environment doesn't provide browser APIs.
Solution: Configure test runner to use jsdom:
// jest.config.js
module.exports = {
testEnvironment: 'jsdom'
};Why is my test fixture not cleaning up?
Problem: Using deprecated tearDown() or not calling stop().
Solution: Always use stop(true):
const fixture = await createFixture
.html`<div>Test</div>`
.build()
.started;
// ... tests
// Cleanup (always in afterEach or after test)
await fixture.stop(true); // true = disposeWhy can't I find my element with getBy()?
Problem: Element not rendered yet or selector is wrong.
Solution: Verify element exists and check selector:
const { getBy, queryBy, printHtml } = fixture;
// Use queryBy to check if element exists
const el = queryBy('.my-class');
if (!el) {
// Debug: print HTML to see what's rendered
printHtml();
}
// Use correct selector
getBy('.my-class'); // Class selector
getBy('#my-id'); // ID selector
getBy('button'); // Tag selector
getBy('[data-test="value"]'); // Attribute selectorWhy are my lifecycle hooks not firing?
Problem: Fixture not started or component not activated.
Solution: Always await .started:
const fixture = await createFixture
.component(class {
attached() {
this.ready = true;
}
ready = false;
})
.html`<div>Test</div>`
.build()
.started; // Important!
expect(fixture.component.ready).toBe(true);How do I debug what's rendered?
Use printHtml() to log current DOM state:
const { printHtml, assertText } = fixture;
printHtml(); // Logs innerHTML to console
// Or manually inspect
console.log(fixture.appHost.innerHTML);
console.log(fixture.testHost.innerHTML);Why is my mock not being used?
Problem: Service registered incorrectly or after component creation.
Solution: Register mock before building fixture:
// Correct order
const fixture = await createFixture
.component(class App {
private service = resolve(IMyService);
})
.html`<div></div>`
.deps(
Registration.instance(IMyService, mockService) // Register first!
)
.build()
.started;See Also
Testing Components - Detailed component testing guide
Testing Attributes - Custom attribute testing
Testing Value Converters - Value converter testing
Fluent API - Advanced fixture builder API
Mocks and Spies - Detailed mocking strategies
Advanced Testing - Advanced techniques
Last updated
Was this helpful?