Mocking Request Header module using Jest - javascript

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

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 handle lots of `mockImplentationOnce` calls

I'm writing integration tests for a class that has a lot of requests. The requests are done through a HttpClient singleton.
So, to avoid making real requests, I mock all calls to HttpClient. The problem is, I have too many requests.
HttpClient.get is called to fetch a token.
HttpClient.get is called to fetch a resource.
HttpClient.get is called to fetch all customers from this resource.
HttpClient.get is called to verify if a single customer exists in another API.
Conditional: HttpClient.post is called to add this one customer to the API, if it does not exist.
HttpClient.post is called to add the resource to another API.
It's actually a little more complicated than that, because some of these calls are done multiple times (inside a loop), but you get the picture.
I wrote a test case for every scenario. One test case to simulate a failed request to fetch the token, another to simulate a failed request to fetch a resource and so on.
To do this, I wrote a "happy" scenario - where everything goes well -, using mockImplementationOnce. My beforeEach looks a little like this:
tokenResponse = { body: { token: 'some-token'}, status: 200 }
HttpClient.get.mockImplementationOnce(() => tokenResponse)
tokenResource = { body: <some-fixture-with-resources>, status: 200 }
HttpClient.get.mockImplementationOnce(() => tokenResource
(...)
To write the scenarios, I reassigned the returned variable
it('fails to fetch the token', () => {
tokenResponse = { status: 500 }
// code that calls my class
// code that asserts that an error was thrown
}
Anyway, I managed to write simple test cases for all scenarios, but my beforeEach has a giant boilerplate. Besides that, now I want to write more advanced test cases where a request is done multiple times (n of customers > 1). It's getting quite complicated to handle all fixtures and keeping track of individual mocks.
Is this a common issue? Is there an easier way to handle mock implementations? I thought about something like mockImplementationNth but couldn't find anything.
Ps.: Changing the code itself is hard because it is legacy code and the APIs are a little clunky.
I thought about isolating the scenarios into a setupMocks function with a default setting that could be overwritten in the test cases with another function. It would look something like this:
describe('Integration test', () => {
beforeEach(() => {
setupMocks()
})
it('goes well', () => {
expect(myClass.execute()).resolves.toBe(true)
})
it('fails to fetch the token', () => {
overrideMocks('token-failed')
expect(myClass.execute()).rejects.toEqual('some-error')
})
(...)
})
At least the test cases will look simpler.

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.

Mocking Redis Constructor with Sinon

I'm trying to figure out a way to mock redis in this module:
const Redis = require('ioredis');
const myFunction = {
exists: (thingToCheck) {
let redis_client = new Redis(
6379,
process.env.REDIS_URL,
{
connectTimeout: 75,
dropBufferSupport: true,
retryStrategy: functionHere
});
redis_client.exists(thingToCheck, function (err, resp) {
// handlings in here
});
}
};
Using this test-code:
const LambdaTester = require('lambda-tester');
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const mockRedis = sinon.mock(require('ioredis'));
describe( 'A Redis Connection error', function() {
before(() => {
mockRedis.expects('constructor').returns({
exists: (sha, callback) => {
callback('error!', null);
}
});
});
it( 'It returns a database error', function() {
return LambdaTester(lambdaToTest)
.event(thingToCheck)
.expectError((err) => {
expect(err.message).to.equal('Database error');
});
});
});
I also tried a few variations, but I'm kind of stuck as I basically need to mock the constructor and I'm not sure Sinon supports this?
mockRedis.expects('exists').returns(
(thing, callback) => {
callback('error!', null);
}
);
sinon.stub(mockRedis, 'constructor').callsFake(() => console.log('test!'));
sinon.stub(mockRedis, 'exists').callsFake(() => console.log('test!'));
Not sure what else to try here, I also tried using rewire as suggested here, but using mockRedis.__set__("exists", myMock); never set that private variable.
I want to fake my error paths ultimately.
I would love to hear what others are doing to test redis in node js 😄.
Your problem is not whether Sinon supports this or that, but rather a missing understanding of how "classes" work in Ecmascript, as shown by the attempt at stubbing constructor property in the test code. That will never work, as that property has nothing to do with how any resulting objects turn out. It is simply a reference to the function that was used to create the object. I have covered a very similar topic on the Sinon tracker that you might have interest in reading to gain some core JS foo :-) Basically, it is not possible to stub a constructor, but you can probably coerce your code to use another constructor function in its place through either DI or link seams.
As a matter of fact, a few answers down in the same thread, you will see me covering an example of how I myself designed a Redis using class to be easily testable by supporting dependency injection. You might want to check it out, as it is more or less directly applicable to your example module above.
Another technique, which you already has tried getting to work, is using link seams (using rewire). The Sinon homepage has a nice article on doing this. Both rewire and proxyquire will do the job just fine here: I think you have just complicated the matter a bit by wrapping the require statement with a mock.
Even though I am on the Sinon maintainer team, I never use the mock functionality, so I cannot tell you how to use that, as I think it obscures the testing, but to get the basic link seams working using rewire I would basically remove all the Sinon code first and get the basic case going (removing redis for a stubbed module you have created).
Only then, add Sinon code as required.

How do I test a function that sends a request in browser that requires authentication?

I'm in the process of writing unit tests in Mocha and Chai, and I'm trying to figure out how to test a function that that uses the fetch API to send a request that requires a session to access. This function is an ES6 method that returns a thenable object.
_auth(record) {
var authMetadata = this._getAuthMetadata(record);
var authUrl = `/${this._getPortal(window.location.pathname)}/tlist_child_auth.html?${this._encodeUri(authMetadata)}`;
if (getPortal() !== 'guardian') {
authUrl += `&frn=${this.coreTableNumber}${this.foreignKey}`;
}
return fetch(authUrl, {
credentials: 'include'
}).then(function(rawData) {
return rawData.text();
});
}
tlist_child_auth.html is the page that requires session authorization to access. Is there any easy way to do this, or should I seek to "invent the wheel"?
With unit testing, the idea is to test the unit that you're interested in, and only that. In this instance, the unit makes use of fetch, which itself goes off and talks to websites, so in effect your unit test ends up doing a round trip to a website so you end up "testing" that too. Not what you want in a unit test.
The correct way to test just the part you're interested in is to mock the fetch function, and use the mock to verify it is called in the way you expect, plus also return data from the mock to your unit that it can use to complete the test. You may perform other checks to ensure your unit has processed the return in the way you expected.
It appears that there is at least one npm package available for mocking fetch.

Categories