How to mock AsyncStorage in jest? - unit-testing

I am using jest for unit testing of a react-native app. I have used AsyncStorage in one of my component.
componentWillMount() {
this.setState({ avatarSource: null });
AsyncStorage.getItem('UserDetails', (err, result) => {
var objData = JSON.parse(result);
this.setState({ userdetail: objData });
axios.get(SERVER_URL + '/image/' + objData.userId + '.jpg' + '?$' + Math.random())
.then(response => {
var obj = { uri: response.config.url };
this.setState({ avatarSource: obj });
});
});
}
How do I mock the 'result' from AsyncStorage in my test file?

The best way to test the get method is:
describe('Verifying getData function returns the right value', () => {
it('Function getData must return the correct value given date', async function () {
await getData('SOME_KEY');
expect(AsyncStorage.getItem).toBeCalledWith('SOME_KEY');
});
});

Related

Jest & AWS.DynamoDB.DocumentClient mocking

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);
});
});
});

How can I resolve AWS mock test with singleton classes

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();
...

How to test async function with axios?

I need to test async function using mocha.
Tried to test function that returns Promise from axios. Looked through many examples with axios-mock-adapter to solve my issue. BUT: axios sends REAL request, not mock as expected.
describe ('login sendRequest', () => {
let sandbox = null;
before(() => {
sandbox = sinon.createSandbox();
});
after(() => {
sandbox.restore();
});
it('should create and return REST promise', done => {
const mockAdapter = new MockAdapter(axios);
const data = { response: true };
mockAdapter.onAny('http://google.com').reply(200, data);
const requestParams = {
method: 'post',
url: 'http://google.com',
data: {},
adapter: adapter,
};
logic.sendRequest(requestParams).then(response => {
console.log(response);
done();
}).catch(err => {
console.log(err);
});
});
});
logic.js
export async function sendRequest(requsetParams) {
return await requestSender.request(requsetParams);
}
Expected to get 200 response and mock data that was set before. Why I don't get the response I need? May someone help?

How to mock pg-promise library with jest

I am trying to mock the pg promise library. I want to be able mock return whether the promise rejects or resolves. Here is an example function and test:
const pgp = require('pg-promise')({});
const someFunc = callback => {
const db = pgp('connectionString');
db
.none('create database test;')
.then(() => {
callback(null, 'success');
})
.catch(err => {
callback(err);
});
};
module.exports = {
someFunc
};
And i wanna test it like so:
const { someFunc } = require('./temp');
let pgp = require('pg-promise')({
noLocking: true
});
// HOW TO MOCK?
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
// how to mock this?
db.none = jest.fn();
db.none.mockReturnValue(Promise.reject('mock'));
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
You can mock the pgp object with a dumb mock like so:
const { someFunc } = require('./temp');
let pgp = jest.fn(() => ({
none: jest.fn(),
})
jest.mock('pg-promise') // Jest will hoist this line to the top of the file
// and prevent you from accidentially calling the
// real package.
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
db.none.mockRejectedValue('mock'); // This is the mock
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
Its an old question, but here is a new answer:
You can have a look at pg-mem, a library I released recently which emulates an in-memory postgres instance.
It supports most of the usual SQL queries (but will fail on less frequent syntaxes - file an issue if you encounter such a situation).
I wrote an article about it here
For your use case, see the this section

Can't mock module function used in my react action thunk jest

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);
});
};
}
});