Jest: Mocking Superagent

Created on 22 Jan 2015  路  19Comments  路  Source: facebook/jest

Has anyone had any luck getting a mock for superagent that works?

My code looks like

        .get("ENDPOINT")
        .accept("json")
        .end(function(err, results) {
          if (err || !results.ok) return res.status(500).send(err || results.status);

          return res.status(200).send(results.body);
        });

It yells at me about all sorts of fun stuff like Buffer of undefined. I found a superagent manual mock on here, but when I install it, it complains that request has no method .get. I don't think the Mock works for the latest superagent, or maybe I don't understand how to use it. does anyone have thoughts?

Most helpful comment

Hi,
I know it has been a while since this issue has been opened, and closed.
But I used this solution and I ran in a problem while using promises, chaining the .then

Here is my updated version of the mock proposed by @pherris

// mock for superagent - __mocks__/superagent.js

let mockDelay;
let mockError;
let mockResponse = {
  status() {
    return 200;
  },
  ok() {
    return true;
  },
  body: {},
  get: jest.genMockFunction(),
  toError: jest.genMockFunction(),
};

const createRequestStub = (obj) => jest.fn(() => obj);

function Request() {
  let self = this;
  self.mockResponse = mockResponse;
  self.mockDelay = mockDelay;
  self.mockError = mockError;

  self.post = createRequestStub(self);
  self.get = createRequestStub(self);
  self.send = createRequestStub(self);
  self.query = createRequestStub(self);
  self.field = createRequestStub(self);
  self.set = createRequestStub(self);
  self.accept = createRequestStub(self);
  self.timeout = createRequestStub(self);
  self.then = (cb) => {
    return new Promise((resolve, reject) => {
      if (self.mockError) {
        return reject(self.mockError);
      }
      return resolve(cb(self.mockResponse));
    });
  };
  self.end = jest.genMockFunction().mockImplementation(function (callback) {
    if (self.mockDelay) {
      this.delayTimer = setTimeout(callback, 0, self.mockError, self.mockResponse);

      return;
    }

    callback(self.mockError, self.mockResponse);
  });
  //expose helper methods for tests to set
  self.__setMockDelay = (boolValue) => {
    self.mockDelay = boolValue;
  },
  self.__setMockResponse = (mockRes) => {
    self.mockResponse = mockRes;
  },
  self.__setMockError = (mockErr) => {
    self.mockError = mockErr;
  }
};

module.exports = new Request();

It allows for promise chaining, but also have stubs on get, post, etc, to be able to verify how many times it has been called, and the argument passed.

I hope it can be of help to someone

All 19 comments

+1

getting the same problem. The error is "Cannot read property 'buffer' of undefined" and looks like it's coming from superagent/node_modules/debug/node.js (using version 0.21.0 of superagent) ..I would say it's a problem with https://github.com/visionmedia/debug but there isn't any instance of "buffer" anywhere in debug..

+1 Same problem here.

I got the mock provided here: http://bl.ocks.org/simenbrekken/b6282f713605b619834f to work by putting it in the __mocks__ folder.

But that mock doesn't provide the convenience methods like get/post/put/etc. I had a similar problem promisifying superagent and getting those functions to work. What I ended up doing is not using the convenience methods and instead using the more constructory method.

e.g. Instead of

request.get('/user').end()

I did

request('GET', '/user').end()

This might be a bit of a pain if you have lots of places to change, but it's been working for me and I don't mind the syntax.

FWIW, I only had luck with chaining methods for a POST when I cribbed the definition of superagent from the original source into the mock:

var superagent = jest.genMockFunction().mockImplementation(function(method, url) {
  // callback
  if ('function' == typeof url) {
    return new Request('GET', method).end(url);
  }

  // url first
  if (1 == arguments.length) {
    return new Request('GET', method);
  }

  return new Request(method, url);
})

I'm using superagent ^1.1.0 and was able to get my tests working with this mock: https://gist.github.com/pherris/aa74aa9b8b1a55ea053b

'use strict';

//mock for superagent - __mocks__/superagent.js

var mockDelay;
var mockError;
var mockResponse = {
  status() { 
    return 200; 
  },
  ok() { 
    return true; 
  },
  get: jest.genMockFunction(),
  toError: jest.genMockFunction()
};

var Request = {
  post() {
    return this;
  },
  get() {
    return this;
  },
  send() {
    return this;
  },
  query() {
    return this;
  },
  field() {
    return this;
  },
  set() {
    return this;
  },
  accept() {
    return this;
  },
  timeout() {
    return this;
  },
  end: jest.genMockFunction().mockImplementation(function(callback) {
    if (mockDelay) {
      this.delayTimer = setTimeout(callback, 0, mockError, mockResponse);

      return;
    }

    callback(mockError, mockResponse);
  }),
  //expose helper methods for tests to set
  __setMockDelay(boolValue) {
    mockDelay = boolValue;
  },
  __setMockResponse(mockRes) {
    mockResponse = mockRes;
  },
  __setMockError(mockErr) {
    mockError = mockErr;
  }
};

module.exports = Request;

My app code:

  request.post(url)
        .send(params)
        .timeout(TIMEOUT)
        .end(function(err, res) {
          if (err) {
            defer.reject(err);
          }
          defer.resolve(res.body);
      });

This mock is also working for me :+1:

Worked for me too! Thanks for sharing

Where exactly do I place this __mocks__folder? I'm having ad hard time figuring this out.

@9Dave9 copy that mock code, put it in superagent.js in a __mocks__ in the root of where you are telling jest to look for __tests__ folders.

@browniefed - Thank you.

Can verify that @pherris' mock works on superagent 1.3.0. I'm using CoffeeScript so had to rewrite it in that - here's a Gist in case it's helpful for anyone. Thanks for this, really helped me out. :+1:

https://gist.github.com/JoelOtter/b97d207acbbca414baba

The mock that people are using here is working well, so closing this issue.

If you're using the above mock, please note this bug:

  __setMockError(mockErr) {
    mockErr = mockErr;
  }

Correct it to

  __setMockError(mockErr) {
    //     VV
    mockError = mockErr;
    //     ^^
  }

thx @MrNice - updated

No worries, eslint's static linter saves the day again 馃憤

Hi,
I know it has been a while since this issue has been opened, and closed.
But I used this solution and I ran in a problem while using promises, chaining the .then

Here is my updated version of the mock proposed by @pherris

// mock for superagent - __mocks__/superagent.js

let mockDelay;
let mockError;
let mockResponse = {
  status() {
    return 200;
  },
  ok() {
    return true;
  },
  body: {},
  get: jest.genMockFunction(),
  toError: jest.genMockFunction(),
};

const createRequestStub = (obj) => jest.fn(() => obj);

function Request() {
  let self = this;
  self.mockResponse = mockResponse;
  self.mockDelay = mockDelay;
  self.mockError = mockError;

  self.post = createRequestStub(self);
  self.get = createRequestStub(self);
  self.send = createRequestStub(self);
  self.query = createRequestStub(self);
  self.field = createRequestStub(self);
  self.set = createRequestStub(self);
  self.accept = createRequestStub(self);
  self.timeout = createRequestStub(self);
  self.then = (cb) => {
    return new Promise((resolve, reject) => {
      if (self.mockError) {
        return reject(self.mockError);
      }
      return resolve(cb(self.mockResponse));
    });
  };
  self.end = jest.genMockFunction().mockImplementation(function (callback) {
    if (self.mockDelay) {
      this.delayTimer = setTimeout(callback, 0, self.mockError, self.mockResponse);

      return;
    }

    callback(self.mockError, self.mockResponse);
  });
  //expose helper methods for tests to set
  self.__setMockDelay = (boolValue) => {
    self.mockDelay = boolValue;
  },
  self.__setMockResponse = (mockRes) => {
    self.mockResponse = mockRes;
  },
  self.__setMockError = (mockErr) => {
    self.mockError = mockErr;
  }
};

module.exports = new Request();

It allows for promise chaining, but also have stubs on get, post, etc, to be able to verify how many times it has been called, and the argument passed.

I hope it can be of help to someone

when I change module.exports = Request; to export default Request test run failed. Manual mock look like not work , any solution for this problem. Thanks you

I found if only mock superagent.get(), can check the answer in how-do-i-mock-async-fetches-with-jest, author is Yevhenii Herasymchuk. He used the syntax sugar jest.fn().mockResolvedValue.

MyComponent.spec.js

import React from 'react'
import superagent from 'superagent-bluebird-promise'
import { shallow } from 'enzyme'
import MyComponent from './'

test('Render the list from ajax', async () => {
  superagent.get = jest.fn().mockResolvedValue({
    body:[
       {id: 1, content: 'AAA'},
       {id: 2, content: 'BBB'}
  ]})

  const wrapper = await shallow(<MyComponent/>)
  expect(wrapper.find('p')).toHaveLength(2)
})

MyComponent.jsx

import React from 'react'
import superagent from 'superagent-bluebird-promise'

export default class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
    responseArr: []
    }
  }
  componentDidMount () {
    superagent.get(THE_REQUEST_URL)
    .then(({ body }) => {
      this.setState({responseArr: body})
    })
   .catch((err) => {
      console.log('Oops! ', err)
    })
  }

  render() {
    return (
      <div>{
          this.state.responseArr.map(item => (
              <p key={item.id}>{item.content}</p>
           ))
       }</div>
    )}
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

kgowru picture kgowru  路  3Comments

paularmstrong picture paularmstrong  路  3Comments

gustavjf picture gustavjf  路  3Comments

kentor picture kentor  路  3Comments

stephenlautier picture stephenlautier  路  3Comments