How We can mock test multiple api calls in jest testing - reactjs

I have a scenario like i have to call 1stAPI then depending on the response of 1st API i have to call 2nd API.
I got a solution to test 1st API :
global.fetch = jest
.fn()
.mockImplementation(() => getMockPromise({ Response: resMock }));
I got my 1st response while mocking
but how can I get response in second ? I am using typescript with react
I tried to search multiple places but only got solution for one mock response only for jest testing like below :
global.fetch = jest
.fn()
.mockImplementation(() => getMockPromise({ Response: resMock }));
I thought if I use the above mockImplementation two times for different response it will work, but still same only one is working.

If you are calling fetch() with different arguments each time, you can use a mock implementation that responds with different data depending on the argument it receives.
//test file
const mockedResponses = {
'firstUrl': {}, // first response object
'secondUrl': {}, // second response object
}
global.fetch = jest
.fn()
.mockImplementation((url: string) => getMockPromise({ Response: mockedResponses[url] }));
Generally it's a good idea to have the actual fetch() call be done inside a separate function, e.g. callFirstApi() and callSecondApi(), and then you can just mock those functions instead. This also means you don't end up overwriting a global function.
You can also look into something like the Nock package which lets you do more elaborate testing of external APIs.

Related

Can you use aws-sdk/util-dynamodb unmarshall in Reactjs?

I have an API Gateway resource which calls a Dynamodb post request to query a table. I'm trying to call the API within my React app using Axios. The API is working, returning the data as expected (console log) but I'm getting errors if I try to use #aws-sdk/util-dynamodb (unmarshall) to convert the api data.items response into JSON and use within React.
./node_modules/#aws-sdk/util-dynamodb/dist-es/convertToNative.js 45:14 Module parse failed: Unexpected token (45:14)
Is there a way to use 'unmarshall' within React? Something like this:
useEffect(() => {
const getGoal = async () => {
try {
const response = await api.get(apiUrl)
setGoal(unmarshall(response.data.Items))
This works if I use a Lambda service, but I'm try to see if I can reduce my code.
While I'm not sure on the issue you are getting with unmarshall function, I would suggest using the DynamoDB Document Client which will return your data already unmarshalled.
The DynamoDB Document client simplifies working with items by abstracting the notion of attribute values. This abstraction annotates native JavaScript types supplied as input parameters, and converts annotated response data to native JavaScript types.

How to sequentially execute functions in React?

I am trying to upload images to firebase storage and then when uploads finish, execute a try/catch block of codes with addDoc() command to create a doc inside fb database. The sample coding is as follows:
const abc = () => {
array.map(() => {
return uploadFilesToFb()
})
// then, when the above function finishes
createDocInFb()
}
I heard about Promises, but is there any other way of doing this? I mean, in firebase there are .then functions but since I have a mapping I couldn't put addDoc() after .then of uploadFilesToFb(). If only alternative is promises, how can I achieve that with promises?

Jest doesn't recognize FileSystemFileHandle createWritable() method

In my code, I am using the relatively new interface of FileSystemFileHandle (documentation here: https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileHandle/createWritable)
In the documentation, it shows you can just call the createWritable() method, and React knows what to do with it. This would be correct, and my code works. However, when trying to create a test for my new method, Jest thinks createWritable() is not a function. This makes sense, since I didn't have to import any library to use this method.
How can I test my code using createWritable(), or is there any workaround so that the test at least passes?
//code example:
this.state = {
handleFile: []
};
async fileWriter({ data }) {
//request writable stream
const writer = await this.state.handleFile.createWritable();
await writer.write(new Blob([data])); // write the Blob directly
await writer.close(); // end writing
}

How do I correct official React.js testing recipe to work for React/Jest/Fetch asynchronous testing?

I am trying to learn the simplest way to mock fetch with jest. I am trying to start with the official React docs recipe for fetch but it doesnt actually work without some modification.
My aim is to use Jest and (only) native React to wait for component rendering to complete with useEffect[].fetch() call before running assertions and testing initialisation worked.
I have imported the Data fetching recipe from official docs:
https://reactjs.org/docs/testing-recipes.html#data-fetching
into codesandbox here
https://codesandbox.io/s/jest-data-fetching-ov8og
Result: test fail
expect(received).toContain(expected) // indexOf
Expected substring: "123, Charming Avenue"
Received string: "loading..."
Possible cause?: I suspect its failing because global.fetch is not being used in the component which appears to be using real fetch hence is stuck "loading".
UPDATE
I have managed to make the test work through trial and error. Changed the call to fetch in the actual component to global.fetch() to match the test. This is not desirable for working code to refer to global prefix everywhere fetch is used and is also not in the example code.
e.g.
export default function User(props) {
const [user, setUser] = useState(null);
async function fetchUserData(id) {
// this doesnt point to the correct mock function
// const response = await fetch("/" + id);
// this fixes the test by pointing to the correct mock function
const response = await global.fetch("/" + id);
const json = await response.json();
setUser(json);
}
...
any help or advice much appreciated.

TypeError: undefined is not a constructor in jasmine unit test with angularjs

I am having above error in my Jesmine tests. Code has a Controller which calls AppsService service to receive a promise response of array of apps followed by onLoad method -
AppsService.initAndGetApps(appCredentialType)
.then(onLoad)
.catch(onError);
Code works fine but getting error for unit tests like -
TypeError: undefined is not a constructor (evaluating 'AppsService.initAndGetApps(appCredentialType).then(onLoad)')
I tried mocking initAndGetApps in my spec file with Jasmine & also as custom method like this (both are giving same above error) -
1.
initAndGetApps : jasmine.createSpy("initAndGetApps").and.callFake(function (credentialType) {
return []; // empty is ok
}
2.
AppsService = {
initAndGetApps: function (credentialType) {
return [];
}
}
$provide.value('AppsService', AppsService);
AppsService uses deferred.promise to return promise response after doing some computation based on credentialType parameter (It also does two Promise calls). Test is not able to call initAndGetApps as not getting console of credentialType at first line of initAndGetApps.
Can someone guide me the right way to mock AppsService.
You are not returning a promise in none of those two mocks. I would try if something along these lines:
initAndGetApps : jasmine.createSpy("initAndGetApps").and.returnValue(
new Promise(function(resolve, reject) {
// not taking our time to do the job
resolve(desiredReturnValue);
}
);
You can change the return value to a mock value so your code works.

Resources