angular2 unit testing using a host component - unit-testing

I'm trying to understand unit testing in Angular2 v2.0.0. I used angular-cli to generate a project, and am running unit tests by launching 'ng test'. The cli generates a sample component including tests.
I have expanded the sample component test by trying to create a host component in which I might test future custom components. Similar to the method I found here:
unit testing using host components
The problem is that after instantiating the test component, it fails a test to look for a bound value inside the test component. It's the last test in the sequence here.
/* tslint:disable:no-unused-variable */
import { TestBed, async } from '#angular/core/testing';
import { AppComponent } from './app.component';
import { Component, Input, OnInit } from '#angular/core';
// let's create a host component to test subcomponents
#Component({
template: `<span>{{testitemname}}</span>`
})
class TestComponent {
testitemname: 'testitem';
testitemtags: ['tag1', 'tag2', 'tag3'];
}
describe('App: Testhostcomp', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
TestComponent
],
});
});
it('should create the app', async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app works!'`, async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app works!');
}));
it('should render title in a h1 tag', async(() => {
let fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('app works!');
}));
// this test fails
it('should render the property value inside the test component', async(() => {
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
let compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('span').textContent).toContain('testitem');
}));
});
It fails with the following error:
26 10 2016 10:48:15.456:INFO [Chrome 54.0.2840 (Windows 7 0.0.0)]: Connected on socket /#mcN6GltigqminZ3yAAAA with id 34237141
Chrome 54.0.2840 (Windows 7 0.0.0) App: Testhostcomp should render the property value inside the test component FAILED
Expected '' to contain 'testitem'.
at webpack:///C:/Angular2Projects/testhostcomp/src/app/app.component.spec.ts:49:55 <- src/test.ts:12000:60
at ZoneDelegate.invoke (webpack:///C:/Angular2Projects/testhostcomp/~/zone.js/dist/zone.js:232:0 <- src/test.ts:20985:26)
at AsyncTestZoneSpec.onInvoke (webpack:///C:/Angular2Projects/testhostcomp/~/zone.js/dist/async-test.js:49:0 <- src/test.ts:13735:39)
at ProxyZoneSpec.onInvoke (webpack:///C:/Angular2Projects/testhostcomp/~/zone.js/dist/proxy.js:76:0 <- src/test.ts:14427:39)
Chrome 54.0.2840 (Windows 7 0.0.0): Executed 4 of 4 (1 FAILED) (0 secs / 0.196 secs)
Chrome 54.0.2840 (Windows 7 0.0.0) App: Testhostcomp should render the property value inside the test component FAILED
Expected '' to contain 'testitem'.
at webpack:///C:/Angular2Projects/testhostcomp/src/app/app.component.spec.ts:49:55 <- src/test.ts:12000:60
at ZoneDelegate.invoke (webpack:///C:/Angular2Projects/testhostcomp/~/zone.js/dist/zone.js:232:0 <- src/test.ts:20985:26)
at AsyncTestZoneSpec.onInvoke (webpack:///C:/Angular2Projects/testhostcomp/~/zone.js/dist/async-test.js:49:0 <- src/test.ts:13735:39)
Chrome 54.0.2840 (Windows 7 0.0.0): Executed 4 of 4 (1 FAILED) (0.273 secs / 0.196 secs)
I noticed that when I changed {{testitemname}} to 'testitem', the test passes. So I think it might have something to do with binding? I don't understand why this doesn't work. Thank you in advance for your help.
[1]: https://angular.io/docs/ts/latest/guide/testing.html#!#component-inside-test-host "host components"

It's because you are using 'testitem' as the type not as the value
field: Type; // colon is used for typing
field = value; // equals sign for assignment
your code
testitemname: 'testitem';
testitemtags: ['tag1', 'tag2', 'tag3'];

Related

VueComponent.mounted : TypeError: Cannot read property 'get' of undefined in mounted hook

I am using jest for unit testing in nuxt js
I have mounted hook like this
async mounted(){
try{
var response = await this.$axios.get("api_url here");
this.result = response.data;
} catch(e){
console.log("Exception: ",e)
}
}
when i do unit test for it my code is . utnit.spec.js
jest.mock("axios", () => ({
get: () => Promise.resolve({ data: [{ val: 1 }] })
}));
import { mount } from '#vue/test-utils';
import file from '../filefile';
import axios from "axios";
describe('file', () => {
test('check comp. working correctly', () => {
var wrapper = mount(file);
afterEach(() => {
wrapper.destroy()
})
})
})
I am getting this warn there and there is no data in the results
Exception: TypeError: Cannot read property 'get' of undefined
at VueComponent.mounted
how do I know what is the problem here, is this I can not access axios in the unit file Is there any specific way to test Axios in mounted hook
The error means that it's this.$axios.get that is not available, not axios.get. The component relies on Axios plugin that is commonly installed in Vue application entry point or Nuxt configuration.
It can be installed for localVue Vue instance in tests, or be supplied directly to the component:
var wrapper = mount(file, { mocks: { $axios: axios } });
Also, the mock will fail if Axios is used as axios() somewhere because default import is expected to be a function:
jest.mock("axios", () => Object.assign(
jest.fn(),
{ get: jest.fn() }
));
axios.get is Jest spy, the implementation is mocked per test depending on the use and isn't limited to hard-coded Promise.resolve({ data: ... }) supplied in the mock.

vue how to mock my external service class

In my vue component , in the mounted i am calling a service class which in turn invokes axios call ..like below
import StudentService from '../utils/student.services'
export default {
name: 'student-summary',
mounted () {
console.log('%c FeeMdoule-Data Recieved on Mount as %s', 'color: blue ;font-size : 12px', JSON.stringify(this.filingData))
StudentService.getDetails().then(data => {
this.sList = data
})
},
// ...
}
I have now written JEST test cases of the vue component and i have mocked axios within vue component test cases..
But i think the right approach is to mock the studentServices rather than not mock axios directly from component...
How to mock the studentservices from the vue compoent test and not have any axios in the test case of my vue component?
Jest documents describe class mocks here
StudentService.spec.js
import StudentService from '../utils/student.services'
jest.mock('../utils/student.services');
describe("StudentService", () => {
let mockDetails = [{ studentId: 1 }]
StudentService.getDetails = jest.fn().mockResolvedValue(mockDetails);
afterEach(() => {
// reset mock after each test
StudentService.getDetails.mockReset();
});
it("should get details", () => {
// ... mount your component
expect(StudentService.getDetails).toHaveBeenCalled();
});
});

Testing component in NativeScript Angular2 app

I'm having issues doing a very simple component test in a NativeScript Angular 2 application. I can't seem to just call "new Component()" and then test it like was shown in this test example. I'm trying an implementation of the Angular 2 TestBed in order to gain access to the component. This doesn't appear to be working either. Has anybody run into a similar problem or have any experience with this?
Component under test:
import { Component } from "#angular/core";
#Component({
selector: "links",
templateUrl: "./components/links/links.component.html"
})
export class LinksComponent {
test = "test";
public constructor() {
}
}
Test:
import "reflect-metadata";
import { LinksComponent } from "../../components/links/links.component";
import { ComponentFixture, TestBed } from '#angular/core/testing';
describe("Links Component", () => {
let comp: LinksComponent;
let fixture: ComponentFixture<LinksComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ LinksComponent ],
});
fixture = TestBed.createComponent(LinksComponent);
comp = fixture.componentInstance;
});
it("will pass because this is a silly test", () => {
expect(comp.test).toEqual("test");
})
});
Log output:
NativeScript / 10.3 (10.3; iPhone) ../../tests/components/links.spec.js at line 0 FAILED
ReferenceError: Can't find variable: Zone
NativeScript / 10.3 (10.3; iPhone): Executed 1 of 0 (1 FAILED) (0 secs / 0 seNativeScript / 10.3 (10.3; iPhone): Executed 1 of 0 (1 FAILED) ERROR (0.008 secs / 0 secs)
CONSOLE LOG file:///app/tns_modules/nativescript-unit-test-runner/main-view-model.js:258:24: NSUTR: completeAck
May 11 16:16:43 --- last message repeated 1 time ---
CONSOLE LOG file:///app/tns_modules/nativescript-unit-test-runner/main-view-model.js:90:28: NSUTR-socket.io: io server disconnect
CONSOLE LOG file:///app/tns_modules/nativescript-unit-test-runner/main-view-model.js:151:24: NSUTR: disregarding second execution
Test run failed.
AFAIK TestBed does not work on NativeScript Angular.
To mock components you need to instance them with new, resolving each dependency.
You should study this repository to be able to do some unit testing on NativeScript.

Angular2 testing error when using templateUrl

I am writing some tests for my Angular2 application according to the documentation but I have run into a problem which I can't seem to fix. I get the following error when trying to launch the spec runner:
Failed: This test module uses the component CategoriesComponent which is using a "templateUrl", but they were never compiled. Please call "TestBed.compileComponents" before your test.
I understand this is happening as I am using a seperate template file for the template within the component but I jhave tried multilpe solutions which don't seem to work.
Here is my component under test:
import { Component } from "#angular/core";
#Component({
selector: 'categories-component',
templateUrl: '/app/views/catalog/categories/categories-dashboard.html',
moduleId: module.id
})
export class CategoriesComponent {
title: 'Categories;
}
The categories-dashboard.html file:
<h1>{{ title }}</h1>
and my testing module for the component:
import {TestBed, ComponentFixture, ComponentFixtureAutoDetect, async} from "#angular/core/testing";
import { By} from "#angular/platform-browser";
import { CategoriesComponent } from "../../../../components/catalog/categories/CategoriesComponent";
import { DebugElement } from "#angular/core";
let comp: CategoriesComponent;
let fixture: ComponentFixture<CategoriesComponent>;
let de: DebugElement;
let el: HTMLElement;
describe('BannerComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CategoriesComponent ],
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true }
]
});
TestBed.compileComponents();
fixture = TestBed.createComponent(CategoriesComponent);
comp = fixture.componentInstance; // BannerComponent test instance
// query for the title <h1> by CSS element selector
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
}));
it('should display original title', () => {
expect(el.textContent).toContain(comp.title);
});
});
I have tried to implement TestBed.compileComponents() into into the component but wherever I put it it doesn't seem to work.
Can anyone see why this error is occurring or point me in the directoin of a solution?
Thanks!
compileComponents resolves asynchronously (as it makes an XHR for the template), so it returns a promise. You should handle anything requiring the resolution of the promise, inside of the then callback of the promise
TestBed.compileComponents().then(() =>{
fixture = TestBed.createComponent(CategoriesComponent);
comp = fixture.componentInstance; // BannerComponent test instance
// query for the title <h1> by CSS element selector
de = fixture.debugElement.query(By.css('h1'));
el = de.nativeElement;
});

Testing Angular 2 service with mocha

I am trying to implement unit tests for an Angular 2 app. But I can't get it it to work.
As test runner mocha is used and executed like this:
mocha -r ts-node/register -t 10000 ./**/*.unit.ts
Consider the following test file where I define two test cases which basically should do the same thing, but neither one is working.
shared.service.unit.ts
import { TestBed, async, inject } from '#angular/core/testing';
import { SharedService } from './shared.service';
import * as Chai from 'chai';
import 'mocha';
const expect = Chai.expect;
describe('SharedService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [SharedService],
providers: [SharedService]
});
});
it('should be an object',
inject([SharedService], (service: SharedService) => {
expect(service).to.be.an('object');
})
);
});
describe('SharedService without the TestBed', () => {
let service: SharedService;
beforeEach(() => {
service = new SharedService();
});
it('should be an object', () => {
expect(service).to.be.an('object');
});
});
The first one 'SharedService' uses the Angular Testing Utility. Running it gives:
ReferenceError: Zone is not defined
The second one 'SharedService without TestBed'does not use any Angular code (similar to this example from Angular 2 Testing guide). Running it gives:
TypeError: Reflect.getMetadata is not a function
After adding these lines to the test file:
import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
Both test cases give the same error (from zone.js\dist\zone.js):
TypeError: Cannot read property 'prototype' of undefined
What am I doing wrong?
Got it, just needed to import 'core-js/es7/reflect':
import 'core-js/es7/reflect';
import 'mocha';
import * as Chai from 'chai';
let expect = Chai.expect;
import { SharedService } from './shared.service';
describe('SharedService', () => {
let service: SharedService;
beforeEach(() => {
service = new SharedService();
})
it('should be an object', () => {
expect(service).to.be.an('object');
})
});
You need to load all that stuff - angular, ngzone, metadata, es shims, etc. - statically in the mocha's - or systemjs or whatever you use for setting this stuff up - configuration.