angular-docs-cn/packages/core/test/fake_async_spec.ts
Andrew Kushnir 495a9dd445 fix(ivy): update token used for fakeAsync test (#28383)
This commit updates the token used in fakeAsync test to the one available in both VE and R3 TestBeds. The goal of the test is to verify that fakeAsync works with inject function, so the actual token that is used for a test is irrelevant in that case. The logic to retrieve tokens from compiler injector (that the comment in "fixmeIvy" refers to) was implemented in PR #28196.

PR Close #28383
2019-01-29 16:39:14 -08:00

361 lines
11 KiB
TypeScript

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, tick} from '@angular/core/testing';
import {Log, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal';
import {EventManager} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
const resolvedPromise = Promise.resolve(null);
const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec'];
{
describe('fake async', () => {
it('should run synchronous code', () => {
let ran = false;
fakeAsync(() => { ran = true; })();
expect(ran).toEqual(true);
});
it('should pass arguments to the wrapped function', () => {
fakeAsync((foo: any /** TODO #9100 */, bar: any /** TODO #9100 */) => {
expect(foo).toEqual('foo');
expect(bar).toEqual('bar');
})('foo', 'bar');
});
it('should work with inject()',
fakeAsync(inject([EventManager], (eventManager: EventManager) => {
expect(eventManager).toBeAnInstanceOf(EventManager);
})));
it('should throw on nested calls', () => {
expect(() => {
fakeAsync(() => { fakeAsync((): any /** TODO #9100 */ => null)(); })();
}).toThrowError('fakeAsync() calls can not be nested');
});
it('should flush microtasks before returning', () => {
let thenRan = false;
fakeAsync(() => { resolvedPromise.then(_ => { thenRan = true; }); })();
expect(thenRan).toEqual(true);
});
it('should propagate the return value',
() => { expect(fakeAsync(() => 'foo')()).toEqual('foo'); });
describe('Promise', () => {
it('should run asynchronous code', fakeAsync(() => {
let thenRan = false;
resolvedPromise.then((_) => { thenRan = true; });
expect(thenRan).toEqual(false);
flushMicrotasks();
expect(thenRan).toEqual(true);
}));
it('should run chained thens', fakeAsync(() => {
const log = new Log();
resolvedPromise.then((_) => log.add(1)).then((_) => log.add(2));
expect(log.result()).toEqual('');
flushMicrotasks();
expect(log.result()).toEqual('1; 2');
}));
it('should run Promise created in Promise', fakeAsync(() => {
const log = new Log();
resolvedPromise.then((_) => {
log.add(1);
resolvedPromise.then((_) => log.add(2));
});
expect(log.result()).toEqual('');
flushMicrotasks();
expect(log.result()).toEqual('1; 2');
}));
it('should complain if the test throws an exception during async calls', () => {
expect(() => {
fakeAsync(() => {
resolvedPromise.then((_) => { throw new Error('async'); });
flushMicrotasks();
})();
}).toThrowError(/Uncaught \(in promise\): Error: async/);
});
it('should complain if a test throws an exception', () => {
expect(() => { fakeAsync(() => { throw new Error('sync'); })(); }).toThrowError('sync');
});
});
describe('timers', () => {
it('should run queued zero duration timer on zero tick', fakeAsync(() => {
let ran = false;
setTimeout(() => { ran = true; }, 0);
expect(ran).toEqual(false);
tick();
expect(ran).toEqual(true);
}));
it('should run queued timer after sufficient clock ticks', fakeAsync(() => {
let ran = false;
setTimeout(() => { ran = true; }, 10);
tick(6);
expect(ran).toEqual(false);
tick(6);
expect(ran).toEqual(true);
}));
it('should run queued timer only once', fakeAsync(() => {
let cycles = 0;
setTimeout(() => { cycles++; }, 10);
tick(10);
expect(cycles).toEqual(1);
tick(10);
expect(cycles).toEqual(1);
tick(10);
expect(cycles).toEqual(1);
}));
it('should not run cancelled timer', fakeAsync(() => {
let ran = false;
const id = setTimeout(() => { ran = true; }, 10);
clearTimeout(id);
tick(10);
expect(ran).toEqual(false);
}));
it('should throw an error on dangling timers', () => {
expect(() => {
fakeAsync(() => { setTimeout(() => {}, 10); })();
}).toThrowError('1 timer(s) still in the queue.');
});
it('should throw an error on dangling periodic timers', () => {
expect(() => {
fakeAsync(() => { setInterval(() => {}, 10); })();
}).toThrowError('1 periodic timer(s) still in the queue.');
});
it('should run periodic timers', fakeAsync(() => {
let cycles = 0;
const id = setInterval(() => { cycles++; }, 10);
tick(10);
expect(cycles).toEqual(1);
tick(10);
expect(cycles).toEqual(2);
tick(10);
expect(cycles).toEqual(3);
clearInterval(id);
}));
it('should not run cancelled periodic timer', fakeAsync(() => {
let ran = false;
const id = setInterval(() => { ran = true; }, 10);
clearInterval(id);
tick(10);
expect(ran).toEqual(false);
}));
it('should be able to cancel periodic timers from a callback', fakeAsync(() => {
let cycles = 0;
let id: any /** TODO #9100 */;
id = setInterval(() => {
cycles++;
clearInterval(id);
}, 10);
tick(10);
expect(cycles).toEqual(1);
tick(10);
expect(cycles).toEqual(1);
}));
it('should clear periodic timers', fakeAsync(() => {
let cycles = 0;
const id = setInterval(() => { cycles++; }, 10);
tick(10);
expect(cycles).toEqual(1);
discardPeriodicTasks();
// Tick once to clear out the timer which already started.
tick(10);
expect(cycles).toEqual(2);
tick(10);
// Nothing should change
expect(cycles).toEqual(2);
}));
it('should process microtasks before timers', fakeAsync(() => {
const log = new Log();
resolvedPromise.then((_) => log.add('microtask'));
setTimeout(() => log.add('timer'), 9);
const id = setInterval(() => log.add('periodic timer'), 10);
expect(log.result()).toEqual('');
tick(10);
expect(log.result()).toEqual('microtask; timer; periodic timer');
clearInterval(id);
}));
it('should process micro-tasks created in timers before next timers', fakeAsync(() => {
const log = new Log();
resolvedPromise.then((_) => log.add('microtask'));
setTimeout(() => {
log.add('timer');
resolvedPromise.then((_) => log.add('t microtask'));
}, 9);
const id = setInterval(() => {
log.add('periodic timer');
resolvedPromise.then((_) => log.add('pt microtask'));
}, 10);
tick(10);
expect(log.result())
.toEqual('microtask; timer; t microtask; periodic timer; pt microtask');
tick(10);
expect(log.result())
.toEqual(
'microtask; timer; t microtask; periodic timer; pt microtask; periodic timer; pt microtask');
clearInterval(id);
}));
it('should flush tasks', fakeAsync(() => {
let ran = false;
setTimeout(() => { ran = true; }, 10);
flush();
expect(ran).toEqual(true);
}));
it('should flush multiple tasks', fakeAsync(() => {
let ran = false;
let ran2 = false;
setTimeout(() => { ran = true; }, 10);
setTimeout(() => { ran2 = true; }, 30);
let elapsed = flush();
expect(ran).toEqual(true);
expect(ran2).toEqual(true);
expect(elapsed).toEqual(30);
}));
it('should move periodic tasks', fakeAsync(() => {
let ran = false;
let count = 0;
setInterval(() => { count++; }, 10);
setTimeout(() => { ran = true; }, 35);
let elapsed = flush();
expect(count).toEqual(3);
expect(ran).toEqual(true);
expect(elapsed).toEqual(35);
discardPeriodicTasks();
}));
});
describe('outside of the fakeAsync zone', () => {
it('calling flushMicrotasks should throw', () => {
expect(() => {
flushMicrotasks();
}).toThrowError('The code should be running in the fakeAsync zone to call this function');
});
it('calling tick should throw', () => {
expect(() => {
tick();
}).toThrowError('The code should be running in the fakeAsync zone to call this function');
});
it('calling flush should throw', () => {
expect(() => {
flush();
}).toThrowError('The code should be running in the fakeAsync zone to call this function');
});
it('calling discardPeriodicTasks should throw', () => {
expect(() => {
discardPeriodicTasks();
}).toThrowError('The code should be running in the fakeAsync zone to call this function');
});
});
describe('only one `fakeAsync` zone per test', () => {
let zoneInBeforeEach: Zone;
let zoneInTest1: Zone;
beforeEach(fakeAsync(() => { zoneInBeforeEach = Zone.current; }));
it('should use the same zone as in beforeEach', fakeAsync(() => {
zoneInTest1 = Zone.current;
expect(zoneInTest1).toBe(zoneInBeforeEach);
}));
});
});
describe('ProxyZone', () => {
beforeEach(() => { ProxyZoneSpec.assertPresent(); });
afterEach(() => { ProxyZoneSpec.assertPresent(); });
it('should allow fakeAsync zone to retroactively set a zoneSpec outside of fakeAsync', () => {
ProxyZoneSpec.assertPresent();
let state: string = 'not run';
const testZone = Zone.current.fork({name: 'test-zone'});
(fakeAsync(() => {
testZone.run(() => {
Promise.resolve('works').then((v) => state = v);
expect(state).toEqual('not run');
flushMicrotasks();
expect(state).toEqual('works');
});
}))();
expect(state).toEqual('works');
});
});
}