最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I test network errors in fetch api? - Stack Overflow

programmeradmin2浏览0评论

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?

Share Improve this question asked Jul 8, 2017 at 7:27 thedeliciousmuffinthedeliciousmuffin 8141 gold badge11 silver badges22 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

The 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.

发布评论

评论列表(0)

  1. 暂无评论