Why isn't my Promise in a Post response in MockAdapter being evaluated? - reactjs

When I mock a get using MockAdapter and reply with a Promise, the promise is evaluated fine and I'm able to select the response data.
When I try the same thing with a Post, it doesn't work. The .then method isn't evaluated and I don't get the response data.
test:
var axios = require("axios");
var MockAdapter = require("axios-mock-adapter");
let mock;
beforeAll(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.reset();
});
test("", async () => {
const response = { data: { assignee: '' }};
mock.onPost(`${APP_ROOT}/${ASSIGN}`).reply(function (config) {
return new Promise(function(resolve, reject) {
setTimeout(function () {
resolve([200, response]);
}, 1000);
});
})
})
useEffect in page:
useEffect(() => {
assign(id)
.then(responseData => {
})
.catch(error => {
})
}
I've got a very similar test using mock.onGet returning a Promise and everything works fine. Is there a reason why this shouldn't work for a Post?
I've tried various url's on the Post. For the onGet, I leave it blank but haven't seen any onPost examples with this - is onPost() with no url legal?
In case it matters, I've also set up a localStorage mock.

Related

React how to wait for all axios to finish

I want to wait until all axios in useEffect are finished.
UseEffect:
useEffect(() => {
async function getHomePageContent() {
await HomePageServices.getSliderContent().then((response) => {
setSliderProduct(response.data);
});
await HomePageServices.getRecommendedProducts().then((response) => {
setRecommendedProducts(response.data);
});
await HomePageServices.getMostOrderProducts().then((response) => {
setMostOrderProducts(response.data);
});
await HomePageServices.getMostRatedProducts().then((response) => {
setMostRatedProducts(response.data);
});
}
getHomePageContent().catch((error) => {
console.log(error)
});
}, []);
Class:
class HomePageServices{
async getSliderContent(){
return await axios.get(baseURL+"/slider")
}
async getMostRatedProducts(){
return await axios.get(baseURL+"/mostRatedProducts")
}
async getMostOrderProducts(){
return await axios.get(baseURL+"/mostOrderProduct")
}
async getRecommendedProducts(){
return await axios.get(baseURL+"/recommendedProduct")
}
}
Can someone explain to me how to wait for all axios to end, and if one failed, how to find out which one it was?
Try using Promise.allSettled() which takes an iterable (e.g. array) of promises and resolves into array of results of each of them.
Results are represented as objects with status key, which can be rejected or fulfilled. The second key of the object is either value containing the resolved value, or reason in case promise was rejected.
Taking this, then your code in useEffect might be something like this:
useEffect(() => {
const getHomePageContent = async () => ({
const promises = [
HomePageServices.getSliderContent(),
HomePageServices.getRecommendedProducts(),
HomePageServices.getMostOrderProducts(),
HomePageServices.getMostRatedProducts()
];
const data = await Promise.allSettled(promises);
const [slider, recommended, mostordered, mostrated] = data;
// result for each of promise
console.log(slider); // { status: 'fulfilled', value: 123 }
console.log(recommended) // { status: 'rejected', reason: 'blah'}
});
getHomePageContent().catch((er) => console.log(er))
}, [])

React class component issue in order of execution

I have the following code in my React class component.
For some reason, I am observing that, inside componentDidMount, despite having the keyword await before the call to this.getKeyForNextRequest(), the execution is jumping to the next call, this.loadGrids().
Am I doing something wrong here?
async componentDidMount() {
await this.getKeyForNextRequest();
await this.loadGrids();
}
getKeyForNextRequest = async () => {
const dataRequester = new DataRequester({
dataSource: `${URL}`,
requestType: "POST",
params: {
},
successCallback: response => {
console.log(response);
}
});
dataRequester.requestData();
}
loadGrids = async () => {
await this.loadGrid1ColumnDefs();
this.loadGrid1Data();
await this.loadGrid2ColumnDefs();
this.loadGrid2Data();
}
You can try using the Promise constructor:
getKeyForNextRequest = () => {
return new Promise((resolve, reject) => {
const dataRequester = new DataRequester({
dataSource: `${URL}`,
requestType: "POST",
params: {},
successCallback: response => {
console.log(response);
resolve(response);
}
});
});
}
This ensures you're waiting for a relevant promise, one that resolves only upon successCallback completing, rather than one that resolves instantly to undefined as you have it currently.
This is called "promisifying" the callback.
If DataRequester offers a promise-based mode, use that instead of promisifying the callback.

Testing a promise inside an async function

I'm trying to write a jest test to test a promise that runs within a async function. I'm having a hard time finding resources that describe how to do that.
Below is what I have:
const foo = async (client) => {
const update = data => {};
await client.query({
query: QUERY,
variables: {
x: xVal,
y: yVal,
},
}).then(response => {
update({ response });
}).catch(error => {
update({ [] });
});
}
...
fetch: () => {
foo(client)
},
Essentially I need to test fetch() and then confirm that update() ran in both the success and error case within foo().

using axios with promise API

I am using a promise based hook in a React app to fetch async data from an API.
I am also using a Axios, a promise based http client to call the API.
Is it an anti-pattern to use a promise based client inside another promise? The below code does not seem to work.
const getData = () => {
return new Promise((resolve, reject) => {
const url = "/getData";
axios.get(url)
.then(function(response) {
resolve(response);
})
.catch(function(error) {
reject(error);
});
});
const useAsync = (asyncFunction) => {
const [value, setValue] = useState(null);
const execute = useCallback(() => {
setPending(true);
setValue(null);
setError(null);
return asyncFunction()
.then(response => setValue(response))
.catch(error => setError(error))
.finally(() => setPending(false));
}, [asyncFunction]);
useEffect(() => {
execute();
}, [execute]);
return { execute, pending, value, error };
};
};
const RidesList = () => {
const {
pending,
value,
error,
} = useAsync(getData);
Oh man. I think you have a fundamental misunderstanding about how Promises work.
First, axios already returns a Promise by default. So your whole first function of getData can be reduced to:
const getData = () => {
const url = "/getData"
return axios.get(url)
}
But the meat of your code seems to indicate you want a querable Promise - so you can check the status of it for whatever reason. Here's an example of how you would do it, adapted from this snippet:
function statusPromiseMaker(promise) {
if (promise.isResolved) return promise
let status = {
pending: true,
rejected: false,
fulfilled: false
}
let result = promise.then(
resolvedValue => {
status.fulfilled = true
return resolvedValue
},
rejectedError => {
status.rejected = true
throw rejectedError
}
)
.finally(() => {
status.pending = false
})
result.status = () => status
return result
}
In this way, you can then do something like let thing = statusPromiseMaker(getData()) and if you look up thing.status.pending you'll get true or false etc...
I didn't actually run what's above, I may have forgotten a bracket or two, but hopefully this helps.
I have to admit - I haven't seen anything like this ever used in the wild. I am interested in knowing what you're actually trying to accomplish by this.
Axios itself returns a promise but if you want to make a custom class having your custom logic after each API call then you can use interceptors I was having the same requirement and this is how I am returning promises after applying my custom logic on each API call.
Interceptors will get executed separately after and before each request you made so we can simply use them if we want to modify our request or response.
here is my working solution have a look at it.
callApi = (method, endpoint, params) => {
this.apiHandler.interceptors.request.use((config) => {
config.method = method
config.url = config.baseURL + endpoint
config.params = params
return config
})
return new Promise((resolve, reject) => {
this.apiHandler.interceptors.response.use((config) => {
if (config.status == 200) {
resolve(config.data)
} else {
reject(config.status)
}
// return config
}, error => reject(error))
this.apiHandler()
})
}
Below is the code to call this function
helper.callApi("get", "wo/getAllWorkOrders").then(d => {
console.log(d)
})

Jest mock module resolve with variable value

Assuming I have a module which returns a promise.
I want to mock different outcomes of this promise to test the function where this module is part of. I mock the module like this:
jest.mock('../request', () => {
return () => new Promise((resolve, reject) => {
return resolve({
response: { ok: true }
});
});
});
My first test is running
test("The function resolves", () => {
const initialState = { apiData: getState("postData", {}, "ready", "POST") };
const store: any = mockStore(initialState);
return expect(
performApiRequest("postData/", {}, { data: "json" })(dispatch, () =>
store.getState()
)
).resolves.toBeUndefined();
});
The problem is now with testing an other function where the value that resolves is supposed to be different, for instance {response: { ok: false } }.
I already tried different things. First wrapping the mock in a function and give the response as an argument. --> fails for mocks can't take out of scope variables.
I tried to call jest.doMock within the test but this does not trigger the request correctly.
I tried to do
const mockResponse = jest.fn();
jest.mock("../request", () => {
return () =>
new Promise((resolve, reject) => {
return resolve({
mockResponse
});
});
});
And then call mockResponse.mockReturnValueOnce(value).
No success yet. Anybody sees a way out?
You can create a default mock function at the top level with jest.fn. Once you create the mock you can override the implementation of the function within the test case with mockImplementation or mockImplementationOnce. You can find more information about this in the Jest documentation.
import request from '../request';
jest.mock("../request", () =>
jest.fn(() =>
Promise.resolve({
response: {
ok: true
}
})
)
);
test("MyTest", () => {
request.mockImplementationOnce(() =>
Promise.resolve({
response: {
ok: false
}
})
);
});
answer with typescript would be:
import request from '../request';
jest.mock("../request", () =>
jest.fn(() =>
Promise.resolve({
response: {
ok: true
}
})
)
);
test("MyTest", () => {
(request as jest.Mock).mockImplementationOnce(() =>
Promise.resolve({
response: {
ok: true
}
})
);
});

Resources