fix(zone.js): add issue numbers of @types/jasmine to the test cases (#34625)

Some cases will still need to use `spy as any` cast, because `@types/jasmine` have some issues,
1. The issue jasmine doesn't handle optional method properties, https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
2. The issue jasmine doesn't handle overload method correctly, https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42455

PR Close #34625
This commit is contained in:
JiaLiPassion 2020-03-31 00:22:25 +09:00 committed by Kara Erickson
parent b28a5f6eef
commit 421b6a97d6
22 changed files with 5993 additions and 5745 deletions

View File

@ -13,6 +13,7 @@ describe('unlocker', () => {
spyOn(process, 'on'); spyOn(process, 'on');
require('../../../src/locking/lock_file_with_child_process/unlocker'); require('../../../src/locking/lock_file_with_child_process/unlocker');
// TODO: @JiaLiPassion, need to wait for @types/jasmine to handle the override case // TODO: @JiaLiPassion, need to wait for @types/jasmine to handle the override case
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42455
expect(process.on).toHaveBeenCalledWith('disconnect' as any, jasmine.any(Function)); expect(process.on).toHaveBeenCalledWith('disconnect' as any, jasmine.any(Function));
}); });
}); });

View File

@ -69,6 +69,7 @@ describe('NodeJSFileSystem', () => {
const result = fs.readdir(abcPath); const result = fs.readdir(abcPath);
expect(result).toEqual([relativeFrom('x'), relativeFrom('y/z')]); expect(result).toEqual([relativeFrom('x'), relativeFrom('y/z')]);
// TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters. // TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters.
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
expect(spy as any).toHaveBeenCalledWith(abcPath); expect(spy as any).toHaveBeenCalledWith(abcPath);
}); });
}); });
@ -90,6 +91,7 @@ describe('NodeJSFileSystem', () => {
const result = fs.stat(abcPath); const result = fs.stat(abcPath);
expect(result).toBe(stats); expect(result).toBe(stats);
// TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters. // TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters.
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
expect(spy as any).toHaveBeenCalledWith(abcPath); expect(spy as any).toHaveBeenCalledWith(abcPath);
}); });
}); });
@ -174,9 +176,11 @@ describe('NodeJSFileSystem', () => {
return false; return false;
}); });
spyOn(fs, 'stat').and.returnValue({isDirectory: () => true} as any); spyOn(fs, 'stat').and.returnValue({isDirectory: () => true} as any);
const mkdirSyncSpy = spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { const mkdirSyncSpy =
spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => {
if (path === abcPath) { if (path === abcPath) {
throw new Error('It exists already. Supposedly.'); throw new Error(
'It exists already. Supposedly.');
} }
}) as any); }) as any);
@ -188,7 +192,8 @@ describe('NodeJSFileSystem', () => {
it('should fail if creating the directory throws and the directory does not exist', () => { it('should fail if creating the directory throws and the directory does not exist', () => {
spyOn(fs, 'exists').and.returnValue(false); spyOn(fs, 'exists').and.returnValue(false);
spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { spyOn(realFs, 'mkdirSync')
.and.callFake(((path: string) => {
if (path === abcPath) { if (path === abcPath) {
throw new Error('Unable to create directory (for whatever reason).'); throw new Error('Unable to create directory (for whatever reason).');
} }

View File

@ -41,7 +41,9 @@ describe('ngc transformer command-line', () => {
basePath = support.basePath; basePath = support.basePath;
outDir = path.join(basePath, 'built'); outDir = path.join(basePath, 'built');
process.chdir(basePath); process.chdir(basePath);
write = (fileName: string, content: string) => { support.write(fileName, content); }; write = (fileName: string, content: string) => {
support.write(fileName, content);
};
write('tsconfig-base.json', `{ write('tsconfig-base.json', `{
"compilerOptions": { "compilerOptions": {
@ -96,8 +98,9 @@ describe('ngc transformer command-line', () => {
}); });
describe('errors', () => { describe('errors', () => {
beforeEach(() => {
beforeEach(() => { errorSpy.and.stub(); }); errorSpy.and.stub();
});
it('should not print the stack trace if user input file does not exist', () => { it('should not print the stack trace if user input file does not exist', () => {
writeConfig(`{ writeConfig(`{
@ -231,7 +234,6 @@ describe('ngc transformer command-line', () => {
}); });
describe('compile ngfactory files', () => { describe('compile ngfactory files', () => {
it('should compile ngfactory files that are not referenced by root files', () => { it('should compile ngfactory files that are not referenced by root files', () => {
writeConfig(`{ writeConfig(`{
"extends": "./tsconfig-base.json", "extends": "./tsconfig-base.json",
@ -1122,7 +1124,6 @@ describe('ngc transformer command-line', () => {
}); });
describe('with external symbol re-exports enabled', () => { describe('with external symbol re-exports enabled', () => {
it('should be able to compile multiple libraries with summaries', () => { it('should be able to compile multiple libraries with summaries', () => {
// Note: we need to emit the generated code for the libraries // Note: we need to emit the generated code for the libraries
// into the node_modules, as that is the only way that we // into the node_modules, as that is the only way that we
@ -1560,11 +1561,13 @@ describe('ngc transformer command-line', () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
const timerToken = 100; const timerToken = 100;
// TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case // TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
spyOn(ts.sys as any, 'setTimeout').and.callFake((callback: () => void) => { spyOn(ts.sys as any, 'setTimeout').and.callFake((callback: () => void) => {
timer = callback; timer = callback;
return timerToken; return timerToken;
}); });
// TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case // TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
spyOn(ts.sys as any, 'clearTimeout').and.callFake((token: number) => { spyOn(ts.sys as any, 'clearTimeout').and.callFake((token: number) => {
if (token == timerToken) { if (token == timerToken) {
timer = undefined; timer = undefined;
@ -1617,7 +1620,9 @@ describe('ngc transformer command-line', () => {
`); `);
}); });
afterEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; }); afterEach(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
function writeAppConfig(location: string) { function writeAppConfig(location: string) {
writeConfig(`{ writeConfig(`{
@ -1672,11 +1677,13 @@ describe('ngc transformer command-line', () => {
`); `);
})); }));
it('should recompile when the html file changes', it('should recompile when the html file changes', expectRecompile(() => {
expectRecompile(() => { write('greet.html', '<p> Hello {{name}} again!</p>'); })); write('greet.html', '<p> Hello {{name}} again!</p>');
}));
it('should recompile when the css file changes', it('should recompile when the css file changes', expectRecompile(() => {
expectRecompile(() => { write('greet.css', `p.greeting { color: blue }`); })); write('greet.css', `p.greeting { color: blue }`);
}));
}); });
describe('regressions', () => { describe('regressions', () => {
@ -2041,8 +2048,8 @@ describe('ngc transformer command-line', () => {
expect(exitCode).toBe(1, 'Compile was expected to fail'); expect(exitCode).toBe(1, 'Compile was expected to fail');
const srcPathWithSep = `lib/`; const srcPathWithSep = `lib/`;
expect(messages[0]) expect(messages[0])
.toEqual( .toEqual(`${
`${srcPathWithSep}test.component.ts(6,21): Error during template compile of 'TestComponent' srcPathWithSep}test.component.ts(6,21): Error during template compile of 'TestComponent'
Tagged template expressions are not supported in metadata in 't1' Tagged template expressions are not supported in metadata in 't1'
't1' references 't2' at ${srcPathWithSep}indirect1.ts(3,27) 't1' references 't2' at ${srcPathWithSep}indirect1.ts(3,27)
't2' contains the error at ${srcPathWithSep}indirect2.ts(4,27). 't2' contains the error at ${srcPathWithSep}indirect2.ts(4,27).
@ -2051,7 +2058,6 @@ describe('ngc transformer command-line', () => {
}); });
describe('tree shakeable services', () => { describe('tree shakeable services', () => {
function compileService(source: string): string { function compileService(source: string): string {
write('service.ts', source); write('service.ts', source);

View File

@ -14,7 +14,7 @@ describe('convertValueToOutputAst', () => {
const ctx = null; const ctx = null;
const value = new Array(3).concat('foo'); const value = new Array(3).concat('foo');
const expr = convertValueToOutputAst(ctx!, value) as o.LiteralArrayExpr; const expr = convertValueToOutputAst(ctx!, value) as o.LiteralArrayExpr;
expect(expr instanceof o.LiteralArrayExpr); expect(expr instanceof o.LiteralArrayExpr).toBe(true);
expect(expr.entries.length).toBe(4); expect(expr.entries.length).toBe(4);
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
expect(expr.entries[i] instanceof o.Expression).toBe(true); expect(expr.entries[i] instanceof o.Expression).toBe(true);

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be * 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 * found in the LICENSE file at https://angular.io/license
*/ */
import {AUTO_STYLE, AnimationPlayer, animate, animateChild, group, query, sequence, stagger, state, style, transition, trigger, ɵAnimationGroupPlayer as AnimationGroupPlayer} from '@angular/animations'; import {animate, animateChild, AnimationPlayer, AUTO_STYLE, group, query, sequence, stagger, state, style, transition, trigger, ɵAnimationGroupPlayer as AnimationGroupPlayer} from '@angular/animations';
import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser'; import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser';
import {matchesElement} from '@angular/animations/browser/src/render/shared'; import {matchesElement} from '@angular/animations/browser/src/render/shared';
import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine'; import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine';
@ -13,7 +13,7 @@ import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '@angular/animations/browser/src/
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing'; import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {Component, HostBinding, ViewChild} from '@angular/core'; import {Component, HostBinding, ViewChild} from '@angular/core';
import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HostListener} from '../../src/metadata/directives'; import {HostListener} from '../../src/metadata/directives';
@ -27,7 +27,9 @@ import {HostListener} from '../../src/metadata/directives';
return MockAnimationDriver.log as MockAnimationPlayer[]; return MockAnimationDriver.log as MockAnimationPlayer[];
} }
function resetLog() { MockAnimationDriver.log = []; } function resetLog() {
MockAnimationDriver.log = [];
}
beforeEach(() => { beforeEach(() => {
resetLog(); resetLog();
@ -68,26 +70,22 @@ import {HostListener} from '../../src/metadata/directives';
trigger( trigger(
'a', 'a',
[ [
transition('* => 1', [ transition('* => 1', [animate(1000, style({opacity: 0}))]),
animate(1000, style({ opacity: 0 }))
]),
]), ]),
trigger( trigger(
'b', 'b',
[ [
transition('* => 1', [ transition(
'* => 1',
[
animate(1000, style({opacity: 0})), animate(1000, style({opacity: 0})),
query('.b-inner', [ query('.b-inner', [animate(1000, style({opacity: 0}))]),
animate(1000, style({ opacity: 0 }))
]),
]), ]),
]), ]),
trigger( trigger(
'c', 'c',
[ [
transition('* => 1', [ transition('* => 1', [animate(1000, style({opacity: 0}))]),
animate(1000, style({ opacity: 0 }))
]),
]), ]),
] ]
}) })
@ -145,26 +143,22 @@ import {HostListener} from '../../src/metadata/directives';
trigger( trigger(
'a', 'a',
[ [
transition('* => 1', [ transition('* => 1', [animate(1000, style({opacity: 0}))]),
animate(1000, style({ opacity: 0 }))
]),
]), ]),
trigger( trigger(
'b', 'b',
[ [
transition('* => 1', [ transition(
'* => 1',
[
animate(1000, style({opacity: 0})), animate(1000, style({opacity: 0})),
query('.b-inner', [ query('.b-inner', [animate(1000, style({opacity: 0}))]),
animate(1000, style({ opacity: 0 }))
]),
]), ]),
]), ]),
trigger( trigger(
'c', 'c',
[ [
transition('* => 1', [ transition('* => 1', [animate(1000, style({opacity: 0}))]),
animate(1000, style({ opacity: 0 }))
]),
]), ]),
] ]
}) })
@ -361,8 +355,7 @@ import {HostListener} from '../../src/metadata/directives';
expect(players[2].element.classList.contains('e-4')).toBeTruthy(); expect(players[2].element.classList.contains('e-4')).toBeTruthy();
}); });
it('should be able to query all actively queued animation triggers via `@*:animating`', it('should be able to query all actively queued animation triggers via `@*:animating`', () => {
() => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
template: ` template: `
@ -454,7 +447,8 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(1); expect(players.length).toEqual(1);
}); });
it('should collect styles for the same elements between queries', () => { it(
'should collect styles for the same elements between queries', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
template: ` template: `
@ -546,12 +540,11 @@ import {HostListener} from '../../src/metadata/directives';
template: ` template: `
<div [@myAnimation]="exp"></div> <div [@myAnimation]="exp"></div>
`, `,
animations: [trigger('myAnimation', [transition( animations: [trigger(
'myAnimation',
[transition(
'* => go', '* => go',
[ [query(':self', style({opacity: '0.5'})), animate(1000, style({opacity: '1'}))])])]
query(':self', style({opacity: '0.5'})),
animate(1000, style({opacity: '1'}))
])])]
}) })
class Cmp { class Cmp {
public exp: any; public exp: any;
@ -793,9 +786,7 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(1); expect(players.length).toEqual(1);
const player = players[0]; const player = players[0];
expect(player.keyframes).toEqual([ expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '444px', offset: 1}]);
{height: '0px', offset: 0}, {height: '444px', offset: 1}
]);
player.finish(); player.finish();
expect(player.element.style.height).toEqual('444px'); expect(player.element.style.height).toEqual('444px');
@ -903,7 +894,9 @@ import {HostListener} from '../../src/metadata/directives';
cmp.items = [0, 1, 2, 3, 4]; cmp.items = [0, 1, 2, 3, 4];
expect(() => { fixture.detectChanges(); }).toThrow(); expect(() => {
fixture.detectChanges();
}).toThrow();
const children = cmp.container.nativeElement.querySelectorAll('.child'); const children = cmp.container.nativeElement.querySelectorAll('.child');
expect(children.length).toEqual(5); expect(children.length).toEqual(5);
@ -1369,7 +1362,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5); expect(players.length).toEqual(5);
let count = 0; let count = 0;
players.forEach(p => { p.onDone(() => count++); }); players.forEach(p => {
p.onDone(() => count++);
});
expect(count).toEqual(0); expect(count).toEqual(0);
@ -1422,7 +1417,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5); expect(players.length).toEqual(5);
let count = 0; let count = 0;
players.forEach(p => { p.onDone(() => count++); }); players.forEach(p => {
p.onDone(() => count++);
});
expect(count).toEqual(0); expect(count).toEqual(0);
@ -1485,7 +1482,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5); expect(players.length).toEqual(5);
let count = 0; let count = 0;
players.forEach(p => { p.onDone(() => count++); }); players.forEach(p => {
p.onDone(() => count++);
});
resetLog(); resetLog();
@ -1500,7 +1499,9 @@ import {HostListener} from '../../src/metadata/directives';
players = getLog(); players = getLog();
expect(players.length).toEqual(3); expect(players.length).toEqual(3);
players.forEach(p => { p.onDone(() => count++); }); players.forEach(p => {
p.onDone(() => count++);
});
cmp.exp1 = 'off'; cmp.exp1 = 'off';
fixture.detectChanges(); fixture.detectChanges();
@ -1555,7 +1556,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5); expect(players.length).toEqual(5);
let count = 0; let count = 0;
players.forEach(p => { p.onDone(() => count++); }); players.forEach(p => {
p.onDone(() => count++);
});
expect(count).toEqual(0); expect(count).toEqual(0);
@ -1631,8 +1634,7 @@ import {HostListener} from '../../src/metadata/directives';
'myAnimation', 'myAnimation',
[transition( [transition(
'* => on', '* => on',
[query( [query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])])]
':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])])]
}) })
class ParentCmp { class ParentCmp {
public exp: any; public exp: any;
@ -1680,8 +1682,7 @@ import {HostListener} from '../../src/metadata/directives';
`, `,
animations: [trigger( animations: [trigger(
'myAnimation', 'myAnimation',
[transition( [transition('* => on', [query(':leave', [animate(1000, style({opacity: 0}))])])])]
'* => on', [query(':leave', [animate(1000, style({opacity: 0}))])])])]
}) })
class ParentCmp { class ParentCmp {
public exp: any; public exp: any;
@ -2018,9 +2019,9 @@ import {HostListener} from '../../src/metadata/directives';
</div> </div>
`, `,
animations: [ animations: [
trigger('child', [transition( trigger(
'a => z', 'child',
[style({opacity: 0}), animate(1000, style({opacity: 1}))])]), [transition('a => z', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]),
trigger('parent', [transition( trigger('parent', [transition(
'a => z', 'a => z',
[ [
@ -2076,28 +2077,19 @@ import {HostListener} from '../../src/metadata/directives';
</div> </div>
`, `,
animations: [ animations: [
trigger('w', [ trigger(
transition('* => go', [ 'w',
style({ width: 0 }), [transition('* => go', [style({width: 0}), animate(1800, style({width: '100px'}))])]),
animate(1800, style({ width: '100px' })) trigger(
]) 'h', [transition(
]), '* => go', [style({height: 0}), animate(1500, style({height: '100px'}))])]),
trigger('h', [ trigger(
transition('* => go', [ 'parent', [transition(
style({ height: 0 }), '* => go',
animate(1500, style({ height: '100px' })) [
]) style({opacity: 0}), animate(1000, style({opacity: 1})),
]), query('.child', [animateChild()]), animate(1000, style({opacity: 0}))
trigger('parent', [ ])])
transition('* => go', [
style({ opacity: 0 }),
animate(1000, style({ opacity: 1 })),
query('.child', [
animateChild()
]),
animate(1000, style({ opacity: 0 }))
])
])
] ]
}) })
class Cmp { class Cmp {
@ -2141,9 +2133,9 @@ import {HostListener} from '../../src/metadata/directives';
</div> </div>
`, `,
animations: [ animations: [
trigger('child', [transition( trigger(
'* => go', 'child',
[style({width: 0}), animate(1800, style({width: '100px'}))])]), [transition('* => go', [style({width: 0}), animate(1800, style({width: '100px'}))])]),
trigger('parent', [transition( trigger('parent', [transition(
'* => go', '* => go',
[ [
@ -2200,9 +2192,9 @@ import {HostListener} from '../../src/metadata/directives';
style({opacity: 0}), animate(1000, style({opacity: 1})), style({opacity: 0}), animate(1000, style({opacity: 1})),
query('.child', animateChild()) query('.child', animateChild())
])]), ])]),
trigger('child', [transition( trigger(
'* => go', 'child',
[style({opacity: 0}), animate(1800, style({opacity: 1}))])]) [transition('* => go', [style({opacity: 0}), animate(1800, style({opacity: 1}))])])
] ]
}) })
class Cmp { class Cmp {
@ -2515,19 +2507,17 @@ import {HostListener} from '../../src/metadata/directives';
it('should collect multiple root levels of :enter and :leave nodes', () => { it('should collect multiple root levels of :enter and :leave nodes', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
animations: [ animations: [trigger(
trigger('pageAnimation', [ 'pageAnimation',
[
transition(':enter', []), transition(':enter', []),
transition('* => *', [ transition(
query(':leave', [ '* => *',
animate('1s', style({ opacity: 0 })) [
], { optional: true }), query(':leave', [animate('1s', style({opacity: 0}))], {optional: true}),
query(':enter', [ query(':enter', [animate('1s', style({opacity: 1}))], {optional: true})
animate('1s', style({ opacity: 1 }))
], { optional: true })
]) ])
]) ])],
],
template: ` template: `
<div [@pageAnimation]="status"> <div [@pageAnimation]="status">
<header> <header>
@ -2679,8 +2669,7 @@ import {HostListener} from '../../src/metadata/directives';
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual([ expect(cmp.log).toEqual([
'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done', 'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done', 'p-done'
'p-done'
]); ]);
})); }));
@ -2764,7 +2753,9 @@ import {HostListener} from '../../src/metadata/directives';
public log: string[] = []; public log: string[] = [];
public remove = false; public remove = false;
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) {
this.log.push(`${event.triggerName}-${event.phaseName}`);
}
} }
@Component({ @Component({
@ -2790,7 +2781,9 @@ import {HostListener} from '../../src/metadata/directives';
class ChildCmp { class ChildCmp {
public exp: any; public exp: any;
public log: string[] = []; public log: string[] = [];
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) {
this.log.push(`${event.triggerName}-${event.phaseName}`);
}
} }
TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]});
@ -2893,7 +2886,9 @@ import {HostListener} from '../../src/metadata/directives';
public child2Exp = ''; public child2Exp = '';
public log: string[] = []; public log: string[] = [];
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) {
this.log.push(`${event.triggerName}-${event.phaseName}`);
}
} }
TestBed.configureTestingModule({declarations: [Cmp]}); TestBed.configureTestingModule({declarations: [Cmp]});
@ -2968,8 +2963,8 @@ import {HostListener} from '../../src/metadata/directives';
engine.flush(); engine.flush();
expect(engine.players.length).toEqual(1); // child player, parent cover, parent player expect(engine.players.length).toEqual(1); // child player, parent cover, parent player
const groupPlayer = (engine.players[0] as TransitionAnimationPlayer) const groupPlayer = (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as
.getRealPlayer() as AnimationGroupPlayer; AnimationGroupPlayer;
const childPlayer = groupPlayer.players.find(player => { const childPlayer = groupPlayer.players.find(player => {
if (player instanceof MockAnimationPlayer) { if (player instanceof MockAnimationPlayer) {
return matchesElement(player.element, '.child'); return matchesElement(player.element, '.child');

View File

@ -9,7 +9,7 @@
import {ResourceLoader, UrlResolver} from '@angular/compiler'; import {ResourceLoader, UrlResolver} from '@angular/compiler';
import {MockResourceLoader} from '@angular/compiler/testing'; import {MockResourceLoader} from '@angular/compiler/testing';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, DebugElement, Directive, DoCheck, EventEmitter, HostBinding, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, Provider, RendererFactory2, RendererType2, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, DebugElement, Directive, DoCheck, EventEmitter, HostBinding, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, Provider, RendererFactory2, RendererType2, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; import {ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by'; import {By} from '@angular/platform-browser/src/dom/debug/by';
import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; import {isTextNode} from '@angular/platform-browser/testing/src/browser_util';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
@ -66,15 +66,13 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
return _bindSimpleProp(`[id]='${expression}'`, compType); return _bindSimpleProp(`[id]='${expression}'`, compType);
} }
function _bindAndCheckSimpleValue( function _bindAndCheckSimpleValue(expression: any, compType: Type<any> = TestComponent): string[] {
expression: any, compType: Type<any> = TestComponent): string[] {
const ctx = _bindSimpleValue(expression, compType); const ctx = _bindSimpleValue(expression, compType);
ctx.detectChanges(false); ctx.detectChanges(false);
return renderLog.log; return renderLog.log;
} }
describe(`ChangeDetection`, () => { describe(`ChangeDetection`, () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS});
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@ -112,79 +110,101 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}); });
describe('expressions', () => { describe('expressions', () => {
it('should support literals', it('should support literals', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']); })); expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']);
}));
it('should strip quotes from literals', it('should strip quotes from literals', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']); })); expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']);
}));
it('should support newlines in literals', it('should support newlines in literals', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']); })); expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']);
}));
it('should support + operations', it('should support + operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']); })); expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']);
}));
it('should support - operations', it('should support - operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']); })); expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']);
}));
it('should support * operations', it('should support * operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']); })); expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']);
}));
it('should support / operations', fakeAsync(() => { it('should support / operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`id=${5.0}`]); expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`id=${5.0}`]);
})); // dart exp=5.0, js exp=5 })); // dart exp=5.0, js exp=5
it('should support % operations', it('should support % operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']); })); expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']);
}));
it('should support == operations on identical', it('should support == operations on identical', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']);
}));
it('should support != operations', it('should support != operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']);
}));
it('should support == operations on coerceible', it('should support == operations on coerceible', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]); })); expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]);
}));
it('should support === operations on identical', it('should support === operations on identical', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']);
}));
it('should support !== operations', it('should support !== operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']);
}));
it('should support === operations on coerceible', fakeAsync(() => { it('should support === operations on coerceible', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['id=false']); expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['id=false']);
})); }));
it('should support true < operations', it('should support true < operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']);
}));
it('should support false < operations', it('should support false < operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']);
}));
it('should support false > operations', it('should support false > operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']);
}));
it('should support true > operations', it('should support true > operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']);
}));
it('should support true <= operations', it('should support true <= operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']);
}));
it('should support equal <= operations', it('should support equal <= operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']);
}));
it('should support false <= operations', it('should support false <= operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']);
}));
it('should support true >= operations', it('should support true >= operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']);
}));
it('should support equal >= operations', it('should support equal >= operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']);
}));
it('should support false >= operations', it('should support false >= operations', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']);
}));
it('should support true && operations', fakeAsync(() => { it('should support true && operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('true && true')).toEqual(['id=true']); expect(_bindAndCheckSimpleValue('true && true')).toEqual(['id=true']);
@ -202,17 +222,21 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
expect(_bindAndCheckSimpleValue('false || false')).toEqual(['id=false']); expect(_bindAndCheckSimpleValue('false || false')).toEqual(['id=false']);
})); }));
it('should support negate', it('should support negate', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']); })); expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']);
}));
it('should support double negate', it('should support double negate', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']); })); expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']);
}));
it('should support true conditionals', it('should support true conditionals', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']); })); expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']);
}));
it('should support false conditionals', it('should support false conditionals', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']); })); expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']);
}));
it('should support keyed access to a list item', fakeAsync(() => { it('should support keyed access to a list item', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['id=foo']); expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['id=foo']);
@ -444,8 +468,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
expect(renderLog.log).toEqual(['id=BA']); expect(renderLog.log).toEqual(['id=BA']);
})); }));
it('should escape values in literals that indicate interpolation', it('should escape values in literals that indicate interpolation', fakeAsync(() => {
fakeAsync(() => { expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']); })); expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']);
}));
it('should read locals', fakeAsync(() => { it('should read locals', fakeAsync(() => {
const ctx = createCompFixture( const ctx = createCompFixture(
@ -479,8 +504,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})); }));
it('should support calling pure pipes with different number of arguments', fakeAsync(() => { it('should support calling pure pipes with different number of arguments', fakeAsync(() => {
const ctx = const ctx = _bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1:2', Person);
_bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1:2', Person);
ctx.componentInstance.name = 'value'; ctx.componentInstance.name = 'value';
ctx.detectChanges(false); ctx.detectChanges(false);
expect(renderLog.loggedValues).toEqual(['value a b default 0 1 2']); expect(renderLog.loggedValues).toEqual(['value a b default 0 1 2']);
@ -553,14 +577,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
// change from some value -> some other value // change from some value -> some other value
ctx.componentInstance.name = 'bart'; ctx.componentInstance.name = 'bart';
ctx.detectChanges(false); ctx.detectChanges(false);
expect(renderLog.loggedValues).toEqual([ expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1', 'bart state:2']);
'null state:0', 'bob state:1', 'bart state:2'
]);
ctx.detectChanges(false); ctx.detectChanges(false);
expect(renderLog.loggedValues).toEqual([ expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1', 'bart state:2']);
'null state:0', 'bob state:1', 'bart state:2'
]);
})); }));
modifiedInIvy('Pure pipes are instantiated differently in view engine and ivy') modifiedInIvy('Pure pipes are instantiated differently in view engine and ivy')
@ -662,7 +681,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})); }));
it('should throw when trying to assign to a local', fakeAsync(() => { it('should throw when trying to assign to a local', fakeAsync(() => {
expect(() => { _bindSimpleProp('(event)="$event=1"'); }) expect(() => {
_bindSimpleProp('(event)="$event=1"');
})
.toThrowError(new RegExp( .toThrowError(new RegExp(
'Cannot assign value (.*) to template variable (.*). Template variables are read-only.')); 'Cannot assign value (.*) to template variable (.*). Template variables are read-only.'));
})); }));
@ -675,7 +696,6 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
expect(ctx.componentInstance.a).toEqual(1); expect(ctx.componentInstance.a).toEqual(1);
})); }));
}); });
}); });
describe('RendererFactory', () => { describe('RendererFactory', () => {
@ -685,6 +705,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
const rf = TestBed.inject(RendererFactory2); const rf = TestBed.inject(RendererFactory2);
// TODO: @JiaLiPassion, need to wait @types/jasmine to fix the // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the
// optional method infer issue. // optional method infer issue.
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
spyOn(rf as any, 'begin'); spyOn(rf as any, 'begin');
spyOn(rf as any, 'end'); spyOn(rf as any, 'end');
expect(rf.begin).not.toHaveBeenCalled(); expect(rf.begin).not.toHaveBeenCalled();
@ -824,8 +845,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]); ]);
})); }));
it('should be called on every detectChanges run, except for checkNoChanges', it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => {
fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>'); const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false); ctx.detectChanges(false);
@ -864,9 +884,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges(false); ctx.detectChanges(false);
expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([ expect(directiveLog.filter(['ngAfterContentInit'])).toEqual(['dir.ngAfterContentInit']);
'dir.ngAfterContentInit'
]);
// reset directives // reset directives
directiveLog.clear(); directiveLog.clear();
@ -895,9 +913,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
} }
expect(errored).toBe(true); expect(errored).toBe(true);
expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([ expect(directiveLog.filter(['ngAfterContentInit'])).toEqual(['dir.ngAfterContentInit']);
'dir.ngAfterContentInit'
]);
directiveLog.clear(); directiveLog.clear();
// Second change detection also fails, but this time ngAfterContentInit should not be // Second change detection also fails, but this time ngAfterContentInit should not be
@ -925,8 +941,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]); ]);
})); }));
it('should be called on every detectChanges run, except for checkNoChanges', it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => {
fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>'); const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false); ctx.detectChanges(false);
@ -1038,15 +1053,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]); ]);
})); }));
it('should be called on every detectChanges run, except for checkNoChanges', it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => {
fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>'); const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false); ctx.detectChanges(false);
expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([ expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual(['dir.ngAfterViewChecked']);
'dir.ngAfterViewChecked'
]);
// reset directives // reset directives
directiveLog.clear(); directiveLog.clear();
@ -1059,9 +1071,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
// re-verify that changes are still detected // re-verify that changes are still detected
ctx.detectChanges(false); ctx.detectChanges(false);
expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([ expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual(['dir.ngAfterViewChecked']);
'dir.ngAfterViewChecked'
]);
})); }));
it('should be called in reverse order so the child is always notified before the parent', it('should be called in reverse order so the child is always notified before the parent',
@ -1136,14 +1146,11 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges(false); ctx.detectChanges(false);
ctx.destroy(); ctx.destroy();
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([ expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['pipeWithOnDestroy.ngOnDestroy']);
'pipeWithOnDestroy.ngOnDestroy'
]);
})); }));
it('should call ngOnDestroy on an injectable class', fakeAsync(() => { it('should call ngOnDestroy on an injectable class', fakeAsync(() => {
TestBed.overrideDirective( TestBed.overrideDirective(TestDirective, {set: {providers: [InjectableWithLifecycle]}});
TestDirective, {set: {providers: [InjectableWithLifecycle]}});
const ctx = createCompFixture('<div testDirective="dir"></div>', TestComponent); const ctx = createCompFixture('<div testDirective="dir"></div>', TestComponent);
@ -1302,7 +1309,6 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges(); ctx.detectChanges();
expect(renderLog.log).toEqual(['{{hello}}']); expect(renderLog.log).toEqual(['{{hello}}']);
})); }));
it('Reattaches in the original cd mode', fakeAsync(() => { it('Reattaches in the original cd mode', fakeAsync(() => {
@ -1321,14 +1327,13 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges(); ctx.detectChanges();
expect(cmp.renderCount).toBe(count); expect(cmp.renderCount).toBe(count);
})); }));
}); });
describe('multi directive order', () => { describe('multi directive order', () => {
modifiedInIvy('order of bindings to directive inputs is different in ivy') modifiedInIvy('order of bindings to directive inputs is different in ivy')
.it('should follow the DI order for the same element', fakeAsync(() => { .it('should follow the DI order for the same element', fakeAsync(() => {
const ctx = createCompFixture( const ctx =
'<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>'); createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>');
ctx.detectChanges(false); ctx.detectChanges(false);
ctx.destroy(); ctx.destroy();
@ -1380,8 +1385,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
@Directive({selector: '[i]'}) @Directive({selector: '[i]'})
class DummyDirective { class DummyDirective {
@Input() @Input() i: any;
i: any;
} }
@Component({ @Component({
@ -1391,7 +1395,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}) })
class MainComp { class MainComp {
constructor(public cdRef: ChangeDetectorRef) {} constructor(public cdRef: ChangeDetectorRef) {}
log(id: string) { log.push(`main-${id}`); } log(id: string) {
log.push(`main-${id}`);
}
} }
@Component({ @Component({
@ -1401,11 +1407,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}) })
class OuterComp { class OuterComp {
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
@ContentChild(TemplateRef, {static: true}) @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>;
tpl !: TemplateRef<any>;
constructor(public cdRef: ChangeDetectorRef) {} constructor(public cdRef: ChangeDetectorRef) {}
log(id: string) { log.push(`outer-${id}`); } log(id: string) {
log.push(`outer-${id}`);
}
} }
@Component({ @Component({
@ -1415,15 +1422,15 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}) })
class InnerComp { class InnerComp {
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
@ContentChild(TemplateRef, {static: true}) @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>;
tpl !: TemplateRef<any>;
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
@Input() @Input() outerTpl!: TemplateRef<any>;
outerTpl !: TemplateRef<any>;
constructor(public cdRef: ChangeDetectorRef) {} constructor(public cdRef: ChangeDetectorRef) {}
log(id: string) { log.push(`inner-${id}`); } log(id: string) {
log.push(`inner-${id}`);
}
} }
let ctx: ComponentFixture<MainComp>; let ctx: ComponentFixture<MainComp>;
@ -1444,13 +1451,11 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
it('should dirty check projected views in regular order', () => { it('should dirty check projected views in regular order', () => {
ctx.detectChanges(false); ctx.detectChanges(false);
expect(log).toEqual( expect(log).toEqual(['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
log = []; log = [];
ctx.detectChanges(false); ctx.detectChanges(false);
expect(log).toEqual( expect(log).toEqual(['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
}); });
it('should not dirty check projected views if neither the declaration nor the insertion place is dirty checked', it('should not dirty check projected views if neither the declaration nor the insertion place is dirty checked',
@ -1526,8 +1531,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
@Directive({selector: '[someDir]'}) @Directive({selector: '[someDir]'})
class SomeDir { class SomeDir {
@HostBinding('class.foo') @HostBinding('class.foo') fooClass = true;
fooClass = true;
} }
const ctx = const ctx =
@ -1544,8 +1548,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
describe('lifecycle asserts', () => { describe('lifecycle asserts', () => {
let logged: string[]; let logged: string[];
function log(value: string) { logged.push(value); } function log(value: string) {
function clearLog() { logged = []; } logged.push(value);
}
function clearLog() {
logged = [];
}
function expectOnceAndOnlyOnce(log: string) { function expectOnceAndOnlyOnce(log: string) {
expect(logged.indexOf(log) >= 0) expect(logged.indexOf(log) >= 0)
@ -1554,7 +1562,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
.toBeTruthy(`'${log}' logged more than once. Log was ${JSON.stringify(logged)}`); .toBeTruthy(`'${log}' logged more than once. Log was ${JSON.stringify(logged)}`);
} }
beforeEach(() => { clearLog(); }); beforeEach(() => {
clearLog();
});
enum LifetimeMethods { enum LifetimeMethods {
None = 0, None = 0,
@ -1593,11 +1603,21 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
constructor() {} constructor() {}
ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } ngDoCheck() {
ngOnInit() { this.check(LifetimeMethods.ngOnInit); } this.check(LifetimeMethods.ngDoCheck);
ngOnChanges() { this.check(LifetimeMethods.ngOnChanges); } }
ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } ngOnInit() {
ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } this.check(LifetimeMethods.ngOnInit);
}
ngOnChanges() {
this.check(LifetimeMethods.ngOnChanges);
}
ngAfterViewInit() {
this.check(LifetimeMethods.ngAfterViewInit);
}
ngAfterContentInit() {
this.check(LifetimeMethods.ngAfterContentInit);
}
private check(method: LifetimeMethods) { private check(method: LifetimeMethods) {
log(`MyChild::${LifetimeMethods[method]}()`); log(`MyChild::${LifetimeMethods[method]}()`);
@ -1625,10 +1645,18 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}) })
class MyComponent { class MyComponent {
constructor(private changeDetectionRef: ChangeDetectorRef) {} constructor(private changeDetectionRef: ChangeDetectorRef) {}
ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } ngDoCheck() {
ngOnInit() { this.check(LifetimeMethods.ngOnInit); } this.check(LifetimeMethods.ngDoCheck);
ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } }
ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } ngOnInit() {
this.check(LifetimeMethods.ngOnInit);
}
ngAfterViewInit() {
this.check(LifetimeMethods.ngAfterViewInit);
}
ngAfterContentInit() {
this.check(LifetimeMethods.ngAfterContentInit);
}
onOutp() { onOutp() {
log('<RECURSION START>'); log('<RECURSION START>');
this.changeDetectionRef.detectChanges(); this.changeDetectionRef.detectChanges();
@ -1670,14 +1698,16 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
} }
forEachMethod(LifetimeMethods.InitMethodsAndChanges, method => { forEachMethod(LifetimeMethods.InitMethodsAndChanges, method => {
it(`should ensure that init hooks are called once an only once with recursion in ${LifetimeMethods[method]} `, it(`should ensure that init hooks are called once an only once with recursion in ${
LifetimeMethods[method]} `,
() => { () => {
// Ensure all the init methods are called once. // Ensure all the init methods are called once.
ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None}); ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None});
}); });
}); });
forEachMethod(LifetimeMethods.All, method => { forEachMethod(LifetimeMethods.All, method => {
it(`should ensure that init hooks are called once an only once with a throw in ${LifetimeMethods[method]} `, it(`should ensure that init hooks are called once an only once with a throw in ${
LifetimeMethods[method]} `,
() => { () => {
// Ensure all the init methods are called once. // Ensure all the init methods are called once.
// the first cycle throws but the next cycle should complete the inits. // the first cycle throws but the next cycle should complete the inits.
@ -1750,7 +1780,9 @@ class DirectiveLog {
this.entries.push(new DirectiveLogEntry(directiveName, method)); this.entries.push(new DirectiveLogEntry(directiveName, method));
} }
clear() { this.entries = []; } clear() {
this.entries = [];
}
filter(methods: string[]): string[] { filter(methods: string[]): string[] {
return this.entries.filter((entry) => methods.indexOf(entry.method) !== -1) return this.entries.filter((entry) => methods.indexOf(entry.method) !== -1)
@ -1762,32 +1794,44 @@ class DirectiveLog {
@Pipe({name: 'countingPipe'}) @Pipe({name: 'countingPipe'})
class CountingPipe implements PipeTransform { class CountingPipe implements PipeTransform {
state: number = 0; state: number = 0;
transform(value: any) { return `${value} state:${this.state++}`; } transform(value: any) {
return `${value} state:${this.state++}`;
}
} }
@Pipe({name: 'countingImpurePipe', pure: false}) @Pipe({name: 'countingImpurePipe', pure: false})
class CountingImpurePipe implements PipeTransform { class CountingImpurePipe implements PipeTransform {
state: number = 0; state: number = 0;
transform(value: any) { return `${value} state:${this.state++}`; } transform(value: any) {
return `${value} state:${this.state++}`;
}
} }
@Pipe({name: 'pipeWithOnDestroy'}) @Pipe({name: 'pipeWithOnDestroy'})
class PipeWithOnDestroy implements PipeTransform, OnDestroy { class PipeWithOnDestroy implements PipeTransform, OnDestroy {
constructor(private directiveLog: DirectiveLog) {} constructor(private directiveLog: DirectiveLog) {}
ngOnDestroy() { this.directiveLog.add('pipeWithOnDestroy', 'ngOnDestroy'); } ngOnDestroy() {
this.directiveLog.add('pipeWithOnDestroy', 'ngOnDestroy');
}
transform(value: any): any { return null; } transform(value: any): any {
return null;
}
} }
@Pipe({name: 'identityPipe'}) @Pipe({name: 'identityPipe'})
class IdentityPipe implements PipeTransform { class IdentityPipe implements PipeTransform {
transform(value: any) { return value; } transform(value: any) {
return value;
}
} }
@Pipe({name: 'wrappedPipe'}) @Pipe({name: 'wrappedPipe'})
class WrappedPipe implements PipeTransform { class WrappedPipe implements PipeTransform {
transform(value: any) { return WrappedValue.wrap(value); } transform(value: any) {
return WrappedValue.wrap(value);
}
} }
@Pipe({name: 'multiArgPipe'}) @Pipe({name: 'multiArgPipe'})
@ -1856,7 +1900,9 @@ class Gh9882 implements AfterContentInit {
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) { constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) {
} }
ngAfterContentInit(): any { this._viewContainer.createEmbeddedView(this._templateRef); } ngAfterContentInit(): any {
this._viewContainer.createEmbeddedView(this._templateRef);
}
} }
@Directive({selector: '[testDirective]', exportAs: 'testDirective'}) @Directive({selector: '[testDirective]', exportAs: 'testDirective'})
@ -1877,9 +1923,13 @@ class TestDirective implements OnInit, DoCheck, OnChanges, AfterContentInit, Aft
constructor(public log: DirectiveLog) {} constructor(public log: DirectiveLog) {}
onEvent(event: any) { this.event = event; } onEvent(event: any) {
this.event = event;
}
ngDoCheck() { this.log.add(this.name, 'ngDoCheck'); } ngDoCheck() {
this.log.add(this.name, 'ngDoCheck');
}
ngOnInit() { ngOnInit() {
this.log.add(this.name, 'ngOnInit'); this.log.add(this.name, 'ngOnInit');
@ -1937,14 +1987,18 @@ class InjectableWithLifecycle {
name = 'injectable'; name = 'injectable';
constructor(public log: DirectiveLog) {} constructor(public log: DirectiveLog) {}
ngOnDestroy() { this.log.add(this.name, 'ngOnDestroy'); } ngOnDestroy() {
this.log.add(this.name, 'ngOnDestroy');
}
} }
@Directive({selector: '[onDestroyDirective]'}) @Directive({selector: '[onDestroyDirective]'})
class OnDestroyDirective implements OnDestroy { class OnDestroyDirective implements OnDestroy {
@Output('destroy') emitter = new EventEmitter<string>(false); @Output('destroy') emitter = new EventEmitter<string>(false);
ngOnDestroy() { this.emitter.emit('destroyed'); } ngOnDestroy() {
this.emitter.emit('destroyed');
}
} }
@Directive({selector: '[orderCheck0]'}) @Directive({selector: '[orderCheck0]'})
@ -2015,9 +2069,13 @@ class Person {
this.address = address; this.address = address;
} }
sayHi(m: any): string { return `Hi, ${m}`; } sayHi(m: any): string {
return `Hi, ${m}`;
}
passThrough(val: any): any { return val; } passThrough(val: any): any {
return val;
}
toString(): string { toString(): string {
const address = this.address == null ? '' : ' address=' + this.address.toString(); const address = this.address == null ? '' : ' address=' + this.address.toString();
@ -2042,11 +2100,17 @@ class Address {
return this._zipcode; return this._zipcode;
} }
set city(v) { this._city = v; } set city(v) {
this._city = v;
}
set zipcode(v) { this._zipcode = v; } set zipcode(v) {
this._zipcode = v;
}
toString(): string { return this.city || '-'; } toString(): string {
return this.city || '-';
}
} }
@Component({selector: 'root', template: 'empty'}) @Component({selector: 'root', template: 'empty'})
@ -2065,7 +2129,9 @@ class TestDataWithGetter {
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
public fn!: Function; public fn!: Function;
get a() { return this.fn(); } get a() {
return this.fn();
}
} }
class Holder<T> { class Holder<T> {

View File

@ -25,26 +25,41 @@ describe('global utils', () => {
describe('publishDefaultGlobalUtils', () => { describe('publishDefaultGlobalUtils', () => {
beforeEach(() => publishDefaultGlobalUtils()); beforeEach(() => publishDefaultGlobalUtils());
it('should publish getComponent', () => { assertPublished('getComponent', getComponent); }); it('should publish getComponent', () => {
assertPublished('getComponent', getComponent);
});
it('should publish getContext', () => { assertPublished('getContext', getContext); }); it('should publish getContext', () => {
assertPublished('getContext', getContext);
});
it('should publish getListeners', () => { assertPublished('getListeners', getListeners); }); it('should publish getListeners', () => {
assertPublished('getListeners', getListeners);
});
it('should publish getOwningComponent', it('should publish getOwningComponent', () => {
() => { assertPublished('getOwningComponent', getOwningComponent); }); assertPublished('getOwningComponent', getOwningComponent);
});
it('should publish getRootComponents', it('should publish getRootComponents', () => {
() => { assertPublished('getRootComponents', getRootComponents); }); assertPublished('getRootComponents', getRootComponents);
});
it('should publish getDirectives', () => { assertPublished('getDirectives', getDirectives); }); it('should publish getDirectives', () => {
assertPublished('getDirectives', getDirectives);
});
it('should publish getHostComponent', it('should publish getHostComponent', () => {
() => { assertPublished('getHostElement', getHostElement); }); assertPublished('getHostElement', getHostElement);
});
it('should publish getInjector', () => { assertPublished('getInjector', getInjector); }); it('should publish getInjector', () => {
assertPublished('getInjector', getInjector);
});
it('should publish applyChanges', () => { assertPublished('applyChanges', applyChanges); }); it('should publish applyChanges', () => {
assertPublished('applyChanges', applyChanges);
});
}); });
}); });

View File

@ -26,10 +26,7 @@ describe('css selector matching', () => {
} }
describe('isNodeMatchingSimpleSelector', () => { describe('isNodeMatchingSimpleSelector', () => {
describe('element matching', () => { describe('element matching', () => {
it('should match element name only if names are the same', () => { it('should match element name only if names are the same', () => {
expect(isMatching('span', null, ['span'])) expect(isMatching('span', null, ['span']))
.toBeTruthy(`Selector 'span' should match <span>`); .toBeTruthy(`Selector 'span' should match <span>`);
@ -55,11 +52,9 @@ describe('css selector matching', () => {
}); });
describe('attributes matching', () => { describe('attributes matching', () => {
// TODO: do we need to differentiate no value and empty value? that is: title vs. title="" ? // TODO: do we need to differentiate no value and empty value? that is: title vs. title="" ?
it('should match single attribute without value', () => { it('should match single attribute without value', () => {
expect(isMatching('span', ['title', ''], [ expect(isMatching('span', ['title', ''], [
'', 'title', '' '', 'title', ''
])).toBeTruthy(`Selector '[title]' should match <span title>`); ])).toBeTruthy(`Selector '[title]' should match <span title>`);
@ -81,7 +76,8 @@ describe('css selector matching', () => {
])).toBeFalsy(`Selector '[other]' should NOT match <span title="">'`); ])).toBeFalsy(`Selector '[other]' should NOT match <span title="">'`);
}); });
// TODO: Not sure how to fix this cases. // TODO: this case will not work, need more discussion
// https://github.com/angular/angular/pull/34625#discussion_r401791275
xit('should match namespaced attributes', () => { xit('should match namespaced attributes', () => {
expect(isMatching( expect(isMatching(
'span', [AttributeMarker.NamespaceURI, 'http://some/uri', 'title', 'name'], 'span', [AttributeMarker.NamespaceURI, 'http://some/uri', 'title', 'name'],
@ -228,7 +224,6 @@ describe('css selector matching', () => {
}); });
describe('class matching', () => { describe('class matching', () => {
it('should match with a class selector when an element has multiple classes', () => { it('should match with a class selector when an element has multiple classes', () => {
expect(isMatching('span', ['class', 'foo bar'], [ expect(isMatching('span', ['class', 'foo bar'], [
'', SelectorFlags.CLASS, 'foo' '', SelectorFlags.CLASS, 'foo'
@ -328,7 +323,6 @@ describe('css selector matching', () => {
}); });
describe('negations', () => { describe('negations', () => {
it('should match when negation part is null', () => { it('should match when negation part is null', () => {
expect(isMatching('span', null, ['span'])).toBeTruthy(`Selector 'span' should match <span>`); expect(isMatching('span', null, ['span'])).toBeTruthy(`Selector 'span' should match <span>`);
}); });
@ -436,11 +430,9 @@ describe('css selector matching', () => {
expect(isMatching('div', ['name', 'name', 'title', '', 'class', 'foo bar'], selector)) expect(isMatching('div', ['name', 'name', 'title', '', 'class', 'foo bar'], selector))
.toBeFalsy(); .toBeFalsy();
}); });
}); });
describe('isNodeMatchingSelectorList', () => { describe('isNodeMatchingSelectorList', () => {
function isAnyMatching( function isAnyMatching(
tagName: string, attrs: string[]|null, selector: CssSelectorList): boolean { tagName: string, attrs: string[]|null, selector: CssSelectorList): boolean {
return isNodeMatchingSelectorList(testLStaticData(tagName, attrs), selector, false); return isNodeMatchingSelectorList(testLStaticData(tagName, attrs), selector, false);
@ -468,16 +460,18 @@ describe('css selector matching', () => {
}); });
describe('reading the ngProjectAs attribute value', function() { describe('reading the ngProjectAs attribute value', function() {
function testTNode(attrs: TAttributes|null) {
function testTNode(attrs: TAttributes | null) { return testLStaticData('tag', attrs); } return testLStaticData('tag', attrs);
}
it('should get ngProjectAs value if present', function() { it('should get ngProjectAs value if present', function() {
expect(getProjectAsAttrValue(testTNode([AttributeMarker.ProjectAs, ['tag', 'foo', 'bar']]))) expect(getProjectAsAttrValue(testTNode([AttributeMarker.ProjectAs, ['tag', 'foo', 'bar']])))
.toEqual(['tag', 'foo', 'bar']); .toEqual(['tag', 'foo', 'bar']);
}); });
it('should return null if there are no attributes', it('should return null if there are no attributes', function() {
function() { expect(getProjectAsAttrValue(testTNode(null))).toBe(null); }); expect(getProjectAsAttrValue(testTNode(null))).toBe(null);
});
it('should return if ngProjectAs is not present', function() { it('should return if ngProjectAs is not present', function() {
expect(getProjectAsAttrValue(testTNode(['foo', 'bar']))).toBe(null); expect(getProjectAsAttrValue(testTNode(['foo', 'bar']))).toBe(null);
@ -486,15 +480,13 @@ describe('css selector matching', () => {
it('should not accidentally identify ngProjectAs in attribute values', function() { it('should not accidentally identify ngProjectAs in attribute values', function() {
expect(getProjectAsAttrValue(testTNode(['foo', AttributeMarker.ProjectAs]))).toBe(null); expect(getProjectAsAttrValue(testTNode(['foo', AttributeMarker.ProjectAs]))).toBe(null);
}); });
}); });
}); });
describe('stringifyCSSSelectorList', () => { describe('stringifyCSSSelectorList', () => {
it('should stringify selector with a tag name only', () => {
it('should stringify selector with a tag name only', expect(stringifyCSSSelectorList([['button']])).toBe('button');
() => { expect(stringifyCSSSelectorList([['button']])).toBe('button'); }); });
it('should stringify selector with attributes', () => { it('should stringify selector with attributes', () => {
expect(stringifyCSSSelectorList([['', 'id', '']])).toBe('[id]'); expect(stringifyCSSSelectorList([['', 'id', '']])).toBe('[id]');

View File

@ -17,6 +17,7 @@ describe('utils', () => {
beforeEach(() => { beforeEach(() => {
// TODO: @JiaLiPassion, need to wait @types/jasmine to fix the wrong return // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the wrong return
// type infer issue. // type infer issue.
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
setTimeoutSpy = spyOn(window, 'setTimeout').and.returnValue(42 as any); setTimeoutSpy = spyOn(window, 'setTimeout').and.returnValue(42 as any);
clearTimeoutSpy = spyOn(window, 'clearTimeout'); clearTimeoutSpy = spyOn(window, 'clearTimeout');
}); });
@ -83,8 +84,9 @@ describe('utils', () => {
expect(camelToDashCase('foo1Bar2Baz3Qux4')).toBe('foo1-bar2-baz3-qux4'); expect(camelToDashCase('foo1Bar2Baz3Qux4')).toBe('foo1-bar2-baz3-qux4');
}); });
it('should keep existing dashes', it('should keep existing dashes', () => {
() => { expect(camelToDashCase('fooBar-baz-Qux')).toBe('foo-bar-baz--qux'); }); expect(camelToDashCase('fooBar-baz-Qux')).toBe('foo-bar-baz--qux');
});
}); });
describe('createCustomEvent()', () => { describe('createCustomEvent()', () => {
@ -99,7 +101,6 @@ describe('utils', () => {
expect(event.cancelable).toBe(false); expect(event.cancelable).toBe(false);
expect(event.detail).toEqual(value); expect(event.detail).toEqual(value);
}); });
}); });
describe('isElement()', () => { describe('isElement()', () => {
@ -218,7 +219,9 @@ describe('utils', () => {
]; ];
values.forEach((v1, i) => { values.forEach((v1, i) => {
values.forEach((v2, j) => { expect(strictEquals(v1, v2)).toBe(i === j); }); values.forEach((v2, j) => {
expect(strictEquals(v1, v2)).toBe(i === j);
});
}); });
}); });

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Inject, ReflectiveInjector, forwardRef, resolveForwardRef} from '@angular/core'; import {forwardRef, Inject, ReflectiveInjector, resolveForwardRef} from '@angular/core';
{ {
describe('forwardRef examples', () => { describe('forwardRef examples', () => {
@ -26,7 +26,9 @@ import {Inject, ReflectiveInjector, forwardRef, resolveForwardRef} from '@angula
// Door attempts to inject Lock, despite it not being defined yet. // Door attempts to inject Lock, despite it not being defined yet.
// forwardRef makes this possible. // forwardRef makes this possible.
constructor(@Inject(forwardRef(() => Lock)) lock: Lock) { this.lock = lock; } constructor(@Inject(forwardRef(() => Lock)) lock: Lock) {
this.lock = lock;
}
} }
// Only at this point Lock is defined. // Only at this point Lock is defined.

View File

@ -17,7 +17,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
let fakeConsole: any; let fakeConsole: any;
if (isNode) return; if (isNode) return;
beforeEach(() => { fakeConsole = {warn: jasmine.createSpy('console.warn')}; }); beforeEach(() => {
fakeConsole = {warn: jasmine.createSpy('console.warn')};
});
describe('with no custom loader', () => { describe('with no custom loader', () => {
beforeEach(() => { beforeEach(() => {
@ -61,7 +63,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
// Inject the NgZone so that we can make it available to the plugin through a fake // Inject the NgZone so that we can make it available to the plugin through a fake
// EventManager. // EventManager.
let ngZone: NgZone; let ngZone: NgZone;
beforeEach(inject([NgZone], (z: NgZone) => { ngZone = z; })); beforeEach(inject([NgZone], (z: NgZone) => {
ngZone = z;
}));
beforeEach(() => { beforeEach(() => {
originalHammerGlobal = (window as any).Hammer; originalHammerGlobal = (window as any).Hammer;
@ -90,7 +94,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
someListener = () => {}; someListener = () => {};
}); });
afterEach(() => { (window as any).Hammer = originalHammerGlobal; }); afterEach(() => {
(window as any).Hammer = originalHammerGlobal;
});
it('should not log a warning when HammerJS is not loaded', () => { it('should not log a warning when HammerJS is not loaded', () => {
plugin.addEventListener(someElement, 'swipe', () => {}); plugin.addEventListener(someElement, 'swipe', () => {});

View File

@ -51,7 +51,6 @@ import {KeyEventsPlugin} from '@angular/platform-browser/src/dom/events/key_even
.toEqual({'domEventName': 'keydown', 'fullKey': 'control.shift'}); .toEqual({'domEventName': 'keydown', 'fullKey': 'control.shift'});
expect(KeyEventsPlugin.parseEventName('keyup.control.shift')) expect(KeyEventsPlugin.parseEventName('keyup.control.shift'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift'}); .toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift'});
}); });
it('should alias esc to escape', () => { it('should alias esc to escape', () => {
@ -67,6 +66,5 @@ import {KeyEventsPlugin} from '@angular/platform-browser/src/dom/events/key_even
expect(() => plugin.addGlobalEventListener('window', 'keyup.control.esc', () => {})) expect(() => plugin.addGlobalEventListener('window', 'keyup.control.esc', () => {}))
.not.toThrowError(); .not.toThrowError();
}); });
}); });
} }

View File

@ -3709,7 +3709,6 @@ describe('Integration', () => {
advance(fixture); advance(fixture);
expect(navigateSpy.calls.mostRecent().args[1]!.queryParams); expect(navigateSpy.calls.mostRecent().args[1]!.queryParams);
}))); })));
}); });

View File

@ -9,7 +9,7 @@
import {PLATFORM_ID} from '@angular/core'; import {PLATFORM_ID} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {NgswCommChannel} from '@angular/service-worker/src/low_level'; import {NgswCommChannel} from '@angular/service-worker/src/low_level';
import {SwRegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module'; import {ngswCommChannelFactory, SwRegistrationOptions} from '@angular/service-worker/src/module';
import {SwPush} from '@angular/service-worker/src/push'; import {SwPush} from '@angular/service-worker/src/push';
import {SwUpdate} from '@angular/service-worker/src/update'; import {SwUpdate} from '@angular/service-worker/src/update';
import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock'; import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock';
@ -32,14 +32,18 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
mock.setupSw(); mock.setupSw();
(comm as any).registration.subscribe((reg: any) => { done(); }); (comm as any).registration.subscribe((reg: any) => {
done();
});
}); });
it('can access the registration when it comes after subscription', done => { it('can access the registration when it comes after subscription', done => {
const mock = new MockServiceWorkerContainer(); const mock = new MockServiceWorkerContainer();
const comm = new NgswCommChannel(mock as any); const comm = new NgswCommChannel(mock as any);
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration; const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
(comm as any).registration.subscribe((reg: any) => { done(); }); (comm as any).registration.subscribe((reg: any) => {
done();
});
mock.setupSw(); mock.setupSw();
}); });
@ -221,7 +225,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
}); });
it('rejects if `PushSubscription.unsubscribe()` fails', async () => { it('rejects if `PushSubscription.unsubscribe()` fails', async () => {
psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); }); psUnsubscribeSpy.and.callFake(() => {
throw new Error('foo');
});
try { try {
await push.requestSubscription({serverPublicKey: 'test'}); await push.requestSubscription({serverPublicKey: 'test'});
@ -271,7 +277,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
subscriptionSpy.calls.reset(); subscriptionSpy.calls.reset();
// Error due to `PushSubscription.unsubscribe()` error. // Error due to `PushSubscription.unsubscribe()` error.
psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); }); psUnsubscribeSpy.and.callFake(() => {
throw new Error('foo');
});
await push.unsubscribe().catch(() => undefined); await push.unsubscribe().catch(() => undefined);
expect(subscriptionSpy).not.toHaveBeenCalled(); expect(subscriptionSpy).not.toHaveBeenCalled();
@ -391,11 +399,16 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
}); });
it('gives an error when registering', done => { it('gives an error when registering', done => {
push.requestSubscription({serverPublicKey: 'test'}).catch(err => { done(); }); push.requestSubscription({serverPublicKey: 'test'}).catch(err => {
done();
});
}); });
it('gives an error when unsubscribing', it('gives an error when unsubscribing', done => {
done => { push.unsubscribe().catch(err => { done(); }); }); push.unsubscribe().catch(err => {
done();
});
});
}); });
}); });
@ -461,7 +474,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
}); });
}); });
return update.activateUpdate() return update.activateUpdate()
.catch(err => { expect(err.message).toEqual('Failed to activate'); }) .catch(err => {
expect(err.message).toEqual('Failed to activate');
})
.then(() => done()) .then(() => done())
.catch(err => done.fail(err)); .catch(err => done.fail(err));
}); });
@ -475,8 +490,12 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
expect(() => TestBed.inject(SwUpdate)).not.toThrow(); expect(() => TestBed.inject(SwUpdate)).not.toThrow();
}); });
describe('with no SW', () => { describe('with no SW', () => {
beforeEach(() => { comm = new NgswCommChannel(undefined); }); beforeEach(() => {
it('can be instantiated', () => { update = new SwUpdate(comm); }); comm = new NgswCommChannel(undefined);
});
it('can be instantiated', () => {
update = new SwUpdate(comm);
});
it('does not crash on subscription to observables', () => { it('does not crash on subscription to observables', () => {
update = new SwUpdate(comm); update = new SwUpdate(comm);
update.available.toPromise().catch(err => fail(err)); update.available.toPromise().catch(err => fail(err));
@ -484,11 +503,15 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
}); });
it('gives an error when checking for updates', done => { it('gives an error when checking for updates', done => {
update = new SwUpdate(comm); update = new SwUpdate(comm);
update.checkForUpdate().catch(err => { done(); }); update.checkForUpdate().catch(err => {
done();
});
}); });
it('gives an error when activating updates', done => { it('gives an error when activating updates', done => {
update = new SwUpdate(comm); update = new SwUpdate(comm);
update.activateUpdate().catch(err => { done(); }); update.activateUpdate().catch(err => {
done();
});
}); });
}); });
}); });

View File

@ -7,7 +7,7 @@
*/ */
import {ApplicationRef, PLATFORM_ID} from '@angular/core'; import {ApplicationRef, PLATFORM_ID} from '@angular/core';
import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing';
import {Subject} from 'rxjs'; import {Subject} from 'rxjs';
import {filter, take} from 'rxjs/operators'; import {filter, take} from 'rxjs/operators';

View File

@ -11,7 +11,7 @@ import {CacheDatabase} from '../src/db-cache';
import {Driver, DriverReadyState} from '../src/driver'; import {Driver, DriverReadyState} from '../src/driver';
import {AssetGroupConfig, DataGroupConfig, Manifest} from '../src/manifest'; import {AssetGroupConfig, DataGroupConfig, Manifest} from '../src/manifest';
import {sha1} from '../src/sha1'; import {sha1} from '../src/sha1';
import {MockCache, clearAllCaches} from '../testing/cache'; import {clearAllCaches, MockCache} from '../testing/cache';
import {MockRequest, MockResponse} from '../testing/fetch'; import {MockRequest, MockResponse} from '../testing/fetch';
import {MockFileSystemBuilder, MockServerStateBuilder, tmpHashTableForFs} from '../testing/mock'; import {MockFileSystemBuilder, MockServerStateBuilder, tmpHashTableForFs} from '../testing/mock';
import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope'; import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
@ -35,8 +35,7 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
.addUnhashedFile('/unhashed/a.txt', 'this is unhashed', {'Cache-Control': 'max-age=10'}) .addUnhashedFile('/unhashed/a.txt', 'this is unhashed', {'Cache-Control': 'max-age=10'})
.addUnhashedFile('/unhashed/b.txt', 'this is unhashed b', {'Cache-Control': 'no-cache'}) .addUnhashedFile('/unhashed/b.txt', 'this is unhashed b', {'Cache-Control': 'no-cache'})
.addUnhashedFile('/api/foo', 'this is api foo', {'Cache-Control': 'no-cache'}) .addUnhashedFile('/api/foo', 'this is api foo', {'Cache-Control': 'no-cache'})
.addUnhashedFile( .addUnhashedFile('/api-static/bar', 'this is static api bar', {'Cache-Control': 'no-cache'})
'/api-static/bar', 'this is static api bar', {'Cache-Control': 'no-cache'})
.build(); .build();
const distUpdate = const distUpdate =
@ -49,8 +48,7 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
.addFile('/quuux.txt', 'this is quuux v2') .addFile('/quuux.txt', 'this is quuux v2')
.addFile('/lazy/unchanged1.txt', 'this is unchanged (1)') .addFile('/lazy/unchanged1.txt', 'this is unchanged (1)')
.addFile('/lazy/unchanged2.txt', 'this is unchanged (2)') .addFile('/lazy/unchanged2.txt', 'this is unchanged (2)')
.addUnhashedFile( .addUnhashedFile('/unhashed/a.txt', 'this is unhashed v2', {'Cache-Control': 'max-age=10'})
'/unhashed/a.txt', 'this is unhashed v2', {'Cache-Control': 'max-age=10'})
.addUnhashedFile('/ignored/file1', 'this is not handled by the SW') .addUnhashedFile('/ignored/file1', 'this is not handled by the SW')
.addUnhashedFile('/ignored/dir/file2', 'this is not handled by the SW either') .addUnhashedFile('/ignored/dir/file2', 'this is not handled by the SW either')
.build(); .build();
@ -271,10 +269,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
const brokenServer = const brokenServer =
new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenManifest).build(); new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenManifest).build();
const brokenLazyServer = new MockServerStateBuilder() const brokenLazyServer =
.withStaticFiles(brokenFs) new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenLazyManifest).build();
.withManifest(brokenLazyManifest)
.build();
const server404 = new MockServerStateBuilder().withStaticFiles(dist).build(); const server404 = new MockServerStateBuilder().withStaticFiles(dist).build();
@ -848,7 +844,6 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
await makeRequest(scope, '/bar?ngsw-byapass&testparam2'); await makeRequest(scope, '/bar?ngsw-byapass&testparam2');
server.assertSawRequestFor('/bar'); server.assertSawRequestFor('/bar');
}); });
it('unregisters when manifest 404s', async () => { it('unregisters when manifest 404s', async () => {
@ -890,7 +885,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
describe('cache naming', () => { describe('cache naming', () => {
// Helpers // Helpers
const cacheKeysFor = (baseHref: string) => const cacheKeysFor = (baseHref: string) =>
[`ngsw:${baseHref}:db:control`, `ngsw:${baseHref}:${manifestHash}:assets:assets:cache`, [`ngsw:${baseHref}:db:control`,
`ngsw:${baseHref}:${manifestHash}:assets:assets:cache`,
`ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:assets:meta`, `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:assets:meta`,
`ngsw:${baseHref}:${manifestHash}:assets:other:cache`, `ngsw:${baseHref}:${manifestHash}:assets:other:cache`,
`ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:other:meta`, `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:other:meta`,
@ -1182,8 +1178,7 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
expect(await navRequest('/ignored/file1')).toBe('this is not handled by the SW'); expect(await navRequest('/ignored/file1')).toBe('this is not handled by the SW');
serverUpdate.assertSawRequestFor('/ignored/file1'); serverUpdate.assertSawRequestFor('/ignored/file1');
expect(await navRequest('/ignored/dir/file2')) expect(await navRequest('/ignored/dir/file2')).toBe('this is not handled by the SW either');
.toBe('this is not handled by the SW either');
serverUpdate.assertSawRequestFor('/ignored/dir/file2'); serverUpdate.assertSawRequestFor('/ignored/dir/file2');
expect(await navRequest('/ignored/directory/file2')).toBe('this is foo v2'); expect(await navRequest('/ignored/directory/file2')).toBe('this is foo v2');
@ -1194,8 +1189,7 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
expect(await navRequest('/foo/file1?query=/a/b')).toBe('this is foo v2'); expect(await navRequest('/foo/file1?query=/a/b')).toBe('this is foo v2');
serverUpdate.assertNoOtherRequests(); serverUpdate.assertNoOtherRequests();
expect(await navRequest('/ignored/file1?query=/a/b')) expect(await navRequest('/ignored/file1?query=/a/b')).toBe('this is not handled by the SW');
.toBe('this is not handled by the SW');
serverUpdate.assertSawRequestFor('/ignored/file1'); serverUpdate.assertSawRequestFor('/ignored/file1');
expect(await navRequest('/ignored/dir/file2?query=/a/b')) expect(await navRequest('/ignored/dir/file2?query=/a/b'))
@ -1240,10 +1234,10 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
it('should delete other caches even if deleting one of them fails', async () => { it('should delete other caches even if deleting one of them fails', async () => {
const oldSwCacheNames = ['ngsw:active', 'ngsw:staged', 'ngsw:manifest:a1b2c3:super:duper']; const oldSwCacheNames = ['ngsw:active', 'ngsw:staged', 'ngsw:manifest:a1b2c3:super:duper'];
const deleteSpy = spyOn(scope.caches, 'delete') const deleteSpy =
spyOn(scope.caches, 'delete')
.and.callFake( .and.callFake(
(cacheName: string) => (cacheName: string) => Promise.reject(`Failed to delete cache '${cacheName}'.`));
Promise.reject(`Failed to delete cache '${cacheName}'.`));
await Promise.all(oldSwCacheNames.map(name => scope.caches.open(name))); await Promise.all(oldSwCacheNames.map(name => scope.caches.open(name)));
const error = await driver.cleanupOldSwCaches().catch(err => err); const error = await driver.cleanupOldSwCaches().catch(err => err);
@ -1488,8 +1482,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
})(); })();
async function makeRequest( async function makeRequest(
scope: SwTestHarness, url: string, clientId: string | null = 'default', init?: Object): scope: SwTestHarness, url: string, clientId: string|null = 'default',
Promise<string|null> { init?: Object): Promise<string|null> {
const [resPromise, done] = scope.handleFetch(new MockRequest(url, init), clientId); const [resPromise, done] = scope.handleFetch(new MockRequest(url, init), clientId);
await done; await done;
const res = await resPromise; const res = await resPromise;
@ -1500,13 +1494,14 @@ async function makeRequest(
} }
function makeNavigationRequest( function makeNavigationRequest(
scope: SwTestHarness, url: string, clientId?: string | null, init: Object = {}): scope: SwTestHarness, url: string, clientId?: string|null,
Promise<string|null> { init: Object = {}): Promise<string|null> {
return makeRequest(scope, url, clientId, { return makeRequest(scope, url, clientId, {
headers: { headers: {
Accept: 'text/plain, text/html, text/css', Accept: 'text/plain, text/html, text/css',
...(init as any).headers, ...(init as any).headers,
}, },
mode: 'navigate', ...init, mode: 'navigate',
...init,
}); });
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ChangeDetectorRef, Component, EventEmitter, Input, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory, NgZone, OnChanges, OnDestroy, Output, SimpleChange, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core'; import {ChangeDetectorRef, Component, destroyPlatform, EventEmitter, forwardRef, Input, NgModule, NgModuleFactory, NgZone, NO_ERRORS_SCHEMA, OnChanges, OnDestroy, Output, SimpleChange, SimpleChanges, Testability} from '@angular/core';
import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {BrowserModule} from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -23,7 +23,6 @@ declare global {
withEachNg1Version(() => { withEachNg1Version(() => {
describe('adapter: ng1 to ng2', () => { describe('adapter: ng1 to ng2', () => {
beforeEach(() => destroyPlatform()); beforeEach(() => destroyPlatform());
afterEach(() => destroyPlatform()); afterEach(() => destroyPlatform());
@ -232,7 +231,9 @@ withEachNg1Version(() => {
}) })
class Ng2 { class Ng2 {
l: any; l: any;
constructor() { this.l = l; } constructor() {
this.l = l;
}
} }
@NgModule({ @NgModule({
@ -262,7 +263,9 @@ withEachNg1Version(() => {
@Component({selector: 'my-app', template: '<my-child [value]="value"></my-child>'}) @Component({selector: 'my-app', template: '<my-child [value]="value"></my-child>'})
class AppComponent { class AppComponent {
value?: number; value?: number;
constructor() { appComponent = this; } constructor() {
appComponent = this;
}
} }
@Component({ @Component({
@ -272,7 +275,9 @@ withEachNg1Version(() => {
class ChildComponent { class ChildComponent {
valueFromPromise?: number; valueFromPromise?: number;
@Input() @Input()
set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); } set value(v: number) {
expect(NgZone.isInAngularZone()).toBe(true);
}
constructor(private zone: NgZone) {} constructor(private zone: NgZone) {}
@ -358,8 +363,9 @@ withEachNg1Version(() => {
it('should bind properties, events', async(() => { it('should bind properties, events', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = const ng1Module = angular.module_('ng1', []).value($EXCEPTION_HANDLER, (err: any) => {
angular.module_('ng1', []).value($EXCEPTION_HANDLER, (err: any) => { throw err; }); throw err;
});
ng1Module.run(($rootScope: any) => { ng1Module.run(($rootScope: any) => {
$rootScope.name = 'world'; $rootScope.name = 'world';
@ -409,8 +415,8 @@ withEachNg1Version(() => {
} }
const actValue = changes[prop].currentValue; const actValue = changes[prop].currentValue;
if (actValue != value) { if (actValue != value) {
throw new Error( throw new Error(`Expected changes record for'${prop}' to be '${
`Expected changes record for'${prop}' to be '${value}' but was '${actValue}'`); value}' but was '${actValue}'`);
} }
}; };
@ -475,7 +481,6 @@ withEachNg1Version(() => {
ref.dispose(); ref.dispose();
}); });
})); }));
it('should support two-way binding and event listener', async(() => { it('should support two-way binding and event listener', async(() => {
@ -590,7 +595,9 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []); const ng1Module = angular.module_('ng1', []);
ng1Module.run(($rootScope: any /** TODO #9100 */) => { $rootScope.modelA = 'A'; }); ng1Module.run(($rootScope: any /** TODO #9100 */) => {
$rootScope.modelA = 'A';
});
let ng2Instance: Ng2; let ng2Instance: Ng2;
@Component({selector: 'ng2', template: '{{_value}}'}) @Component({selector: 'ng2', template: '{{_value}}'})
@ -598,11 +605,21 @@ withEachNg1Version(() => {
private _value: any = ''; private _value: any = '';
private _onChangeCallback: (_: any) => void = () => {}; private _onChangeCallback: (_: any) => void = () => {};
private _onTouchedCallback: () => void = () => {}; private _onTouchedCallback: () => void = () => {};
constructor() { ng2Instance = this; } constructor() {
writeValue(value: any) { this._value = value; } ng2Instance = this;
registerOnChange(fn: any) { this._onChangeCallback = fn; } }
registerOnTouched(fn: any) { this._onTouchedCallback = fn; } writeValue(value: any) {
doTouch() { this._onTouchedCallback(); } this._value = value;
}
registerOnChange(fn: any) {
this._onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this._onTouchedCallback = fn;
}
doTouch() {
this._onTouchedCallback();
}
doChange(newValue: string) { doChange(newValue: string) {
this._value = newValue; this._value = newValue;
this._onChangeCallback(newValue); this._onChangeCallback(newValue);
@ -653,14 +670,18 @@ withEachNg1Version(() => {
return { return {
template: '<div ng-if="!destroyIt"><ng2></ng2></div>', template: '<div ng-if="!destroyIt"><ng2></ng2></div>',
controller: function($rootScope: any, $timeout: Function) { controller: function($rootScope: any, $timeout: Function) {
$timeout(() => { $rootScope.destroyIt = true; }); $timeout(() => {
$rootScope.destroyIt = true;
});
} }
}; };
}); });
@Component({selector: 'ng2', template: 'test'}) @Component({selector: 'ng2', template: 'test'})
class Ng2 { class Ng2 {
ngOnDestroy() { onDestroyed.emit('destroyed'); } ngOnDestroy() {
onDestroyed.emit('destroyed');
}
} }
@NgModule({ @NgModule({
@ -673,7 +694,9 @@ withEachNg1Version(() => {
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
const element = html('<ng1></ng1>'); const element = html('<ng1></ng1>');
adapter.bootstrap(element, ['ng1']).ready((ref) => { adapter.bootstrap(element, ['ng1']).ready((ref) => {
onDestroyed.subscribe(() => { ref.dispose(); }); onDestroyed.subscribe(() => {
ref.dispose();
});
}); });
})); }));
@ -689,7 +712,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2-inner', template: 'test'}) @Component({selector: 'ng2-inner', template: 'test'})
class Ng2InnerComponent implements OnDestroy { class Ng2InnerComponent implements OnDestroy {
ngOnDestroy() { destroyed = true; } ngOnDestroy() {
destroyed = true;
}
} }
@NgModule({ @NgModule({
@ -868,7 +893,9 @@ withEachNg1Version(() => {
dataA = 'foo'; dataA = 'foo';
dataB = 'bar'; dataB = 'bar';
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -932,7 +959,9 @@ withEachNg1Version(() => {
dataA = {value: 'foo'}; dataA = {value: 'foo'};
dataB = {value: 'bar'}; dataB = {value: 'bar'};
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -996,7 +1025,9 @@ withEachNg1Version(() => {
dataA = {value: 'foo'}; dataA = {value: 'foo'};
dataB = {value: 'bar'}; dataB = {value: 'bar'};
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -1204,7 +1235,9 @@ withEachNg1Version(() => {
restrict: 'E', restrict: 'E',
template: '{{someText}} - Length: {{data.length}}', template: '{{someText}} - Length: {{data.length}}',
scope: {data: '='}, scope: {data: '='},
controller: function($scope: any) { $scope.someText = 'ng1 - Data: ' + $scope.data; } controller: function($scope: any) {
$scope.someText = 'ng1 - Data: ' + $scope.data;
}
}; };
}; };
@ -1248,7 +1281,9 @@ withEachNg1Version(() => {
restrict: 'E', restrict: 'E',
template: '{{someText}} - Length: {{data.length}}', template: '{{someText}} - Length: {{data.length}}',
scope: {data: '='}, scope: {data: '='},
link: function($scope: any) { $scope.someText = 'ng1 - Data: ' + $scope.data; } link: function($scope: any) {
$scope.someText = 'ng1 - Data: ' + $scope.data;
}
}; };
}; };
@ -1291,7 +1326,9 @@ withEachNg1Version(() => {
cbFn(200, `${method}:${url}`); cbFn(200, `${method}:${url}`);
}); });
const ng1 = () => { return {templateUrl: 'url.html'}; }; const ng1 = () => {
return {templateUrl: 'url.html'};
};
ng1Module.directive('ng1', ng1); ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'}) @Component({selector: 'ng2', template: '<ng1></ng1>'})
class Ng2 { class Ng2 {
@ -1320,7 +1357,13 @@ withEachNg1Version(() => {
cbFn(200, `${method}:${url}`); cbFn(200, `${method}:${url}`);
}); });
const ng1 = () => { return {templateUrl() { return 'url.html'; }}; }; const ng1 = () => {
return {
templateUrl() {
return 'url.html';
}
};
};
ng1Module.directive('ng1', ng1); ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'}) @Component({selector: 'ng2', template: '<ng1></ng1>'})
class Ng2 { class Ng2 {
@ -1345,7 +1388,9 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []); const ng1Module = angular.module_('ng1', []);
const ng1 = () => { return {template: ''}; }; const ng1 = () => {
return {template: ''};
};
ng1Module.directive('ng1', ng1); ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'}) @Component({selector: 'ng2', template: '<ng1></ng1>'})
@ -1371,7 +1416,13 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []); const ng1Module = angular.module_('ng1', []);
const ng1 = () => { return {template() { return ''; }}; }; const ng1 = () => {
return {
template() {
return '';
}
};
};
ng1Module.directive('ng1', ng1); ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'}) @Component({selector: 'ng2', template: '<ng1></ng1>'})
@ -1398,7 +1449,9 @@ withEachNg1Version(() => {
const ng1Module = angular.module_('ng1', []); const ng1Module = angular.module_('ng1', []);
ng1Module.run(($templateCache: any) => $templateCache.put('url.html', 'WORKS')); ng1Module.run(($templateCache: any) => $templateCache.put('url.html', 'WORKS'));
const ng1 = () => { return {templateUrl: 'url.html'}; }; const ng1 = () => {
return {templateUrl: 'url.html'};
};
ng1Module.directive('ng1', ng1); ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'}) @Component({selector: 'ng2', template: '<ng1></ng1>'})
@ -1431,13 +1484,20 @@ withEachNg1Version(() => {
'{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}', '{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}',
controllerAs: 'ctl', controllerAs: 'ctl',
controller: class { controller: class {
scope: any; hasElement: string; $element: any; isClass: any; scope: any;
hasElement: string;
$element: any;
isClass: any;
constructor($scope: any, $element: any) { constructor($scope: any, $element: any) {
this.verifyIAmAClass(); this.verifyIAmAClass();
this.scope = $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope'; this.scope = $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope';
this.hasElement = $element[0].nodeName; this.hasElement = $element[0].nodeName;
this.$element = $element; this.$element = $element;
} verifyIAmAClass() { this.isClass = 'isClass'; } isPublished() { }
verifyIAmAClass() {
this.isClass = 'isClass';
}
isPublished() {
return this.$element.controller('ng1') == this ? 'published' : 'not-published'; return this.$element.controller('ng1') == this ? 'published' : 'not-published';
} }
} }
@ -1543,7 +1603,9 @@ withEachNg1Version(() => {
template: '{{ctl.status}}', template: '{{ctl.status}}',
require: 'ng1', require: 'ng1',
controllerAs: 'ctrl', controllerAs: 'ctrl',
controller: class {status = 'WORKS';}, controller: class {
status = 'WORKS';
},
link: function(scope: any, element: any, attrs: any, linkController: any) { link: function(scope: any, element: any, attrs: any, linkController: any) {
expect(scope.$root).toEqual($rootScope); expect(scope.$root).toEqual($rootScope);
expect(element[0].nodeName).toEqual('NG1'); expect(element[0].nodeName).toEqual('NG1');
@ -1577,7 +1639,13 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []); const ng1Module = angular.module_('ng1', []);
const parent = () => { return {controller: class {parent = 'PARENT';}}; }; const parent = () => {
return {
controller: class {
parent = 'PARENT';
}
};
};
const ng1 = () => { const ng1 = () => {
return { return {
scope: {title: '@'}, scope: {title: '@'},
@ -1585,7 +1653,9 @@ withEachNg1Version(() => {
template: '{{parent.parent}}:{{ng1.status}}', template: '{{parent.parent}}:{{ng1.status}}',
require: ['ng1', '^parent', '?^^notFound'], require: ['ng1', '^parent', '?^^notFound'],
controllerAs: 'ctrl', controllerAs: 'ctrl',
controller: class {status = 'WORKS';}, controller: class {
status = 'WORKS';
},
link: function(scope: any, element: any, attrs: any, linkControllers: any) { link: function(scope: any, element: any, attrs: any, linkControllers: any) {
expect(linkControllers[0].status).toEqual('WORKS'); expect(linkControllers[0].status).toEqual('WORKS');
expect(linkControllers[1].parent).toEqual('PARENT'); expect(linkControllers[1].parent).toEqual('PARENT');
@ -1633,15 +1703,20 @@ withEachNg1Version(() => {
scope: {}, scope: {},
bindToController: true, bindToController: true,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: class {$onInit() { $onInitSpyA(); }} controller: class {
$onInit() {
$onInitSpyA();
}
}
})) }))
.directive( .directive('ng1B', () => ({
'ng1B', () => ({
template: '', template: '',
scope: {}, scope: {},
bindToController: false, bindToController: false,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: function(this: any) { this.$onInit = $onInitSpyB; } controller: function(this: any) {
this.$onInit = $onInitSpyB;
}
})) }))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component)); .directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -1718,7 +1793,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'}) @Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'})
class Ng2Component { class Ng2Component {
constructor(cd: ChangeDetectorRef) { changeDetector = cd; } constructor(cd: ChangeDetectorRef) {
changeDetector = cd;
}
} }
angular.module_('ng1', []) angular.module_('ng1', [])
@ -1727,15 +1804,20 @@ withEachNg1Version(() => {
scope: {}, scope: {},
bindToController: true, bindToController: true,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: class {$doCheck() { $doCheckSpyA(); }} controller: class {
$doCheck() {
$doCheckSpyA();
}
}
})) }))
.directive( .directive('ng1B', () => ({
'ng1B', () => ({
template: '', template: '',
scope: {}, scope: {},
bindToController: false, bindToController: false,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: function(this: any) { this.$doCheck = $doCheckSpyB; } controller: function(this: any) {
this.$doCheck = $doCheckSpyB;
}
})) }))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component)); .directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -1773,7 +1855,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'}) @Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'})
class Ng2Component { class Ng2Component {
constructor(cd: ChangeDetectorRef) { changeDetector = cd; } constructor(cd: ChangeDetectorRef) {
changeDetector = cd;
}
} }
angular.module_('ng1', []) angular.module_('ng1', [])
@ -1835,15 +1919,20 @@ withEachNg1Version(() => {
scope: {}, scope: {},
bindToController: true, bindToController: true,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: class {$postLink() { $postLinkSpyA(); }} controller: class {
$postLink() {
$postLinkSpyA();
}
}
})) }))
.directive( .directive('ng1B', () => ({
'ng1B', () => ({
template: '', template: '',
scope: {}, scope: {},
bindToController: false, bindToController: false,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: function(this: any) { this.$postLink = $postLinkSpyB; } controller: function(this: any) {
this.$postLink = $postLinkSpyB;
}
})) }))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component)); .directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -1924,7 +2013,9 @@ withEachNg1Version(() => {
template: '<ng1-a [valA]="val"></ng1-a> | <ng1-b [valB]="val"></ng1-b>' template: '<ng1-a [valA]="val"></ng1-a> | <ng1-b [valB]="val"></ng1-b>'
}) })
class Ng2Component { class Ng2Component {
constructor() { ng2Instance = this; } constructor() {
ng2Instance = this;
}
} }
angular.module_('ng1', []) angular.module_('ng1', [])
@ -1937,15 +2028,15 @@ withEachNg1Version(() => {
this.$onChanges = $onChangesControllerSpyA; this.$onChanges = $onChangesControllerSpyA;
} }
})) }))
.directive( .directive('ng1B', () => ({
'ng1B',
() => ({
template: '', template: '',
scope: {valB: '<'}, scope: {valB: '<'},
bindToController: false, bindToController: false,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: class { controller: class {
$onChanges(changes: SimpleChanges) { $onChangesControllerSpyB(changes); } $onChanges(changes: SimpleChanges) {
$onChangesControllerSpyB(changes);
}
} }
})) }))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component)) .directive('ng2', adapter.downgradeNg2Component(Ng2Component))
@ -2022,7 +2113,9 @@ withEachNg1Version(() => {
}) })
class Ng2Component { class Ng2Component {
ng2Destroy: boolean = false; ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
@ -2036,15 +2129,20 @@ withEachNg1Version(() => {
scope: {}, scope: {},
bindToController: true, bindToController: true,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: class {$onDestroy() { $onDestroySpyA(); }} controller: class {
$onDestroy() {
$onDestroySpyA();
}
}
})) }))
.directive( .directive('ng1B', () => ({
'ng1B', () => ({
template: '', template: '',
scope: {}, scope: {},
bindToController: false, bindToController: false,
controllerAs: '$ctrl', controllerAs: '$ctrl',
controller: function(this: any) { this.$onDestroy = $onDestroySpyB; } controller: function(this: any) {
this.$onDestroy = $onDestroySpyB;
}
})) }))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component)); .directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -2112,7 +2210,9 @@ withEachNg1Version(() => {
}) })
class Ng2Component { class Ng2Component {
ng2Destroy: boolean = false; ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
@ -2187,7 +2287,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'}) @Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'})
class Ng2Component { class Ng2Component {
ng2Destroy: boolean = false; ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
@ -2233,7 +2335,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'}) @Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'})
class Ng2Component { class Ng2Component {
ng2Destroy: boolean = false; ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
@ -2301,7 +2405,9 @@ withEachNg1Version(() => {
class Ng2ComponentA { class Ng2ComponentA {
destroyIt = false; destroyIt = false;
constructor() { ng2ComponentAInstance = this; } constructor() {
ng2ComponentAInstance = this;
}
} }
@Component({selector: 'ng2B', template: '<ng1></ng1>'}) @Component({selector: 'ng2B', template: '<ng1></ng1>'})
@ -2367,7 +2473,9 @@ withEachNg1Version(() => {
class Ng2ComponentA { class Ng2ComponentA {
destroyIt = false; destroyIt = false;
constructor() { ng2ComponentAInstance = this; } constructor() {
ng2ComponentAInstance = this;
}
} }
@Component({selector: 'ng2B', template: '<ng1></ng1>'}) @Component({selector: 'ng2B', template: '<ng1></ng1>'})
@ -2420,7 +2528,11 @@ withEachNg1Version(() => {
const ng1Directive: angular.IDirective = { const ng1Directive: angular.IDirective = {
template: '', template: '',
link: {pre: () => log.push('ng1-pre')}, link: {pre: () => log.push('ng1-pre')},
controller: class {constructor() { log.push('ng1-ctrl'); }} controller: class {
constructor() {
log.push('ng1-ctrl');
}
}
}; };
// Define `Ng2Component` // Define `Ng2Component`
@ -2577,7 +2689,11 @@ withEachNg1Version(() => {
const ng1Directive: angular.IDirective = { const ng1Directive: angular.IDirective = {
template: '', template: '',
link: () => log.push('ng1-post'), link: () => log.push('ng1-post'),
controller: class {$postLink() { log.push('ng1-$post'); }} controller: class {
$postLink() {
log.push('ng1-$post');
}
}
}; };
// Define `Ng2Component` // Define `Ng2Component`
@ -2627,13 +2743,17 @@ withEachNg1Version(() => {
class Ng2ComponentA { class Ng2ComponentA {
value = 'foo'; value = 'foo';
showB = false; showB = false;
constructor() { ng2ComponentAInstance = this; } constructor() {
ng2ComponentAInstance = this;
}
} }
@Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) @Component({selector: 'ng2B', template: 'ng2B({{ value }})'})
class Ng2ComponentB { class Ng2ComponentB {
value = 'bar'; value = 'bar';
constructor() { ng2ComponentBInstance = this; } constructor() {
ng2ComponentBInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -2678,7 +2798,10 @@ withEachNg1Version(() => {
template: 'ng1(<div ng-transclude>{{ $ctrl.value }}</div>)', template: 'ng1(<div ng-transclude>{{ $ctrl.value }}</div>)',
transclude: true, transclude: true,
controller: class { controller: class {
value = 'from-ng1'; constructor() { ng1ControllerInstances.push(this); } value = 'from-ng1';
constructor() {
ng1ControllerInstances.push(this);
}
} }
}; };
@ -2697,7 +2820,9 @@ withEachNg1Version(() => {
}) })
class Ng2Component { class Ng2Component {
value = 'from-ng2'; value = 'from-ng2';
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -2756,7 +2881,9 @@ withEachNg1Version(() => {
class Ng2Component { class Ng2Component {
x = 'foo'; x = 'foo';
y = 'bar'; y = 'bar';
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -2798,8 +2925,12 @@ withEachNg1Version(() => {
const ng1Component: angular.IComponent = { const ng1Component: angular.IComponent = {
template: 'ng1(default(<div ng-transclude="">fallback-{{ $ctrl.value }}</div>))', template: 'ng1(default(<div ng-transclude="">fallback-{{ $ctrl.value }}</div>))',
transclude: {slotX: 'contentX', slotY: 'contentY'}, transclude: {slotX: 'contentX', slotY: 'contentY'},
controller: controller: class {
class {value = 'ng1'; constructor() { ng1ControllerInstances.push(this); }} value = 'ng1';
constructor() {
ng1ControllerInstances.push(this);
}
}
}; };
// Define `Ng2Component` // Define `Ng2Component`
@ -2830,7 +2961,9 @@ withEachNg1Version(() => {
class Ng2Component { class Ng2Component {
x = 'foo'; x = 'foo';
y = 'bar'; y = 'bar';
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -2880,7 +3013,11 @@ withEachNg1Version(() => {
)`, )`,
transclude: {slotX: '?contentX', slotY: '?contentY'}, transclude: {slotX: '?contentX', slotY: '?contentY'},
controller: class { controller: class {
x = 'ng1X'; y = 'ng1Y'; constructor() { ng1ControllerInstances.push(this); } x = 'ng1X';
y = 'ng1Y';
constructor() {
ng1ControllerInstances.push(this);
}
} }
}; };
@ -2896,7 +3033,9 @@ withEachNg1Version(() => {
class Ng2Component { class Ng2Component {
x = 'ng2X'; x = 'ng2X';
y = 'ng2Y'; y = 'ng2Y';
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -3000,7 +3139,9 @@ withEachNg1Version(() => {
x = 'foo'; x = 'foo';
y = 'bar'; y = 'bar';
show = true; show = true;
constructor() { ng2ComponentInstance = this; } constructor() {
ng2ComponentInstance = this;
}
} }
// Define `ng1Module` // Define `ng1Module`
@ -3202,13 +3343,18 @@ withEachNg1Version(() => {
const ng1Module = angular.module_('ng1', []); const ng1Module = angular.module_('ng1', []);
let a1Injector: angular.IInjectorService|undefined; let a1Injector: angular.IInjectorService|undefined;
ng1Module.run([ ng1Module.run([
'$injector', function($injector: angular.IInjectorService) { a1Injector = $injector; } '$injector',
function($injector: angular.IInjectorService) {
a1Injector = $injector;
}
]); ]);
const element = html('<div></div>'); const element = html('<div></div>');
window.name = 'NG_DEFER_BOOTSTRAP!' + window.name; window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;
adapter.bootstrap(element, [ng1Module.name]).ready((ref) => { ref.dispose(); }); adapter.bootstrap(element, [ng1Module.name]).ready((ref) => {
ref.dispose();
});
tick(100); tick(100);

View File

@ -284,11 +284,7 @@ describe('bluebird promise', () => {
.each( .each(
BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)),
(r: number, idx: number) => { (r: number, idx: number) => {
<<<<<<< HEAD
expect(r).toBe(arr[idx]); expect(r).toBe(arr[idx]);
=======
expect(r === arr[idx]).toBeTrue();
>>>>>>> 253023848d... build: update jasmine to 3.5
expect(Zone.current.name).toEqual('bluebird'); expect(Zone.current.name).toEqual('bluebird');
}) })
.then((r: any) => { .then((r: any) => {
@ -309,11 +305,7 @@ describe('bluebird promise', () => {
.mapSeries( .mapSeries(
BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)),
(r: number, idx: number) => { (r: number, idx: number) => {
<<<<<<< HEAD
expect(r).toBe(arr[idx]); expect(r).toBe(arr[idx]);
=======
expect(r === arr[idx]).toBeTrue();
>>>>>>> 253023848d... build: update jasmine to 3.5
expect(Zone.current.name).toEqual('bluebird'); expect(Zone.current.name).toEqual('bluebird');
}) })
.then((r: any) => { .then((r: any) => {

View File

@ -21,7 +21,9 @@ describe('crypto test', () => {
const zoneASpec = { const zoneASpec = {
name: 'A', name: 'A',
onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task):
Task => { return delegate.scheduleTask(targetZone, task); } Task => {
return delegate.scheduleTask(targetZone, task);
}
}; };
const zoneA = Zone.current.fork(zoneASpec); const zoneA = Zone.current.fork(zoneASpec);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough(); spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
@ -44,7 +46,9 @@ describe('crypto test', () => {
const zoneASpec = { const zoneASpec = {
name: 'A', name: 'A',
onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task):
Task => { return delegate.scheduleTask(targetZone, task); } Task => {
return delegate.scheduleTask(targetZone, task);
}
}; };
const zoneA = Zone.current.fork(zoneASpec); const zoneA = Zone.current.fork(zoneASpec);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough(); spyOn(zoneASpec, 'onScheduleTask').and.callThrough();