test angular2, comment simuler un sous-composant
Comment puis-je simuler un sous-élément dans les tests jasmine?
j'ai MyComponent
, qui utilise MyNavbarComponent
et 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 {}
quand je teste ce composant, Je ne veux pas charger et tester ces deux sous-composants; MyNavbarComponent, MyToolbarComponent, donc je veux le moquer.
je sais comment faire pour se moquer avec les services de l'aide provide(MyService, useClass(...))
, mais je n'ai aucune idée de la façon de se moquer de directives; composants;
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');
});
});
Voici mon plunker exemple;
4 réponses
Comme demandé, je poste une autre réponse sur la façon de se moquer de sous-composants input
/output
:
commençons donc par dire que nous avons TaskListComponent
qui affiche les tâches, et se rafraîchit chaque fois que l'une d'elles est cliquée:
<div id="task-list">
<div *ngFor="let task of (tasks$ | async)">
<app-task [task]="task" (click)="refresh()"></app-task>
</div>
</div>
app-task
est un sous-élément [task]
et (click)
sortie.
Ok super, maintenant nous voulons écrire des tests pour mon TaskListComponent
et bien sûr, nous ne voulons pas de test réel app-task
composant.
comme @Klas nous a suggéré de configurer notre TestModule
avec:
schemas: [CUSTOM_ELEMENTS_SCHEMA]
il se peut que nous n'ayons pas d'erreurs à la compilation ou à l'exécution, mais nous ne pourrons pas tester autre chose que l'existence du sous-composant.
alors comment pouvons-nous simuler des sous-composants?
nous allons d'abord définir une directive mock pour notre sous-composant (même sélecteur):
@Directive({
selector: 'app-task'
})
class MockTaskDirective {
@Input('task')
public task: ITask;
@Output('click')
public clickEmitter = new EventEmitter<void>();
}
Maintenant, nous allons déclarer dans le test module:
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;
});
- notez que puisque la génération du sous-composant de l'appareil se produit de façon asynchrone après sa création, nous activons sa fonctionnalité autoDetectChanges.
dans nos tests, nous pouvons maintenant interroger la directive, accéder à L'injecteur de son Débugelement, et obtenir notre instance de la directive mock à travers elle:
import { By } from '@angular/platform-browser';
const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective));
const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective;
[Cette partie doit être habituellement beforeEach
section, propre code.]
à Partir d'ici, les tests sont un morceau de gâteau :)
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 vous utilisez schemas: [CUSTOM_ELEMENTS_SCHEMA]
TestBed
le composant à l'essai ne charge pas les sous-composants.
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');
}));
});
cela fonctionne dans la version publiée D'Angular 2.0. exemple de code Complet ici.
une alternative à CUSTOM_ELEMENTS_SCHEMA
NO_ERRORS_SCHEMA
grâce à Eric Martinez, j'ai trouvé cette solution.
nous pouvons utiliser overrideDirective
fonction qui est documentée ici,
https://angular.io/docs/ts/latest/api/testing/TestComponentBuilder-class.html
Résolu solution est ici à http://plnkr.co/edit/a71wxC?p=preview
ceci est l'exemple de code de la 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');
});
});
j'ai mis en place un simple MockComponent
module pour aider à rendre cela un peu plus facile:
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);
...
});
...
});
il est disponible à https://www.npmjs.com/package/ng2-mock-component.