parent
6c6bc95ac0
commit
ccceff5ecc
|
@ -1,8 +1,7 @@
|
|||
// tslint:disable-next-line:no-unused-variable
|
||||
import { async, fakeAsync, tick } from '@angular/core/testing';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { delay } from 'rxjs/operators';
|
||||
import { interval, of } from 'rxjs';
|
||||
import { delay, take } from 'rxjs/operators';
|
||||
|
||||
describe('Angular async helper', () => {
|
||||
let actuallyDone = false;
|
||||
|
@ -21,49 +20,120 @@ describe('Angular async helper', () => {
|
|||
});
|
||||
|
||||
it('should run async test with task',
|
||||
async(() => { setTimeout(() => { actuallyDone = true; }, 0); }));
|
||||
async(() => { setTimeout(() => { actuallyDone = true; }, 0); }));
|
||||
|
||||
it('should run async test with task', async(() => {
|
||||
const id = setInterval(() => {
|
||||
actuallyDone = true;
|
||||
clearInterval(id);
|
||||
}, 100);
|
||||
}));
|
||||
|
||||
it('should run async test with successful promise', async(() => {
|
||||
const p = new Promise(resolve => { setTimeout(resolve, 10); });
|
||||
p.then(() => { actuallyDone = true; });
|
||||
}));
|
||||
const p = new Promise(resolve => { setTimeout(resolve, 10); });
|
||||
p.then(() => { actuallyDone = true; });
|
||||
}));
|
||||
|
||||
it('should run async test with failed promise', async(() => {
|
||||
const p = new Promise((resolve, reject) => { setTimeout(reject, 10); });
|
||||
p.catch(() => { actuallyDone = true; });
|
||||
}));
|
||||
const p = new Promise((resolve, reject) => { setTimeout(reject, 10); });
|
||||
p.catch(() => { actuallyDone = true; });
|
||||
}));
|
||||
|
||||
// Use done. Cannot use setInterval with async or fakeAsync
|
||||
// See https://github.com/angular/angular/issues/10127
|
||||
// Use done. Can also use async or fakeAsync.
|
||||
it('should run async test with successful delayed Observable', (done: DoneFn) => {
|
||||
const source = of(true).pipe(delay(10));
|
||||
source.subscribe(
|
||||
val => actuallyDone = true,
|
||||
err => fail(err),
|
||||
done
|
||||
);
|
||||
const source = of (true).pipe(delay(10));
|
||||
source.subscribe(val => actuallyDone = true, err => fail(err), done);
|
||||
});
|
||||
|
||||
// Cannot use setInterval from within an async zone test
|
||||
// See https://github.com/angular/angular/issues/10127
|
||||
// xit('should run async test with successful delayed Observable', async(() => {
|
||||
// const source = of(true).pipe(delay(10));
|
||||
// source.subscribe(
|
||||
// val => actuallyDone = true,
|
||||
// err => fail(err)
|
||||
// );
|
||||
// }));
|
||||
// #docregion fake-async-test-tick
|
||||
it('should run timeout callback with delay after call tick with millis', fakeAsync(() => {
|
||||
let called = false;
|
||||
setTimeout(() => { called = true; }, 100);
|
||||
tick(100);
|
||||
expect(called).toBe(true);
|
||||
}));
|
||||
// #enddocregion fake-async-test-tick
|
||||
|
||||
// // Fail message: Error: 1 periodic timer(s) still in the queue
|
||||
// // See https://github.com/angular/angular/issues/10127
|
||||
// xit('should run async test with successful delayed Observable', fakeAsync(() => {
|
||||
// const source = of(true).pipe(delay(10));
|
||||
// source.subscribe(
|
||||
// val => actuallyDone = true,
|
||||
// err => fail(err)
|
||||
// );
|
||||
// #docregion fake-async-test-date
|
||||
it('should get Date diff correctly in fakeAsync', fakeAsync(() => {
|
||||
const start = Date.now();
|
||||
tick(100);
|
||||
const end = Date.now();
|
||||
expect(end - start).toBe(100);
|
||||
}));
|
||||
// #enddocregion fake-async-test-date
|
||||
|
||||
// tick();
|
||||
// }));
|
||||
// #docregion fake-async-test-rxjs
|
||||
it('should get Date diff correctly in fakeAsync with rxjs scheduler', fakeAsync(() => {
|
||||
// need to add `import 'zone.js/dist/zone-patch-rxjs-fake-async'
|
||||
// to patch rxjs scheduler
|
||||
let result = null;
|
||||
of ('hello').pipe(delay(1000)).subscribe(v => { result = v; });
|
||||
expect(result).toBeNull();
|
||||
tick(1000);
|
||||
expect(result).toBe('hello');
|
||||
|
||||
const start = new Date().getTime();
|
||||
let dateDiff = 0;
|
||||
interval(1000).pipe(take(2)).subscribe(() => dateDiff = (new Date().getTime() - start));
|
||||
|
||||
tick(1000);
|
||||
expect(dateDiff).toBe(1000);
|
||||
tick(1000);
|
||||
expect(dateDiff).toBe(2000);
|
||||
}));
|
||||
// #enddocregion fake-async-test-rxjs
|
||||
|
||||
// #docregion fake-async-test-clock
|
||||
describe('use jasmine.clock()', () => {
|
||||
// need to config __zone_symbol__fakeAsyncPatchLock flag
|
||||
// before loading zone.js/dist/zone-testing
|
||||
beforeEach(() => { jasmine.clock().install(); });
|
||||
afterEach(() => { jasmine.clock().uninstall(); });
|
||||
it('should auto enter fakeAsync', () => {
|
||||
// is in fakeAsync now, don't need to call fakeAsync(testFn)
|
||||
let called = false;
|
||||
setTimeout(() => { called = true; }, 100);
|
||||
jasmine.clock().tick(100);
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
});
|
||||
// #enddocregion fake-async-test-clock
|
||||
|
||||
// #docregion async-test-promise-then
|
||||
describe('test jsonp', () => {
|
||||
function jsonp(url: string, callback: Function) {
|
||||
// do a jsonp call which is not zone aware
|
||||
}
|
||||
// need to config __zone_symbol__supportWaitUnResolvedChainedPromise flag
|
||||
// before loading zone.js/dist/zone-testing
|
||||
it('should wait until promise.then is called', async(() => {
|
||||
let finished = false;
|
||||
new Promise((res, rej) => {
|
||||
jsonp('localhost:8080/jsonp', () => {
|
||||
// success callback and resolve the promise
|
||||
finished = true;
|
||||
res();
|
||||
});
|
||||
}).then(() => {
|
||||
// async will wait until promise.then is called
|
||||
// if __zone_symbol__supportWaitUnResolvedChainedPromise is set
|
||||
expect(finished).toBe(true);
|
||||
});
|
||||
}));
|
||||
});
|
||||
// #enddocregion async-test-promise-then
|
||||
|
||||
it('should run async test with successful delayed Observable', async(() => {
|
||||
const source = of (true).pipe(delay(10));
|
||||
source.subscribe(val => actuallyDone = true, err => fail(err));
|
||||
}));
|
||||
|
||||
it('should run async test with successful delayed Observable', fakeAsync(() => {
|
||||
const source = of (true).pipe(delay(10));
|
||||
source.subscribe(val => actuallyDone = true, err => fail(err));
|
||||
|
||||
tick(10);
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
|
@ -356,3 +356,24 @@ If you develop angular locally with `ng serve`, there will be `websocket` connec
|
|||
|
||||
In windows, by default one application can only have 6 websocket connections, <a href="https://msdn.microsoft.com/library/ee330736%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#websocket_maxconn" title="MSDN WebSocket settings">MSDN WebSocket Settings</a>.
|
||||
So if IE was refreshed manunally or automatically by `ng serve`, sometimes, the websocket will not close properly, when websocket connections exceed limitations, `SecurityError` will be thrown, this error will not affect the angular application, you can just restart IE to clear this error, or modify the windows registry to update the limitations.
|
||||
|
||||
## Appendix: test using `fakeAsync()/async()`
|
||||
|
||||
If you use the `fakeAsync()/async()` helper function to run unit tests (for details, read [testing guide](guide/testing#async-test-with-fakeasync)), you need to import `zone.js/dist/zone-testing` in your test setup file.
|
||||
|
||||
<div class="alert is-important">
|
||||
If you create project with `Angular/CLI`, it is already imported in `src/test.ts`.
|
||||
</div>
|
||||
|
||||
And in the earlier versions of `Angular`, the following files were imported or added in your html file:
|
||||
|
||||
```
|
||||
import 'zone.js/dist/long-stack-trace-zone';
|
||||
import 'zone.js/dist/proxy';
|
||||
import 'zone.js/dist/sync-test';
|
||||
import 'zone.js/dist/jasmine-patch';
|
||||
import 'zone.js/dist/async-test';
|
||||
import 'zone.js/dist/fake-async-test';
|
||||
```
|
||||
|
||||
You can still load those files separately, but the order is important, you must import `proxy` before `sync-test`, `async-test`, `fake-async-test` and `jasmine-patch`. And you also need to import `sync-test` before `jasmine-patch`, so it is recommended to just import `zone-testing` instead of loading those separated files.
|
|
@ -1237,6 +1237,8 @@ value becomes available. The test must become _asynchronous_.
|
|||
|
||||
#### Async test with _fakeAsync()_
|
||||
|
||||
To use `fakeAsync()` functionality, you need to import `zone-testing`, for details, please read [setup guide](guide/setup#appendix-test-using-fakeasyncasync).
|
||||
|
||||
The following test confirms the expected behavior when the service returns an `ErrorObservable`.
|
||||
|
||||
<code-example
|
||||
|
@ -1250,7 +1252,7 @@ Note that the `it()` function receives an argument of the following form.
|
|||
fakeAsync(() => { /* test body */ })`
|
||||
```
|
||||
|
||||
The `fakeAsync` function enables a linear coding style by running the test body in a special _fakeAsync test zone_.
|
||||
The `fakeAsync()` function enables a linear coding style by running the test body in a special `fakeAsync test zone`.
|
||||
The test body appears to be synchronous.
|
||||
There is no nested syntax (like a `Promise.then()`) to disrupt the flow of control.
|
||||
|
||||
|
@ -1263,12 +1265,55 @@ You do have to call `tick()` to advance the (virtual) clock.
|
|||
Calling `tick()` simulates the passage of time until all pending asynchronous activities finish.
|
||||
In this case, it waits for the error handler's `setTimeout()`;
|
||||
|
||||
The `tick` function is one of the Angular testing utilities that you import with `TestBed`.
|
||||
It's a companion to `fakeAsync` and you can only call it within a `fakeAsync` body.
|
||||
The `tick()` function accepts milliseconds as parameter (defaults to 0 if not provided). The parameter represents how much the virtual clock advances. For example, if you have a `setTimeout(fn, 100)` in a `fakeAsync()` test, you need to use tick(100) to trigger the fn callback.
|
||||
|
||||
<code-example
|
||||
path="testing/src/app/demo/async-helper.spec.ts"
|
||||
region="fake-async-test-tick">
|
||||
</code-example>
|
||||
|
||||
The `tick()` function is one of the Angular testing utilities that you import with `TestBed`.
|
||||
It's a companion to `fakeAsync()` and you can only call it within a `fakeAsync()` body.
|
||||
|
||||
#### Comparing dates inside fakeAsync()
|
||||
|
||||
`fakeAsync()` simulates passage of time, which allows you to calculate the difference between dates inside `fakeAsync()`.
|
||||
|
||||
<code-example
|
||||
path="testing/src/app/demo/async-helper.spec.ts"
|
||||
region="fake-async-test-date">
|
||||
</code-example>
|
||||
|
||||
#### jasmine.clock with fakeAsync()
|
||||
|
||||
Jasmine also provides a `clock` feature to mock dates. Angular automatically runs tests that are run after
|
||||
`jasmine.clock().install()` is called inside a `fakeAsync()` method until `jasmine.clock().uninstall()` is called. `fakeAsync()` is not needed and throws an error if nested.
|
||||
|
||||
By default, this feature is disabled. To enable it, set a global flag before import `zone-testing`.
|
||||
|
||||
If you use the Angular CLI, configure this flag in `src/test.ts`.
|
||||
|
||||
```
|
||||
(window as any)['__zone_symbol__fakeAsyncPatchLock'] = true;
|
||||
import 'zone.js/dist/zone-testing';
|
||||
```
|
||||
|
||||
<code-example
|
||||
path="testing/src/app/demo/async-helper.spec.ts"
|
||||
region="fake-async-test-clock">
|
||||
</code-example>
|
||||
|
||||
#### Using the RxJS scheduler inside fakeAsync()
|
||||
|
||||
You can also use RxJS scheduler in `fakeAsync()` just like using `setTimeout()` or `setInterval()`, but you need to import `zone.js/dist/zone-patch-rxjs-fake-async` to patch RxJS scheduler.
|
||||
<code-example
|
||||
path="testing/src/app/demo/async-helper.spec.ts"
|
||||
region="fake-async-test-rxjs">
|
||||
</code-example>
|
||||
|
||||
#### Support more macroTasks
|
||||
|
||||
By default `fakeAsync` supports the following `macroTasks`.
|
||||
By default `fakeAsync()` supports the following `macroTasks`.
|
||||
|
||||
- setTimeout
|
||||
- setInterval
|
||||
|
@ -1289,7 +1334,7 @@ If you run other `macroTask` such as `HTMLCanvasElement.toBlob()`, `Unknown macr
|
|||
</code-pane>
|
||||
</code-tabs>
|
||||
|
||||
If you want to support such case, you need to define the `macroTask` you want to support in `beforeEach`.
|
||||
If you want to support such case, you need to define the `macroTask` you want to support in `beforeEach()`.
|
||||
For example:
|
||||
|
||||
```javascript
|
||||
|
@ -1386,6 +1431,8 @@ Then you can assert that the quote element displays the expected text.
|
|||
|
||||
#### Async test with _async()_
|
||||
|
||||
To use `async()` functionality, you need to import `zone-testing`, for details, please read [setup guide](guide/setup#appendix-test-using-fakeasyncasync).
|
||||
|
||||
The `fakeAsync()` utility function has a few limitations.
|
||||
In particular, it won't work if the test body makes an `XHR` call.
|
||||
|
||||
|
@ -1409,12 +1456,13 @@ Here's the previous `fakeAsync()` test, re-written with the `async()` utility.
|
|||
|
||||
The `async()` utility hides some asynchronous boilerplate by arranging for the tester's code
|
||||
to run in a special _async test zone_.
|
||||
You don't have to pass Jasmine's `done()` into the test and call `done()`
|
||||
in promise or observable callbacks.
|
||||
You don't need to pass Jasmine's `done()` into the test and call `done()` because it is `undefined` in promise or observable callbacks.
|
||||
|
||||
But the test's asynchronous nature is revealed by the call to `fixture.whenStable()`,
|
||||
which breaks the linear flow of control.
|
||||
|
||||
When using an `intervalTimer()` such as `setInterval()` in `async()`, remember to cancel the timer with `clearInterval()` after the test, otherwise the `async()` never ends.
|
||||
|
||||
{@a when-stable}
|
||||
|
||||
#### _whenStable_
|
||||
|
@ -1433,18 +1481,19 @@ update the quote element with the expected text.
|
|||
|
||||
#### Jasmine _done()_
|
||||
|
||||
While the `async` and `fakeAsync` functions greatly
|
||||
While the `async()` and `fakeAsync()` functions greatly
|
||||
simplify Angular asynchronous testing,
|
||||
you can still fall back to the traditional technique
|
||||
and pass `it` a function that takes a
|
||||
[`done` callback](http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support).
|
||||
|
||||
You can't call `done()` in `async()` or `fakeAsync()` functions, because the `done parameter`
|
||||
is `undefined`.
|
||||
|
||||
Now you are responsible for chaining promises, handling errors, and calling `done()` at the appropriate moments.
|
||||
|
||||
Writing test functions with `done()`, is more cumbersome than `async`and `fakeAsync`.
|
||||
But it is occasionally necessary.
|
||||
For example, you can't call `async` or `fakeAsync` when testing
|
||||
code that involves the `intervalTimer()` or the RxJS `delay()` operator.
|
||||
Writing test functions with `done()`, is more cumbersome than `async()`and `fakeAsync()`.
|
||||
But it is occasionally necessary when code involves the `intervalTimer()` like `setInterval`.
|
||||
|
||||
Here are two more versions of the previous test, written with `done()`.
|
||||
The first one subscribes to the `Observable` exposed to the template by the component's `quote` property.
|
||||
|
@ -2307,7 +2356,6 @@ Here are a few more `HeroDetailComponent` tests to reinforce the point.
|
|||
|
||||
{@a compile-components}
|
||||
### Calling _compileComponents()_
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
You can ignore this section if you _only_ run tests with the CLI `ng test` command
|
||||
|
@ -2871,7 +2919,7 @@ Here's a summary of the stand-alone functions, in order of likely utility:
|
|||
|
||||
<td>
|
||||
|
||||
When a `fakeAsync` test ends with pending timer event _tasks_ (queued `setTimeOut` and `setInterval` callbacks),
|
||||
When a `fakeAsync()` test ends with pending timer event _tasks_ (queued `setTimeOut` and `setInterval` callbacks),
|
||||
the test fails with a clear error message.
|
||||
|
||||
In general, a test should end with no queued tasks.
|
||||
|
@ -2888,7 +2936,7 @@ Here's a summary of the stand-alone functions, in order of likely utility:
|
|||
|
||||
<td>
|
||||
|
||||
When a `fakeAsync` test ends with pending _micro-tasks_ such as unresolved promises,
|
||||
When a `fakeAsync()` test ends with pending _micro-tasks_ such as unresolved promises,
|
||||
the test fails with a clear error message.
|
||||
|
||||
In general, a test should wait for micro-tasks to finish.
|
||||
|
|
Loading…
Reference in New Issue