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');
require('../../../src/locking/lock_file_with_child_process/unlocker');
// 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));
});
});

View File

@ -69,6 +69,7 @@ describe('NodeJSFileSystem', () => {
const result = fs.readdir(abcPath);
expect(result).toEqual([relativeFrom('x'), relativeFrom('y/z')]);
// 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);
});
});
@ -90,6 +91,7 @@ describe('NodeJSFileSystem', () => {
const result = fs.stat(abcPath);
expect(result).toBe(stats);
// 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);
});
});
@ -174,9 +176,11 @@ describe('NodeJSFileSystem', () => {
return false;
});
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) {
throw new Error('It exists already. Supposedly.');
throw new Error(
'It exists already. Supposedly.');
}
}) as any);
@ -188,7 +192,8 @@ describe('NodeJSFileSystem', () => {
it('should fail if creating the directory throws and the directory does not exist', () => {
spyOn(fs, 'exists').and.returnValue(false);
spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => {
spyOn(realFs, 'mkdirSync')
.and.callFake(((path: string) => {
if (path === abcPath) {
throw new Error('Unable to create directory (for whatever reason).');
}

View File

@ -41,7 +41,9 @@ describe('ngc transformer command-line', () => {
basePath = support.basePath;
outDir = path.join(basePath, 'built');
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', `{
"compilerOptions": {
@ -96,8 +98,9 @@ describe('ngc transformer command-line', () => {
});
describe('errors', () => {
beforeEach(() => { errorSpy.and.stub(); });
beforeEach(() => {
errorSpy.and.stub();
});
it('should not print the stack trace if user input file does not exist', () => {
writeConfig(`{
@ -231,7 +234,6 @@ describe('ngc transformer command-line', () => {
});
describe('compile ngfactory files', () => {
it('should compile ngfactory files that are not referenced by root files', () => {
writeConfig(`{
"extends": "./tsconfig-base.json",
@ -1122,7 +1124,6 @@ describe('ngc transformer command-line', () => {
});
describe('with external symbol re-exports enabled', () => {
it('should be able to compile multiple libraries with summaries', () => {
// Note: we need to emit the generated code for the libraries
// 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;
const timerToken = 100;
// 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) => {
timer = callback;
return timerToken;
});
// 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) => {
if (token == timerToken) {
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) {
writeConfig(`{
@ -1672,11 +1677,13 @@ describe('ngc transformer command-line', () => {
`);
}));
it('should recompile when the html file changes',
expectRecompile(() => { write('greet.html', '<p> Hello {{name}} again!</p>'); }));
it('should recompile when the html file changes', expectRecompile(() => {
write('greet.html', '<p> Hello {{name}} again!</p>');
}));
it('should recompile when the css file changes',
expectRecompile(() => { write('greet.css', `p.greeting { color: blue }`); }));
it('should recompile when the css file changes', expectRecompile(() => {
write('greet.css', `p.greeting { color: blue }`);
}));
});
describe('regressions', () => {
@ -2041,8 +2048,8 @@ describe('ngc transformer command-line', () => {
expect(exitCode).toBe(1, 'Compile was expected to fail');
const srcPathWithSep = `lib/`;
expect(messages[0])
.toEqual(
`${srcPathWithSep}test.component.ts(6,21): Error during template compile of 'TestComponent'
.toEqual(`${
srcPathWithSep}test.component.ts(6,21): Error during template compile of 'TestComponent'
Tagged template expressions are not supported in metadata in 't1'
't1' references 't2' at ${srcPathWithSep}indirect1.ts(3,27)
't2' contains the error at ${srcPathWithSep}indirect2.ts(4,27).
@ -2051,7 +2058,6 @@ describe('ngc transformer command-line', () => {
});
describe('tree shakeable services', () => {
function compileService(source: string): string {
write('service.ts', source);

View File

@ -14,7 +14,7 @@ describe('convertValueToOutputAst', () => {
const ctx = null;
const value = new Array(3).concat('foo');
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);
for (let i = 0; i < 4; ++i) {
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
* 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 {matchesElement} from '@angular/animations/browser/src/render/shared';
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 {CommonModule} from '@angular/common';
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 {HostListener} from '../../src/metadata/directives';
@ -27,7 +27,9 @@ import {HostListener} from '../../src/metadata/directives';
return MockAnimationDriver.log as MockAnimationPlayer[];
}
function resetLog() { MockAnimationDriver.log = []; }
function resetLog() {
MockAnimationDriver.log = [];
}
beforeEach(() => {
resetLog();
@ -68,26 +70,22 @@ import {HostListener} from '../../src/metadata/directives';
trigger(
'a',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
transition('* => 1', [animate(1000, style({opacity: 0}))]),
]),
trigger(
'b',
[
transition('* => 1', [
transition(
'* => 1',
[
animate(1000, style({opacity: 0})),
query('.b-inner', [
animate(1000, style({ opacity: 0 }))
]),
query('.b-inner', [animate(1000, style({opacity: 0}))]),
]),
]),
trigger(
'c',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
transition('* => 1', [animate(1000, style({opacity: 0}))]),
]),
]
})
@ -145,26 +143,22 @@ import {HostListener} from '../../src/metadata/directives';
trigger(
'a',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
transition('* => 1', [animate(1000, style({opacity: 0}))]),
]),
trigger(
'b',
[
transition('* => 1', [
transition(
'* => 1',
[
animate(1000, style({opacity: 0})),
query('.b-inner', [
animate(1000, style({ opacity: 0 }))
]),
query('.b-inner', [animate(1000, style({opacity: 0}))]),
]),
]),
trigger(
'c',
[
transition('* => 1', [
animate(1000, style({ opacity: 0 }))
]),
transition('* => 1', [animate(1000, style({opacity: 0}))]),
]),
]
})
@ -361,8 +355,7 @@ import {HostListener} from '../../src/metadata/directives';
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({
selector: 'ani-cmp',
template: `
@ -454,7 +447,8 @@ import {HostListener} from '../../src/metadata/directives';
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({
selector: 'ani-cmp',
template: `
@ -546,12 +540,11 @@ import {HostListener} from '../../src/metadata/directives';
template: `
<div [@myAnimation]="exp"></div>
`,
animations: [trigger('myAnimation', [transition(
animations: [trigger(
'myAnimation',
[transition(
'* => 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 {
public exp: any;
@ -793,9 +786,7 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(1);
const player = players[0];
expect(player.keyframes).toEqual([
{height: '0px', offset: 0}, {height: '444px', offset: 1}
]);
expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '444px', offset: 1}]);
player.finish();
expect(player.element.style.height).toEqual('444px');
@ -903,7 +894,9 @@ import {HostListener} from '../../src/metadata/directives';
cmp.items = [0, 1, 2, 3, 4];
expect(() => { fixture.detectChanges(); }).toThrow();
expect(() => {
fixture.detectChanges();
}).toThrow();
const children = cmp.container.nativeElement.querySelectorAll('.child');
expect(children.length).toEqual(5);
@ -1369,7 +1362,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5);
let count = 0;
players.forEach(p => { p.onDone(() => count++); });
players.forEach(p => {
p.onDone(() => count++);
});
expect(count).toEqual(0);
@ -1422,7 +1417,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5);
let count = 0;
players.forEach(p => { p.onDone(() => count++); });
players.forEach(p => {
p.onDone(() => count++);
});
expect(count).toEqual(0);
@ -1485,7 +1482,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5);
let count = 0;
players.forEach(p => { p.onDone(() => count++); });
players.forEach(p => {
p.onDone(() => count++);
});
resetLog();
@ -1500,7 +1499,9 @@ import {HostListener} from '../../src/metadata/directives';
players = getLog();
expect(players.length).toEqual(3);
players.forEach(p => { p.onDone(() => count++); });
players.forEach(p => {
p.onDone(() => count++);
});
cmp.exp1 = 'off';
fixture.detectChanges();
@ -1555,7 +1556,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(players.length).toEqual(5);
let count = 0;
players.forEach(p => { p.onDone(() => count++); });
players.forEach(p => {
p.onDone(() => count++);
});
expect(count).toEqual(0);
@ -1631,8 +1634,7 @@ import {HostListener} from '../../src/metadata/directives';
'myAnimation',
[transition(
'* => on',
[query(
':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])])]
[query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])])]
})
class ParentCmp {
public exp: any;
@ -1680,8 +1682,7 @@ import {HostListener} from '../../src/metadata/directives';
`,
animations: [trigger(
'myAnimation',
[transition(
'* => on', [query(':leave', [animate(1000, style({opacity: 0}))])])])]
[transition('* => on', [query(':leave', [animate(1000, style({opacity: 0}))])])])]
})
class ParentCmp {
public exp: any;
@ -2018,9 +2019,9 @@ import {HostListener} from '../../src/metadata/directives';
</div>
`,
animations: [
trigger('child', [transition(
'a => z',
[style({opacity: 0}), animate(1000, style({opacity: 1}))])]),
trigger(
'child',
[transition('a => z', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]),
trigger('parent', [transition(
'a => z',
[
@ -2076,28 +2077,19 @@ import {HostListener} from '../../src/metadata/directives';
</div>
`,
animations: [
trigger('w', [
transition('* => go', [
style({ width: 0 }),
animate(1800, style({ width: '100px' }))
])
]),
trigger('h', [
transition('* => go', [
style({ height: 0 }),
animate(1500, style({ height: '100px' }))
])
]),
trigger('parent', [
transition('* => go', [
style({ opacity: 0 }),
animate(1000, style({ opacity: 1 })),
query('.child', [
animateChild()
]),
animate(1000, style({ opacity: 0 }))
])
])
trigger(
'w',
[transition('* => go', [style({width: 0}), animate(1800, style({width: '100px'}))])]),
trigger(
'h', [transition(
'* => go', [style({height: 0}), animate(1500, style({height: '100px'}))])]),
trigger(
'parent', [transition(
'* => go',
[
style({opacity: 0}), animate(1000, style({opacity: 1})),
query('.child', [animateChild()]), animate(1000, style({opacity: 0}))
])])
]
})
class Cmp {
@ -2141,9 +2133,9 @@ import {HostListener} from '../../src/metadata/directives';
</div>
`,
animations: [
trigger('child', [transition(
'* => go',
[style({width: 0}), animate(1800, style({width: '100px'}))])]),
trigger(
'child',
[transition('* => go', [style({width: 0}), animate(1800, style({width: '100px'}))])]),
trigger('parent', [transition(
'* => go',
[
@ -2200,9 +2192,9 @@ import {HostListener} from '../../src/metadata/directives';
style({opacity: 0}), animate(1000, style({opacity: 1})),
query('.child', animateChild())
])]),
trigger('child', [transition(
'* => go',
[style({opacity: 0}), animate(1800, style({opacity: 1}))])])
trigger(
'child',
[transition('* => go', [style({opacity: 0}), animate(1800, style({opacity: 1}))])])
]
})
class Cmp {
@ -2515,19 +2507,17 @@ import {HostListener} from '../../src/metadata/directives';
it('should collect multiple root levels of :enter and :leave nodes', () => {
@Component({
selector: 'ani-cmp',
animations: [
trigger('pageAnimation', [
animations: [trigger(
'pageAnimation',
[
transition(':enter', []),
transition('* => *', [
query(':leave', [
animate('1s', style({ opacity: 0 }))
], { optional: true }),
query(':enter', [
animate('1s', style({ opacity: 1 }))
], { optional: true })
transition(
'* => *',
[
query(':leave', [animate('1s', style({opacity: 0}))], {optional: true}),
query(':enter', [animate('1s', style({opacity: 1}))], {optional: true})
])
])
],
])],
template: `
<div [@pageAnimation]="status">
<header>
@ -2679,8 +2669,7 @@ import {HostListener} from '../../src/metadata/directives';
fixture.detectChanges();
flushMicrotasks();
expect(cmp.log).toEqual([
'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done',
'p-done'
'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done', 'p-done'
]);
}));
@ -2764,7 +2753,9 @@ import {HostListener} from '../../src/metadata/directives';
public log: string[] = [];
public remove = false;
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
track(event: any) {
this.log.push(`${event.triggerName}-${event.phaseName}`);
}
}
@Component({
@ -2790,7 +2781,9 @@ import {HostListener} from '../../src/metadata/directives';
class ChildCmp {
public exp: any;
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]});
@ -2893,7 +2886,9 @@ import {HostListener} from '../../src/metadata/directives';
public child2Exp = '';
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]});
@ -2968,8 +2963,8 @@ import {HostListener} from '../../src/metadata/directives';
engine.flush();
expect(engine.players.length).toEqual(1); // child player, parent cover, parent player
const groupPlayer = (engine.players[0] as TransitionAnimationPlayer)
.getRealPlayer() as AnimationGroupPlayer;
const groupPlayer = (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as
AnimationGroupPlayer;
const childPlayer = groupPlayer.players.find(player => {
if (player instanceof MockAnimationPlayer) {
return matchesElement(player.element, '.child');

View File

@ -9,7 +9,7 @@
import {ResourceLoader, UrlResolver} from '@angular/compiler';
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 {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 {isTextNode} from '@angular/platform-browser/testing/src/browser_util';
import {expect} from '@angular/platform-browser/testing/src/matchers';
@ -66,15 +66,13 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
return _bindSimpleProp(`[id]='${expression}'`, compType);
}
function _bindAndCheckSimpleValue(
expression: any, compType: Type<any> = TestComponent): string[] {
function _bindAndCheckSimpleValue(expression: any, compType: Type<any> = TestComponent): string[] {
const ctx = _bindSimpleValue(expression, compType);
ctx.detectChanges(false);
return renderLog.log;
}
describe(`ChangeDetection`, () => {
beforeEach(() => {
TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS});
TestBed.configureTestingModule({
@ -112,79 +110,101 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
});
describe('expressions', () => {
it('should support literals',
fakeAsync(() => { expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']); }));
it('should support literals', fakeAsync(() => {
expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']);
}));
it('should strip quotes from literals',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']); }));
it('should strip quotes from literals', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']);
}));
it('should support newlines in literals',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']); }));
it('should support newlines in literals', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']);
}));
it('should support + operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']); }));
it('should support + operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']);
}));
it('should support - operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']); }));
it('should support - operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']);
}));
it('should support * operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']); }));
it('should support * operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']);
}));
it('should support / operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`id=${5.0}`]);
})); // dart exp=5.0, js exp=5
it('should support % operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']); }));
it('should support % operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']);
}));
it('should support == operations on identical',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']); }));
it('should support == operations on identical', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']);
}));
it('should support != operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']); }));
it('should support != operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']);
}));
it('should support == operations on coerceible',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]); }));
it('should support == operations on coerceible', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]);
}));
it('should support === operations on identical',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']); }));
it('should support === operations on identical', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']);
}));
it('should support !== operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']); }));
it('should support !== operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']);
}));
it('should support === operations on coerceible', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['id=false']);
}));
it('should support true < operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']); }));
it('should support true < operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']);
}));
it('should support false < operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']); }));
it('should support false < operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']);
}));
it('should support false > operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']); }));
it('should support false > operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']);
}));
it('should support true > operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']); }));
it('should support true > operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']);
}));
it('should support true <= operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']); }));
it('should support true <= operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']);
}));
it('should support equal <= operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']); }));
it('should support equal <= operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']);
}));
it('should support false <= operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']); }));
it('should support false <= operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']);
}));
it('should support true >= operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']); }));
it('should support true >= operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']);
}));
it('should support equal >= operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']); }));
it('should support equal >= operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']);
}));
it('should support false >= operations',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']); }));
it('should support false >= operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']);
}));
it('should support true && operations', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('true && true')).toEqual(['id=true']);
@ -202,17 +222,21 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
expect(_bindAndCheckSimpleValue('false || false')).toEqual(['id=false']);
}));
it('should support negate',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']); }));
it('should support negate', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']);
}));
it('should support double negate',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']); }));
it('should support double negate', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']);
}));
it('should support true conditionals',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']); }));
it('should support true conditionals', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']);
}));
it('should support false conditionals',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']); }));
it('should support false conditionals', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']);
}));
it('should support keyed access to a list item', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['id=foo']);
@ -444,8 +468,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
expect(renderLog.log).toEqual(['id=BA']);
}));
it('should escape values in literals that indicate interpolation',
fakeAsync(() => { expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']); }));
it('should escape values in literals that indicate interpolation', fakeAsync(() => {
expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']);
}));
it('should read locals', fakeAsync(() => {
const ctx = createCompFixture(
@ -479,8 +504,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}));
it('should support calling pure pipes with different number of arguments', fakeAsync(() => {
const ctx =
_bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1:2', Person);
const ctx = _bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1:2', Person);
ctx.componentInstance.name = 'value';
ctx.detectChanges(false);
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
ctx.componentInstance.name = 'bart';
ctx.detectChanges(false);
expect(renderLog.loggedValues).toEqual([
'null state:0', 'bob state:1', 'bart state:2'
]);
expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1', 'bart state:2']);
ctx.detectChanges(false);
expect(renderLog.loggedValues).toEqual([
'null state:0', 'bob state:1', 'bart state:2'
]);
expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1', 'bart state:2']);
}));
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(() => {
expect(() => { _bindSimpleProp('(event)="$event=1"'); })
expect(() => {
_bindSimpleProp('(event)="$event=1"');
})
.toThrowError(new RegExp(
'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);
}));
});
});
describe('RendererFactory', () => {
@ -685,6 +705,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
const rf = TestBed.inject(RendererFactory2);
// TODO: @JiaLiPassion, need to wait @types/jasmine to fix the
// optional method infer issue.
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486
spyOn(rf as any, 'begin');
spyOn(rf as any, 'end');
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',
fakeAsync(() => {
it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false);
@ -864,9 +884,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges(false);
expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([
'dir.ngAfterContentInit'
]);
expect(directiveLog.filter(['ngAfterContentInit'])).toEqual(['dir.ngAfterContentInit']);
// reset directives
directiveLog.clear();
@ -895,9 +913,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}
expect(errored).toBe(true);
expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([
'dir.ngAfterContentInit'
]);
expect(directiveLog.filter(['ngAfterContentInit'])).toEqual(['dir.ngAfterContentInit']);
directiveLog.clear();
// 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',
fakeAsync(() => {
it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false);
@ -1038,15 +1053,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]);
}));
it('should be called on every detectChanges run, except for checkNoChanges',
fakeAsync(() => {
it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false);
expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([
'dir.ngAfterViewChecked'
]);
expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual(['dir.ngAfterViewChecked']);
// reset directives
directiveLog.clear();
@ -1059,9 +1071,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
// re-verify that changes are still detected
ctx.detectChanges(false);
expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([
'dir.ngAfterViewChecked'
]);
expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual(['dir.ngAfterViewChecked']);
}));
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.destroy();
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
'pipeWithOnDestroy.ngOnDestroy'
]);
expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['pipeWithOnDestroy.ngOnDestroy']);
}));
it('should call ngOnDestroy on an injectable class', fakeAsync(() => {
TestBed.overrideDirective(
TestDirective, {set: {providers: [InjectableWithLifecycle]}});
TestBed.overrideDirective(TestDirective, {set: {providers: [InjectableWithLifecycle]}});
const ctx = createCompFixture('<div testDirective="dir"></div>', TestComponent);
@ -1302,7 +1309,6 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges();
expect(renderLog.log).toEqual(['{{hello}}']);
}));
it('Reattaches in the original cd mode', fakeAsync(() => {
@ -1321,14 +1327,13 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
ctx.detectChanges();
expect(cmp.renderCount).toBe(count);
}));
});
describe('multi directive order', () => {
modifiedInIvy('order of bindings to directive inputs is different in ivy')
.it('should follow the DI order for the same element', fakeAsync(() => {
const ctx = createCompFixture(
'<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>');
const ctx =
createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>');
ctx.detectChanges(false);
ctx.destroy();
@ -1380,8 +1385,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
@Directive({selector: '[i]'})
class DummyDirective {
@Input()
i: any;
@Input() i: any;
}
@Component({
@ -1391,7 +1395,9 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})
class MainComp {
constructor(public cdRef: ChangeDetectorRef) {}
log(id: string) { log.push(`main-${id}`); }
log(id: string) {
log.push(`main-${id}`);
}
}
@Component({
@ -1401,11 +1407,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})
class OuterComp {
// TODO(issue/24571): remove '!'.
@ContentChild(TemplateRef, {static: true})
tpl !: TemplateRef<any>;
@ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>;
constructor(public cdRef: ChangeDetectorRef) {}
log(id: string) { log.push(`outer-${id}`); }
log(id: string) {
log.push(`outer-${id}`);
}
}
@Component({
@ -1415,15 +1422,15 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})
class InnerComp {
// TODO(issue/24571): remove '!'.
@ContentChild(TemplateRef, {static: true})
tpl !: TemplateRef<any>;
@ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>;
// TODO(issue/24571): remove '!'.
@Input()
outerTpl !: TemplateRef<any>;
@Input() outerTpl!: TemplateRef<any>;
constructor(public cdRef: ChangeDetectorRef) {}
log(id: string) { log.push(`inner-${id}`); }
log(id: string) {
log.push(`inner-${id}`);
}
}
let ctx: ComponentFixture<MainComp>;
@ -1444,13 +1451,11 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
it('should dirty check projected views in regular order', () => {
ctx.detectChanges(false);
expect(log).toEqual(
['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
expect(log).toEqual(['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
log = [];
ctx.detectChanges(false);
expect(log).toEqual(
['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']);
expect(log).toEqual(['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',
@ -1526,8 +1531,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
@Directive({selector: '[someDir]'})
class SomeDir {
@HostBinding('class.foo')
fooClass = true;
@HostBinding('class.foo') fooClass = true;
}
const ctx =
@ -1544,8 +1548,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
describe('lifecycle asserts', () => {
let logged: string[];
function log(value: string) { logged.push(value); }
function clearLog() { logged = []; }
function log(value: string) {
logged.push(value);
}
function clearLog() {
logged = [];
}
function expectOnceAndOnlyOnce(log: string) {
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)}`);
}
beforeEach(() => { clearLog(); });
beforeEach(() => {
clearLog();
});
enum LifetimeMethods {
None = 0,
@ -1593,11 +1603,21 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
constructor() {}
ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); }
ngOnInit() { this.check(LifetimeMethods.ngOnInit); }
ngOnChanges() { this.check(LifetimeMethods.ngOnChanges); }
ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); }
ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); }
ngDoCheck() {
this.check(LifetimeMethods.ngDoCheck);
}
ngOnInit() {
this.check(LifetimeMethods.ngOnInit);
}
ngOnChanges() {
this.check(LifetimeMethods.ngOnChanges);
}
ngAfterViewInit() {
this.check(LifetimeMethods.ngAfterViewInit);
}
ngAfterContentInit() {
this.check(LifetimeMethods.ngAfterContentInit);
}
private check(method: LifetimeMethods) {
log(`MyChild::${LifetimeMethods[method]}()`);
@ -1625,10 +1645,18 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})
class MyComponent {
constructor(private changeDetectionRef: ChangeDetectorRef) {}
ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); }
ngOnInit() { this.check(LifetimeMethods.ngOnInit); }
ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); }
ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); }
ngDoCheck() {
this.check(LifetimeMethods.ngDoCheck);
}
ngOnInit() {
this.check(LifetimeMethods.ngOnInit);
}
ngAfterViewInit() {
this.check(LifetimeMethods.ngAfterViewInit);
}
ngAfterContentInit() {
this.check(LifetimeMethods.ngAfterContentInit);
}
onOutp() {
log('<RECURSION START>');
this.changeDetectionRef.detectChanges();
@ -1670,14 +1698,16 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}
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.
ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None});
});
});
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.
// 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));
}
clear() { this.entries = []; }
clear() {
this.entries = [];
}
filter(methods: string[]): string[] {
return this.entries.filter((entry) => methods.indexOf(entry.method) !== -1)
@ -1762,32 +1794,44 @@ class DirectiveLog {
@Pipe({name: 'countingPipe'})
class CountingPipe implements PipeTransform {
state: number = 0;
transform(value: any) { return `${value} state:${this.state++}`; }
transform(value: any) {
return `${value} state:${this.state++}`;
}
}
@Pipe({name: 'countingImpurePipe', pure: false})
class CountingImpurePipe implements PipeTransform {
state: number = 0;
transform(value: any) { return `${value} state:${this.state++}`; }
transform(value: any) {
return `${value} state:${this.state++}`;
}
}
@Pipe({name: 'pipeWithOnDestroy'})
class PipeWithOnDestroy implements PipeTransform, OnDestroy {
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'})
class IdentityPipe implements PipeTransform {
transform(value: any) { return value; }
transform(value: any) {
return value;
}
}
@Pipe({name: 'wrappedPipe'})
class WrappedPipe implements PipeTransform {
transform(value: any) { return WrappedValue.wrap(value); }
transform(value: any) {
return WrappedValue.wrap(value);
}
}
@Pipe({name: 'multiArgPipe'})
@ -1856,7 +1900,9 @@ class Gh9882 implements AfterContentInit {
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'})
@ -1877,9 +1923,13 @@ class TestDirective implements OnInit, DoCheck, OnChanges, AfterContentInit, Aft
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() {
this.log.add(this.name, 'ngOnInit');
@ -1937,14 +1987,18 @@ class InjectableWithLifecycle {
name = 'injectable';
constructor(public log: DirectiveLog) {}
ngOnDestroy() { this.log.add(this.name, 'ngOnDestroy'); }
ngOnDestroy() {
this.log.add(this.name, 'ngOnDestroy');
}
}
@Directive({selector: '[onDestroyDirective]'})
class OnDestroyDirective implements OnDestroy {
@Output('destroy') emitter = new EventEmitter<string>(false);
ngOnDestroy() { this.emitter.emit('destroyed'); }
ngOnDestroy() {
this.emitter.emit('destroyed');
}
}
@Directive({selector: '[orderCheck0]'})
@ -2015,9 +2069,13 @@ class Person {
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 {
const address = this.address == null ? '' : ' address=' + this.address.toString();
@ -2042,11 +2100,17 @@ class Address {
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'})
@ -2065,7 +2129,9 @@ class TestDataWithGetter {
// TODO(issue/24571): remove '!'.
public fn!: Function;
get a() { return this.fn(); }
get a() {
return this.fn();
}
}
class Holder<T> {

View File

@ -25,26 +25,41 @@ describe('global utils', () => {
describe('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',
() => { assertPublished('getOwningComponent', getOwningComponent); });
it('should publish getOwningComponent', () => {
assertPublished('getOwningComponent', getOwningComponent);
});
it('should publish getRootComponents',
() => { assertPublished('getRootComponents', getRootComponents); });
it('should publish getRootComponents', () => {
assertPublished('getRootComponents', getRootComponents);
});
it('should publish getDirectives', () => { assertPublished('getDirectives', getDirectives); });
it('should publish getDirectives', () => {
assertPublished('getDirectives', getDirectives);
});
it('should publish getHostComponent',
() => { assertPublished('getHostElement', getHostElement); });
it('should publish getHostComponent', () => {
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('element matching', () => {
it('should match element name only if names are the same', () => {
expect(isMatching('span', null, ['span']))
.toBeTruthy(`Selector 'span' should match <span>`);
@ -55,11 +52,9 @@ describe('css selector matching', () => {
});
describe('attributes matching', () => {
// TODO: do we need to differentiate no value and empty value? that is: title vs. title="" ?
it('should match single attribute without value', () => {
expect(isMatching('span', ['title', ''], [
'', 'title', ''
])).toBeTruthy(`Selector '[title]' should match <span title>`);
@ -81,7 +76,8 @@ describe('css selector matching', () => {
])).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', () => {
expect(isMatching(
'span', [AttributeMarker.NamespaceURI, 'http://some/uri', 'title', 'name'],
@ -228,7 +224,6 @@ describe('css selector matching', () => {
});
describe('class matching', () => {
it('should match with a class selector when an element has multiple classes', () => {
expect(isMatching('span', ['class', 'foo bar'], [
'', SelectorFlags.CLASS, 'foo'
@ -328,7 +323,6 @@ describe('css selector matching', () => {
});
describe('negations', () => {
it('should match when negation part is null', () => {
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))
.toBeFalsy();
});
});
describe('isNodeMatchingSelectorList', () => {
function isAnyMatching(
tagName: string, attrs: string[]|null, selector: CssSelectorList): boolean {
return isNodeMatchingSelectorList(testLStaticData(tagName, attrs), selector, false);
@ -468,16 +460,18 @@ describe('css selector matching', () => {
});
describe('reading the ngProjectAs attribute value', function() {
function testTNode(attrs: TAttributes | null) { return testLStaticData('tag', attrs); }
function testTNode(attrs: TAttributes|null) {
return testLStaticData('tag', attrs);
}
it('should get ngProjectAs value if present', function() {
expect(getProjectAsAttrValue(testTNode([AttributeMarker.ProjectAs, ['tag', 'foo', 'bar']])))
.toEqual(['tag', 'foo', 'bar']);
});
it('should return null if there are no attributes',
function() { expect(getProjectAsAttrValue(testTNode(null))).toBe(null); });
it('should return null if there are no attributes', function() {
expect(getProjectAsAttrValue(testTNode(null))).toBe(null);
});
it('should return if ngProjectAs is not present', function() {
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() {
expect(getProjectAsAttrValue(testTNode(['foo', AttributeMarker.ProjectAs]))).toBe(null);
});
});
});
describe('stringifyCSSSelectorList', () => {
it('should stringify selector with a tag name only',
() => { expect(stringifyCSSSelectorList([['button']])).toBe('button'); });
it('should stringify selector with a tag name only', () => {
expect(stringifyCSSSelectorList([['button']])).toBe('button');
});
it('should stringify selector with attributes', () => {
expect(stringifyCSSSelectorList([['', 'id', '']])).toBe('[id]');

View File

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

View File

@ -17,7 +17,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
let fakeConsole: any;
if (isNode) return;
beforeEach(() => { fakeConsole = {warn: jasmine.createSpy('console.warn')}; });
beforeEach(() => {
fakeConsole = {warn: jasmine.createSpy('console.warn')};
});
describe('with no custom loader', () => {
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
// EventManager.
let ngZone: NgZone;
beforeEach(inject([NgZone], (z: NgZone) => { ngZone = z; }));
beforeEach(inject([NgZone], (z: NgZone) => {
ngZone = z;
}));
beforeEach(() => {
originalHammerGlobal = (window as any).Hammer;
@ -90,7 +94,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
someListener = () => {};
});
afterEach(() => { (window as any).Hammer = originalHammerGlobal; });
afterEach(() => {
(window as any).Hammer = originalHammerGlobal;
});
it('should not log a warning when HammerJS is not loaded', () => {
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'});
expect(KeyEventsPlugin.parseEventName('keyup.control.shift'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift'});
});
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', () => {}))
.not.toThrowError();
});
});
}

View File

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

View File

@ -9,7 +9,7 @@
import {PLATFORM_ID} from '@angular/core';
import {TestBed} from '@angular/core/testing';
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 {SwUpdate} from '@angular/service-worker/src/update';
import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock';
@ -32,14 +32,18 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
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 => {
const mock = new MockServiceWorkerContainer();
const comm = new NgswCommChannel(mock as any);
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();
});
@ -221,7 +225,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
});
it('rejects if `PushSubscription.unsubscribe()` fails', async () => {
psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); });
psUnsubscribeSpy.and.callFake(() => {
throw new Error('foo');
});
try {
await push.requestSubscription({serverPublicKey: 'test'});
@ -271,7 +277,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
subscriptionSpy.calls.reset();
// 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);
expect(subscriptionSpy).not.toHaveBeenCalled();
@ -391,11 +399,16 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
});
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',
done => { push.unsubscribe().catch(err => { done(); }); });
it('gives an error when unsubscribing', done => {
push.unsubscribe().catch(err => {
done();
});
});
});
});
@ -461,7 +474,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
});
});
return update.activateUpdate()
.catch(err => { expect(err.message).toEqual('Failed to activate'); })
.catch(err => {
expect(err.message).toEqual('Failed to activate');
})
.then(() => done())
.catch(err => done.fail(err));
});
@ -475,8 +490,12 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS
expect(() => TestBed.inject(SwUpdate)).not.toThrow();
});
describe('with no SW', () => {
beforeEach(() => { comm = new NgswCommChannel(undefined); });
it('can be instantiated', () => { update = new SwUpdate(comm); });
beforeEach(() => {
comm = new NgswCommChannel(undefined);
});
it('can be instantiated', () => {
update = new SwUpdate(comm);
});
it('does not crash on subscription to observables', () => {
update = new SwUpdate(comm);
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 => {
update = new SwUpdate(comm);
update.checkForUpdate().catch(err => { done(); });
update.checkForUpdate().catch(err => {
done();
});
});
it('gives an error when activating updates', done => {
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 {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing';
import {Subject} from 'rxjs';
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 {AssetGroupConfig, DataGroupConfig, Manifest} from '../src/manifest';
import {sha1} from '../src/sha1';
import {MockCache, clearAllCaches} from '../testing/cache';
import {clearAllCaches, MockCache} from '../testing/cache';
import {MockRequest, MockResponse} from '../testing/fetch';
import {MockFileSystemBuilder, MockServerStateBuilder, tmpHashTableForFs} from '../testing/mock';
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/b.txt', 'this is unhashed b', {'Cache-Control': 'no-cache'})
.addUnhashedFile('/api/foo', 'this is api foo', {'Cache-Control': 'no-cache'})
.addUnhashedFile(
'/api-static/bar', 'this is static api bar', {'Cache-Control': 'no-cache'})
.addUnhashedFile('/api-static/bar', 'this is static api bar', {'Cache-Control': 'no-cache'})
.build();
const distUpdate =
@ -49,8 +48,7 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
.addFile('/quuux.txt', 'this is quuux v2')
.addFile('/lazy/unchanged1.txt', 'this is unchanged (1)')
.addFile('/lazy/unchanged2.txt', 'this is unchanged (2)')
.addUnhashedFile(
'/unhashed/a.txt', 'this is unhashed v2', {'Cache-Control': 'max-age=10'})
.addUnhashedFile('/unhashed/a.txt', 'this is unhashed v2', {'Cache-Control': 'max-age=10'})
.addUnhashedFile('/ignored/file1', 'this is not handled by the SW')
.addUnhashedFile('/ignored/dir/file2', 'this is not handled by the SW either')
.build();
@ -271,10 +269,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
const brokenServer =
new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenManifest).build();
const brokenLazyServer = new MockServerStateBuilder()
.withStaticFiles(brokenFs)
.withManifest(brokenLazyManifest)
.build();
const brokenLazyServer =
new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenLazyManifest).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');
server.assertSawRequestFor('/bar');
});
it('unregisters when manifest 404s', async () => {
@ -890,7 +885,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
describe('cache naming', () => {
// Helpers
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}:${manifestHash}:assets:other:cache`,
`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');
serverUpdate.assertSawRequestFor('/ignored/file1');
expect(await navRequest('/ignored/dir/file2'))
.toBe('this is not handled by the SW either');
expect(await navRequest('/ignored/dir/file2')).toBe('this is not handled by the SW either');
serverUpdate.assertSawRequestFor('/ignored/dir/file2');
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');
serverUpdate.assertNoOtherRequests();
expect(await navRequest('/ignored/file1?query=/a/b'))
.toBe('this is not handled by the SW');
expect(await navRequest('/ignored/file1?query=/a/b')).toBe('this is not handled by the SW');
serverUpdate.assertSawRequestFor('/ignored/file1');
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 () => {
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(
(cacheName: string) =>
Promise.reject(`Failed to delete cache '${cacheName}'.`));
(cacheName: string) => Promise.reject(`Failed to delete cache '${cacheName}'.`));
await Promise.all(oldSwCacheNames.map(name => scope.caches.open(name)));
const error = await driver.cleanupOldSwCaches().catch(err => err);
@ -1488,8 +1482,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope';
})();
async function makeRequest(
scope: SwTestHarness, url: string, clientId: string | null = 'default', init?: Object):
Promise<string|null> {
scope: SwTestHarness, url: string, clientId: string|null = 'default',
init?: Object): Promise<string|null> {
const [resPromise, done] = scope.handleFetch(new MockRequest(url, init), clientId);
await done;
const res = await resPromise;
@ -1500,13 +1494,14 @@ async function makeRequest(
}
function makeNavigationRequest(
scope: SwTestHarness, url: string, clientId?: string | null, init: Object = {}):
Promise<string|null> {
scope: SwTestHarness, url: string, clientId?: string|null,
init: Object = {}): Promise<string|null> {
return makeRequest(scope, url, clientId, {
headers: {
Accept: 'text/plain, text/html, text/css',
...(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
*/
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 {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -23,7 +23,6 @@ declare global {
withEachNg1Version(() => {
describe('adapter: ng1 to ng2', () => {
beforeEach(() => destroyPlatform());
afterEach(() => destroyPlatform());
@ -232,7 +231,9 @@ withEachNg1Version(() => {
})
class Ng2 {
l: any;
constructor() { this.l = l; }
constructor() {
this.l = l;
}
}
@NgModule({
@ -262,7 +263,9 @@ withEachNg1Version(() => {
@Component({selector: 'my-app', template: '<my-child [value]="value"></my-child>'})
class AppComponent {
value?: number;
constructor() { appComponent = this; }
constructor() {
appComponent = this;
}
}
@Component({
@ -272,7 +275,9 @@ withEachNg1Version(() => {
class ChildComponent {
valueFromPromise?: number;
@Input()
set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); }
set value(v: number) {
expect(NgZone.isInAngularZone()).toBe(true);
}
constructor(private zone: NgZone) {}
@ -358,8 +363,9 @@ withEachNg1Version(() => {
it('should bind properties, events', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module =
angular.module_('ng1', []).value($EXCEPTION_HANDLER, (err: any) => { throw err; });
const ng1Module = angular.module_('ng1', []).value($EXCEPTION_HANDLER, (err: any) => {
throw err;
});
ng1Module.run(($rootScope: any) => {
$rootScope.name = 'world';
@ -409,8 +415,8 @@ withEachNg1Version(() => {
}
const actValue = changes[prop].currentValue;
if (actValue != value) {
throw new Error(
`Expected changes record for'${prop}' to be '${value}' but was '${actValue}'`);
throw new Error(`Expected changes record for'${prop}' to be '${
value}' but was '${actValue}'`);
}
};
@ -475,7 +481,6 @@ withEachNg1Version(() => {
ref.dispose();
});
}));
it('should support two-way binding and event listener', async(() => {
@ -590,7 +595,9 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
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;
@Component({selector: 'ng2', template: '{{_value}}'})
@ -598,11 +605,21 @@ withEachNg1Version(() => {
private _value: any = '';
private _onChangeCallback: (_: any) => void = () => {};
private _onTouchedCallback: () => void = () => {};
constructor() { ng2Instance = this; }
writeValue(value: any) { this._value = value; }
registerOnChange(fn: any) { this._onChangeCallback = fn; }
registerOnTouched(fn: any) { this._onTouchedCallback = fn; }
doTouch() { this._onTouchedCallback(); }
constructor() {
ng2Instance = this;
}
writeValue(value: any) {
this._value = value;
}
registerOnChange(fn: any) {
this._onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this._onTouchedCallback = fn;
}
doTouch() {
this._onTouchedCallback();
}
doChange(newValue: string) {
this._value = newValue;
this._onChangeCallback(newValue);
@ -653,14 +670,18 @@ withEachNg1Version(() => {
return {
template: '<div ng-if="!destroyIt"><ng2></ng2></div>',
controller: function($rootScope: any, $timeout: Function) {
$timeout(() => { $rootScope.destroyIt = true; });
$timeout(() => {
$rootScope.destroyIt = true;
});
}
};
});
@Component({selector: 'ng2', template: 'test'})
class Ng2 {
ngOnDestroy() { onDestroyed.emit('destroyed'); }
ngOnDestroy() {
onDestroyed.emit('destroyed');
}
}
@NgModule({
@ -673,7 +694,9 @@ withEachNg1Version(() => {
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
const element = html('<ng1></ng1>');
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'})
class Ng2InnerComponent implements OnDestroy {
ngOnDestroy() { destroyed = true; }
ngOnDestroy() {
destroyed = true;
}
}
@NgModule({
@ -868,7 +893,9 @@ withEachNg1Version(() => {
dataA = 'foo';
dataB = 'bar';
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -932,7 +959,9 @@ withEachNg1Version(() => {
dataA = {value: 'foo'};
dataB = {value: 'bar'};
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -996,7 +1025,9 @@ withEachNg1Version(() => {
dataA = {value: 'foo'};
dataB = {value: 'bar'};
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -1204,7 +1235,9 @@ withEachNg1Version(() => {
restrict: 'E',
template: '{{someText}} - Length: {{data.length}}',
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',
template: '{{someText}} - Length: {{data.length}}',
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}`);
});
const ng1 = () => { return {templateUrl: 'url.html'}; };
const ng1 = () => {
return {templateUrl: 'url.html'};
};
ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'})
class Ng2 {
@ -1320,7 +1357,13 @@ withEachNg1Version(() => {
cbFn(200, `${method}:${url}`);
});
const ng1 = () => { return {templateUrl() { return 'url.html'; }}; };
const ng1 = () => {
return {
templateUrl() {
return 'url.html';
}
};
};
ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'})
class Ng2 {
@ -1345,7 +1388,9 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []);
const ng1 = () => { return {template: ''}; };
const ng1 = () => {
return {template: ''};
};
ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'})
@ -1371,7 +1416,13 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []);
const ng1 = () => { return {template() { return ''; }}; };
const ng1 = () => {
return {
template() {
return '';
}
};
};
ng1Module.directive('ng1', ng1);
@Component({selector: 'ng2', template: '<ng1></ng1>'})
@ -1398,7 +1449,9 @@ withEachNg1Version(() => {
const ng1Module = angular.module_('ng1', []);
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);
@Component({selector: 'ng2', template: '<ng1></ng1>'})
@ -1431,13 +1484,20 @@ withEachNg1Version(() => {
'{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}',
controllerAs: 'ctl',
controller: class {
scope: any; hasElement: string; $element: any; isClass: any;
scope: any;
hasElement: string;
$element: any;
isClass: any;
constructor($scope: any, $element: any) {
this.verifyIAmAClass();
this.scope = $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope';
this.hasElement = $element[0].nodeName;
this.$element = $element;
} verifyIAmAClass() { this.isClass = 'isClass'; } isPublished() {
}
verifyIAmAClass() {
this.isClass = 'isClass';
}
isPublished() {
return this.$element.controller('ng1') == this ? 'published' : 'not-published';
}
}
@ -1543,7 +1603,9 @@ withEachNg1Version(() => {
template: '{{ctl.status}}',
require: 'ng1',
controllerAs: 'ctrl',
controller: class {status = 'WORKS';},
controller: class {
status = 'WORKS';
},
link: function(scope: any, element: any, attrs: any, linkController: any) {
expect(scope.$root).toEqual($rootScope);
expect(element[0].nodeName).toEqual('NG1');
@ -1577,7 +1639,13 @@ withEachNg1Version(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
const ng1Module = angular.module_('ng1', []);
const parent = () => { return {controller: class {parent = 'PARENT';}}; };
const parent = () => {
return {
controller: class {
parent = 'PARENT';
}
};
};
const ng1 = () => {
return {
scope: {title: '@'},
@ -1585,7 +1653,9 @@ withEachNg1Version(() => {
template: '{{parent.parent}}:{{ng1.status}}',
require: ['ng1', '^parent', '?^^notFound'],
controllerAs: 'ctrl',
controller: class {status = 'WORKS';},
controller: class {
status = 'WORKS';
},
link: function(scope: any, element: any, attrs: any, linkControllers: any) {
expect(linkControllers[0].status).toEqual('WORKS');
expect(linkControllers[1].parent).toEqual('PARENT');
@ -1633,15 +1703,20 @@ withEachNg1Version(() => {
scope: {},
bindToController: true,
controllerAs: '$ctrl',
controller: class {$onInit() { $onInitSpyA(); }}
controller: class {
$onInit() {
$onInitSpyA();
}
}
}))
.directive(
'ng1B', () => ({
.directive('ng1B', () => ({
template: '',
scope: {},
bindToController: false,
controllerAs: '$ctrl',
controller: function(this: any) { this.$onInit = $onInitSpyB; }
controller: function(this: any) {
this.$onInit = $onInitSpyB;
}
}))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -1718,7 +1793,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'})
class Ng2Component {
constructor(cd: ChangeDetectorRef) { changeDetector = cd; }
constructor(cd: ChangeDetectorRef) {
changeDetector = cd;
}
}
angular.module_('ng1', [])
@ -1727,15 +1804,20 @@ withEachNg1Version(() => {
scope: {},
bindToController: true,
controllerAs: '$ctrl',
controller: class {$doCheck() { $doCheckSpyA(); }}
controller: class {
$doCheck() {
$doCheckSpyA();
}
}
}))
.directive(
'ng1B', () => ({
.directive('ng1B', () => ({
template: '',
scope: {},
bindToController: false,
controllerAs: '$ctrl',
controller: function(this: any) { this.$doCheck = $doCheckSpyB; }
controller: function(this: any) {
this.$doCheck = $doCheckSpyB;
}
}))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -1773,7 +1855,9 @@ withEachNg1Version(() => {
@Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'})
class Ng2Component {
constructor(cd: ChangeDetectorRef) { changeDetector = cd; }
constructor(cd: ChangeDetectorRef) {
changeDetector = cd;
}
}
angular.module_('ng1', [])
@ -1835,15 +1919,20 @@ withEachNg1Version(() => {
scope: {},
bindToController: true,
controllerAs: '$ctrl',
controller: class {$postLink() { $postLinkSpyA(); }}
controller: class {
$postLink() {
$postLinkSpyA();
}
}
}))
.directive(
'ng1B', () => ({
.directive('ng1B', () => ({
template: '',
scope: {},
bindToController: false,
controllerAs: '$ctrl',
controller: function(this: any) { this.$postLink = $postLinkSpyB; }
controller: function(this: any) {
this.$postLink = $postLinkSpyB;
}
}))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -1924,7 +2013,9 @@ withEachNg1Version(() => {
template: '<ng1-a [valA]="val"></ng1-a> | <ng1-b [valB]="val"></ng1-b>'
})
class Ng2Component {
constructor() { ng2Instance = this; }
constructor() {
ng2Instance = this;
}
}
angular.module_('ng1', [])
@ -1937,15 +2028,15 @@ withEachNg1Version(() => {
this.$onChanges = $onChangesControllerSpyA;
}
}))
.directive(
'ng1B',
() => ({
.directive('ng1B', () => ({
template: '',
scope: {valB: '<'},
bindToController: false,
controllerAs: '$ctrl',
controller: class {
$onChanges(changes: SimpleChanges) { $onChangesControllerSpyB(changes); }
$onChanges(changes: SimpleChanges) {
$onChangesControllerSpyB(changes);
}
}
}))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component))
@ -2022,7 +2113,9 @@ withEachNg1Version(() => {
})
class Ng2Component {
ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
@ -2036,15 +2129,20 @@ withEachNg1Version(() => {
scope: {},
bindToController: true,
controllerAs: '$ctrl',
controller: class {$onDestroy() { $onDestroySpyA(); }}
controller: class {
$onDestroy() {
$onDestroySpyA();
}
}
}))
.directive(
'ng1B', () => ({
.directive('ng1B', () => ({
template: '',
scope: {},
bindToController: false,
controllerAs: '$ctrl',
controller: function(this: any) { this.$onDestroy = $onDestroySpyB; }
controller: function(this: any) {
this.$onDestroy = $onDestroySpyB;
}
}))
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
@ -2112,7 +2210,9 @@ withEachNg1Version(() => {
})
class Ng2Component {
ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// 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>'})
class Ng2Component {
ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// 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>'})
class Ng2Component {
ng2Destroy: boolean = false;
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3),
@ -2301,7 +2405,9 @@ withEachNg1Version(() => {
class Ng2ComponentA {
destroyIt = false;
constructor() { ng2ComponentAInstance = this; }
constructor() {
ng2ComponentAInstance = this;
}
}
@Component({selector: 'ng2B', template: '<ng1></ng1>'})
@ -2367,7 +2473,9 @@ withEachNg1Version(() => {
class Ng2ComponentA {
destroyIt = false;
constructor() { ng2ComponentAInstance = this; }
constructor() {
ng2ComponentAInstance = this;
}
}
@Component({selector: 'ng2B', template: '<ng1></ng1>'})
@ -2420,7 +2528,11 @@ withEachNg1Version(() => {
const ng1Directive: angular.IDirective = {
template: '',
link: {pre: () => log.push('ng1-pre')},
controller: class {constructor() { log.push('ng1-ctrl'); }}
controller: class {
constructor() {
log.push('ng1-ctrl');
}
}
};
// Define `Ng2Component`
@ -2577,7 +2689,11 @@ withEachNg1Version(() => {
const ng1Directive: angular.IDirective = {
template: '',
link: () => log.push('ng1-post'),
controller: class {$postLink() { log.push('ng1-$post'); }}
controller: class {
$postLink() {
log.push('ng1-$post');
}
}
};
// Define `Ng2Component`
@ -2627,13 +2743,17 @@ withEachNg1Version(() => {
class Ng2ComponentA {
value = 'foo';
showB = false;
constructor() { ng2ComponentAInstance = this; }
constructor() {
ng2ComponentAInstance = this;
}
}
@Component({selector: 'ng2B', template: 'ng2B({{ value }})'})
class Ng2ComponentB {
value = 'bar';
constructor() { ng2ComponentBInstance = this; }
constructor() {
ng2ComponentBInstance = this;
}
}
// Define `ng1Module`
@ -2678,7 +2798,10 @@ withEachNg1Version(() => {
template: 'ng1(<div ng-transclude>{{ $ctrl.value }}</div>)',
transclude: true,
controller: class {
value = 'from-ng1'; constructor() { ng1ControllerInstances.push(this); }
value = 'from-ng1';
constructor() {
ng1ControllerInstances.push(this);
}
}
};
@ -2697,7 +2820,9 @@ withEachNg1Version(() => {
})
class Ng2Component {
value = 'from-ng2';
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -2756,7 +2881,9 @@ withEachNg1Version(() => {
class Ng2Component {
x = 'foo';
y = 'bar';
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -2798,8 +2925,12 @@ withEachNg1Version(() => {
const ng1Component: angular.IComponent = {
template: 'ng1(default(<div ng-transclude="">fallback-{{ $ctrl.value }}</div>))',
transclude: {slotX: 'contentX', slotY: 'contentY'},
controller:
class {value = 'ng1'; constructor() { ng1ControllerInstances.push(this); }}
controller: class {
value = 'ng1';
constructor() {
ng1ControllerInstances.push(this);
}
}
};
// Define `Ng2Component`
@ -2830,7 +2961,9 @@ withEachNg1Version(() => {
class Ng2Component {
x = 'foo';
y = 'bar';
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -2880,7 +3013,11 @@ withEachNg1Version(() => {
)`,
transclude: {slotX: '?contentX', slotY: '?contentY'},
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 {
x = 'ng2X';
y = 'ng2Y';
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -3000,7 +3139,9 @@ withEachNg1Version(() => {
x = 'foo';
y = 'bar';
show = true;
constructor() { ng2ComponentInstance = this; }
constructor() {
ng2ComponentInstance = this;
}
}
// Define `ng1Module`
@ -3202,13 +3343,18 @@ withEachNg1Version(() => {
const ng1Module = angular.module_('ng1', []);
let a1Injector: angular.IInjectorService|undefined;
ng1Module.run([
'$injector', function($injector: angular.IInjectorService) { a1Injector = $injector; }
'$injector',
function($injector: angular.IInjectorService) {
a1Injector = $injector;
}
]);
const element = html('<div></div>');
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);

View File

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

View File

@ -21,7 +21,9 @@ describe('crypto test', () => {
const zoneASpec = {
name: 'A',
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);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
@ -44,7 +46,9 @@ describe('crypto test', () => {
const zoneASpec = {
name: 'A',
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);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();