use jest mock to run async function in isolation - javascript

async await jest mock http request in node.jest
I can write my test like so
it('works with async/await', async () => {
expect.assertions(1);
const data = await user.getUserName(4);
expect(data).toEqual('Mark');
});
but getUserName will be executed and it hit my backend and database, how to mock the function so that my test can be run in isolation?

You need to actually mock the user object. I don't have full context but you probably have something like const User = require('../user.js'). So with jest you can mock this by doing
jest.mock('../user.js')
jest.mock accepts also a callback where you can add there your own implementation but I prefer having a seperate mocks folder where you can keep your own implementation of the mock as it might make the tests a bit more cluttered.
You can check how it's used here where you call jest.mock and then the mock implementation.

Related

How should I get API token before executing Unit Test cases?

Within my unit test cases, I'm trying to do unit tests against some data in the API therefore an API token is required. I'm hoping to find a way to call token API and store it in Redux before firing any API.
I'm aware of setup.js in Jest, tried calling my API there and store in Redux didn't work well. I don't think the setup.js waited the method to finish completely before starting the unit test.
// Within the Setup.js, I was calling method directly
const getAPItoken = async() => {
await getToken();
}
getAPItoken();
Currently I'm getting the API token in 1 of the Unit Test files. Upon the method completion, rest of the Unit Tests will run fine since they are getting the API token from Redux.
Sample of what I'm doing now
describe('Get API token', () => {
test('it should return true after getting token', async () => {
// Within the method itself, it actually store the token to redux upon receiving from API, also it will return TRUE upon success
const retrievedToken = await getToken();
expect(retrievedToken).toBeTruthy();
});
Is there a better way to handle this?
You can use globalSetup. It accepts an async function that is triggered once before all test suites.
So you can optain the API key and set it on node global object so you can access if from anywhere.
// setup.js
module.exports = async () => {
global.__API_KEY__ = 'yoru API key';
};
// jest.config.js
module.exports = {
globalSetup: './setup.js',
};

How to properly create unit test for logic inside arrow function

I'm working on an existing NodeJS web service using HapiJS, Hapi Lab for testing along with Sinon. The service connects to a Postgres DB using massiveJs. There's a method implemented by someone else, that doesn't have unit tests. Now I'm reusing this method and I want to implement some unit tests for it.
This method executes a massivejs transaction inside of it, persisting to several tables.
async createSomething(payload) {
const { code, member } = payload;
const foundCompany = await this.rawDb.ethnics.tenants.findOne({ code });
if (foundCompany && foundCompany.companyId) {
const { companyId } = foundCompany;
const { foreignId } = member;
return await this.rawDb.withTransaction(async (tx) => {
const foundMember = await tx.ethnics.members.findOne({ foreign_id: foreignId, company_id: companyId });
if (!foundMember) {
//some business logic...
const newMember = await tx.ethnics.members.insert(member);
//more business logic persisting to other tables...
return newMember;
}
});
}
}
Problem is, I don't know how to stub stuff only inside the arrow function, without stubbing the entire arrow function. I just want to stub the calls of tx. I also don't want to use a database but stub the rawDb property. Is that doable from unit testing perspective?
Yes it is doable. There are 2 alternatives:
Stub MassiveJS methods directly.
Example to stub massive method findOne:
const massive = require('massive');
const sinon = require('sinon');
// Stub massive.Readable class method findOne.
// You need to find where is the real method findOne and stub it.
const stub = sinon.stub(massive.Readable, 'findOne');
// You can resolve it.
stub.resolves();
// Or you can throw it.
stub.throws(new Error('xxx'));
Use pg in memory for test.
Just for testing purpose, you can use module like: test-pg-pool or pg-mem. Before testing, start the test pg and after the test finish, destroy it.

How to really call fetch in Jest test

Is there a way to call fetch in a Jest test? I just want to call the live API to make sure it is still working. If there are 500 errors or the data is not what I expect than the test should report that.
I noticed that using request from the http module doesn't work. Calling fetch, like I normally do in the code that is not for testing, will give an error: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout. The API returns in less than a second when I call it in the browser. I use approximately the following to conduct the test but I also have simply returned the fetch function from within the test without using done with a similar lack of success:
import { JestEnvironment } from "#jest/environment";
import 'isomorphic-fetch';
import { request, } from "http";
jest.mock('../MY-API');
describe('tests of score structuring and display', () => {
test('call API - happy path', (done) => {
fetch(API).then(
res => res.json()
).then(res => {
expect(Array.isArray(response)).toBe(true);
console.log(`success: ${success}`);
done();
}).catch(reason => {
console.log(`reason: ${reason}`);
expect(reason).not.toBeTruthy();
done();
});
});
});
Oddly, there is an error message I can see as a console message after the timeout is reached: reason: ReferenceError: XMLHttpRequest is not defined
How can I make an actual, not a mocked, call to a live API in a Jest test? Is that simply prohibited? I don't see why this would fail given the documentation so I suspect there is something that is implicitly imported in React-Native that must be explicitly imported in a Jest test to make the fetch or request function work.
Putting aside any discussion about whether making actual network calls in unit tests is best practice...
There's no reason why you couldn't do it.
Here is a simple working example that pulls data from JSONPlaceholder:
import 'isomorphic-fetch';
test('real fetch call', async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
const result = await res.json();
expect(result.name).toBe('Leanne Graham'); // Success!
});
With all the work Jest does behind the scenes (defines globals like describe, beforeAll, test, etc., routes code files to transpilers, handles module caching and mocking, etc.) ultimately the actual tests are just JavaScript code and Jest just runs whatever JavaScript code it finds, so there really aren't any limitations on what you can run within your unit tests.

Jest - is it possible to test specific variables within an async module?

I am wondering if it is possible to test variables for specific values within a module call. For example:
module.exports = async(request, context, postgres) => {
let userId = request.user.id;
let balanceQuery = 'SELECT balance FROM account WHERE user_id = $1';
let userBalanceStr = await postgres.query(balanceQuery,[userId]).then(result => result.rows[0].balance);
let totalCount = BigFunction(userBalanceStr);
......
}
How would I go about testing/accessing the value of balanceQuery or userBalanceStr within a jest test?
I'm only able to access the userId portion of the query, and I am sort of confused how to go about accessing other variables within the module.
You can achieve that by mocking postgres.query and BigFunction and then asserting the arguments passed in each call. And to be able to test the async code, you can implement an async test.
API reference: Mock Functions
When mocking postgres.query, you could implement a fake returning value, which will be assigned to userBalanceStr, and then can be asserted with the mocked BigFunction.
To mock BigFunction, you can either mock its importation present in the module under test, or changing the exported function to pass BigFunction as a dependency, like postgres, passing the mock function directly as argument.

Mocking Request Header module using Jest

function createRequest(method) {
const init = {
method,
headers: new Headers({.....}),
};
return new Request(url, init); }
I am using Request headers (with Fetch) in the above code (https://davidwalsh.name/fetch )
However while writing unit test cases using Jest, it gives me this error: ReferenceError: Headers is not defined
DO I need to mock even these standard modules? How should I import Headers in unit test cases
I say yes, mocking Headers is definitely an option in a testing context.
In my particular case, I have simply mocked it like so:
global.Headers = ()=>{}
This will work just fine if you want to test that your code is behaving properly based on the response returned by fetch.
If you also need to check that the correct headers are sent, you would need a more sophisticated mock, and/or perhaps a specialized test suite for your networking methods.
adding ' import "isomorphic-fetch" ' to the jest setup file should resolve this issue as this will make the missing dom APIs available in the tests
I know this is an old question, but for anyone who runs into this (as I did), this worked for me:
// before running each test
beforeEach(() => {
// define `append` as a mocked fn
const append = jest.fn();
// set test `Headers`
global.Headers = () => ({
append: append,
});
});

Categories