I have a function which has 2 APi calls. Iam destructuring the response and sending each response to different functions to perform some operation. I need to write test case to make API call., fetch response & pass it to respective functions.
This is my code
async _fetchComponentDetails() {
const [firstResponse, secondResponse] = await Promise.all([
this._getfirstApiResponse(param1, param2),
this._getSecondApiResponse(param1, param2),
]);
this.formatFirstApiResult = await componentSerives.formatFirstResponseData(firstResponse);
this.formatSecondApiResult = await componentSerives.formatSecondResponseData(secondResponse);
}
This is my Service call
async _getfirstApiResponse(param1, param2) {
const url = 'api/firstApi';
const firstResponse = await componentSerives.fetchApiDetails(url, param1, param2);
return firstResponse;
}
async _getSecondApiResponse(param1, param2) {
const url = 'api/secondApi';
const secondResponse = await componentSerives.fetchApiDetails(url, param1, param2);
return secondResponse;
}
This is the Test case I written
it('it should make make API calls for first and second',async () => {
sinon.stub(componentSerives, 'fetchApiDetails').resolves(bannerResponse);
});
The issue iam facing is., I dont know how to send both first & second APi response in resolves();
on passing it as an array of objects like below., I see firstResponse & secondResponse loading in both objects.
[{firstResponse, secondResponse}]
can you help me how to stub both the APis and assign it to different responses in destructuring?
You are stubbing the wrong thing, according to your own test:
it('it should make make API calls for first and second',async () => {
If you are testing fetchApiDetails you cannot stub that function out. That makes no sense! Then you would just be testing your own stub.
What you need to stub out or inject, are its dependencies: _getfirstApiResponse and _getSecondApiResponse. Stub those out simply by having them just resolve some value:
const firstResponse = 42;
const secondResponse = -42;
sinon.replace(componentSerives, '_getfirstApiResponse', sinon.fake.resolves(firstResponse));
sinon.replace(componentSerives, '_getSecondApiResponse', sinon.fake.resolves(secondResponse ));
await componentSerives.fetchApiDetails();
assertEquals(componentSerives.formatFirstApiResult, "Result: 42");
assertEquals(componentSerives.formatSecondApiResult, "Result: -42");
Related
How to use data as a result from api call as a response in another concurrently?
I've got this function
const foo = async() => {
await firstCall()
await secondCall()
}
calling firstCall() i want to get data and save them inside some variable and when this data is received use data as params inside secondCall()
Declare a variable data inside your async function foo and assign it a value which is the value returned from calling the firstCall function:
const foo = async() => {
const data = await firstCall()
await secondCall(data)
}
For more info you can read documentations at MDN - async function.
I am trying to test some api calls in Jest, however the test is failing as the api call is dependent on another call to complete first, so the returned value is empty as opposed to what should be in there. I am using react-query for the api calls. Or is there a better or other way to test async calls? I am using MSW also, to intercept the api calls.
Async call
const getApi = async (): Promise<any> => {
const response = await axios.get(`https://www.xxxxx`).then(res => res.data);
return response;
}
test
const queryClient = new QueryClient()
describe('Comp1 tests', (): void => {
beforeEach(() => {
jest.useFakeTimers();
});
it('Should give correct response with render', async () => {
renderWithQueryClient(<QueryClientProvider client={queryClient}><Comp1 /></QueryClientProvider>);
expect(await screen.findByTestId('main-header')).toBeInTheDocument();
});
});
I get:
Unable to find an element by: [data-testid="main-header"]
I am querying AMPS SOW using javascript API. My functions look like this:
sow_query = async(topic, filter, options) => {
await this.connection
await this.client.sow(this.onMessage, topic, filter, options)
return this.message
}
onMessage = (message)=>{
this.message.push(message.data)
}
//Calling functions
const getData = async(date) =>{
let data = await getAmpsData(date)
}
async getAmpsData(date){
const filter = "some filter"
const data = await ampsClient.sow_query(topic, filter)
data.forEach((element) => console.log(element))
}
It looks like my call to ampsClient.sow_query doesnt wait for the callback to finish so returns an empty list. Therefore, I cannot loop through the data in my calling function getAmpsData.
I know it has to do with async/await because if I simply do console.log(data) in getAmpsData i can see the data (perhaps after 2 seconds) when the promise is resolved. Is there anyway i can get this working?
If I understand you correctly, data in getAmpsData is an array as expected, but data in getData is undefined. It's not an async/await problem, you just forgot to add return data; to getAmpsData.
I not sure about what package you are using. But, maybe, it using a callback function to get the result of .sow function - message.data.
With your logic, onMessage function will be called after data.forEach done, you can try adding a console.log line to onMessage function.
Maybe, the package has an important reason to do that. But, to fix this issue, you can wrap .sow function into a promise.
sow_query = async (topic, filter, options) => {
await this.connection // ???
return new Promise((resolve) => { // wrap in a promise
this.client.sow( // no need to wait .sow
(message) => {
resolve(message.data); // just resolve when we get the message's data
},
topic, filter, options)
});
}
//Calling functions
const getData = async (date) => {
let data = await getAmpsData(date)
}
async getAmpsData(date) {
const filter = "some filter"
const data = await ampsClient.sow_query(topic, filter)
data.forEach((element) => console.log(element))
}
I have a DataService which is responsible for my API calls - I am trying to mock the api call in jest but it does not seem to be working. I am not sure what I am doing wrong - my DataService seems to be undefined.
Here is the function
const getStepData = (id) => {
return async dispatch => {
try {
dispatch(fetchStepBegin());
const res = await DataService.fetchStepData(id);
const sortedTask = sortedTaskData(res)
const sortedStepData = sortStepData(res)
const newData = createSortedDataForDragAndDrop(sortedTask, sortedStepData)
dispatch(fetchRawStepDataSuccess(res.data))
dispatch(fetchStepDataSuccess(newData))
}
catch (err) {
dispatch(fetchStepError(err))
throw (err)
}
}
}
Here is the test that I have written - I am pretty sure I am mocking incorrectly
it('Data Api end point called with corrent studyId', () => {
jest.mock(DataService);
DataService.fetchStepData() = jest.fn()
CellStepManagementOperations.getStepData(5);
expect(DataService.fetchStepData).toHaveBeenCalledWith(5);
});
I think the problem here is that you are trying to test asynchronous action creators, synchronously. So your expect function doesn't wait for your getStepData to finish before running.
I've had to something very similar to what you're trying to do and I used a library called redux-testkit. Please see the part about testing async action creators with services here. You can even set mock return values for your API services which I've found very helpful when testing.
Using this library, you will be able to await for your getStepData async action creator to complete before running your expect function.
You will have to play around with your code but it might look something like this:
it('Data Api end point called with corrent studyId', () => {
jest.mock(DataService);
DataService.fetchStepData() = jest.fn()
const dispatches = await Thunk(CellStepManagementOperations.getStepData).execute(5);
expect(DataService.fetchStepData).toHaveBeenCalledWith(5);
});
I'd like to test my koa API routes using supertest and check what's in DynamoDB before and after to make sure that the end point did what was intended.
// app related
const pool = require('../../src/common/pool');
const app = require('../../server');
// for testing
const uuid = require('uuid');
const supertest = require('supertest');
// listen on port 40002
const request = supertest.agent(app.listen(4002));
describe('test', () => {
it.only('should', async (done) => {
debugger;
const id = uuid.v4().replace(/-/g, '');
await pool.add(id, 'data', 30);
return request
.get('/api/1')
.expect(204)
// .then(async (res) => {
// .then((res) => {
.end((res) => {
// still returns 'data' instead of 'dataNew' after the route is hit
const record = await pool.get(id);
debugger;
done();
});
});
});
In the code above, I'm creating a record in the db, then I hit the end point, and I tried a then() and an end() chained function to check the db once again. The end point will just data to dataNew and in the then() function, it still returns the original data.
Any ideas on how I can verify the new record in the db ?
References:
Supertest: Verify database after request - In TLDR at the bottom, the solution was to use co. I tried this and had issues probably cause I'm using await instead of generators.
The above was fixed by chaining the pool.add() which returns a promise, to the supertest request and then awaiting the record to verify it. Sometimes it still gets the record too quickly because the pool.update() method is not awaited within the end point that request is hitting.
describe('test', () => {
it.only('should', async () => {
const id = uuid.v4().replace(/-/g, '');
await pool.add(id, 'data', 30).then(() => {
return request
.get('/api/1')
.expect(204)
// check custom headers
//.expect('pool-before', 'data')
//.expect('pool-after', 'dataModified')
.then(async (res) => {
const record = await pool.get(id);
debugger;
expect('dataModified').to.equal(record.fields.S);
});
});
});
});
The only other way I can think of is to check the value via a custom header, a delay, or use a mock.
Let me know if anyone has a better solution.