3

I have the following custom Axios instance:

import axios from 'axios'

export const BASE_URL = 'http://jsonplaceholder.typicode.com'

export default axios.create({
  baseURL: BASE_URL
})

With the corresponding service:

import http from './http'

export async function fetchUserPosts(id) {
  const reponse = await http.get(`/users/${id}/posts`)
  return reponse.data
}

And this is the test for said service:

import moxios from 'moxios'
import sinon from 'sinon'
import http from '@/api/http'
import { fetchUserPosts } from '@/api/usersService'

describe('users service', () => {
  beforeEach(() => {
    moxios.install(http)
  })

  afterEach(() => {
    moxios.uninstall(http)
  })

  it('fetches the posts of a given user', (done) => {
    const id = 1
    const expectedPosts = ['Post1', 'Post2']

    moxios.stubRequest(`/users/${id}/posts`, {
      status: 200,
      response: expectedPosts
    })

    const onFulfilled = sinon.spy()
    fetchUserPosts(1).then(onFulfilled)

    moxios.wait(() => {
      expect(onFulfilled.getCall(0).args[0].data).toBe(expectedPosts)
      done()
    })
  })
})

Which when executed using Karma + Jasmine raises the following error:

Uncaught TypeError: Cannot read property 'args' of null thrown

What I would like to test is that when the endpoint /users/{id}/posts is hit a mocked response is sent back. All this while using my custom axios instance http.

I've tried stubbing as the first example of the documentation of moxios shows. However I don't think that fits my use case, as I would like to check that the request is formed correctly in my service.

I've also tried with the following code, which works as expected, however I would like to test my service (which the following code does not do):

import axios from 'axios'
import moxios from 'moxios'
import sinon from 'sinon'

describe('users service', () => {
  beforeEach(() => {
    moxios.install()
  })

  afterEach(() => {
    moxios.uninstall()
  })

  it('fetches the posts of a given user', (done) => {
    const id = 1
    const expectedPosts = ['Post1', 'Post2']

    moxios.stubRequest(`/users/${id}/posts`, {
      status: 200,
      response: expectedPosts
    })

    const onFulfilled = sinon.spy()
    axios.get(`/users/${id}/posts`).then(onFulfilled)

    moxios.wait(() => {
      expect(onFulfilled.getCall(0).args[0].data).toBe(expectedPosts)
      done()
    })
  })
})

Any ideas on how could I fix the error?

César Alberca
  • 2,321
  • 2
  • 20
  • 32

1 Answers1

13

I know that is an old question but as I came across with it with the same problem, I'll post my approach:

You don't need to use sinon in this case, as you have an instance of axios, use it to configure moxios (as you already have done)

beforeEach(() => {
    moxios.install(http)
  })
  afterEach(() => {
    moxios.uninstall(http)
})

then you test your method like this:

it('test get', async () => {
     const expectedPosts = ['Post1', 'Post2']

     moxios.wait(() => {
          const request = moxios.requests.mostRecent()
          request.respondWith({ status: 200, response: expectedPosts }) //mocked response
     })

     const result = await fetchUserPosts(1)
     console.log(result) // ['Post1','Post2'] 
     expect(result).toEqual(expectedPosts)
})

That's it.

Regards

kboul
  • 13,836
  • 5
  • 42
  • 53
Elmer Dantas
  • 4,649
  • 5
  • 30
  • 36
  • Hey I am getting the Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. – ganesh kaspate Dec 21 '18 at 10:15
  • I can't help without seeing the code you're using but I think your problem is `async` tests...check your `it` signature. Check this link https://stackoverflow.com/questions/22604644/jasmine-async-callback-was-not-invoked-within-timeout-specified-by-jasmine-defa for more information – Elmer Dantas Dec 21 '18 at 14:17
  • @ElmerDantas: I am curious to know when to put the moxios.stubRequest outside of moxios.wait() and when to put it inside moxios.wait()? I am still trying to figure out how the whole mocking of a network call works. Is `stubRequest` the same as `respondWith`? Would your solution have worked if you had put the `request.respondWith` outside moxios.wait()? When does the code inside moxios.wait() actually get called? Thanks – Yeasir Arafat Majumder Sep 16 '19 at 11:58
  • @YeasirArafatMajumder `respondWith` is a function from a `request` (from `moxios.request`) `stubRequest` is a function from `moxios` that you can use together with `sinon`...With the later you can specify the exact URL you want to test but then you'll need `sinon` to help you. As far as I can tell, you have to execute the code inside `wait` as you have to wait until the async operation is finished before you can use the result. You can always read the [docs](https://github.com/axios/moxios) – Elmer Dantas Sep 17 '19 at 08:44