Reputation: 2181
I have this wrapper around fetch
that we use and in it I want to allow the consumer to call it like shown in this test.
it("When we get a failure response Then we get rejected promise with error", done => {
try {
fetch.mockImplementation(
mockFetch([
{
url: "/url",
errorResponse: true,
response: () => ({ error: "whoops" })
}
])
);
store.getState.mockReturnValue({
userContext: {}
});
const p = http.get("url", { sampleConfig: "sample" });
setTimeout(() => {
p.then(r => expect(r.result)).catch(e => {
try {
expect(e.error).toBe("whoops"); <== CODE MAKES IT HERE
done();
} catch (e) {
done.fail(e);
}
});
});
} catch (e) {
done.fail(e);
}
});
This is the code that is called by http.get
return fetch(buildUrl(url), addJwtToken(config)).then(response => {
if (response.headers) {
setJwtTokenFromHeaderResponse(response.headers.get("Authorization"));
}
if (response.ok) {
if (response.headers.map["content-type"].includes("stream")) {
return response;
}
return response.json();
}
const unauthorized = 401;
if (response.status === unauthorized) {
// All else failed so redirect user to FMS to reauthenticate
localStorage.removeItem("jwtToken");
return response.json().then(() => redirectToSignOut());
}
return response.json().then(r => Promise.reject(r)); <== THIS RIGHT HERE
});
I don't want the caller to have to deal with doing
http.get('/foo').catch(r => r.json()).then(e => processError(e))
And instead want to handle resolving the json()
error for them so they can just do this.
http.get('/foo').catch(processError)
I feel it's a reasonable design but maybe I'm missing something as node complains in my test by showing these warnings.
(node:6412) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): [object Promise]
(node:6412) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:6412) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 2)
I can't figure out how to get it to stop spamming my tests with these warning or to figure out if there is an idiomatic way to accomplish my goals.
Edit 1 I updated the code to return the promise chain which was an unrelated bug.
Upvotes: 0
Views: 100
Reputation: 222493
There's a number of problems.
There will be an error if a response is processed with response.json()
multiple times. response.json()
should be called once:
if (response.status === unauthorized) {
// All else failed so redirect user ot FMS to reauthenticate
localStorage.removeItem("jwtToken");
response.json().then(() => redirectToSignOut());
}
return response.json().then(r => Promise.reject(r));
All promises should be chained. This
response.json().then(() => redirectToSignOut());
results in flawed control flow. It's unclear how it's expected to work but every promise should be returned from then
.
Using done
in tests is an antipattern with promises because its use results in human errors; all modern testing frameworks support promises. try..catch
is inappropriate here because it cannot catch asynchronous errors from promises outside async
function. setTimeout
is inappropriate here, too.
It's also unclear why r.result
should be a rejected promise because it isn't defined anywhere in the code.
With async
it could be something like:
it("When we get a failure response Then we get rejected promise with error", async () => {
fetch.mockImplementation(
mockFetch([
{
url: "/url",
errorResponse: true,
response: () => ({ error: "whoops" })
}
])
);
store.getState.mockReturnValue({
userContext: {}
});
const responsePromise = http.get("url", { sampleConfig: "sample" })
await expect(responsePromise).rejects.toEqual({ error: whoops });
});
Upvotes: 1