Reputation: 13262
I'm working with an API that doesn't return anything "error-like" for an incorrect login (just a normal object with a code -- incorrect_password
or invalid_username
-- an HTML message), so in my API calling function I'm turning the code into an error:
export async function loginWithApi(creds) {
try {
const res = await axios.get(ApiUrls.login, { params: creds });
if (res.data.data) {
return res.data;
} else if (res.data.code) {
throw Error(res.data.code.titleize());
} // else, it should be an actual error
} catch (err) {
return err;
}
}
This works correctly, throws correctly, returns an Error when it should.
However, when testing my saga generator action that calls this function, the error isn't being caught, it's going unabated through the try
block:
export function* loginSaga({ username, password }) {
const creds = { username, password };
try {
const res = yield call(loginWithApi, creds);
console.log(res);
yield put({ type: "LOGIN_SUCCESS", user: res.data });
} catch (error) {
yield put({ type: "LOGIN_FAILURE", error });
}
}
describe("login action", () => {
let gen;
afterEach(() => {
expect(gen.next().done).toBe(true);
});
it("should return a user object on a successful login", () => {
gen = loginSaga(success.creds);
gen.next(); // call api
expect(gen.next(mockResponse.success).value).toEqual(
put({ type: "LOGIN_SUCCESS", user: mockResponse.success.data })
);
});
it("should return an error when passed an invalid username", () => {
gen = loginSaga(badUser.creds);
gen.next(); // call api
// mockReponse.usernameError: Error("Invalid Username")
expect(gen.next(mockResponse.usernameError).value).toEqual(
put({ type: "LOGIN_FAILURE", error: "Invalid Username" })
);
});
it("should return an error when passed an invalid password", () => {
gen = loginSaga(badPw.creds);
gen.next(); // call api
// mockResponse.passwordError: Error("Incorrect Password"),
expect(gen.next(mockResponse.passwordError).value).toEqual(
put({ type: "LOGIN_FAILURE", error: "Incorrect Password" })
);
});
});
● Saga Actions › login action › should return an error when passed an invalid username
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
Object {
"@@redux-saga/IO": true,
"combinator": false,
"payload": Object {
"action": Object {
- "error": "Invalid Username",
- "type": "LOGIN_FAILURE",
+ "type": "LOGIN_SUCCESS",
+ "user": undefined,
},
"channel": undefined,
},
"type": "PUT",
● Saga Actions › login action › should return an error when passed an invalid password
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
Object {
"@@redux-saga/IO": true,
"combinator": false,
"payload": Object {
"action": Object {
- "error": "Incorrect Password",
- "type": "LOGIN_FAILURE",
+ "type": "LOGIN_SUCCESS",
+ "user": undefined,
},
"channel": undefined,
},
"type": "PUT",
}
Logging confirms that the loginSaga
function is receiving an Error
in the second two tests. I can't quite determine why that error isn't being caught.
Upvotes: 0
Views: 57
Reputation: 23685
Finally got it.
So you need make generator think that Exception happened for one of its yield
. To make that we have generator.prototype.throw()
.
So next code should work as expected:
it("should return an error when passed an invalid username", () => {
gen = loginSaga(badUser.creds);
gen.next(); // call api
// mockReponse.usernameError: Error("Invalid Username")
expect(gen.throw(mockResponse.usernameError).value).toEqual(
put({ type: "LOGIN_FAILURE", error: "Invalid Username" })
);
});
Upvotes: 1