简体   繁体   中英

How do you stub fetch api request

I am having a problem with stubbing/testing function that is using fetch.

Using simple example:

export const clickTimeseries => {
  return fetch('...url...')
    .then(response => {
      if(response.status == 200)
        return response.json()
      else
        throw 'something'
    })
    .then(json => {
      return {
        success: true,
        data: json,
      }
    })
    .catch(err => {
      return {
        success: false,
        error: err,
      }
    })
}

And my test:

import { expect } from 'chai'
import sinon from 'sinon' 

import Promise from 'es6-promise' 
Promise.polyfill() 

import 'whatwg-fetch'

import clickTimeseries from './above'

const jsonOK = body => {  
  const mockResponse = new Response(JSON.stringify(body), {  
    status: 200,
    headers: { 
      'Content-type': 'application/json'
    }
  })

  return Promise.resolve(mockResponse) 
}

describe('APIs', () => {  
  describe('Click timeseries', () => { 
    it('builds a correct data on success', () => { 
      sinon.stub(window, 'fetch').returns(jsonOK({stuff: [1,2,3]})) 

      expect(clickTimeseries()).to.eq({ 
        success: true,
        data: {stuff: [1,2,3]}
      })
    })
  })
})

I am getting error:

expected { Object (, _state, ...) } to equal { success: true, data: {stuff: [ 1, 2, 3, 4 ] }}

It looks like spendTimeseries returns promise, instead of the result of calling both then blocks.

How would you have to setup your test to have it pass?

It took some time of playing with your code until I realized what was wrong, because everything looked correct. And in fact, it was. Except for one thing: the result you are testing for is delivered asynchronously, but you are testing for it synchronously. That means you need to change your test to be async.

I am assuming you are using Mocha as your test runner, and it has two ways of testing async code. One standard way for any async code, plus one special way of handling Promises. You can use whatever fits your style.

If you have any async code where the result is delivered at a later time, this is the general formula:

it('should test an async function', (callback) => {
    const expectedResult = 42;
    doSomethingAsync((result) => {
        try{
            expect(expectedResult).to.equal(result);
            callback();
        } catch(err) {
            callback(err);
        }
    })
});

For a promise returning function this would look like this:

it('should test a promise', (callback) => {
    const expectedResult = 42;
    doSomethingAsync().then((result) => {
        expect(expectedResult).to.equal(result);
        callback();
    }).catch(callback);
});

Mocha has some sugar for promises making it possible to write the last function like this (no callback in function wrapper!):

it('should test a promise', () => {
    const expectedResult = 42;
    return doSomethingAsync().then((result) => {
        expect(expectedResult).to.equal(result);
    })
});

In conclusion: just change the test to read like this:

return clickTimeseries().then( result => {
    expect(result).to.eq({ 
        success: true,
        data: {stuff: [1,2,3]}
    })
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM