For example:
apolloServer(request => ({
schema: typeDefinitionArray,
graphiql: true,
context: request.session
}))
http://docs.apollostack.com/apollo-server/tools.html
I know => means es6 function with bound this, but what does the () after the => do?
If you skip the () then it will be ambiguous if it's a body of a lambda or an object literal that you want to return. So it's either
apolloServer(request => {
return {
schema: typeDefinitionArray,
graphiql: true,
context: request.session
}})
or
apolloServer(request => ({
schema: typeDefinitionArray,
graphiql: true,
context: request.session
}))
Related
I'm trying to run a unity test on a method by mocking an addressList but it says that it cannot read the property of undefined.
The method:
async paginate(
user: User,
options: IPaginationOptions,
): Promise<Pagination<AddressResponse>> {
const pagination = await this.addressRepository.paginate(user, options);
return new Pagination(
await Promise.all(
pagination.items.map(async (address) => new AddressResponse(address)),
),
pagination.meta,
pagination.links,
);
}
The problem is, when I put a console.log() to read the variable "pagination" it shows me an array that is not empty on the concole:
console.log
addressList: [ Address {} ]
this is what the repository is returning to me.
The test that I'm trying to run is this one:
describe('AddressService', () => {
let addressService: AddressService;
const user = new User();
const addressList: Address[] = [new Address()];
console.log('addressList: ', addressList);
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AddressService,
{
provide: getRepositoryToken(AddressRepository),
useValue: {
paginate: jest.fn().mockResolvedValue(addressList),
create: jest.fn(),
save: jest.fn(),
findById: jest.fn(),
findOne: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
},
},
],
}).compile();
addressService = module.get<AddressService>(AddressService);
});
it('should be defined', () => {
expect(addressService).toBeDefined();
});
describe('paginate', () => {
it('should return an address list successfully', async () => {
// Act
const result = await addressService.paginate(user, {
page: 1,
limit: 10,
});
// Assert
expect(result).toEqual(addressList);
});
});
});
What is the issue with my code? I'm trying to fix this by days.
Your paginate variable is indeed defined and populated, but the property you first accecss in the code is not. You try to access paginate.items while your mock just returns an array of Address. Change your paginate mock to be paginate: jest.fn().mockResolvedValue({ items: addressList }) and it should be fixed
I am having trouble in mocking ExecutionContext in Guard middleware.
Here's my RoleGuard extends JwtGuard
#Injectable()
export class RoleGuard extends JwtAuthGuard {
...
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const params = request.params;
...
}
}
This is what I am trying on my unit test.
let context: ExecutionContext = jest.genMockFromModule('#nestjs/common');
context.switchToHttp = jest.fn().mockResolvedValue({
getRequest: () => ({
originalUrl: '/',
method: 'GET',
params: undefined,
query: undefined,
body: undefined,
}),
getResponse: () => ({
statusCode: 200,
}),
});
jest.spyOn(context.switchToHttp(), 'getRequest').mockImplementation(() => {
return Promise.resolve(null);
});
And I am getting this kind of error.
Cannot spy the getRequest property because it is not a function; undefined given instead
I would like you to suggest any other way to mock context. Thank you.
Please check this library https://www.npmjs.com/package/#golevelup/ts-jest
Then you could mock ExecutionContext as following.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from '#nestjs/common';
describe('Mocked Execution Context', () => {
it('should have a fully mocked Execution Context', () => {
const mockExecutionContext = createMock<ExecutionContext>();
expect(mockExecutionContext.switchToHttp()).toBeDefined();
...
});
});
Hope it helps
When it comes to the ExecutionContext, depending on what I'm tetsting, I just supply a simple object instead, something like
const ctxMock = {
switchToHttp: () => ({
getRequest: () => ({
params: paramsToAdd,
url: 'some url path',
...
}),
}),
}
And use that as I need. If I need access to jest functions I save those to a variable before hand and assign the context's function to the variable, then I can use expect(variable).toHaveBeenCalledTimes(x) without a problem.
Another option is to use #golevelup/ts-jest to create type safe mock objects for you. I've made extensive use of this library as well for other libraries I've made.
I'm currently testing vuex module specifically actions.
Here's my code:
store/modules/users.js
export const state = () => ({
users: [],
})
export const mutations = () => ({
SET_USERS(state, users) {
console.log('Should reach Here');
state.users = users
}
})
export const actions = () => ({
getUsers({ commit }) {
return axios.get('/users')
.then(response => {
console.log('Reaching Here');
commit('SET_USERS', response.data.data.results)
})
.catch(error => {
console.log(error);
})
}
})
export const getters = () => {
users(state) {
return state.users;
}
};
Then when I test my actions:
tests/store/modules/users.js
it('should dispatch getUsers', () => {
mock.onGet('/users').reply(200, {
data: {
results: [
{ uid: 1, name: 'John Doe' },
{ uid: 2, name: 'Sam Smith' }
]
},
status: {
code: 200,
errorDetail: "",
message: "OK"
}
});
const commit = sinon.spy();
const state = {};
actions.getUsers({ commit, state });
expect(getters.users(state)).to.have.lengthOf(2);
});
when I try to run the test npm run dev it shows the console.log from action but from mutation SET_USERS it doesn't show the console.log
I'm referring to this documentation which I can use spy using sinon()
https://vuex.vuejs.org/guide/testing.html
How can I access the commit inside action to call mutation SET_USERS?
According to sinon docs
A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls. There are two types of spies: Some are anonymous functions, while others wrap methods that already exist in the system under test.
const commit = sinon.spy();
That is not the 'commit' from Vuex, you should test your mutation individually
actions.getUsers({ commit, state });
The commit argument is actually the spy, it will never trigger the mutation.
To test your mutation it could be something like this
mutations.SET_USERS(state, mockedUsers)
expect(state).to.have.lengthOf(mockedUsers.length)
...
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)
})
})
So I'm using Enzyme to render a component with a bunch of context:
const surveysByType = "test";
const wrapper = shallow(
<Dashboard routeParams={{}} />,
{
context: {
assetUrl: () => {
return "https://www.example.com/broken.gif"
},
executeAction: () => {},
getStore: (whatever) => {
return {
getState: () => {
return {
_surveysByType: surveysByType,
};
},
on: () => {
return {};
}
}
},
router: {
createHref: () => {},
go: () => {},
goBack: () => {},
goForward: () => {},
isActive: () => {},
push: () => {},
replace: () => {},
setRouteLeaveHook: () => {},
},
siteUrl: () => {
return "https://www.example.com"
},
}
}
);
However, when I start trying to use said context, I find that only a single function is there, i.e.
console.log(wrapper.context())
yields
{ getStore: [Function: getStore] }
rather than all the functions. Indeed, if I try to do
expect(wrapper.context().assetUrl())
I get an error:
TypeError: wrapper.context(...).assetUrl is not a function
while this works fine:
expect(wrapper.context().getStore().getState())
What version of enzyme are you on?
Shallow takes an options param and there are some predefined options that it honors, but I don't see a context object: https://github.com/airbnb/enzyme/blob/master/src/shallow.js
How are you expecting the context object to be used exactly?
You probably need to provide more code to help diagnose this. Where is the console.log statement you quote above being called from, for example?
Making some assumptions, you should check what Dashboard.contextTypes contains. If it contains only getStore: PropTypes.function, that may explain why you only see that in the shallow render. If the other properties are used by components that wrap dashboard (e.g. a wrapper), the code where console.log is being called may not be getting the whole context you're passing into shallow(), because as I understand it, React only provides the objects from context that are defined in the component's contextTypes static method.