unit test run unit-testing testing jasmine angular components

unit testing - test - prueba angular2, ¿cómo me burlo del componente secundario?



testing angular 2 (4)

Gracias a Eric Martinez, encontré esta solución.

Podemos usar la función overrideDirective que está documentada aquí, https://angular.io/docs/ts/latest/api/testing/TestComponentBuilder-class.html

Toma tres piremetros; 1. Componente para implementar 2. Componente hijo para sobrescribir 3. Componente simulado

La solución resuelta está aquí en http://plnkr.co/edit/a71wxC?p=preview

Este es el ejemplo de código del plunker

import {MyNavbarComponent} from ''../src/my-navbar.component''; import {MyToolbarComponent} from ''../src/my-toolbar.component''; @Component({template:''''}) class EmptyComponent{} describe(''MyComponent'', () => { beforeEach(injectAsync([TestComponentBuilder], (tcb) => { return tcb .overrideDirective(MyComponent, MyNavbarComponent, EmptyComponent) .overrideDirective(MyComponent, MyToolbarComponent, EmptyComponent) .createAsync(MyComponent) .then((componentFixture: ComponentFixture) => { this.fixture = componentFixture; }); )); it(''should bind to {{foo}}'', () => { let el = this.fixture.nativeElement; let myComponent = this.fixture.componentInstance; myComponent.foo = ''FOO''; fixture.detectChanges(); expect(el.innerHTML).toMatch(''FOO''); }); });

¿Cómo me burlo del componente secundario en las pruebas de jazmín?

Tengo MyComponent , que usa MyNavbarComponent y MyToolbarComponent

import {Component} from ''angular2/core''; import {MyNavbarComponent} from ''./my-navbar.component''; import {MyToolbarComponent} from ''./my-toolbar.component''; @Component({ selector: ''my-app'', template: ` <my-toolbar></my-toolbar> {{foo}} <my-navbar></my-navbar> `, directives: [MyNavbarComponent, MyToolbarComponent] }) export class MyComponent {}

Cuando pruebo este componente, no quiero cargar y probar esos dos subcomponentes; MyNavbarComponent, MyToolbarComponent, así que quiero simularlo.

Sé cómo provide(MyService, useClass(...)) servicios con provide(MyService, useClass(...)) , pero no tengo idea de cómo simular las directivas; componentes;

beforeEach(() => { setBaseTestProviders( TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS ); //TODO: want to mock unnecessary directives for this component test // which are MyNavbarComponent and MyToolbarComponent }) it(''should bind to {{foo}}'', injectAsync([TestComponentBuilder], (tcb) => { return tcb.createAsync(MyComponent).then((fixture) => { let DOM = fixture.nativeElement; let myComponent = fixture.componentInstance; myComponent.foo = ''FOO''; fixture.detectChanges(); expect(DOM.innerHTML).toMatch(''FOO''); }); });

Aquí está mi ejemplo de Plunker;

http://plnkr.co/edit/q1l1y8?p=preview


Según lo solicitado, publicaré otra respuesta sobre cómo simular subcomponentes con input / output :

Así que comencemos diciendo que tenemos TaskListComponent que muestra tareas y las actualiza cada vez que se hace clic en una de ellas:

<div id="task-list"> <div *ngFor="let task of (tasks$ | async)"> <app-task [task]="task" (click)="refresh()"></app-task> </div> </div>

app-task es un subcomponente con la entrada [task] y la salida (click) .

Bien, ahora queremos escribir pruebas para TaskListComponent y, por supuesto, no queremos probar el componente real de la app-task .

así que @Klas sugirió que podemos configurar nuestro TestModule con:

schemas: [CUSTOM_ELEMENTS_SCHEMA]

Es posible que no tengamos errores ni en la compilación ni en el tiempo de ejecución, pero no podremos probar mucho más que la existencia del subcomponente.

Entonces, ¿cómo podemos simular subcomponentes?

Primero definiremos una directiva simulada para nuestro subcomponente (mismo selector):

@Directive({ selector: ''app-task'' }) class MockTaskDirective { @Input(''task'') public task: ITask; @Output(''click'') public clickEmitter = new EventEmitter<void>(); }

Ahora lo declararemos en el módulo de prueba:

let fixture : ComponentFixture<TaskListComponent>; let cmp : TaskListComponent; beforeEach(() => { TestBed.configureTestingModule({ declarations: [TaskListComponent, **MockTaskDirective**], // schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [ { provide: TasksService, useClass: MockService } ] }); fixture = TestBed.createComponent(TaskListComponent); **fixture.autoDetectChanges();** cmp = fixture.componentInstance; });

  • Tenga en cuenta que debido a que la generación del subcomponente del dispositivo está sucediendo de forma asíncrona después de su creación, activamos su función autoDetectChanges.

En nuestras pruebas, ahora podemos consultar la directiva, acceder a su inyector DebugElement y obtener nuestra instancia de directiva simulada a través de ella:

import { By } from ''@angular/platform-browser''; const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective)); const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective;

[Esta parte generalmente debe estar en la sección beforeEach , para obtener un código más limpio.]

A partir de aquí, las pruebas son pan comido :)

it(''should contain task component'', ()=> { // Arrange. const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective)); // Assert. expect(mockTaskEl).toBeTruthy(); }); it(''should pass down task object'', ()=>{ // Arrange. const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective)); const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective; // Assert. expect(mockTaskCmp.task).toBeTruthy(); expect(mockTaskCmp.task.name).toBe(''1''); }); it(''should refresh when task is clicked'', ()=> { // Arrange spyOn(cmp, ''refresh''); const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective)); const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective; // Act. mockTaskCmp.clickEmitter.emit(); // Assert. expect(cmp.refresh).toHaveBeenCalled(); });


Si usa schemas: [CUSTOM_ELEMENTS_SCHEMA] en TestBed el componente bajo prueba no cargará subcomponentes.

import { CUSTOM_ELEMENTS_SCHEMA } from ''@angular/core''; import { TestBed, async } from ''@angular/core/testing''; import { MyComponent } from ''./my.component''; describe(''App'', () => { beforeEach(() => { TestBed .configureTestingModule({ declarations: [ MyComponent ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); }); it(`should have as title ''app works!''`, async(() => { let fixture = TestBed.createComponent(MyComponent); let app = fixture.debugElement.componentInstance; expect(app.title).toEqual(''Todo List''); })); });

Esto funciona en la versión lanzada de Angular 2.0. Muestra de código completo aquí .

Una alternativa a CUSTOM_ELEMENTS_SCHEMA es NO_ERRORS_SCHEMA


MockComponent módulo simple de MockComponent para ayudar a hacer esto un poco más fácil:

import { TestBed } from ''@angular/core/testing''; import { MyComponent } from ''./src/my.component''; import { MockComponent } from ''ng2-mock-component''; describe(''MyComponent'', () => { beforeEach(() => { TestBed.configureTestingModule({ declarations: [ MyComponent, MockComponent({ selector: ''my-subcomponent'', inputs: [''someInput''], outputs: [ ''someOutput'' ] }) ] }); let fixture = TestBed.createComponent(MyComponent); ... }); ... });

Está disponible en https://www.npmjs.com/package/ng2-mock-component .