Angular2 final version: Injected Service method under unit test returning undefined - unit-testing

I am trying to write some unit-tests on a component that got some services injected into it, to load the data from server. Data is loaded in this component on OnInit() method. I am trying that service method returns some dummy data, using spyOn. Following is unit-test setup -
let comp: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let staticDataService: any;
let spy: jasmine.Spy;
let allCountries: string[];
describe('MyComponent', () => {
beforeEach( async(() => {
TestBed.configureTestingModule({
imports : [ FormsModule, HttpModule ],
declarations : [MyComponent],
providers: [ StaticDataService ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
comp = fixture.componentInstance;
staticDataService = fixture.debugElement.injector.get(StaticDataService);
allCountries = [] = ["US", "UK"];
spy = spyOn(staticDataService, 'getCountries').and.returnValue(Promise.resolve(allCountries));
});
it('Countries should be set', () => {
expect(comp.allCountries).toEqual(allCountries);
});
});
Following is the component class that I am unit-testing -
#Component({
moduleId: module.id,
selector: 'myeditor',
templateUrl: 'my.component.html',
styleUrls: ['my.component.css']
})
export class MyComponent implements OnInit {
allCountries: string[];
constructor(private _staticDataServices: StaticDataService) {}
ngOnInit() {
this.getDataFromServer();
}
getDataFromServer()
{
this.allCountries = this._staticDataServices.getCountries();
}
I am getting the following error -
Chrome 53.0.2785 (Windows 7 0.0.0) MyComponent Countries should be set FAILED
[1] Expected undefined to equal [ 'US', 'UK' ].
Under the same unit-tests few other tests are working fine, that are not dependent on injected services. Getting 'undefined' while testing the properties that are set by services.
Can someone please help what I am doing wrong here?
Thanks

You need to call fixture.detectChanges() for the ngOnInit to be called.
fixture = TestBed.createComponent(MyComponent);
fixture.detectChanges();
getCountries returns a Promise so you need to then it, otherwise the value of allCountries will just be promise and not the data
getDataFromServer() {
this._staticDataServices.getCountries().then(data => {
this.countries = data;
});
}
Since the promise is asynchronous, you need to use async and wait for the asynchronous task to complete by calling fixture.whenStable()
import { async } from '#angular/core/testing';
it('...', async(() => {
fixture.whenStable().then(() => {
expect(comp.allCountries).toEqual(allCountries);
})
})
UDPATE
Without seeing the StaticDataService, I'm guessing you are trying to inject Http into it. This wont work in a test environment without further configuration. What I suggest you do is just make the service a mock
staticDataService = {
getCountries: jasmine.createSpy('getCountries').and.returnValue(...);
}
providers: [
{ provide: StaticDataService, useValue: staticDataService }
]

Related

How to test NestJS Controller if it has a lot of dependent services?

I have a trouble with Testing Nest JS Controller because I cannot realise how to make a Testing Module with all the dependencies. I've already tried Mocks but still it's not working.
Here's how the controller I want to test looks like
calculator.controller.ts
#Controller('/calculator')
export class CalculatorController {
constructor(
#Inject(HISTORY_SERVICE)
private historyService: HistoryService,
#Inject(CACHE_SERVICE)
private readonly cacheService: CacheService,
#Inject(CALCULATOR_SERVICE)
private readonly calculatorService: CalculatorService,
) {}
#Get()
getResult(#Query() expressionDto: ExpressionDto): Promise<ClientResponseDto> {
const expression: string = expressionDto.expression;
const response: Promise<ClientResponseDto> = this.cacheService
.checkInCache(expression)
.then((response) => {
if (!response) {
const calculationResult =
this.calculatorService.getResult(expression);
const clientDto = this.historyService
.create({
expression,
result: calculationResult,
})
.then((dbResponse) => {
return this.cacheService.setToCache(dbResponse);
});
return clientDto;
}
return this.historyService.create({ expression, result: response });
});
return response;
}
}
And this is how it's spec looked like before mocks implementation
controller.spec.ts
let calculatorController: CalculatorController;
let calculatorService: CalculatorService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [HistoryModule],
controllers: [CalculatorController],
providers: [
CalculatorService,
],
})
.useMocker(() => createMock())
.compile();
calculatorController =
moduleRef.get<CalculatorController>(CalculatorController);
calculatorService = moduleRef.get<CalculatorService>(CalculatorService);
jest.clearAllMocks();
});
describe('Calculator Controller', () => {
it('should be defined', () => {
expect(calculatorController).toBeDefined();
});
it('should have all methods', () => {
expect(calculatorController.getResult).toBeDefined();
expect(calculatorController.getResult(calculatorStub().request)).toBe(
typeof Promise,
);
});
});
And this test failed when calling getResult function cause inside this Function firstly I call CacheService to check data in Cache. So at this moment test failed telling that
TypeError: this.cacheService.checkInCache(...).then is not a function
24 | const response: Promise<ClientResponseDto> = this.cacheService
25 | .checkInCache(expression)
> 26 | .then((response) => {
| ^
I started to think that the problem is Testing module somehow doesn't have access to the Cache Service, so I added mock to the providers like this
let calculatorController: CalculatorController;
let calculatorService: CalculatorService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [HistoryModule],
controllers: [CalculatorController],
providers: [
CalculatorService,
{
provide: CacheService,
useValue: {
checkInCache: jest.fn().mockResolvedValue(Promise<null>),
},
},
],
})
.useMocker(() => createMock())
.compile();
calculatorController =
moduleRef.get<CalculatorController>(CalculatorController);
calculatorService = moduleRef.get<CalculatorService>(CalculatorService);
jest.clearAllMocks();
});
But now tests don't even run cause I have Nest dependencies problems
Nest can't resolve dependencies of the CalculatorController (HISTORY_SERVICE, ?,
CALCULATOR_SERVICE). Please make sure that the argument dependency at index [1] is
available in the RootTestModule context.
What is the issue and how is it possible to solve this problem?
Generally speaking, when unit testing a service or a controller, you want to provide mocks for the controller's or service's dependencies. Most of the time, these are going to be objects with the same method names but the methods are set to be jest.fn() or similar for other mock libraries. You'll want to use custom providers to create the mock providers that will be injected. Taking your controller above, you'll want the setup of your test to look something like this:
describe('CaclulatorController', () => {
let controller: CalculatorController;
let service: Pick<jest.MockedObject<CalculatorService>, 'getResult'>;
let cache: Pick<jest.MockedObject<CacheService>, 'checkInCache' | 'setToCache'>;
let history: Pick<jest.MockedObject<HistoryService>, 'create'>;
beforeAll(async () => {
const modRef = await Test.createTestModule({
controller: [CalculatorController],
providers: [
{
provide: CALCULATOR_SERVICE,
useValue: {
getResult: jest.fn(),
},
},
{
provide: CACHE_SERVICE,
useValue: {
checkInCache: jest.fn(),
setToCache: jest.fn(),
},
},
{
provide: HISTORY_SERVICE,
useValue: {
create: jest.fn(),
},
},
]
}).compile();
controller = app.get(CalculatorController);
service = app.get(CALCULATOR_SERVICE);
cache = app.get(CACHE_SERVICE);
history = app.get(HISTORY_SERVICE);
});
Okay that's a lot to look at at once, so let's step through the big parts and explain what's going on here. The first this I do is set up local variables to reference during the test for the class that I'm testing (CalculatorController) and the dependencies of the class so I can modify them as necessary. Next, I use a Pick<T, K> generic with the jest.MockedOject<T> generic to tell Typescript that "This class has been mocked by jest, and I only am worried about these methods of it" so later on when I use cache. I'll get some intellisense for the checkInCache and setToCache methods, and they'll have jest's mock function types.
In the beforeAll I set up the initial mocks for the dependencies, you can also set return values here using the appropriate mockReturnValue or mockResolvedValue methods.
Now that the mocks and dependencies are set up, we can actually write a test. My approach is to use a describe block per method and its per variation of the method's outcome and branches. I'll write a single branch to show you and let you work out the rest from there.
describe('getResult', () => {
it('should get no response from the cache and perform a full caclulation', async () => {
cache.checkInCache.mockResolvedValueOnce(undefined);
service.getResult.mockResolvedValueOnce(calculationResult);
histoy.create.mockResolvedValueOnce(dbResult);
cache.setInCache.mockResolvedValueOnce(cacheSaveResult);
await expect(controller.getResult({ expression: someExpression })).resolves.toEqual(cacheSaveResult)
});
})
This should cover the case where there's no value in the cache and the full set of steps has to be taken. By using mockResolvedValueOnce we ensure that the methods don't return if called more than once as that's most likely not the expected case here, and we're making sure to return promsies as you use .thens. You might want to look into async/await syntax to help clean that up.
putting the two snippets together we have the following:
describe('CaclulatorController', () => {
let controller: CalculatorController;
let service: Pick<jest.MockedObject<CalculatorService>, 'getResult'>;
let cache: Pick<jest.MockedObject<CacheService>, 'checkInCache' | 'setToCache'>;
let history: Pick<jest.MockedObject<HistoryService>, 'create'>;
beforeAll(async () => {
const modRef = await Test.createTestModule({
controller: [CalculatorController],
providers: [
{
provide: CALCULATOR_SERVICE,
useValue: {
getResult: jest.fn(),
},
},
{
provide: CACHE_SERVICE,
useValue: {
checkInCache: jest.fn(),
setToCache: jest.fn(),
},
},
{
provide: HISTORY_SERVICE,
useValue: {
create: jest.fn(),
},
},
]
}).compile();
controller = app.get(CalculatorController);
service = app.get(CALCULATOR_SERVICE);
cache = app.get(CACHE_SERVICE);
history = app.get(HISTORY_SERVICE);
});
describe('getResult', () => {
it('should get no response from the cache and perform a full caclulation', async () => {
cache.checkInCache.mockResolvedValueOnce(undefined);
service.getResult.mockResolvedValueOnce(calculationResult);
histoy.create.mockResolvedValueOnce(dbResult);
cache.setInCache.mockResolvedValueOnce(cacheSaveResult);
await expect(controller.getResult({ expression: someExpression })).resolves.toEqual(cacheSaveResult)
});
});
});
That should be enough to get you started on testing the rest of your controller. If you need more test setup examples, there's an entire GitHub repository of them with different setups

How to handle bootstrap-daterangepicker in angular component unit test?

I am trying to write a unit test of an angular 6 component which is initializing the bootstrap-daterangepicker in the ngAfterViewInit() method. When I run my unit test it gives the following error:
TypeError: $(...).daterangepicker is not a function
this is the code from the actual component(EmployeeComponent):
ngAfterViewInit(): void {
this.initializeDatePicker(this);
}
initializeDatePicker(that: any) {
const start = moment().subtract(7, 'days');
const end = moment();
$('#reportrange').daterangepicker({
startDate: start,
endDate: end,
maxDate: moment(),
ranges: {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')]
}
}, cb);
cb(start, end);
}
this is the code from my test class:
describe('EmployeeComponent', () => {
let component: EmployeeComponent;
let fixture: ComponentFixture<EmployeeComponent>;
let messageService: NotificationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [EmployeeComponent]
})
.overrideComponent(EmployeeComponent, {
set: {
template: '',
providers: [
{ provide: NotificationService, useValue: messageService },
{ provide: ActivatedRoute, useValue: { queryParams: of({ emp: "123" }) } }
]
}
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EmployeeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
You don't need to handle it in your test cases. That component should be initialized in a separate service and you can simply mock that method from the service. In the way you can avoid this error.
let say you move all the code of the initializeDatePicker() in a method in some service let say common-service.ts and you can simply call that service from this method like
this.commonServiceObj.initializeDatePicker();
Now after doing this, you can simply mock initializeDatePicker() from the service object and error should be gone.

debugElement return null in my angular5 test

I wish to test an anguar5 component using a host component as described in angular.io doc.
But my test keep failing because of
TypeError: Cannot read property 'query' of null
at UserContext.<anonymous> (http://localhost:9876/base/config-webpack/spec-bundle.js:293832:39)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/base/config-webpack/spec-bundle.js:288418:26)
at ProxyZoneSpec../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (http://localhost:9876/base/config-webpack/spec-bundle.js:287920:39)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/base/config-webpack/spec-bundle.js:288417:32)
at Zone../node_modules/zone.js/dist/zone.js.Zone.run (http://localhost:9876/base/config-webpack/spec-bundle.js:288168:43)
at UserContext.<anonymous> (http://localhost:9876/base/config-webpack/spec-bundle.js:287799:34)
at attempt (http://localhost:9876/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:4289:46)
at ZoneQueueRunner.QueueRunner.run (http://localhost:9876/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:4217:20)
at ZoneQueueRunner.QueueRunner.execute (http://localhost:9876/base/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:4199:10)
at ZoneQueueRunner../node_modules/zone.js/dist/jasmine-patch.js.jasmine.QueueRunner.ZoneQueueRunner.execute (http://localhost:9876/base/config-webpack/spec-bundle.js:287827:42)
Indeed, when I log my fixture.debugElement, it return null.
my test code is :
import {} from 'jasmine';
import { Component } from '#angular/core';
import { TestBed, ComponentFixture } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DropDownListComponent } from './dropDownList.component';
#Component({
template: '<dropdown-list [valuesList]="valuesList" [selectedValue]="valuesSelected" ></dropdown-list>'
})
class TestComponent {
valuesList = [{label: 'test_select', value:'test'}, {label: 'test_select2', value:'test2'}];
valuesSelected = {label: 'test_select', value:'test'};
}
describe('DropDownListComponent', () => {
let fixture, component;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent, DropDownListComponent]
}).compileComponents();
});
it('should display selectedValue', () => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
console.log(fixture.isStable());
console.log(fixture);
console.log(component);
console.log(fixture.debugElement);
//const fixture = TestBed.createComponent(TestComponent);
let de = fixture.debugElement.query(By.css(".value-container"));
let el = de.nativeElement;
expect(el.textContent).toContain('test_select');
});
});
When you write a test you need to test only your component / service / pipe / directive etc, but not its dependencies.
From the code above I assume DropDownListComponent has a DI dependency that wasn't declared in providers of TestBed and it causes the issue. Anyway in this context it should be a mock, not a real component.
If you want to test DropDownListComponent - then please share its code. Without understanding its interface it's hard to guess how to write tests for it.
You can use ng-mocks to mock it and then you would only need to test that [valuesList] and [selectedValue] got right values.
Also to compile all components correctly you need to handle compileComponents's promise.
describe('TestComponent', () => {
beforeEach(() => {
return TestBed.configureTestingModule({
declarations: [TestComponent, MockComponent(DropDownListComponent)],
}).compileComponents();
});
it('should display selectedValue', () => {
const fixture = MockRender(TestComponent);
const dropdown = MockHelper.findOrFail(fixture.debugElement, DropDownListComponent);
expect(dropdown.valuesList).toEqual(fixture.point.valuesList);
expect(dropdown.selectedValue).toEqual(fixture.point.valuesSelected);
});
});
Profit.

Testing Observable based call hierarchy in angular

I am trying to test a component which uses Observables and then cascades through several function calls when the Observable resolves. Here is a version of the component.
export class NotificationComponent implements OnInit {
private answerSubscription: Subscription;
constructor(public toasterService: ToasterService, private commentService: CommentService) { }
ngOnInit() {
this.answerSubscription = this.commentService.answer$.subscribe(
answer => this.commentComplete(answer));
}
commentComplete(answer) {
this.toasterService.clear(answer.toastId);
let promptAns = this.search(answer.toastId);
}
}
and here is my test:
class MockToastService {
clear() {}
}
class MockCommentService {
answer$: Observable<any>;
constructor() {
this.answer$ = Observable.of({toastId: '123'});
}
}
describe('NotificationComponent', () => {
let component: NotificationComponent; let fixture: ComponentFixture<NotificationComponent>;
let mockComment = new MockCommentService(); let mockToast = new MockToastService();
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [NotificationComponent, MockToast],
providers: [{ provide: ToasterService, useValue: mockToast },
{ provide: CommentService, useValue: mockComment }]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NotificationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should complete notification on answer', () => {
spyOn(component, 'commentComplete'); spyOn(mockToast, 'clear');
expect(component.commentComplete).not.toHaveBeenCalled();
component.ngOnInit();
expect(component.commentComplete).toHaveBeenCalled();
expect(mockToast.clear).toHaveBeenCalled();
});
});
The test passes on expect(component.commentComplete).toHaveBeenCalled();, but fails on expect(mockToast.clear).toHaveBeenCalled(). As you can see from the component, toasterService.clear( should be called straight after commentComplete, however, I have stepped through with a debugger, and the test criteria is being checked before the clear function is being called.
I have tried adding fakeAsync and tick(), but am still facing the issue. Any idea how I can make this test's timing work?
You should use fake Async here but as understand there the issues was not with it.
You fake 'commentComplete' function by spyOn(component,'commentComplete') but you need to spy and do its job. change to 'spyOn(component, 'commentComplete').and.callThrough();'
Spies: and.callThrough. By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation.
https://jasmine.github.io/2.0/introduction.html
here is the code that should work:
it('should complete notification on answer', fakeAsync(() => {
const spyComplete = spyOn(component, 'commentComplete').and.callThrough();
const spyToast = spyOn(mockToast, 'clear');
expect(component.commentComplete).not.toHaveBeenCalled();
component.ngOnInit();
tick();
expect(spyComplete).toHaveBeenCalled();
expect(spyToast).toHaveBeenCalled();
}));

angular2 test, how do I mock sub component

How do I mock sub component in jasmine tests?
I have MyComponent, which uses MyNavbarComponent and 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 {}
When I test this component, I do not want to load and test those two sub components; MyNavbarComponent, MyToolbarComponent, so I want to mock it.
I know how to mock with services using provide(MyService, useClass(...)), but I have no idea how to mock directives; components;
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');
});
});
Here is my plunker example;
http://plnkr.co/edit/q1l1y8?p=preview
As requested, I'm posting another answer about how to mock sub components with input/output:
So Lets start by saying we have TaskListComponent that displays tasks, and refreshes whenever one of them is clicked:
<div id="task-list">
<div *ngFor="let task of (tasks$ | async)">
<app-task [task]="task" (click)="refresh()"></app-task>
</div>
</div>
app-task is a sub component with the [task] input and the (click) output.
Ok great, now we want to write tests for my TaskListComponent and of course we don't want to test the real app-taskcomponent.
so as #Klas suggested we can configure our TestModule with:
schemas: [CUSTOM_ELEMENTS_SCHEMA]
We might not get any errors at either build or runtime, but we won't be able to test much other than the existence of the sub component.
So how can we mock sub components?
First we'll define a mock directive for our sub component (same selector):
#Directive({
selector: 'app-task'
})
class MockTaskDirective {
#Input('task')
public task: ITask;
#Output('click')
public clickEmitter = new EventEmitter<void>();
}
Now we'll declare it in the testing 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;
});
Notice that because the generation of sub component of the fixture is happening asynchronously after its creation, we activate its autoDetectChanges feature.
In our tests, we can now query for the directive, access its DebugElement's injector, and get our mock directive instance through it:
import { By } from '#angular/platform-browser';
const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective));
const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective;
[This part should usually be in the beforeEach section, for cleaner code.]
From here, the tests are a piece of cake :)
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();
});
If you use schemas: [CUSTOM_ELEMENTS_SCHEMA]in TestBed the component under test will not load sub components.
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');
}));
});
This works in the released version of Angular 2.0.
Full code sample here.
An alternative to CUSTOM_ELEMENTS_SCHEMA is NO_ERRORS_SCHEMA
Thanks to Eric Martinez, I found this solution.
We can use overrideDirective function which is documented here,
https://angular.io/docs/ts/latest/api/testing/TestComponentBuilder-class.html
It takes three prarmeters;
1. Component to implement
2. Child component to override
3. Mock component
Resolved solution is here at http://plnkr.co/edit/a71wxC?p=preview
This is the code example from the 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');
});
});
I put together a simple MockComponent module to help make this a little easier:
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);
...
});
...
});
It's available at
https://www.npmjs.com/package/ng2-mock-component.