I'm currently trying to test my thunk action (getUserFeatureNames) to see if it calls a success action(getUserFeatureNamesSuccess) using jest. getUserFeatureNames thunk action currently resides in loginActions.js file which is import homeQueries(which i'm trying to mock). So far I'm getting the following error when running my jest test..
TypeError: _homeQueries2.default.getFeatureNames is not a function
How do i mock homeQueries.getFeatureNames?
function createStore(state = {}, expectActions = {}){
const mockStore = configureMockStore([thunk]);
return mockStore(state, expectActions);
}
describe("home_async_tests", () => {
test("getUserFeatureNamesSuccess action is called if request was success", (done) => {
jest.mock('../../../graphQL/homeQueries', () => {
return jest.fn(() => {
{
getFeatureNames: () =>{
return new Promise((resolve, reject) => {
let array = [{iconFile: 'Personalization.png', description: 'Personalization'},{iconFile: 'Home.png', description: 'Home'}];
resolve(array);
});
};
}
});
});
jest.dontMock('../../../app/redux/actions/homeActions');
let homeActions = require('../../../app/redux/actions/homeActions');
const expectedAction = {type: types.userFeatureNamesSuccess, payLoad: {isError: false, data: '' }};
const store = createStore();
store.dispatch(homeActions.getUserFeatureNames({token:"fdis4554" })).then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(expectedAction.type);
expect(actions[0].payLoad.isError).toEqual(expectedAction.payLoad.isError);
done();
});
});
I assume that the module just return an object and not a function that returns an object, so your mock should look like this:
jest.mock('../../../graphQL/homeQueries', () = > ({
getFeatureNames: () = > {
return new Promise((resolve, reject) = > {
let array = [{
iconFile: 'Personalization.png',
description: 'Personalization'
}, {
iconFile: 'Home.png',
description: 'Home'
}];
resolve(array);
});
};
}
});
Related
I'm trying to mock a call to AWS.DynamoDB.DocumentClient. I tried several solutions I found online, but I cannot get it to work.
This is my best effort so far:
import * as AWS from 'aws-sdk';
import * as dynamoDbUtils from '../../src/utils/dynamo-db.utils';
jest.mock("aws-sdk");
describe('dynamo-db.utils', () => {
describe('updateEntity', () => {
it('Should return', async () => {
AWS.DynamoDB.DocumentClient.prototype.update.mockImplementation((_, cb) => {
cb(null, user);
});
await dynamoDbUtils.updateEntity('tableName', 'id', 2000);
});
});
});
I get error message
Property 'mockImplementation' does not exist on type '(params: UpdateItemInput, callback?: (err: AWSError, data: UpdateItemOutput) => void) => Request<UpdateItemOutput, AWSError>'.ts(2339)
My source file:
import AWS from 'aws-sdk';
let db: AWS.DynamoDB.DocumentClient;
export function init() {
db = new AWS.DynamoDB.DocumentClient({
region: ('region')
});
}
export async function updateEntity(tableName: string, id: string, totalNumberOfCharacters: number): Promise<AWS.DynamoDB.UpdateItemOutput> {
try {
const params = {
TableName: tableName,
Key: { 'id': id },
UpdateExpression: 'set totalNumberOfCharacters = :totalNumberOfCharacters',
ExpressionAttributeValues: {
':totalNumberOfCharacters': totalNumberOfCharacters
},
ReturnValues: 'UPDATED_NEW'
};
const updatedItem = await db.update(params).promise();
return updatedItem;
} catch (err) {
throw err;
}
}
Please advise how can I properly mock the response of AWS.DynamoDB.DocumentClient.update
Have some way to do the that thing (I think so).
This is one of them:
You use AWS.DynamoDB.DocumentClient, then we will mock AWS object to return an object with DocumentClient is mocked object.
jest.mock("aws-sdk", () => {
return {
DynamoDB: {
DocumentClient: jest.fn(),
},
};
});
Now, AWS.DynamoDB.DocumentClient is mocked obj. Usage of update function like update(params).promise() => Call with params, returns an "object" with promise is a function, promise() returns a Promise. Do step by step.
updateMocked = jest.fn();
updatePromiseMocked = jest.fn();
updateMocked.mockReturnValue({
promise: updatePromiseMocked,
});
mocked(AWS.DynamoDB.DocumentClient).mockImplementation(() => {
return { update: updateMocked } as unknown as AWS.DynamoDB.DocumentClient;
});
mocked import from ts-jest/utils, updateMocked to check the update will be call or not, updatePromiseMocked to control result of update function (success/ throw error).
Complete example:
import * as AWS from 'aws-sdk';
import * as dynamoDbUtils from './index';
import { mocked } from 'ts-jest/utils'
jest.mock("aws-sdk", () => {
return {
DynamoDB: {
DocumentClient: jest.fn(),
},
};
});
describe('dynamo-db.utils', () => {
describe('updateEntity', () => {
let updateMocked: jest.Mock;
let updatePromiseMocked: jest.Mock;
beforeEach(() => {
updateMocked = jest.fn();
updatePromiseMocked = jest.fn();
updateMocked.mockReturnValue({
promise: updatePromiseMocked,
});
mocked(AWS.DynamoDB.DocumentClient).mockImplementation(() => {
return { update: updateMocked } as unknown as AWS.DynamoDB.DocumentClient;
});
dynamoDbUtils.init();
});
it('Should request to Dynamodb with correct param and forward result from Dynamodb', async () => {
const totalNumberOfCharacters = 2000;
const id = 'id';
const tableName = 'tableName';
const updatedItem = {};
const params = {
TableName: tableName,
Key: { 'id': id },
UpdateExpression: 'set totalNumberOfCharacters = :totalNumberOfCharacters',
ExpressionAttributeValues: {
':totalNumberOfCharacters': totalNumberOfCharacters
},
ReturnValues: 'UPDATED_NEW'
};
updatePromiseMocked.mockResolvedValue(updatedItem);
const result = await dynamoDbUtils.updateEntity(tableName, id, totalNumberOfCharacters);
expect(result).toEqual(updatedItem);
expect(updateMocked).toHaveBeenCalledWith(params);
});
});
});
when I execute Jest in Javascript test with AWS mock via npm, it will be Failure.
because I use singleton class.
The difference like here.
「module.exports = Users;」 or 「module.exports = new Users();」
I guess AWS mock doesn't work with singleton class.
in that cause, how should I do to solve this problem?
'use strick';
var aws = require('aws-sdk')
aws.config.update({region:'ap-northeast-1'})
class Users {
constructor() {
this.table = 'Users'
this.dynamodb = new aws.DynamoDB()
}
getData(email) {
let params = {
TableName: this.table,
Key : { 'email': {'S':email} }
}
return this.dynamodb.getItem(params).promise()
}
}
// module.exports = Users // ← this will be success.
module.exports = new Users(); // ← this will be failure.
'use strict';
var aws = require('aws-sdk-mock'),
users = require('./user'),
chai = require('chai'),
path = require('path'),
should = chai.should(),
input = 'test#gmail.com',
usersObj;
aws.setSDK(path.resolve('node_modules/aws-sdk'));
describe('All Tests', function () {
// this.timeout(0);
beforeEach(function () {
aws.mock('DynamoDB', 'getItem', function (params, callback) {
callback(null, {Item: {email: params.Key.email.S}});
});
// usersObj = new users(); ← this will be success.
usersObj = users; // ← this will be failure.
});
it('getData', function (done) {
usersObj.getData(input).then(function (res) {
console.log(res);
res.Item.email.should.equal(input);
done();
});
});
});
This line:
module.exports = new Users();
...means that a Users object will get created as soon as the code runs...and it runs as soon as user.js is required.
This line:
users = require('./user')
...is at the top of your test file and this line:
aws.mock('DynamoDB', 'getItem', function (params, callback) {
callback(null, {Item: {email: params.Key.email.S}});
});
...is in a beforeEach...
...which means that user.js is required and runs before the mock has been created...which causes the test to fail.
If you are going to export an instance of Users then you just need to make sure you don't require the user.js file in your test until after you have set up your mock:
var aws = require('aws-sdk-mock'),
chai = require('chai'),
path = require('path'),
input = 'test#gmail.com',
usersObj;
chai.should()
aws.setSDK(path.resolve('node_modules/aws-sdk'));
describe('All Tests', function () {
beforeEach(function () {
aws.mock('DynamoDB', 'getItem', function (params, callback) {
callback(null, { Item: { email: params.Key.email.S } });
}); // <= set up the mock first...
usersObj = require('./user'); // <= ...then require user.js
});
it('getData', function (done) {
usersObj.getData(input).then(function (res) {
res.Item.email.should.equal(input); // Success!
done();
});
});
});
I could resolve this pattern too.
'use strict';
var aws = require('aws-sdk-mock'),
users = require('./user'),
chai = require('chai'),
path = require('path'),
should = chai.should(),
input = 'test#gmail.com',
usersObj;
const awsObject = require('aws-sdk');
aws.setSDK(path.resolve('node_modules/aws-sdk'));
describe('All Tests', function () {
// this.timeout(0);
beforeEach(function () {
aws.mock('DynamoDB', 'getItem', function (params, callback) {
callback(null, {Item: {email: params.Key.email.S}});
});
// it will be resolve problem by creating new AWS instance.
users.dynamodb = new awsObject.DynamoDB();
});
it('getData', function (done) {
users.getData(input).then(function (res) {
console.log(res);
res.Item.email.should.equal(input);
done();
});
});
});
You must call the aws client inside the class constructor
class MyClass {
constructor(){
this.dynamodb = new DynamoDB.DocumentClient({ region: "us-west-2" });
}
...
In the test file you must create a new instance of your class just after call de AWSMock. Example:
it('Should save on dinamoDB with param atributes void()', async () => {
AWSMock.mock('DynamoDB.DocumentClient', 'update', function (params, callback){
callback(null, { Attributes: { currentValue: 1 } } );
});
AWSMock.mock('DynamoDB.DocumentClient', 'put', function (params, callback){
callback(null, true);
});
const myClass = new MyClass();
...
I am trying to create async tests with axios-mock and jest.
This is my test file:
var axios = require('axios');
var MockAdapter = require('axios-mock-adapter');
const middlewares = [thunk,axiosMiddleware]
const mockStore = configureMockStore(middlewares)
describe('async-actions', () => {
var instance;
var mock;
beforeEach(function() {
instance = axios.create();
mock = new MockAdapter(instance);
});
afterEach(() => {
mock.reset()
mock.restore()
})
it('creates FETCH_BOOKINGS_SUCCESS when fetch bookings has been done', () => {
mock
.onGet('/bookings').reply(200, {
data: [
{ id: 1, name: 'test booking' }
]
});
const expectedActions = [
{type: "FETCH_BOOKINGS_START" },
{type: "FETCH_BOOKINGS_SUCCESS", }
]
const store = mockStore({
session: {
token: {
token: "test_token"
}
}
})
return store.dispatch(actions.fetchBookingsTest())
.then(
() => {
expect(store.getActions()).toEqual(expectedActions)
})
// return of async actions
})
})
And my action:
export function fetchBookingsTest() {
return (dispatch) => {
dispatch(async.fetchDataStart(namedType));
return dispatch(rest.get(BOOKINGS))
.then(
(data) => {
dispatch(async.fetchDataSuccess(data,namedType));
},
(error) => {
dispatch(async.fetchDataFailure(error,namedType));
}
)
}
}
I have middleware setup that uses the authentication token from the redux store for each get request. That is why I have setup "test_token" in the mock store.
When I run this test I receive the response
[{"type": "FETCH_BOOKINGS_START"}, {"payload": [Error: Network Error], "type": "FETCH_BOOKINGS_FAILURE"}]
Why am I getting a network error? Do i need to do more setup with Jest to avoid authentication with mock-axios?
I'm having troubles stubbing out an async action for redux-thunk. Mocha keeps giving me timeout:
// actions.js
const fetchUserThings = userId => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([{ foo: 'bar' }]);
}
});
};
const displayUserThings = userThings => ({
type: 'DISPLAY',
userThings
});
export const loadUserThings = userId => {
return dispatch => {
fetchUserThings(userId)
.then(userThings => displayUserThings(userThings));
};
}
And here's my mocha test. I'm using redux on version 3.3.1 and redux-mock-store on version 0.0.6.
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import * as actions from './actions';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('actions', () => {
it('creates DISPLAY after fetching', done => {
const userId = 1;
const userThings = [{ foo: 'bar' }];
const expectedActions = [
{ type: 'DISPLAY', userThings }
];
const store = mockStore({userThings: []}, expectedActions, done);
store.dispatch(actions.loadUserThings(userId);
});
});
What am I missing?
I'm new to unit testing Redux-Thunk async actions using Jest.
Here is my code:
export const functionA = (a, b) => (dispatch) => {
dispatch({ type: CONSTANT_A, payload: a });
dispatch({ type: CONSTANT_B, payload: b });
}
How can I test this function using Jest?
You have an example in the Redux docs: http://redux.js.org/docs/recipes/WritingTests.html#async-action-creators
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
describe('async actions', () => {
it('should dispatch actions of ConstantA and ConstantB', () => {
const expectedActions = [
{type: 'CONSTANT_A', payload: 'a'},
{type: 'CONSTANT_B', payload: 'b'}
]
const store = mockStore({ yourInitialState })
store.dispatch(functionA('a', 'b'))
expect(store.getActions()).toEqual(expectedActions)
})
})
Also, for more more convenience, you can use this module: https://www.npmjs.com/package/redux-thunk-tester
Example:
import React from 'react';
import {createStore, applyMiddleware, combineReducers} from 'redux';
import {reducer} from './example';
import ReduxThunkTester from 'redux-thunk-tester';
import thunk from 'redux-thunk';
const request = (ms) => new Promise((resolve) => {
setTimeout(() => resolve('success response'), ms);
});
const resultRequestAction = (value) => ({ type: SOME_BACKEND_REQUEST, payload: value });
const toggleLoadingAction = (value) => ({ type: TOGGLE_LOADING, payload: value });
const asyncThunkWithRequest = () => async (dispatch) => {
try {
dispatch(toggleLoadingAction(true));
const result = await request(200);
dispatch(resultRequestAction(result));
} finally {
dispatch(toggleLoadingAction(false));
}
};
const createMockStore = () => {
const reduxThunkTester = new ReduxThunkTester();
const store = createStore(
combineReducers({exampleSimple: reducer}),
applyMiddleware(
reduxThunkTester.createReduxThunkHistoryMiddleware(),
thunk
),
);
return {reduxThunkTester, store};
};
describe('Simple example.', () => {
test('Success request.', async () => {
const {store, reduxThunkTester: {getActionHistoryAsync, getActionHistoryStringifyAsync}} = createMockStore();
store.dispatch(asyncThunkWithRequest());
const actionHistory = await getActionHistoryAsync(); // need to wait async thunk (all inner dispatch)
expect(actionHistory).toEqual([
{type: 'TOGGLE_LOADING', payload: true},
{type: 'SOME_BACKEND_REQUEST', payload: 'success response'},
{type: 'TOGGLE_LOADING', payload: false},
]);
expect(store.getState().exampleSimple).toEqual({
loading: false,
result: 'success response'
});
console.log(await getActionHistoryStringifyAsync({withColor: true}));
});
});
I recommend you to write something like this to avoid async problems:
return store
.dispatch(actionCreators.login({}))
.then(() => expect(store.getActions()).toEqual(expectedActions));