feat(core): support global fakeAsync functionality across multiple test cases. #40611
Conversation
|
What happens when developer forgets to invoke An alternative approach may be something as shown below. Have you consider it? What do you think are advantages/disadvantages of the two approaches?
|
|
@mhevery, yeah, I like your idea,
I will update the PR |
ee3ccbb
to
b599041
b599041
to
c36741a
aio/content/examples/testing/src/app/auth/auth.component.spec.ts
Outdated
Show resolved
Hide resolved
aio/content/examples/testing/src/app/auth/auth.component.spec.ts
Outdated
Show resolved
Hide resolved
aio/content/examples/testing/src/app/auth/auth.component.spec.ts
Outdated
Show resolved
Hide resolved
|
By the way, should the hooks be |
c36741a
to
17582fd
|
@petebacondarwin , yes, you are right, |
72fba02
to
56fd0d6
…ach()` hooks functions. Close #40387 Wrap the `fakeAsync()` with the `beforeEach()/afterEach()` hooks. For example, we have a Component like this. @component({...}) export class AppComponent { timerId: number; ngOnInit() { this.timerId = setTimeout(() => {}); } ngOnDestroy() { clearTimeout(this.timerId); } } And without hook functions, we need to write test like this. describe('AppComponent test', () => { let fixture: ComponentFixture<AppComponent>; beforeEach(() => { ... fixture = TestBed.createComponent(AppComponent); }); it('test case1', fakeAsync(() => { fixture.detectChanges(); // do some test with fixture fixture.destroy(); })); it('test case2', fakeAsync(() => { fixture.detectChanges(); // do some test with fixture fixture.destroy(); })); }); We need to call `fixture.destroy()` inside each tests, since each `it()` use it's own fakeAsync() and we need to clean up the timerId created in that FakeAsyncZone. With the hook functions, we can write case in this way. describe('AppComponent test', () => { let fixture: ComponentFixture<AppComponent>; const fakeAsyncWithFixture = fakeAsync.wrap({ beforeEach: () => { fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); } afterEach: () => fixture.destroy(); }); it('test case1', fakeAsyncWithFixture(() => { // do some test with fixture })); it('test case2', fakeAsyncWithFixture(() => { // do some test with fixture })); }); Also the wrap() function support nesting. describe('AppComponent test', () => { let fixture: ComponentFixture<AppComponent>; const fakeAsyncWithFixture = fakeAsync.wrap({ beforeEach: () => { fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); } afterEach: () => fixture.destroy(); }); it('test case1', fakeAsyncWithFixture(() => { // do some test with fixture })); it('test case2', fakeAsyncWithFixture(() => { // do some test with fixture })); describe('AppComponent sub test: auth test', () => { const fakeAsyncNested = fakeAsyncWithFeature.wrap({ beforeEach: () => fixture.componentInstance.login(), afterEach: () => fixture.componentInstance.logout(); }); it('should show user info', () => { // do some test with fixture with authenticated user. }); }); }); This feature is useful when we want to do some common initial/cleanup when the component has some `async` tasks (especially `setInterval`) running by 3rd party library.
d34964d
to
fe770f6
|
You can preview fe770f6 at https://pr40611-fe770f6.ngbuilds.io/. |
In the previous commit, `zone.js` provides a new API `fakeAsync.wrap()` to support `hooks` of `fakeAsync()` to allow user to write common `initial`/'cleanup` logic. This commit add this new `wrap()` API to `@angular/core/testing`.
fe770f6
to
0f8d2ac
|
You can preview 0f8d2ac at https://pr40611-0f8d2ac.ngbuilds.io/. |

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

Close #40387
Enable global
fakeAsync()feature by introducing two new functions.beginFakeAsync()andendFakeAsync().Motivation
Consider the similar function from
jest.useFakeTimers(), we can write test cases like this.So with
jest.useFakeTimers(), all the following tests are automatically using the fake timers, and the developers can write the commoninit,cleanuplogic inbeforeEach()/afterEach().But with
fakeAsync(), we can not do the same thing for now.For example, we have a Component like this.
We need to call
fixture.destroy()inside each tests, since each it() useit's own fakeAsync() and we need to clean up the timerId created in that
FakeAsyncZoneSpec. Otherwise the
fakeAsync()will throwthere are still pending timerserror.Solution
So in this PR, there are two functions are introduced.
beginFakeAsync()begin fakeAsync globally, so we can use share one FakeAsyncZoneSpec
instance across multiple test cases.
With this feature, we can do some common cleanup in afterEach().
With the
beginFakeAsync(), we can write case in this way.This feature will be useful when we want to do some global cleanup
in
afterEach()when the component have someasynctasks(especially
setInterval) running by 3rd party library.