@ -30,8 +30,7 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
[
|
||||
state('collapsed, void', style({height: '0px', color: 'maroon', borderColor: 'maroon'})),
|
||||
state('expanded', style({height: '*', borderColor: 'green', color: 'green'})),
|
||||
transition(
|
||||
'collapsed <=> expanded', [animate(500, style({height: '250px'})), animate(500)])
|
||||
transition('collapsed <=> expanded', [animate(500, style({height: '250px'})), animate(500)])
|
||||
])],
|
||||
template: `
|
||||
<button (click)="expand()">Open</button>
|
||||
@ -44,10 +43,16 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
})
|
||||
export class MyExpandoCmp {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
stateExpression !: string;
|
||||
constructor() { this.collapse(); }
|
||||
expand() { this.stateExpression = 'expanded'; }
|
||||
collapse() { this.stateExpression = 'collapsed'; }
|
||||
stateExpression!: string;
|
||||
constructor() {
|
||||
this.collapse();
|
||||
}
|
||||
expand() {
|
||||
this.stateExpression = 'expanded';
|
||||
}
|
||||
collapse() {
|
||||
this.stateExpression = 'collapsed';
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule(
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {$, ExpectedConditions, browser, by, element} from 'protractor';
|
||||
import {$, browser, by, element, ExpectedConditions} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from '../../../../../test-utils';
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {DebugElement} from '@angular/core';
|
||||
|
||||
let debugElement: DebugElement = undefined !;
|
||||
let debugElement: DebugElement = undefined!;
|
||||
let predicate: any;
|
||||
|
||||
// #docregion scope_all
|
||||
|
@ -11,7 +11,7 @@ import {Component, ContentChild, Directive, Input} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id !: string;
|
||||
@Input() id!: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -21,7 +21,7 @@ export class Pane {
|
||||
`
|
||||
})
|
||||
export class Tab {
|
||||
@ContentChild(Pane) pane !: Pane;
|
||||
@ContentChild(Pane) pane!: Pane;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -38,6 +38,8 @@ export class Tab {
|
||||
export class ContentChildComp {
|
||||
shouldShow = true;
|
||||
|
||||
toggle() { this.shouldShow = !this.shouldShow; }
|
||||
toggle() {
|
||||
this.shouldShow = !this.shouldShow;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -15,7 +15,7 @@ class ChildDirective {
|
||||
|
||||
@Directive({selector: 'someDir'})
|
||||
class SomeDir implements AfterContentInit {
|
||||
@ContentChild(ChildDirective) contentChild !: ChildDirective;
|
||||
@ContentChild(ChildDirective) contentChild!: ChildDirective;
|
||||
|
||||
ngAfterContentInit() {
|
||||
// contentChild is set
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {browser, by, element, ElementFinder} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from '../../../../../test-utils';
|
||||
|
||||
describe('contentChild example', () => {
|
||||
|
@ -11,7 +11,7 @@ import {Component, ContentChildren, Directive, Input, QueryList} from '@angular/
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id !: string;
|
||||
@Input() id!: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -22,8 +22,8 @@ export class Pane {
|
||||
`
|
||||
})
|
||||
export class Tab {
|
||||
@ContentChildren(Pane) topLevelPanes !: QueryList<Pane>;
|
||||
@ContentChildren(Pane, {descendants: true}) arbitraryNestedPanes !: QueryList<Pane>;
|
||||
@ContentChildren(Pane) topLevelPanes!: QueryList<Pane>;
|
||||
@ContentChildren(Pane, {descendants: true}) arbitraryNestedPanes!: QueryList<Pane>;
|
||||
|
||||
get serializedPanes(): string {
|
||||
return this.topLevelPanes ? this.topLevelPanes.map(p => p.id).join(', ') : '';
|
||||
@ -53,6 +53,8 @@ export class Tab {
|
||||
export class ContentChildrenComp {
|
||||
shouldShow = false;
|
||||
|
||||
show() { this.shouldShow = true; }
|
||||
show() {
|
||||
this.shouldShow = true;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -15,7 +15,7 @@ class ChildDirective {
|
||||
|
||||
@Directive({selector: 'someDir'})
|
||||
class SomeDir implements AfterContentInit {
|
||||
@ContentChildren(ChildDirective) contentChildren !: QueryList<ChildDirective>;
|
||||
@ContentChildren(ChildDirective) contentChildren!: QueryList<ChildDirective>;
|
||||
|
||||
ngAfterContentInit() {
|
||||
// contentChildren is set
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {browser, by, element, ElementFinder} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from '../../../../../test-utils';
|
||||
|
||||
describe('contentChildren example', () => {
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {InjectFlags, InjectionToken, Injector, Type, inject, ɵsetCurrentInjector as setCurrentInjector} from '@angular/core';
|
||||
import {inject, InjectFlags, InjectionToken, Injector, Type, ɵsetCurrentInjector as setCurrentInjector} from '@angular/core';
|
||||
|
||||
class MockRootScopeInjector implements Injector {
|
||||
constructor(readonly parent: Injector) {}
|
||||
|
@ -59,9 +59,8 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
}
|
||||
|
||||
const injector = Injector.create({
|
||||
providers: [
|
||||
{provide: NeedsService, deps: [UsefulService]}, {provide: UsefulService, deps: []}
|
||||
]
|
||||
providers:
|
||||
[{provide: NeedsService, deps: [UsefulService]}, {provide: UsefulService, deps: []}]
|
||||
});
|
||||
expect(injector.get(NeedsService).service instanceof UsefulService).toBe(true);
|
||||
// #enddocregion
|
||||
@ -104,7 +103,9 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
@Injectable()
|
||||
class NeedsDependency {
|
||||
constructor(@SkipSelf() public dependency: Dependency) { this.dependency = dependency; }
|
||||
constructor(@SkipSelf() public dependency: Dependency) {
|
||||
this.dependency = dependency;
|
||||
}
|
||||
}
|
||||
|
||||
const parent = Injector.create({providers: [{provide: Dependency, deps: []}]});
|
||||
@ -158,7 +159,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
declarations: [App, ParentCmp, ChildDirective],
|
||||
});
|
||||
|
||||
let cmp: ComponentFixture<App> = undefined !;
|
||||
let cmp: ComponentFixture<App> = undefined!;
|
||||
expect(() => cmp = TestBed.createComponent(App)).not.toThrow();
|
||||
|
||||
expect(cmp.debugElement.children[0].children[0].injector.get(ChildDirective).logs).toEqual([
|
||||
@ -167,6 +168,5 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -55,7 +55,9 @@ import {Injectable, InjectionToken, Injector, Optional, ReflectiveInjector} from
|
||||
describe('ClassProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion ClassProvider
|
||||
abstract class Shape { name !: string; }
|
||||
abstract class Shape {
|
||||
name!: string;
|
||||
}
|
||||
|
||||
class Square extends Shape {
|
||||
name = 'square';
|
||||
@ -92,7 +94,9 @@ import {Injectable, InjectionToken, Injector, Optional, ReflectiveInjector} from
|
||||
describe('StaticClassProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion StaticClassProvider
|
||||
abstract class Shape { name !: string; }
|
||||
abstract class Shape {
|
||||
name!: string;
|
||||
}
|
||||
|
||||
class Square extends Shape {
|
||||
name = 'square';
|
||||
@ -200,6 +204,5 @@ import {Injectable, InjectionToken, Injector, Optional, ReflectiveInjector} from
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {browser, by, element, ElementFinder} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from '../../../../../test-utils';
|
||||
|
||||
describe('viewChild example', () => {
|
||||
|
@ -11,7 +11,7 @@ import {Component, Directive, Input, ViewChild} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id !: string;
|
||||
@Input() id!: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -28,10 +28,14 @@ export class Pane {
|
||||
export class ViewChildComp {
|
||||
@ViewChild(Pane)
|
||||
set pane(v: Pane) {
|
||||
setTimeout(() => { this.selectedPane = v.id; }, 0);
|
||||
setTimeout(() => {
|
||||
this.selectedPane = v.id;
|
||||
}, 0);
|
||||
}
|
||||
selectedPane: string = '';
|
||||
shouldShow = true;
|
||||
toggle() { this.shouldShow = !this.shouldShow; }
|
||||
toggle() {
|
||||
this.shouldShow = !this.shouldShow;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -15,7 +15,7 @@ class ChildDirective {
|
||||
|
||||
@Component({selector: 'someCmp', templateUrl: 'someCmp.html'})
|
||||
class SomeCmp implements AfterViewInit {
|
||||
@ViewChild(ChildDirective) child !: ChildDirective;
|
||||
@ViewChild(ChildDirective) child!: ChildDirective;
|
||||
|
||||
ngAfterViewInit() {
|
||||
// child is set
|
||||
|
@ -7,7 +7,8 @@
|
||||
*/
|
||||
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {browser, by, element, ElementFinder} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from '../../../../../test-utils';
|
||||
|
||||
describe('viewChildren example', () => {
|
||||
|
@ -11,7 +11,7 @@ import {AfterViewInit, Component, Directive, Input, QueryList, ViewChildren} fro
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id !: string;
|
||||
@Input() id!: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -27,20 +27,26 @@ export class Pane {
|
||||
`,
|
||||
})
|
||||
export class ViewChildrenComp implements AfterViewInit {
|
||||
@ViewChildren(Pane) panes !: QueryList<Pane>;
|
||||
@ViewChildren(Pane) panes!: QueryList<Pane>;
|
||||
serializedPanes: string = '';
|
||||
|
||||
shouldShow = false;
|
||||
|
||||
show() { this.shouldShow = true; }
|
||||
show() {
|
||||
this.shouldShow = true;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.calculateSerializedPanes();
|
||||
this.panes.changes.subscribe((r) => { this.calculateSerializedPanes(); });
|
||||
this.panes.changes.subscribe((r) => {
|
||||
this.calculateSerializedPanes();
|
||||
});
|
||||
}
|
||||
|
||||
calculateSerializedPanes() {
|
||||
setTimeout(() => { this.serializedPanes = this.panes.map(p => p.id).join(', '); }, 0);
|
||||
setTimeout(() => {
|
||||
this.serializedPanes = this.panes.map(p => p.id).join(', ');
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -15,7 +15,7 @@ class ChildDirective {
|
||||
|
||||
@Component({selector: 'someCmp', templateUrl: 'someCmp.html'})
|
||||
class SomeCmp implements AfterViewInit {
|
||||
@ViewChildren(ChildDirective) viewChildren !: QueryList<ChildDirective>;
|
||||
@ViewChildren(ChildDirective) viewChildren!: QueryList<ChildDirective>;
|
||||
|
||||
ngAfterViewInit() {
|
||||
// viewChildren is set
|
||||
|
@ -29,7 +29,9 @@ describe('testability example', () => {
|
||||
let waitWithResultScript = function(done: any) {
|
||||
let rootEl = document.querySelector('example-app');
|
||||
let testability = window.getAngularTestability(rootEl);
|
||||
testability.whenStable((didWork: boolean, tasks: any) => { done(tasks); }, 1000);
|
||||
testability.whenStable((didWork: boolean, tasks: any) => {
|
||||
done(tasks);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
element(by.css('.start-button')).click();
|
||||
@ -43,6 +45,8 @@ describe('testability example', () => {
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => { browser.ignoreSynchronization = false; });
|
||||
afterAll(() => {
|
||||
browser.ignoreSynchronization = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -20,7 +20,9 @@ export class StableTestCmp {
|
||||
status = 'none';
|
||||
start() {
|
||||
this.status = 'running';
|
||||
setTimeout(() => { this.status = 'done'; }, 5000);
|
||||
setTimeout(() => {
|
||||
this.status = 'done';
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,9 @@ import {discardPeriodicTasks, fakeAsync, tick} from '@angular/core/testing';
|
||||
describe('this test', () => {
|
||||
it('looks async but is synchronous', <any>fakeAsync((): void => {
|
||||
let flag = false;
|
||||
setTimeout(() => { flag = true; }, 100);
|
||||
setTimeout(() => {
|
||||
flag = true;
|
||||
}, 100);
|
||||
expect(flag).toBe(false);
|
||||
tick(50);
|
||||
expect(flag).toBe(false);
|
||||
|
@ -33,7 +33,9 @@ class AppComponent {
|
||||
// #docregion detach
|
||||
class DataListProvider {
|
||||
// in a real application the returned data will be different every time
|
||||
get data() { return [1, 2, 3, 4, 5]; }
|
||||
get data() {
|
||||
return [1, 2, 3, 4, 5];
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -45,7 +47,9 @@ class DataListProvider {
|
||||
class GiantList {
|
||||
constructor(private ref: ChangeDetectorRef, public dataProvider: DataListProvider) {
|
||||
ref.detach();
|
||||
setInterval(() => { this.ref.detectChanges(); }, 5000);
|
||||
setInterval(() => {
|
||||
this.ref.detectChanges();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +68,9 @@ class App {
|
||||
class DataProvider {
|
||||
data = 1;
|
||||
constructor() {
|
||||
setInterval(() => { this.data = 2; }, 500);
|
||||
setInterval(() => {
|
||||
this.data = 2;
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,8 +60,12 @@ export class IntervalDirComponent {
|
||||
`
|
||||
})
|
||||
export class MyOutputComponent {
|
||||
onEverySecond() { console.log('second'); }
|
||||
onEveryFiveSeconds() { console.log('five seconds'); }
|
||||
onEverySecond() {
|
||||
console.log('second');
|
||||
}
|
||||
onEveryFiveSeconds() {
|
||||
console.log('five seconds');
|
||||
}
|
||||
}
|
||||
// #enddocregion component-output-interval
|
||||
|
||||
|
@ -10,142 +10,143 @@ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit,
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
(function() {
|
||||
describe('lifecycle hooks examples', () => {
|
||||
it('should work with ngOnInit', () => {
|
||||
// #docregion OnInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
// ...
|
||||
}
|
||||
describe('lifecycle hooks examples', () => {
|
||||
it('should work with ngOnInit', () => {
|
||||
// #docregion OnInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
// ...
|
||||
}
|
||||
// #enddocregion
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngOnInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngDoCheck', () => {
|
||||
// #docregion DoCheck
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements DoCheck {
|
||||
ngDoCheck() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngDoCheck', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterContentChecked', () => {
|
||||
// #docregion AfterContentChecked
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterContentChecked {
|
||||
ngAfterContentChecked() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentChecked', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterContentInit', () => {
|
||||
// #docregion AfterContentInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterContentInit {
|
||||
ngAfterContentInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterViewChecked', () => {
|
||||
// #docregion AfterViewChecked
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterViewChecked {
|
||||
ngAfterViewChecked() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewChecked', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterViewInit', () => {
|
||||
// #docregion AfterViewInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterViewInit {
|
||||
ngAfterViewInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngOnDestroy', () => {
|
||||
// #docregion OnDestroy
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnDestroy {
|
||||
ngOnDestroy() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngOnDestroy', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngOnChanges', () => {
|
||||
// #docregion OnChanges
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnChanges {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input()
|
||||
prop !: number;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
// changes.prop contains the old and the new value...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
const log = createAndLogComponent(MyComponent, ['prop']);
|
||||
expect(log.length).toBe(1);
|
||||
expect(log[0][0]).toBe('ngOnChanges');
|
||||
const changes: SimpleChanges = log[0][1][0];
|
||||
expect(changes['prop'].currentValue).toBe(true);
|
||||
});
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngOnInit', []]]);
|
||||
});
|
||||
|
||||
function createAndLogComponent(clazz: Type<any>, inputs: string[] = []): any[] {
|
||||
const log: any[] = [];
|
||||
createLoggingSpiesFromProto(clazz, log);
|
||||
|
||||
const inputBindings = inputs.map(input => `[${input}] = true`).join(' ');
|
||||
|
||||
@Component({template: `<my-cmp ${inputBindings}></my-cmp>`})
|
||||
class ParentComponent {
|
||||
it('should work with ngDoCheck', () => {
|
||||
// #docregion DoCheck
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements DoCheck {
|
||||
ngDoCheck() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngDoCheck', []]]);
|
||||
});
|
||||
|
||||
const fixture = TestBed.configureTestingModule({declarations: [ParentComponent, clazz]})
|
||||
.createComponent(ParentComponent);
|
||||
fixture.detectChanges();
|
||||
fixture.destroy();
|
||||
return log;
|
||||
it('should work with ngAfterContentChecked', () => {
|
||||
// #docregion AfterContentChecked
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterContentChecked {
|
||||
ngAfterContentChecked() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentChecked', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterContentInit', () => {
|
||||
// #docregion AfterContentInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterContentInit {
|
||||
ngAfterContentInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterViewChecked', () => {
|
||||
// #docregion AfterViewChecked
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterViewChecked {
|
||||
ngAfterViewChecked() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewChecked', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterViewInit', () => {
|
||||
// #docregion AfterViewInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterViewInit {
|
||||
ngAfterViewInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngOnDestroy', () => {
|
||||
// #docregion OnDestroy
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnDestroy {
|
||||
ngOnDestroy() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngOnDestroy', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngOnChanges', () => {
|
||||
// #docregion OnChanges
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnChanges {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() prop!: number;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
// changes.prop contains the old and the new value...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
const log = createAndLogComponent(MyComponent, ['prop']);
|
||||
expect(log.length).toBe(1);
|
||||
expect(log[0][0]).toBe('ngOnChanges');
|
||||
const changes: SimpleChanges = log[0][1][0];
|
||||
expect(changes['prop'].currentValue).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function createAndLogComponent(clazz: Type<any>, inputs: string[] = []): any[] {
|
||||
const log: any[] = [];
|
||||
createLoggingSpiesFromProto(clazz, log);
|
||||
|
||||
const inputBindings = inputs.map(input => `[${input}] = true`).join(' ');
|
||||
|
||||
@Component({template: `<my-cmp ${inputBindings}></my-cmp>`})
|
||||
class ParentComponent {
|
||||
}
|
||||
|
||||
function createLoggingSpiesFromProto(clazz: Type<any>, log: any[]) {
|
||||
const proto = clazz.prototype;
|
||||
Object.keys(proto).forEach((method) => {
|
||||
proto[method] = (...args: any[]) => { log.push([method, args]); };
|
||||
});
|
||||
}
|
||||
|
||||
const fixture = TestBed.configureTestingModule({declarations: [ParentComponent, clazz]})
|
||||
.createComponent(ParentComponent);
|
||||
fixture.detectChanges();
|
||||
fixture.destroy();
|
||||
return log;
|
||||
}
|
||||
|
||||
function createLoggingSpiesFromProto(clazz: Type<any>, log: any[]) {
|
||||
const proto = clazz.prototype;
|
||||
Object.keys(proto).forEach((method) => {
|
||||
proto[method] = (...args: any[]) => {
|
||||
log.push([method, args]);
|
||||
};
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -21,7 +21,9 @@ class Greet {
|
||||
@Component({selector: 'page', template: 'Title: {{title}}'})
|
||||
class Page {
|
||||
title: string;
|
||||
constructor(@Attribute('title') title: string) { this.title = title; }
|
||||
constructor(@Attribute('title') title: string) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
@ -46,6 +48,8 @@ class InputDirective {
|
||||
// #docregion pipe
|
||||
@Pipe({name: 'lowercase'})
|
||||
class Lowercase {
|
||||
transform(v: string, args: any[]) { return v.toLowerCase(); }
|
||||
transform(v: string, args: any[]) {
|
||||
return v.toLowerCase();
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -7,9 +7,10 @@
|
||||
*/
|
||||
|
||||
// #docregion enableProdMode
|
||||
import {NgModule, enableProdMode} from '@angular/core';
|
||||
import {enableProdMode, NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
import {MyComponent} from './my_component';
|
||||
|
||||
enableProdMode();
|
||||
|
Reference in New Issue
Block a user