Testing components

Testing components in Aurelia 2 is a straightforward process thanks to the framework's design and the utilities provided by the @aurelia/testing package. This guide will walk you through the steps to test your components effectively, ensuring they work as expected within the context of a view.

In Aurelia, a component typically consists of a view (HTML) and a view model (JavaScript or TypeScript). To ensure the quality and correctness of your components, you should write tests that cover both aspects. Testing components involves checking that the view renders correctly with given data and that the view model behaves as intended when interacting with the view.

Testing Strategy

When testing components, we will focus on integration tests that involve both the view and view model. This approach allows us to verify the component as a whole, as it would function within an Aurelia application.

Example Component

For demonstration purposes, we will use a simple PersonDetail component with bindable properties name and age.

person-detail.ts
import { bindable } from 'aurelia';

export class PersonDetail {
    @bindable name: string;
    @bindable age: number;
}
person-detail.html
<template>
    <p>Person is called ${name} and is ${age} years old.</p>
</template>

Writing the Test

We aim to test that the PersonDetail component renders the expected text when provided with name and age properties.

Test Setup

Before writing the test, ensure your environment is correctly set up for testing. Refer to the Overview section for details on how to initialize the Aurelia testing platform.

Test Implementation

Create a test file for your component, such as person-detail.spec.ts, and implement your tests using the syntax of your chosen test runner. The following example uses Jest:

In this example, createFixture is used to instantiate the component with a test context, binding name and age to specified values. We then assert that the component's text content includes the correct information. After the test completes, stop(true) cleans up the component instance to avoid memory leaks and ensure test isolation.

Testing Components with Dependencies

If your component has dependencies, such as services or other custom elements, you'll need to register these within the Aurelia testing container.

Example with a Dependency

Assume PersonDetail depends on a PersonFormatter service:

To test this component, you can create a mock PersonFormatter and register it with the Aurelia container:

In the test above, we use Jest's jest.fn() to create a mock implementation of PersonFormatter. We then verify that the mock's format method is called with the correct arguments and that the component's text content includes the formatted details.

Advanced Testing Patterns

Testing Component Lifecycle

Components have lifecycle hooks that can be tested to ensure proper behavior:

Test the lifecycle hooks:

Testing Component Events and Communication

Test components that emit custom events:

Test event publishing:

Testing Async Operations

Test components with async operations using task queue utilities:

Test async operations:

Testing State Management Integration

Test components that use state management:

Test state bindings:

Testing Conditional Rendering

Test components with conditional rendering logic:

With template:

Test conditional rendering:

Testing Component Performance

Test component render performance and memory usage:

Best Practices for Advanced Testing

1. Test Organization

  • Group related tests using describe blocks

  • Use descriptive test names that explain the behavior being tested

  • Follow the AAA pattern: Arrange, Act, Assert

2. Async Testing

  • Always use await with startPromise and stop(true)

  • Use tasksSettled() when testing async operations

  • Handle promise rejections properly in tests

  • Note: tearDown() is deprecated, use stop(true) instead

3. Mocking Strategies

  • Mock external dependencies using Registration.instance from @aurelia/kernel

  • Use Jest spies to verify method calls

  • Mock only what's necessary for the test

  • Register mocks in the fourth parameter of createFixture

4. Performance Testing

  • Use performance.now() for timing measurements

  • Test with realistic data sizes

  • Monitor memory usage in long-running tests

  • Always use stop(true) for proper cleanup

5. Error Handling

  • Test both success and failure scenarios

  • Verify error messages and error states

  • Test error recovery mechanisms

Next Steps

For more sophisticated testing scenarios, see:

Conclusion

Testing Aurelia components involves setting up a test environment, creating fixtures, and writing assertions based on your expectations. By following these patterns and best practices, you can ensure that your components are reliable, performant, and maintainable. Remember to clean up after your tests to maintain a clean test environment and to avoid any side effects between tests.

The patterns shown here cover lifecycle testing, event handling, async operations, state management, conditional rendering, and basic performance testing. For more advanced testing techniques and comprehensive API coverage, refer to the Advanced Testing guide.

Complete Fixture API Reference

The createFixture function returns a comprehensive fixture object with many utility methods for testing:

Query Methods

Assertion Methods

Event Triggering

Utility Methods

Error Testing Patterns

Test error conditions and recovery:

Testing Custom Events

Last updated

Was this helpful?