I have been successfully able to test a resolved promise on a simple application I have been working on to learn ES6 but been having issues testing the case where there may be network errors.
I wrote this test case:
import {Weather} from '../js/weather';
import chai from 'chai';
import sinon from 'sinon';
import * as chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
let assert = chai.assert;
let should = chai.should;
describe('weatherbot-1', function () {
beforeEach(function () {
sinon.stub(window, 'fetch');
let data = '{"cod": "400", "message": "Nothing to geocode"}';
let res = new window.Response(data, {
ok: false,
status: 400,
headers: {
'Content-type': 'application/json'
}
});
window.fetch.returns(Promise.reject(res));
});
afterEach(function () {
window.fetch.restore();
});
it('should ensure that promise is rejected', function () {
let weather = new Weather(0, 0);
return assert.isRejected(weather.getWeather(), 'Rejected');
});
});
The method in question is:
getWeather() {
let headers = new Headers();
let init = {
method: 'GET',
headers: headers,
cache: 'default'
};
let url = 'http://localhost:8080/weather?lat=' + '' + '&lon=' + this.longitude;
return fetch(url, init).then(function (response) {
return response.json();
}).catch((error) => {
return error;
});
}
For testing the promise, I am using chai-as-promised
& chai
with mocha
& sinon
to stub the fetch
api.
Whenever I run the test I get this error:
AssertionError: expected promise to be rejected with an error including 'Rejected' but it was fulfilled with { type: 'default',
url: '',
redirected: false,
status: 400,
ok: false,
statusText: 'OK',
headers:
{ append: [Function: append],
delete: [Function: delete],
get: [Function: get],
getAll: [Function: getAll],
has: [Function: has],
set: [Function: set],
keys: [Function: keys],
values: [Function: values],
entries: [Function: entries],
forEach: [Function: forEach] },
body: {},
bodyUsed: false,
clone: [Function: clone],
arrayBuffer: [Function: arrayBuffer],
blob: [Function: blob],
json: [Function: json],
text: [Function: text] }
From what it looks like, the Promise.reject()
may not be working properly. Is there any other way I could test network errors?
I have been successfully able to test a resolved promise on a simple application I have been working on to learn ES6 but been having issues testing the case where there may be network errors.
I wrote this test case:
import {Weather} from '../js/weather';
import chai from 'chai';
import sinon from 'sinon';
import * as chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
let assert = chai.assert;
let should = chai.should;
describe('weatherbot-1', function () {
beforeEach(function () {
sinon.stub(window, 'fetch');
let data = '{"cod": "400", "message": "Nothing to geocode"}';
let res = new window.Response(data, {
ok: false,
status: 400,
headers: {
'Content-type': 'application/json'
}
});
window.fetch.returns(Promise.reject(res));
});
afterEach(function () {
window.fetch.restore();
});
it('should ensure that promise is rejected', function () {
let weather = new Weather(0, 0);
return assert.isRejected(weather.getWeather(), 'Rejected');
});
});
The method in question is:
getWeather() {
let headers = new Headers();
let init = {
method: 'GET',
headers: headers,
cache: 'default'
};
let url = 'http://localhost:8080/weather?lat=' + '' + '&lon=' + this.longitude;
return fetch(url, init).then(function (response) {
return response.json();
}).catch((error) => {
return error;
});
}
For testing the promise, I am using chai-as-promised
& chai
with mocha
& sinon
to stub the fetch
api.
Whenever I run the test I get this error:
AssertionError: expected promise to be rejected with an error including 'Rejected' but it was fulfilled with { type: 'default',
url: '',
redirected: false,
status: 400,
ok: false,
statusText: 'OK',
headers:
{ append: [Function: append],
delete: [Function: delete],
get: [Function: get],
getAll: [Function: getAll],
has: [Function: has],
set: [Function: set],
keys: [Function: keys],
values: [Function: values],
entries: [Function: entries],
forEach: [Function: forEach] },
body: {},
bodyUsed: false,
clone: [Function: clone],
arrayBuffer: [Function: arrayBuffer],
blob: [Function: blob],
json: [Function: json],
text: [Function: text] }
From what it looks like, the Promise.reject()
may not be working properly. Is there any other way I could test network errors?
2 Answers
Reset to default 4The problem is in getWeather
, not the test:
return fetch(url, init)
.then(function (response) {
return response.json();
})
.catch((error) => {
return error;
})
Promise#catch
returns a resolved Promise, because its job is to handle errors. The rest of the application should be able to function after catching a rejection, just like with try/catch
.
If you want the rejection to reach the test, your code shouldn't catch the rejection:
return fetch(url, init)
.then(function (response) {
return response.json();
})
In general you should only catch
where you can properly handle the error. In this example you might want to handle the rejection in a view where you can display an error message.
Also, your code models an invalid situation. fetch
returns a resolved Promise for all valid HTTP responses including non-200 status.
It does reject when it cannot make a connection at all, e.g. fetch("http://sdfdsfsd")
. In this case it rejects with an Error
object.
To properly test a fetch
rejection you should simulate this condition and have the stub return Promise.reject(new Error("a message"))
.
The catch clause in the getWeather
function returns a new, fulfilled promise. Basically, catch takes away your ability to test for rejection. What you can do, is use a spy for the rejection handler, and then test it is called.