using Vue.js 2 , with vue-resource
after running correctly this unit test, the coverage is incomplete as I can see in lcov-report/src/vuex/actions.js.html ..,
only
return api.addNewShoppingList(shoppinglist)
is executed (1x), not the code inside the .then() block
thanks to anyone who can give me some feedback on this issue? ( if it's an issue.. or normal behavior )
actions.spec.js
import actions from '#/vuex/actions'
import * as types from '#/vuex/mutation_types'
describe('actions.js', () => {
var server, store, lists, successPost
successPost = {'post': true}
beforeEach(() => {
// mock shopping lists
lists = [{
id: '1',
title: 'Groceries'
}, {
id: '2',
title: 'Clothes'
}]
// mock store commit and dispatch methods
store = {
commit: (method, data) => {},
dispatch: () => {
return Promise.resolve() // static method
},
state: {
shoppinglists: lists
}
}
sinon.stub(store, 'commit')
// mock server
server = sinon.fakeServer.create()
server.respondWith('POST', /shoppinglists/, xhr => {
xhr.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(successPost))
})
server.autoRespond = true
})
afterEach(() => {
store.commit.restore()
server.restore()
})
describe('createShoppingList', () => {
it('should return successful POST response', () => {
let newList = { title: 'new list', id: '3' }
actions.createShoppingList(store, newList).then((resp) => {
expect(resp.body).to.eql(successPost)
})
})
})
})
actions.js
import * as types from './mutation_types'
import api from '../api'
import getters from './getters'
export default {
populateShoppingLists: ({ commit }) => {
return api.fetchShoppingLists().then(response => {
commit(types.POPULATE_SHOPPING_LISTS, response.data)
})
},
createShoppingList: (store, shoppinglist) => {
return api.addNewShoppingList(shoppinglist)
.then(() => {
store.commit(types.ADD_SHOPPING_LIST, shoppinglist)
store.dispatch('populateShoppingLists')
})
},
}
api/index.js
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
const ShoppingListsResource = Vue.resource('http://localhost:3000/' + 'shoppinglists{/id}')
export default {
addNewShoppingList: (data) => {
return ShoppingListsResource.save(data)
}
}
mutations.js
import * as types from './mutation_types'
import getters from './getters'
import _ from 'underscore'
export default {
[types.POPULATE_SHOPPING_LISTS] (state, lists) {
state.shoppinglists = lists
},
[types.ADD_SHOPPING_LIST] (state, newList) {
if (_.isObject(newList)) {
state.shoppinglists.push(newList)
}
}
}
mutations.types
export const POPULATE_SHOPPING_LISTS = 'POPULATE_SHOPPING_LISTS'
export const ADD_SHOPPING_LIST = 'ADD_SHOPPING_LIST'
getters.js
import _ from 'underscore'
export default {
getLists: state => state.shoppinglists,
}
console
mymac:lcov-report yves$ npm run unit
> shopping-list#1.0.0 unit /Users/yves/Developments/shopping-list
> cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run
[karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
[launcher]: Launching browser PhantomJS with unlimited concurrency
launcher]: Starting browser PhantomJS
[PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket -XTe5WWPBnSfAtg_AAAA with id 73492961
actions.js
...
createShoppingList
✓ should return successful POST response
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 13 of 13 SUCCESS (0.086 secs / 0.034 secs)
TOTAL: 13 SUCCESS
=============================== Coverage summary ==================
Statements : 64.44% ( 29/45 )
Branches : 50% ( 2/4 )
Functions : 81.25% ( 13/16 )
Lines : 64.44% ( 29/45 )
================================================================
lcov-report/src/vuex/actions.js.html
import * as types from './mutation_types'
import api from '../api'
import getters from './getters'
export default {
createShoppingList: (store, shoppinglist) => {
**1× return api.addNewShoppingList(shoppinglist)**
.then(() => {
store.commit(types.ADD_SHOPPING_LIST, shoppinglist)
store.dispatch('populateShoppingLists')
})
},
}
Related
Before using vuex modules , my mutation tests were OK :
import mutations from '#/vuex/mutations.js'
import vueAuthInstance from '#/services/auth.js'
import { IS_AUTHENTICATED, CURRENT_USER_ID } from '#/vuex/mutation_types.js'
describe('mutations.js', () => {
var state
beforeEach(() => {
state = {
isAuthenticated: vueAuthInstance.isAuthenticated(),
currentUserId: ''
}
})
describe('IS_AUTHENTICATED', () => {
it('should set authentication status', () => {
state.isAuthenticated = false
mutations[IS_AUTHENTICATED](state, {isAuthenticated: true})
expect(state.isAuthenticated).to.eql(true)
})
})
...
})
Now I refactored my vuex folders, my state and mutations are inside each vuex/modules/../index.js file
src
|_ vuex
| L_ modules
| L_ login
| |_ index.js
| |_ actions.js
| |_ getters.js
| |_ mutation_types.js
|_ App.vue
|_ main.js
vuex/modules/login/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import getters from './getters'
import * as types from './mutation_types'
import vueAuthInstance from '#/services/auth.js'
Vue.use(Vuex)
const state = {
isAuthenticated: vueAuthInstance.isAuthenticated(),
currentUserId: ''
}
const mutations = {
[types.IS_AUTHENTICATED] (state, payload) {
state.isAuthenticated = payload.isAuthenticated
},
...
}
export default {
state,
mutations,
actions,
getters
}
Withe a vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import login from '#/vuex/modules/login'
// import other modules
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
login,
... (other modules )
}
})
To take in account this new structure, I rewrote the unit test as following :
test/unit/specs/vuex/modules/login/index.spec.js
import { mutations } from '#/vuex/modules/login/index.js'
import vueAuthInstance from '#/services/auth.js'
import types from '#/vuex/modules/login/mutation_types.js'
describe('mutations.js', () => {
var state
beforeEach(() => {
state = {
isAuthenticated: vueAuthInstance.isAuthenticated(),
currentUserId: ''
}
})
describe('IS_AUTHENTICATED', () => {
it('should set authentication status', () => {
state.isAuthenticated = false
mutations[types.IS_AUTHENTICATED](state, {isAuthenticated: true})
expect(state.isAuthenticated).to.eql(true)
})
})
})
And I get an error, on the mutation :
✗ should set authentication status
TypeError: Cannot read property 'IS_AUTHENTICATED' of undefined
I tried to change the import { mutations } statement , and import directly the store.js, in which the modules are defined, and use store._mutations,
LOG: 'MUTATIONS: ', Object{IS_AUTHENTICATED: [function wrappedMutationHandler(payload) { ... }], ...}
using store._mutations.IS_AUTHENTICATED0 , seems to work, ( don't know why an array? ..) but something is wrong with this function and the state, payload args, as the test doesn't pass
import store from '#/vuex/store'
import vueAuthInstance from '#/services/auth.js'
describe('mutations.js', () => {
var state
beforeEach(() => {
state = {
isAuthenticated: vueAuthInstance.isAuthenticated(),
currentUserId: ''
}
})
describe('IS_AUTHENTICATED', () => {
it('should set authentication status', () => {
state.isAuthenticated = false
console.log('MUTATIONS: ', store._mutations.IS_AUTHENTICATED())
store._mutations.IS_AUTHENTICATED[0](state, {isAuthenticated: true})
expect(state.isAuthenticated).to.eql(true)
})
})
...
})
1) should set authentication status
mutations.js IS_AUTHENTICATED
AssertionError: expected false to deeply equal true
I checked the passed args to the mutation in the index.js file
const mutations = {
[types.IS_AUTHENTICATED] (state, payload) {
console.log('MUTATION state: ', state)
console.log('MUTATION payload: ', payload)
state.isAuthenticated = payload.isAuthenticated
},
[types.CURRENT_USER_ID] (state, payload) {
state.currentUserId = payload.currentUserId
}
}
And. I do not see the passed arg values, it seems that the state args is the only passed value from my test :
LOG: 'MUTATION state: ', Object{isAuthenticated: false, currentUserId: ''}
LOG: 'MUTATION payload: ', Object{isAuthenticated: false, currentUserId: ''}
What's wrong with this code ? how to proceed for testing the mutations in this case, using vuex modules ?
thanks for feedback
I found a way to test the mutation using vuex modules, but I don't know if it's the best way...
my test is quite simple , using store.commit as I cannot call directly the mutation handler, and I import only the vuex/store
src/test/unit/specs/modules/login/index.js
import store from '#/vuex/store'
describe('mutations.js', () => {
describe('IS_AUTHENTICATED', () => {
it('should set authentication status', () => {
store.commit('IS_AUTHENTICATED', {isAuthenticated: true})
expect(store.state.login.isAuthenticated).to.eql(true)
})
})
...
})
Actually, this is bad approach.
You should create mock state, and use it.
import { createLocalVue } from '#vue/test-utils';
import Vuex from 'vuex';
import { storeModule } from '#path/to/store/modules';
const mutations = storeModule.mutations;
describe('mutations', () => {
it('testCase#1', () => {
createLocalVue().use(Vuex);
const state = {
//mock state values
};
const store = new Vuex.Store({state, mutations});
store.commit('mutationToTest', arg);
expect(state.arg).toBe(1);
})
})
I would like to stub this method ( this.login(°. ) in my submit method of a component, but I get an error :
✗ calls store action login when the form is submitted
TypeError: Cannot stub non-existent own property login
here is the method :
methods: _.extend({}, mapActions(['login']), {
clearErrorMessage () {
this.hasError = false
},
submit () {
return this.login({user: { email: this.email, password: this.password }})
.then((logged) => {
if (logged) {
this.$router.push('shoppinglists')
} else {
this.hasError = true
}
})
}
}),
I tried the following
sandbox.stub(LoginPage, 'login').withArgs(payload).returns(Promise.resolve(response))
in my spec
describe('LoginPage.vue', () => {
let actions
let getters
let store
var sandbox, payload, response
beforeEach(() => {
sandbox = sinon.sandbox.create()
...
})
afterEach(() => {
sandbox.restore()
})
it('calls store action login when the form is submitted', () => {
payload = {user: {email: 'john.doe#domain.com', password: 'john123'}}
response = true
sandbox.stub(LoginPage, 'login').withArgs(payload).returns(Promise.resolve(response))
const wrapper = mount(LoginPage, { store })
const form = wrapper.find('form')[0]
form.trigger('submit')
expect(actions.login.calledOnce).to.equal(true)
})
just stubbing the action with a Promise resolving the status ( true / false
import LoginPage from '#/pages/LoginPage'
import Vue from 'vue'
import Vuex from 'vuex'
import sinon from 'sinon'
import { mount } from 'avoriaz'
Vue.use(Vuex)
describe('LoginPage.vue', () => {
let actions
let store
let sandbox
beforeEach(() => {
sandbox = sinon.sandbox.create()
})
afterEach(() => {
sandbox.restore()
})
it('calls store action login when the form is submitted, w good credentials', (done) => {
actions = {
login: sandbox.stub().returns(Promise.resolve(true))
}
store = new Vuex.Store({
actions
})
const wrapper = mount(LoginPage, { store })
const form = wrapper.find('form')[0]
form.trigger('submit')
wrapper.vm.$nextTick(() => {
expect(actions.login.calledOnce).to.equal(true)
expect(wrapper.data().hasError).to.equal(false)
done()
})
})
it('calls store action login when the form is submitted, w wrong credentials', (done) => {
actions = {
login: sandbox.stub().returns(Promise.resolve(false))
}
store = new Vuex.Store({
actions
})
const wrapper = mount(LoginPage, { store })
const form = wrapper.find('form')[0]
form.trigger('submit')
wrapper.vm.$nextTick(() => {
expect(actions.login.calledOnce).to.equal(true)
expect(wrapper.data().hasError).to.equal(true)
done()
})
})
})
I am trying to perform unit test on vuex actions, using Mocha and Sinon
here is my action.spec.js
import actions from '#/vuex/actions'
import * as types from '#/vuex/mutation_types'
describe('actions.js', () => {
var server, store, lists, successPut, successPost, successDelete
successDelete = {'delete': true}
successPost = {'post': true}
successPut = {'put': true}
beforeEach(() => {
// mock shopping lists
lists = [{
id: '1',
title: 'Groceries'
}, {
id: '2',
title: 'Clothes'
}]
// mock store commit and dispatch methods
store = {
commit: (method, data) => {},
dispatch: () => {
return Promise.resolve()
},
state: {
shoppinglists: lists
}
}
sinon.stub(store, 'commit')
// mock server
server = sinon.fakeServer.create()
server.respondWith('GET', /shoppinglists/, xhr => {
xhr.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(lists))
})
server.respondWith('POST', /shoppinglists/, xhr => {
xhr.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(successPost))
})
server.respondWith('PUT', /shoppinglists/, xhr => {
xhr.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(successPut))
})
server.respondWith('DELETE', /shoppinglists/, xhr => {
xhr.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(successDelete))
})
server.autoRespond = true
})
afterEach(() => {
// restore stubs and server mock
store.commit.restore()
server.restore()
})
describe('populateShoppingLists', () => {
it('should call commit method with POPULATE_SHOPPING_LIST string parameter', done => {
actions.populateShoppingLists(store).then(() => {
expect(store.commit).to.have.been.calledWith(types.POPULATE_SHOPPING_LISTS, lists)
done()
}).catch(done)
})
})
describe('changeTitle', () => {
it('should call commit method with CHANGE_TITLE string', (done) => {
let title = 'new title'
actions.changeTitle(store, {title: title, id: '1'}).then(() => {
expect(store.commit).to.have.been.calledWith(types.CHANGE_TITLE, {title: title, id: '1'})
done()
}).catch(done)
})
})
describe('updateList', () => {
it('should return successful PUT response', (done) => {
actions.updateList(store, '1').then((data) => {
expect(data.data).to.eql(successPut)
done()
}).catch(done)
})
})
describe('createShoppingList', () => {
it('should return successful POST response', (done) => {
let newList = { title: 'new list', id: '3' }
actions.createShoppingList(store, newList).then((testResponse) => {
console.log('testResponse: ', testResponse)
expect(testResponse.body).to.eql(successPost)
done()
}).catch(done)
})
})
})
here is my action.js
import { CHANGE_TITLE, POPULATE_SHOPPING_LISTS } from './mutation_types'
import api from '../api'
import getters from './getters'
export default {
populateShoppingLists: ({ commit }) => {
return api.fetchShoppingLists().then(response => {
commit(POPULATE_SHOPPING_LISTS, response.data)
})
},
changeTitle: (store, data) => {
store.commit(CHANGE_TITLE, data)
return store.dispatch('updateList', data.id)
},
updateList: (store, id) => {
let shoppingList = getters.getListById(store.state, id)
return api.updateShoppingList(shoppingList)
},
createShoppingList: (store, shoppinglist) => {
return api.addNewShoppingList(shoppinglist).then((actionResponse) => {
console.log('actionResponse: ', actionResponse)
store.dispatch('populateShoppingLists')
})
},
}
running my unit tests , I have an issue with the createShoppingList test
console.log
actions.js
populateShoppingLists
✓ should call commit method with POPULATE_SHOPPING_LIST string parameter
changeTitle
✓ should call commit method with CHANGE_TITLE string
updateList
✓ should return successful PUT response
LOG LOG: 'actionResponse: ', Response{url: 'http://localhost:3000/shoppinglists', ok: true, status: 200, statusText: 'OK', headers: Headers{map: Object{Content-Type: ...}}, body: Object{post: true}, bodyText: '{"post":true}'}
LOG LOG: 'testResponse: ', undefined
createShoppingList
✗ should return successful POST response
undefined is not an object (evaluating 'testResponse.body')
webpack:///test/unit/specs/vuex/actions.spec.js:90:28 <- index.js:15508:28
webpack:///~/vue-resource/dist/vue-resource.es2015.js:151:0 <- index.js:17984:52
webpack:///~/vue/dist/vue.esm.js:701:0 <- index.js:3198:18
nextTickHandler#webpack:///~/vue/dist/vue.esm.js:648:0 <- index.js:3145:16
whicj indicates that in the createShoppingList action, the reponse is not sent back on the return, so expect(testResponse.body).to.eql(successPost) is not true...
what's wrong with my Promise handling in this case ?
thanks for feedback
You're on the right track - testResponse is undefined, because createShoppingList resolves with the return value of addNewShoppingList.then, which is unspecified, and defaults to undefined.
Should createShoppingList resolve with addNewShoppingList's response or the response from populateShoppingLists? If the former, return actionResponse from the handler:
return api.addNewShoppingList(shoppinglist).then((actionResponse) => {
store.dispatch('populateShoppingLists')
return actionResponse
});
As a side-note, because the actions you're testing are promises, you can get rid of done in your tests by returning the actions directly:
it('should call commit method with POPULATE_SHOPPING_LIST string parameter', () => {
// mocha will fail the test if the promise chain rejects or the expectation is not met
return actions.populateShoppingLists(store).then(() => {
expect(store.commit).to.have.been.calledWith(types.POPULATE_SHOPPING_LISTS, lists)
})
})
Given the following collection and access control defintion
class TasksCollection extends Mongo.Collection {
insert (task, callback) {
const doc = _.extend({}, task, {
createdOn: new Date(),
owner: this.userId
})
super.insert(doc, callback)
}
}
export const Tasks = new TasksCollection('tasks')
// Simple checks to ensure that the user is logged in before making changes.
Tasks.allow({
insert: (userId, doc) =>=> !!userId,
update: (userId, doc, fields, modifier) => !!userId,
remove: (userId, doc) => !!userId
})
How would you test to ensure that it works using Mocha/Chai/Sinon? This is what I have tried.
import { Meteor } from 'meteor/meteor'
import { resetDatabase } from 'meteor/xolvio:cleaner';
import { assert, expect } from 'chai'
import { Tasks } from '/imports/api/tasks'
import sinon from 'sinon'
describe('collection test', () => {
beforeEach(() => {
resetDatabase()
})
it('can see a collection', () => {
assert(Tasks, 'unable to see sample collection')
})
it('can query an empty collection', () => {
expect(Tasks.find({}).fetch()).to.be.empty
})
it('fails to add to a collection when the user is not logged in', (done) => {
expect(Tasks.find({}).fetch()).to.be.empty
Tasks.insert({
text: 'hello world'
}, (error) => {
console.log('expected', error) // this is also a 404
assert(error)
done()
})
})
describe('logged in', () => {
let sandbox
beforeEach(() => {
sandbox = sinon.sandbox.create()
sandbox.stub(Meteor, 'userId').returns(42)
})
afterEach(() => {
sandbox.restore()
})
it('can add to a collection', (done) => {
expect(Tasks.find({}).fetch()).to.be.empty
Tasks.insert({
text: 'hello world'
}, (error, _id) => {
console.log(error)
assert(!error)
const results = Tasks.find({}).fetch()
expect(results).to.have.lengthOf(1)
expect(results[0].defaultValue).to.equal(42)
expect(results[0]._id).to.equal(_id)
expect(results[0].createdOn).to.not.be.undefined
done()
})
})
})
})
UPDATE: But I get a 404 error when calling the server.
The insecure package is already removed.
UPDATE: I am only testing on the client for now as the authorization can only be done from a client call.
I've created a component which I'm trying to test using Karma and Jasmine. Everything works fine for other components that doesn't have services injected by DI. But this one throws an error without any message and just with a stack.
Here's the component:
import {Component} from 'angular2/core';
import {Application} from './application';
import {ApplicationsService} from './applications.service';
#Component({
selector: 'applications-selector',
styles: [require('./applications-selector.scss')],
template: require('./applications-selector.html'),
providers: [ApplicationsService]
})
export class ApplicationsSelectorComponent {
applications: Application[];
selectedWeek: number;
selectedApplications: Application[];
selectedCycle: string;
constructor(private _applicationsService: ApplicationsService) {
this.getApplications();
}
getApplications() {
this._applicationsService.getApplications().then(applications => this.applications = applications);
}
}
And here's the unit test for this component:
import {
it,
inject,
injectAsync,
describe,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import {provide} from 'angular2/core';
import {ApplicationsSelectorComponent} from './applications-selector.component';
import {ApplicationsService} from './applications.service';
class ApplicationsServiceMock {
getApplications() {
return ['ABC', 'XYZ'];
}
}
describe('ApplicationsSelectorComponent', () => {
beforeEachProviders(() => [
provide(ApplicationsService, { useClass: ApplicationsServiceMock }),
ApplicationsSelectorComponent
]);
it('should have empty default values', inject([ApplicationsSelectorComponent], (component) => {
expect(component.selectedWeek).toBe(undefined);
expect(component.selectedApplications).toBe(undefined);
expect(component.selectedCycle).toBe(undefined);
}));
});
And here's an error that I get as soon as I run this test:
ApplicationsSelectorComponent
× should have empty default values
PhantomJS 2.1.1 (Windows 7 0.0.0)
_instantiateProvider#d:/git/gatekeeper/web/spec-bundle.js:11896:38 <- webpack:///angular2/src/core/di/injector.ts:770:31
_new#d:/git/gatekeeper/web/spec-bundle.js:11885:42 <- webpack:///angular2/src/core/di/injector.ts:759:37
getObjByKeyId#d:/git/gatekeeper/web/spec-bundle.js:11495:55 <- webpack:///angular2/src/core/di/injector.ts:356:44
_getByKeyDefault#d:/git/gatekeeper/web/spec-bundle.js:12083:51 <- webpack:///angular2/src/core/di/injector.ts:977:44
_getByKey#d:/git/gatekeeper/web/spec-bundle.js:12029:42 <- webpack:///angular2/src/core/di/injector.ts:914:35
get#d:/git/gatekeeper/web/spec-bundle.js:11704:31 <- webpack:///angular2/src/core/di/injector.ts:577:26
d:/git/gatekeeper/web/spec-bundle.js:9128:74 <- webpack:///angular2/src/testing/test_injector.ts:151:52
map#[native code]
apply#[native code]
call#[native code]
call#[native code]
map#d:/git/gatekeeper/web/spec-bundle.js:2377:21 <- webpack:///~/es6-shim/es6-shim.js:1113:0
execute#d:/git/gatekeeper/web/spec-bundle.js:9128:39 <- webpack:///angular2/src/testing/test_injector.ts:151:34
execute#d:/git/gatekeeper/web/spec-bundle.js:9017:27 <- webpack:///angular2/src/testing/test_injector.ts:42:22
d:/git/gatekeeper/web/spec-bundle.js:8393:58 <- webpack:///angular2/src/testing/testing.ts:137:49
_instantiate#d:/git/gatekeeper/web/spec-bundle.js:12003:87 <- webpack:///angular2/src/core/di/injector.ts:883:67
An error occurs on inject([ApplicationsSelectorComponent] statement. As soon as I remove it, there's no error, but I need this component to perform tests on it.
What can cause this injection error?
It seems like you're trying to inject components the same way as providers which will not work.
Here is complete minimal example of mocking providers for specific component:
class ApplicationsService {
getApplications() {
return ['ABC'];
}
}
class ApplicationsServiceMock {
getApplications() {
return ['ABC', 'XYZ'];
}
}
#Component({
selector: 'apps',
template: '',
providers: [ApplicationsService]
})
class ApplicationsSelectorComponent {
constructor(private apps: ApplicationsService) {}
}
describe('App', () => {
describe('ApplicationsSelectorComponent', () => {
beforeEach(injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.overrideProviders(ApplicationsSelectorComponent, [provide(ApplicationsService, { useClass: ApplicationsServiceMock })])
.createAsync(ApplicationsSelectorComponent)
.then((componentFixture: any) => {
this.component = componentFixture;
});
}));
it('should have empty default values', () => {
expect(this.component.componentInstance.apps.getApplications()).toEqual(['ABC', 'XYZ'])
});
});
});
Finally, it turned out that all the setup was correct but I was just returning incorrect value from ApplicationsServiceMock. Base service is returning Promise and I was returnig just an array of value in my mock. That's why when this line this._applicationsService.getApplications().then(applications => this.applications = applications); was executed from constructor no then method on array could be found. And tests were failing.
As soon as I've fixed return value from my mock everything works fine.
Here's working code for my test:
import {
it,
beforeEach,
injectAsync,
describe,
TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';
import {Application} from './application';
import {ApplicationsService} from './applications.service';
import {ApplicationsSelectorComponent} from './applications-selector.component';
class ApplicationsServiceMock {
getApplications() {
return Promise.resolve([{ 'id': 1, 'name': 'TST', 'project': 'PRJ' }]);
}
}
describe('ApplicationsSelectorComponent', () => {
beforeEach(injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.overrideProviders(ApplicationsSelectorComponent, [provide(ApplicationsService, { useClass: ApplicationsServiceMock })])
.createAsync(ApplicationsSelectorComponent)
.then((componentFixture: any) => {
this.component = componentFixture;
});
}));
it('should have empty default values', () => {
expect(this.component.componentInstance._applicationsService.getApplications().then(apps => { apps.toEqual([{ 'id': 1, 'name': 'TST', 'project': 'PRJ' }]) }));
});
});