Class AngularContext

Provides the foundation for an opinionated testing pattern.

  • All test are run in the fakeAsync zone. This gives you full control over the timing of everything by default.
  • Variables that are initialized for each test exist in a context that is thrown away, so they cannot leak between tests.
  • Clearly separates initialization code from the test itself.
  • Gives control over the simulated date & time with a single line of code.
  • Automatically includes provideHttpClientTesting() to stub network requests without additional setup.
  • Always verifies that no unexpected http requests were made.
  • Automatically discards periodic tasks and flushes pending timers at the end of each test to avoid the error "X timer(s) still in the queue".

This example tests a simple service that uses HttpClient, and is tested by using AngularContext directly. More often AngularContext will be used as a super class. See ComponentContext for more common use cases.

// This is the class we will test.
@Injectable({ providedIn: 'root' })
class MemoriesService {
constructor(private httpClient: HttpClient) {}

getLastYearToday(): Observable<any> {
const datetime = new Date();
datetime.setFullYear(datetime.getFullYear() - 1);
const date = datetime.toISOString().split('T')[0];
return this.httpClient.get(`http://example.com/post-from/${date}`);
}
}

describe('MemoriesService', () => {
// Tests should have exactly 1 variable outside an "it": `ctx`.
let ctx: AngularContext;
beforeEach(() => {
ctx = new AngularContext({ providers: [provideHttpClient()] });
});

it('requests a post from 1 year ago', () => {
// Before calling `run`, set up any context variables this test needs.
ctx.startTime = new Date('2004-02-16T10:15:00.000Z');

// Pass the test itself as a callback to `run()`.
ctx.run(() => {
const httpBackend = ctx.inject(HttpTestingController);
const myService = ctx.inject(MemoriesService);

myService.getLastYearToday().subscribe();

httpBackend.expectOne('http://example.com/post-from/2003-02-16');
});
});
});

Hierarchy (view full)

Constructors

Properties

startTime: Date = ...

Set this before calling run() to mock the time at which the test starts.

Methods

  • This is a hook for subclasses to override. It is called during run(), before the test() callback. This implementation does nothing, but if you override this it is still recommended to call super.init() in case this implementation does something in the future.

    Returns void

  • Gets a service or other injectable from the root injector.

    This implementation is a simple pass-through to TestBed.inject(), but subclasses may provide their own implementation. It is recommended to use this in your tests instead of using TestBed directly.

    Type Parameters

    • T

    Parameters

    • token: AbstractType<T> | InjectionToken<T> | Type<T>

    Returns T

  • Runs test in a fakeAsync zone. It can use async/await, but be sure anything you await is already due to execute (e.g. if a timeout is due in 3 seconds, call .tick(3000) before awaiting its result).

    Also runs the following in this order, all within the same zone:

    1. this.init()
    2. test()
    3. this.verifyPostTestConditions()
    4. this.cleanUp()

    Parameters

    • test: (() => void | Promise<void>)
        • (): void | Promise<void>
        • Returns void | Promise<void>

    Returns void