describe("Section Block Component", () => { const mocks = helpers.getMocks(); let fixture: ComponentFixture<SectionBlockComponent>; let component: SectionBlockComponent; const person = mocks.person; let block: any; const blockService = mocks.blockService; beforeEach(async(() => { blockService.uploadImages = jasmine.createSpy("uploadImages").and.returnValue(Promise.resolve({})); TestBed.configureTestingModule({ declarations: [SectionBlockComponent], providers: [ { provide: BlockService, useValue: blockService }, { provide: TranslatorService, useValue: mocks.translatorService } ], schemas: [CUSTOM_ELEMENTS_SCHEMA], imports: [PopoverModule.forRoot(), FormsModule, TranslateModule.forRoot()] }); fixture = TestBed.createComponent(SectionBlockComponent); component = fixture.componentInstance; component.owner = person; component.designMode = true; block = { id: 1, settings: { name: 'some name', description: 'some description' }, images: [{ id: 1, filename: "file1.png", url: "/image_uploads/0000/0005/file1.png" }, { id: 2, filename: "file2.png", url: "/image_uploads/0000/0005/file2.png" } ] }; component.block = block; fixture.detectChanges(); spyOn(component.popover, 'hide').and.callThrough(); })); it("should hide if there is no image, name, description or title", () => { component.block = { id: 1, title: undefined, settings: { name: undefined, description: undefined }, images: [] }; component.ngOnChanges(); expect(component.block.hide).toBeTruthy(); }); it("should show if there is a title", () => { component.block = { id: 1, title: 'Section Block', settings: { name: undefined, description: undefined }, images: [] }; component.ngOnChanges(); expect(component.block.hide).toBeFalsy(); }); it("should show if there is a name", () => { component.block = { id: 1, title: undefined, settings: { name: 'mariko', description: undefined }, images: [] }; component.ngOnChanges(); expect(component.block.hide).toBeFalsy(); }); it("should show if there is a descriton", () => { component.block = { id: 1, title: undefined, settings: { name: undefined, description: 'nice manga' }, images: [] }; component.ngOnChanges(); expect(component.block.hide).toBeFalsy(); }); it("should show if there is an image", () => { component.block = { id: 1, title: undefined, settings: { name: undefined, description: undefined }, images: [{ id: 1, filename: "file1.png", url: "/image_uploads/0000/0005/file1.png" }] }; component.ngOnChanges(); expect(component.block.hide).toBeFalsy(); }); it("initialize modifiedLink link", fakeAsync(() => { component.ngOnInit(); tick(); expect(component.modifiedLink).toEqual(block.settings); })); it("should display section name", () => { expect(fixture.debugElement.nativeElement.querySelector(".section-block .name").innerHTML).toContain(block.settings.name); }); it("should display section description", () => { expect(fixture.debugElement.nativeElement.querySelector(".section-block .description").innerHTML).toContain(block.settings.description); }); it("should return the last image of component images list", () => { expect(component.getSectionImage()).toEqual(block.images[1]); }); it("should return null if there is an empty array in component images list", () => { component.block.images = []; expect(component.getSectionImage()).toBeNull(); }); it("should return null if images block attribute is null", () => { component.block.images = null; expect(component.getSectionImage()).toBeNull(); }); it("should show the last image from block images", () => { expect(fixture.debugElement.nativeElement.querySelector(".section-image").src).toContain('/image_uploads/0000/0005/file2.png'); }); it("not show image if there is no image", () => { component.block.images = []; fixture.detectChanges(); expect(fixture.debugElement.nativeElement.querySelector(".section-image")).toBeFalsy(); }); it("copyLink copy the link present in block to modifiedLink variable", () => { component.modifiedLink = {}; expect(component.modifiedLink).toEqual({}); component.block.settings = { name: 'another name', description: 'another description' }; component.copyLink(); expect(component.modifiedLink).toEqual(component.block.settings); }); it("cancel copy the old link present in block attribute", () => { const newLink = { name: 'new name link', description: 'new description link' } component.modifiedLink = newLink; expect(component.modifiedLink).toEqual(newLink); component.block.settings = { name: 'another name', description: 'another description' }; component.cancel(); expect(component.modifiedLink).toEqual(component.block.settings); }); it("cancel should call hide popover function", () => { component.cancel(); expect(component.popover.hide).toHaveBeenCalled(); }); it("save should call hide popover function", () => { component.save(); expect(component.popover.hide).toHaveBeenCalled(); }); it("save shoulld copy modifiedLink value to block attributes", () => { const newLink = { name: 'new name link', description: 'new description link' } component.modifiedLink = newLink; expect(component.block.settings === component.modifiedLink).toBeFalsy(); component.save(); expect(component.block.settings).toEqual(component.modifiedLink); }); it("should uploadImages service be called by upload method", () => { const data = {}; component.upload(data); expect(blockService.uploadImages).toHaveBeenCalledWith(component.block, [data]); }); it("should upload set new information to block", fakeAsync(() => { const data = { data: { id: 3 } }; component['blockService'].uploadImages = jasmine.createSpy("uploadImages").and.returnValue(Promise.resolve(data)); component.upload(data); tick(); expect(component.block).toEqual(data.data); })); it("should set background color in view", () => { const color = 'ff0000' component.backgroundColor = color; fixture.detectChanges(); expect(fixture.debugElement.nativeElement.querySelector(".section-block").style.backgroundColor).toContain('rgb(255, 0, 0)'); }); it("should set color color in view", () => { const color = 'ff00ff' component.fontColor = color; fixture.detectChanges(); expect(fixture.debugElement.nativeElement.querySelector(".section-block").style.color).toContain('rgb(255, 0, 255)'); }); });
describe('template-driven forms integration tests', () => { beforeEach(() => { TestBed.configureTestingModule({imports: [FormsModule]}); }); it('should support ngModel for single fields', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div><input type="text" [(ngModel)]="name"></div>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'oldValue'; fixture.detectChanges(); var input = fixture.debugElement.query(By.css('input')).nativeElement; tick(); expect(input.value).toEqual('oldValue'); input.value = 'updatedValue'; dispatchEvent(input, 'input'); tick(); expect(fixture.debugElement.componentInstance.name).toEqual('updatedValue'); }))); it('should support ngModel registration with a parent form', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = ` <form> <input name="first" [(ngModel)]="name" maxlength="4"> </form> `; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'Nancy'; fixture.detectChanges(); var form = fixture.debugElement.children[0].injector.get(NgForm); tick(); expect(form.value).toEqual({first: 'Nancy'}); expect(form.valid).toBe(false); }))); it('should add new controls and control groups', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <div ngModelGroup="user"> <input type="text" name="login" ngModel> </div> </form>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = null; fixture.detectChanges(); var form = fixture.debugElement.children[0].injector.get(NgForm); expect(form.controls['user']).not.toBeDefined(); tick(); expect(form.controls['user']).toBeDefined(); expect(form.controls['user'].controls['login']).toBeDefined(); }))); it('should emit ngSubmit event on submit', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div><form (ngSubmit)="name='updated'"></form></div>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'old'; var form = fixture.debugElement.query(By.css('form')); dispatchEvent(form.nativeElement, 'submit'); tick(); expect(fixture.debugElement.componentInstance.name).toEqual('updated'); }))); it('should mark NgForm as submitted on submit event', inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => { const t = `<div> <form #f="ngForm" (ngSubmit)="data=f.submitted"></form> <span>{{data}}</span> </div>`; var fixture: ComponentFixture<MyComp8>; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((root) => { fixture = root; }); tick(); fixture.debugElement.componentInstance.data = false; tick(); var form = fixture.debugElement.query(By.css('form')); dispatchEvent(form.nativeElement, 'submit'); tick(); expect(fixture.debugElement.componentInstance.data).toEqual(true); }))); it('should reset the form to empty when reset button is clicked', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = ` <form> <input name="name" [(ngModel)]="name"> </form> `; const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'should be cleared'; fixture.detectChanges(); tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); const formEl = fixture.debugElement.query(By.css('form')); dispatchEvent(formEl.nativeElement, 'reset'); fixture.detectChanges(); tick(); expect(fixture.debugElement.componentInstance.name).toBe(null); expect(form.value.name).toEqual(null); }))); it('should emit valueChanges and statusChanges on init', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <input type="text" name="first" [ngModel]="name" minlength="3"> </form>`; const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); const form = fixture.debugElement.children[0].injector.get(NgForm); fixture.debugElement.componentInstance.name = 'aa'; fixture.detectChanges(); expect(form.valid).toEqual(true); expect(form.value).toEqual({}); let formValidity: string; let formValue: Object; ObservableWrapper.subscribe( form.statusChanges, (status: string) => { formValidity = status; }); ObservableWrapper.subscribe(form.valueChanges, (value: string) => { formValue = value; }); tick(); expect(formValidity).toEqual('INVALID'); expect(formValue).toEqual({first: 'aa'}); }))); it('should not create a template-driven form when ngNoForm is used', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { const t = `<form ngNoForm> </form>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { fixture.debugElement.componentInstance.name = null; fixture.detectChanges(); expect(fixture.debugElement.children[0].providerTokens.length).toEqual(0); async.done(); }); })); it('should remove controls', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <div *ngIf="name == 'show'"> <input type="text" name="login" ngModel> </div> </form>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'show'; fixture.detectChanges(); tick(); var form = fixture.debugElement.children[0].injector.get(NgForm); expect(form.controls['login']).toBeDefined(); fixture.debugElement.componentInstance.name = 'hide'; fixture.detectChanges(); tick(); expect(form.controls['login']).not.toBeDefined(); }))); it('should remove control groups', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <div *ngIf="name=='show'" ngModelGroup="user"> <input type="text" name="login" ngModel> </div> </form>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'show'; fixture.detectChanges(); tick(); var form = fixture.debugElement.children[0].injector.get(NgForm); expect(form.controls['user']).toBeDefined(); fixture.debugElement.componentInstance.name = 'hide'; fixture.detectChanges(); tick(); expect(form.controls['user']).not.toBeDefined(); }))); it('should support ngModel for complex forms', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <input type="text" name="name" [(ngModel)]="name"> </form>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = 'oldValue'; fixture.detectChanges(); tick(); var input = fixture.debugElement.query(By.css('input')).nativeElement; expect(input.value).toEqual('oldValue'); input.value = 'updatedValue'; dispatchEvent(input, 'input'); tick(); expect(fixture.debugElement.componentInstance.name).toEqual('updatedValue'); }))); it('should throw if ngModel has a parent form but no name attr or standalone label', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { const t = `<form> <input [(ngModel)]="name"> </form>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { expect(() => fixture.detectChanges()) .toThrowError(new RegExp(`name attribute must be set`)); async.done(); }); })); it('should not throw if ngModel has a parent form, no name attr, and a standalone label', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { const t = `<form> <input [(ngModel)]="name" [ngModelOptions]="{standalone: true}"> </form>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { expect(() => fixture.detectChanges()).not.toThrow(); async.done(); }); })); it('should override name attribute with ngModelOptions name if provided', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = ` <form> <input name="one" [(ngModel)]="data" [ngModelOptions]="{name: 'two'}"> </form> `; const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.data = 'some data'; fixture.detectChanges(); const form = fixture.debugElement.children[0].injector.get(NgForm); tick(); expect(form.value).toEqual({two: 'some data'}); }))); it('should not register standalone ngModels with parent form', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = ` <form> <input name="one" [(ngModel)]="data"> <input [(ngModel)]="list" [ngModelOptions]="{standalone: true}"> </form> `; const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.data = 'some data'; fixture.debugElement.componentInstance.list = 'should not show'; fixture.detectChanges(); const form = fixture.debugElement.children[0].injector.get(NgForm); const inputs = fixture.debugElement.queryAll(By.css('input')); tick(); expect(form.value).toEqual({one: 'some data'}); expect(inputs[1].nativeElement.value).toEqual('should not show'); }))); it('should set status classes with ngModel', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { const t = `<div><input [(ngModel)]="name" required></div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { fixture.debugElement.componentInstance.name = ''; fixture.detectChanges(); var input = fixture.debugElement.query(By.css('input')).nativeElement; expect(sortedClassList(input)).toEqual([ 'ng-invalid', 'ng-pristine', 'ng-untouched' ]); dispatchEvent(input, 'blur'); fixture.detectChanges(); expect(sortedClassList(input)).toEqual(['ng-invalid', 'ng-pristine', 'ng-touched']); input.value = 'updatedValue'; dispatchEvent(input, 'input'); fixture.detectChanges(); expect(sortedClassList(input)).toEqual(['ng-dirty', 'ng-touched', 'ng-valid']); async.done(); }); })); it('should mark controls as dirty before emitting a value change event', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <input type="text" name="login" ngModel> </form>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { fixture.detectChanges(); const form = fixture.debugElement.children[0].injector.get(NgForm).form; fixture.detectChanges(); tick(); form.find('login').valueChanges.subscribe( () => { expect(form.find('login').dirty).toBe(true); }); const loginEl = fixture.debugElement.query(By.css('input')).nativeElement; loginEl.value = 'newValue'; dispatchEvent(loginEl, 'input'); }); }))); it('should mark control as pristine before emitting a value change event when resetting ', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <input type="text" name="login" ngModel> </form>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { fixture.detectChanges(); const form = fixture.debugElement.children[0].injector.get(NgForm).form; const formEl = fixture.debugElement.query(By.css('form')).nativeElement; const loginEl = fixture.debugElement.query(By.css('input')).nativeElement; fixture.detectChanges(); tick(); loginEl.value = 'newValue'; dispatchEvent(loginEl, 'input'); expect(form.find('login').pristine).toBe(false); form.find('login').valueChanges.subscribe( () => { expect(form.find('login').pristine).toBe(true); }); dispatchEvent(formEl, 'reset'); }); }))); describe('radio value accessor', () => { it('should support <type=radio>', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <input type="radio" name="food" [(ngModel)]="data.food" value="chicken"> <input type="radio" name="food" [(ngModel)]="data.food" value="fish"> </form>`; const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.data = {food: 'fish'}; fixture.detectChanges(); tick(); const inputs = fixture.debugElement.queryAll(By.css('input')); expect(inputs[0].nativeElement.checked).toEqual(false); expect(inputs[1].nativeElement.checked).toEqual(true); dispatchEvent(inputs[0].nativeElement, 'change'); tick(); const data = fixture.debugElement.componentInstance.data; expect(data.food).toEqual('chicken'); expect(inputs[1].nativeElement.checked).toEqual(false); }))); it('should support multiple named <type=radio> groups', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<form> <input type="radio" name="food" [(ngModel)]="data.food" value="chicken"> <input type="radio" name="food" [(ngModel)]="data.food" value="fish"> <input type="radio" name="drink" [(ngModel)]="data.drink" value="cola"> <input type="radio" name="drink" [(ngModel)]="data.drink" value="sprite"> </form>`; const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.data = {food: 'fish', drink: 'sprite'}; fixture.detectChanges(); tick(); const inputs = fixture.debugElement.queryAll(By.css('input')); expect(inputs[0].nativeElement.checked).toEqual(false); expect(inputs[1].nativeElement.checked).toEqual(true); expect(inputs[2].nativeElement.checked).toEqual(false); expect(inputs[3].nativeElement.checked).toEqual(true); dispatchEvent(inputs[0].nativeElement, 'change'); tick(); const data = fixture.debugElement.componentInstance.data; expect(data.food).toEqual('chicken'); expect(data.drink).toEqual('sprite'); expect(inputs[1].nativeElement.checked).toEqual(false); expect(inputs[2].nativeElement.checked).toEqual(false); expect(inputs[3].nativeElement.checked).toEqual(true); }))); }); describe('select value accessor', () => { it('with option values that are objects', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}]; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); var select = fixture.debugElement.query(By.css('select')); var nycOption = fixture.debugElement.queryAll(By.css('option'))[1]; tick(); expect(select.nativeElement.value).toEqual('1: Object'); expect(nycOption.nativeElement.selected).toBe(true); select.nativeElement.value = '2: Object'; dispatchEvent(select.nativeElement, 'change'); fixture.detectChanges(); tick(); expect(testComp.selectedCity['name']).toEqual('Buffalo'); }); }))); it('when new options are added (selection through the model)', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp: MyComp8 = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); testComp.list.push({'name': 'Buffalo'}); testComp.selectedCity = testComp.list[2]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var buffalo = fixture.debugElement.queryAll(By.css('option'))[2]; expect(select.nativeElement.value).toEqual('2: Object'); expect(buffalo.nativeElement.selected).toBe(true); }); }))); it('when new options are added (selection through the UI)', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp: MyComp8 = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); var select = fixture.debugElement.query(By.css('select')); var ny = fixture.debugElement.queryAll(By.css('option'))[1]; select.nativeElement.value = '1: Object'; dispatchEvent(select.nativeElement, 'change'); testComp.list.push({'name': 'Buffalo'}); fixture.detectChanges(); expect(select.nativeElement.value).toEqual('1: Object'); expect(ny.nativeElement.selected).toBe(true); async.done(); }); })); it('when options are removed', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp: MyComp8 = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); expect(select.nativeElement.value).toEqual('1: Object'); testComp.list.pop(); fixture.detectChanges(); tick(); expect(select.nativeElement.value).not.toEqual('1: Object'); }); }))); it('when option values change identity while tracking by index', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list; trackBy:customTrackBy" [ngValue]="c">{{c}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); testComp.list[1] = 'Buffalo'; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var buffalo = fixture.debugElement.queryAll(By.css('option'))[1]; expect(select.nativeElement.value).toEqual('1: Buffalo'); expect(buffalo.nativeElement.selected).toBe(true); }); }))); it('with duplicate option values', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c.name}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'NYC'}, {'name': 'SF'}, {'name': 'SF'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var firstSF = fixture.debugElement.queryAll(By.css('option'))[1]; expect(select.nativeElement.value).toEqual('1: Object'); expect(firstSF.nativeElement.selected).toBe(true); }); }))); it('when option values have same content, but different identities', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); testComp.selectedCity = testComp.list[2]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var secondNYC = fixture.debugElement.queryAll(By.css('option'))[2]; expect(select.nativeElement.value).toEqual('2: Object'); expect(secondNYC.nativeElement.selected).toBe(true); }); }))); }); describe('ngModel corner cases', () => { it('should update the view when the model is set back to what used to be in the view', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<input type="text" [(ngModel)]="name">`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.debugElement.componentInstance.name = ''; fixture.detectChanges(); // Type "aa" into the input. var input = fixture.debugElement.query(By.css('input')).nativeElement; input.value = 'aa'; input.selectionStart = 1; dispatchEvent(input, 'input'); fixture.detectChanges(); tick(); expect(fixture.debugElement.componentInstance.name).toEqual('aa'); // Programmatically update the input value to be "bb". fixture.debugElement.componentInstance.name = 'bb'; fixture.detectChanges(); tick(); expect(input.value).toEqual('bb'); // Programatically set it back to "aa". fixture.debugElement.componentInstance.name = 'aa'; fixture.detectChanges(); tick(); expect(input.value).toEqual('aa'); }))); it('should not crash when validity is checked from a binding', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { // {{x.valid}} used to crash because valid() tried to read a property // from form.control before it was set. This test verifies this bug is // fixed. const t = `<form><div ngModelGroup="x" #x="ngModelGroup"> <input type="text" name="test" ngModel></div>{{x.valid}}</form>`; let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); tick(); fixture.detectChanges(); }))); }); });
describe('select value accessor', () => { it('with option values that are objects', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}]; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); var select = fixture.debugElement.query(By.css('select')); var nycOption = fixture.debugElement.queryAll(By.css('option'))[1]; tick(); expect(select.nativeElement.value).toEqual('1: Object'); expect(nycOption.nativeElement.selected).toBe(true); select.nativeElement.value = '2: Object'; dispatchEvent(select.nativeElement, 'change'); fixture.detectChanges(); tick(); expect(testComp.selectedCity['name']).toEqual('Buffalo'); }); }))); it('when new options are added (selection through the model)', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp: MyComp8 = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); testComp.list.push({'name': 'Buffalo'}); testComp.selectedCity = testComp.list[2]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var buffalo = fixture.debugElement.queryAll(By.css('option'))[2]; expect(select.nativeElement.value).toEqual('2: Object'); expect(buffalo.nativeElement.selected).toBe(true); }); }))); it('when new options are added (selection through the UI)', inject( [TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: AsyncTestCompleter) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp: MyComp8 = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); var select = fixture.debugElement.query(By.css('select')); var ny = fixture.debugElement.queryAll(By.css('option'))[1]; select.nativeElement.value = '1: Object'; dispatchEvent(select.nativeElement, 'change'); testComp.list.push({'name': 'Buffalo'}); fixture.detectChanges(); expect(select.nativeElement.value).toEqual('1: Object'); expect(ny.nativeElement.selected).toBe(true); async.done(); }); })); it('when options are removed', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp: MyComp8 = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); expect(select.nativeElement.value).toEqual('1: Object'); testComp.list.pop(); fixture.detectChanges(); tick(); expect(select.nativeElement.value).not.toEqual('1: Object'); }); }))); it('when option values change identity while tracking by index', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list; trackBy:customTrackBy" [ngValue]="c">{{c}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); testComp.list[1] = 'Buffalo'; testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var buffalo = fixture.debugElement.queryAll(By.css('option'))[1]; expect(select.nativeElement.value).toEqual('1: Buffalo'); expect(buffalo.nativeElement.selected).toBe(true); }); }))); it('with duplicate option values', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c.name}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'NYC'}, {'name': 'SF'}, {'name': 'SF'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); testComp.selectedCity = testComp.list[1]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var firstSF = fixture.debugElement.queryAll(By.css('option'))[1]; expect(select.nativeElement.value).toEqual('1: Object'); expect(firstSF.nativeElement.selected).toBe(true); }); }))); it('when option values have same content, but different identities', fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { const t = `<div> <select [(ngModel)]="selectedCity"> <option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option> </select> </div>`; tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => { var testComp = fixture.debugElement.componentInstance; testComp.list = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'NYC'}]; testComp.selectedCity = testComp.list[0]; fixture.detectChanges(); testComp.selectedCity = testComp.list[2]; fixture.detectChanges(); tick(); var select = fixture.debugElement.query(By.css('select')); var secondNYC = fixture.debugElement.queryAll(By.css('option'))[2]; expect(select.nativeElement.value).toEqual('2: Object'); expect(secondNYC.nativeElement.selected).toBe(true); }); }))); });
describe('getReadme', () => { it('should not get the readme if not connected to github', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { service['octo'] = null; service.getReadme('myOwner', 'myRepository', 'packages/') .then(() => { throw('Should not get here'); }) .catch((error) => { error.should.equal('no connection to GitHub'); }); tick(); }))); it('should get the readme', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let octoReadmeFileMock = { name: 'README.md', content: 'YSByZWFkbWUgZmlsZQ==' }; let repoMock = { contents: sinon.stub() }; repoMock.contents.returns({ fetch: sinon.stub().returns(Promise.resolve(octoReadmeFileMock)) }); let octoMock = { repos: sinon.stub().returns(repoMock) }; service['octo'] = octoMock; service.getReadme('myOwner', 'myRepository', 'packages/') .then((result) => { result.should.deep.equal({name: 'README.md', data: 'a readme file'}); }); tick(); }))); it('should handle having no readme', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let repoMock = { contents: sinon.stub() }; repoMock.contents.returns({ fetch: sinon.stub().returns(Promise.reject({status: 404})) }); let octoMock = { repos: sinon.stub().returns(repoMock) }; service['octo'] = octoMock; service.getReadme('myOwner', 'myRepository', 'packages/') .then((result) => { should.not.exist(result); }); tick(); }))); it('should handle error', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let repoMock = { contents: sinon.stub() }; repoMock.contents.returns({ fetch: sinon.stub().returns(Promise.reject('some error')) }); let octoMock = { repos: sinon.stub().returns(repoMock) }; service['octo'] = octoMock; service.getReadme('myOwner', 'myRepository', 'packages/') .then(() => { throw('should not get here'); }) .catch((error) => { error.should.equal('some error'); }); tick(); }))); });
describe('Angulartics2GoogleGlobalSiteTag', () => { let gtag: any; let ga: any; let fixture: ComponentFixture<any>; beforeEach(() => { TestBed.configureTestingModule({ imports: [TestModule], providers: [Angulartics2GoogleGlobalSiteTag], }); window.gtag = gtag = jasmine.createSpy('gtag'); window.ga = ga = { getAll: function() { return { forEach: function(callback) { const tracker = { get: function(value) { return 'UA-111111111-1'; }, }; callback(tracker); }, }; }, }; }); it('should track pages', fakeAsync(inject([Angulartics2, Angulartics2GoogleGlobalSiteTag], (angulartics2: Angulartics2, angulartics2GoogleGlobalSiteTag: Angulartics2GoogleGlobalSiteTag) => { fixture = createRoot(RootCmp); angulartics2.pageTrack.next({ path: '/abc' }); advance(fixture); expect(gtag.calls.count()).toEqual(1); expect(gtag).toHaveBeenCalledWith('config', 'UA-111111111-1', {'page_path': '/abc'}); }, )), ); it('should track events', fakeAsync(inject([Angulartics2, Angulartics2GoogleGlobalSiteTag], (angulartics2: Angulartics2, angulartics2GoogleGlobalSiteTag: Angulartics2GoogleGlobalSiteTag) => { fixture = createRoot(RootCmp); angulartics2.eventTrack.next({ action: 'do', properties: { value: 1, label: 'abc', gstCustom: { customKey: 'customValue', }, } }); advance(fixture); expect(gtag).toHaveBeenCalledWith('event', 'do', { event_category: 'interaction', event_label: 'abc', value: 1, non_interaction: undefined, customKey: 'customValue', }); } )), ); it('should track exceptions', fakeAsync(inject([Angulartics2, Angulartics2GoogleGlobalSiteTag], (angulartics2: Angulartics2, angulartics2GoogleGlobalSiteTag: Angulartics2GoogleGlobalSiteTag) => { fixture = createRoot(RootCmp); angulartics2.exceptionTrack.next({ description: 'bugger', gstCustom: { appId: 'app', appName: 'Test App', appVersion: '0.1' } }); advance(fixture); expect(gtag).toHaveBeenCalledWith('event', 'exception', { event_category: 'interaction', event_label: undefined, value: undefined, non_interaction: undefined, description: 'bugger', fatal: true, appId: 'app', appName: 'Test App', appVersion: '0.1', }); } )), ); });
describe('getSampleNetworkInfo', () => { it('should not get the json for the sample if not connected to github', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { service['octo'] = null; service.getSampleNetworkInfo('myOwner', 'myRepository', 'packages/') .then(() => { throw('Should not get here'); }) .catch((error) => { error.should.equal('no connection to GitHub'); }); tick(); }))); it('should get the json for the sample', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let octoJsonMock = { content: 'eyJuYW1lIiA6ICJib2IifQ==' }; let octoMock = { repos: sinon.stub().returns({ contents: sinon.stub().returns({ fetch: sinon.stub().returns(Promise.resolve(octoJsonMock)) }) }) }; service['octo'] = octoMock; service.getSampleNetworkInfo('myOwner', 'myRepository', 'packages/') .then((result) => { result.should.deep.equal({name: 'bob', composerPath: 'packages/'}); }); tick(); }))); it('should handle error with json', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { // contains malformed json let octoJsonMock = { content: 'eyJuYW1lIiA6ICJib2Ii' }; let octoMock = { repos: sinon.stub().returns({ contents: sinon.stub().returns({ fetch: sinon.stub().returns(Promise.resolve(octoJsonMock)) }) }) }; service['octo'] = octoMock; service.getSampleNetworkInfo('myOwner', 'myRepository', 'packages/') .then(() => { throw('should not get here'); }) .catch((error) => { error.message.should.equal('Unexpected end of JSON input'); }); tick(); }))); it('should handle error', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let octoMock = { repos: sinon.stub().returns({ contents: sinon.stub().returns({ fetch: sinon.stub().returns(Promise.reject('some error')) }) }) }; service['octo'] = octoMock; service.getSampleNetworkInfo('myOwner', 'myRepository', 'packages/') .then(() => { throw('should not get here'); }) .catch((error) => { error.should.equal('some error'); }); tick(); }))); });
describe('getModel', () => { it('should not get the model if not connected to github', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { service['octo'] = null; service.getModel('myOwner', 'myRepository', 'packages/') .then(() => { throw('Should not get here'); }) .catch((error) => { error.should.equal('no connection to GitHub'); }); tick(); }))); it('should get the model', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let octoModelMock = { items: [{name: 'modelOne', path: 'modelOne'}] }; let octoModelFileMock = { content: 'QSBtb2RlbCBmaWxl' }; let repoMock = { contents: sinon.stub() }; repoMock.contents.withArgs('packages/models').returns({ fetch: sinon.stub().returns(Promise.resolve(octoModelMock)) }); repoMock.contents.withArgs('modelOne').returns({ fetch: sinon.stub().returns(Promise.resolve(octoModelFileMock)) }); let octoMock = { repos: sinon.stub().returns(repoMock) }; service['octo'] = octoMock; service.getModel('myOwner', 'myRepository', 'packages/') .then((result) => { result.length.should.equal(1); result[0].should.equal('A model file'); }); tick(); }))); it('should handle error', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => { let repoMock = { contents: sinon.stub() }; repoMock.contents.withArgs('packages/models').returns({ fetch: sinon.stub().returns(Promise.reject('some error')) }); let octoMock = { repos: sinon.stub().returns(repoMock) }; service['octo'] = octoMock; service.getModel('myOwner', 'myRepository', 'packages/') .then(() => { throw('should not get here'); }) .catch((error) => { error.should.equal('some error'); }); tick(); }))); });
describe('ngOninit', () => { it('should initialise the footer', fakeAsync(inject([XHRBackend, ConfigService], (mockBackend, configService: ConfigService) => { let myConfig = new Config(); myConfig.webonly = true; myConfig.title = 'My Title'; myConfig.banner = ['My', 'Banner']; myConfig.docURL = 'https://doc_url'; myConfig.links = { docs: 'My Docs', tutorial: 'My Tutorial', community: 'My Community', github: 'My Github', install: 'My Install', legal: 'My License' }; configService['configLoaded'] = true; configService['config'] = myConfig; mockBackend.connections.subscribe((connection) => { connection.mockRespond(new Response(new ResponseOptions({ body: JSON.stringify(mockResponseAboutService) }))); }); fixture.detectChanges(); tick(); fixture.detectChanges(); component['playgroundVersion'].should.match(/[0-9]+.[0-9]+.[0-9]+/); component['config'].should.deep.equal(myConfig); fixture.detectChanges(); tick(); links = fixture.debugElement.queryAll(By.css('a')); links.length.should.equal(5); links[0].nativeElement.textContent.should.equal('Legal'); links[1].nativeElement.textContent.should.equal('GitHub'); links[2].nativeElement.textContent.should.equal('Tutorial'); links[3].nativeElement.textContent.should.equal('Docs'); links[4].nativeElement.textContent.should.equal('Community'); }))); it('should load config if not already loaded', fakeAsync(inject([XHRBackend, ConfigService], (mockBackend, configService: ConfigService) => { let myConfig = new Config(); myConfig.webonly = true; myConfig.title = 'My Title'; myConfig.banner = ['My', 'Banner']; myConfig.docURL = 'https://doc_url'; myConfig.links = { docs: 'My Docs', tutorial: 'My Tutorial', community: 'My Community', github: 'My Github', install: 'My Install', legal: 'My License' }; mockBackend.connections.subscribe((connection) => { connection.mockRespond(new Response(new ResponseOptions({ body: JSON.stringify(mockResponseConfigService) }))); }); fixture.detectChanges(); tick(); fixture.detectChanges(); component['config'].should.deep.equal(myConfig); }))); it('should handle error from about service', fakeAsync(inject([ConfigService, XHRBackend], (configService, mockBackend) => { let myConfig = new Config(); myConfig.webonly = true; myConfig.title = 'My Title'; myConfig.banner = ['My', 'Banner']; myConfig.docURL = 'https://doc_url'; myConfig.links = { docs: 'My Docs', tutorial: 'My Tutorial', community: 'My Community', github: 'My Github', install: 'My Install', legal: 'My License' }; configService['configLoaded'] = true; configService['config'] = myConfig; component['alertService'].errorStatus$.subscribe( (message) => { if (message !== null) { message.should.equal('error'); } }); mockBackend.connections.subscribe( (connection) => { connection.mockError('error'); } ); fixture.detectChanges(); tick(); fixture.detectChanges(); }))); });
describe('asyncValidator', () => { it('should run validator with the initial value', fakeAsync(() => { const c = new FormControl('value', null, asyncValidator('expected')); tick(); expect(c.valid).toEqual(false); expect(c.errors).toEqual({'async': true}); })); it('should support validators returning observables', fakeAsync(() => { const c = new FormControl('value', null, asyncValidatorReturningObservable); tick(); expect(c.valid).toEqual(false); expect(c.errors).toEqual({'async': true}); })); it('should rerun the validator when the value changes', fakeAsync(() => { const c = new FormControl('value', null, asyncValidator('expected')); c.setValue('expected'); tick(); expect(c.valid).toEqual(true); })); it('should run the async validator only when the sync validator passes', fakeAsync(() => { const c = new FormControl('', Validators.required, asyncValidator('expected')); tick(); expect(c.errors).toEqual({'required': true}); c.setValue('some value'); tick(); expect(c.errors).toEqual({'async': true}); })); it('should mark the control as pending while running the async validation', fakeAsync(() => { const c = new FormControl('', null, asyncValidator('expected')); expect(c.pending).toEqual(true); tick(); expect(c.pending).toEqual(false); })); it('should only use the latest async validation run', fakeAsync(() => { const c = new FormControl( '', null, asyncValidator('expected', {'long': 200, 'expected': 100})); c.setValue('long'); c.setValue('expected'); tick(300); expect(c.valid).toEqual(true); })); it('should support arrays of async validator functions if passed', fakeAsync(() => { const c = new FormControl('value', null, [asyncValidator('expected'), otherAsyncValidator]); tick(); expect(c.errors).toEqual({'async': true, 'other': true}); })); it('should add single async validator', fakeAsync(() => { const c = new FormControl('value', null); c.setAsyncValidators(asyncValidator('expected')); expect(c.asyncValidator).not.toEqual(null); c.setValue('expected'); tick(); expect(c.valid).toEqual(true); })); it('should add async validator from array', fakeAsync(() => { const c = new FormControl('value', null); c.setAsyncValidators([asyncValidator('expected')]); expect(c.asyncValidator).not.toEqual(null); c.setValue('expected'); tick(); expect(c.valid).toEqual(true); })); it('should clear async validators', fakeAsync(() => { const c = new FormControl('value', [asyncValidator('expected'), otherAsyncValidator]); c.clearValidators(); expect(c.asyncValidator).toEqual(null); })); it('should not change validity state if control is disabled while async validating', fakeAsync(() => { const c = new FormControl('value', [asyncValidator('expected')]); c.disable(); tick(); expect(c.status).toEqual('DISABLED'); })); });
describe('RuntimeCompiler', () => { let compiler: Compiler; let resourceLoader: SpyResourceLoader; let dirResolver: MockDirectiveResolver; let injector: Injector; beforeEach(() => { TestBed.configureCompiler({providers: [SpyResourceLoader.PROVIDE]}); }); beforeEach(fakeAsync(inject( [Compiler, ResourceLoader, DirectiveResolver, Injector], (_compiler: Compiler, _resourceLoader: SpyResourceLoader, _dirResolver: MockDirectiveResolver, _injector: Injector) => { compiler = _compiler; resourceLoader = _resourceLoader; dirResolver = _dirResolver; injector = _injector; }))); describe('compileModuleAsync', () => { it('should allow to use templateUrl components', fakeAsync(() => { @NgModule({ declarations: [SomeCompWithUrlTemplate], entryComponents: [SomeCompWithUrlTemplate] }) class SomeModule { } resourceLoader.spy('get').and.callFake(() => Promise.resolve('hello')); let ngModuleFactory: NgModuleFactory<any> = undefined !; compiler.compileModuleAsync(SomeModule).then((f) => ngModuleFactory = f); tick(); expect(ngModuleFactory.moduleType).toBe(SomeModule); })); }); describe('compileModuleSync', () => { it('should throw when using a templateUrl that has not been compiled before', () => { @NgModule( {declarations: [SomeCompWithUrlTemplate], entryComponents: [SomeCompWithUrlTemplate]}) class SomeModule { } resourceLoader.spy('get').and.callFake(() => Promise.resolve('')); expect(() => compiler.compileModuleSync(SomeModule)) .toThrowError( `Can't compile synchronously as ${stringify(SomeCompWithUrlTemplate)} is still being loaded!`); }); it('should throw when using a templateUrl in a nested component that has not been compiled before', () => { @NgModule({declarations: [SomeComp, ChildComp], entryComponents: [SomeComp]}) class SomeModule { } resourceLoader.spy('get').and.callFake(() => Promise.resolve('')); dirResolver.setView(SomeComp, new ViewMetadata({template: ''})); dirResolver.setView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'})); expect(() => compiler.compileModuleSync(SomeModule)) .toThrowError( `Can't compile synchronously as ${stringify(ChildComp)} is still being loaded!`); }); it('should allow to use templateUrl components that have been loaded before', fakeAsync(() => { @NgModule({ declarations: [SomeCompWithUrlTemplate], entryComponents: [SomeCompWithUrlTemplate] }) class SomeModule { } resourceLoader.spy('get').and.callFake(() => Promise.resolve('hello')); compiler.compileModuleAsync(SomeModule); tick(); const ngModuleFactory = compiler.compileModuleSync(SomeModule); expect(ngModuleFactory).toBeTruthy(); })); }); });