8

I'm really struggling trying to test a request in VueJS using Mocha/Chai-Sinon, with Axios as the request library and having tried a mixture of Moxios and axios-mock-adaptor. The below examples are with the latter.

What I'm trying to do is make a request when the component is created, which is simple enough.

But the tests either complain about the results variable being undefined or an async timout.

Am I doing it right by assigning the variable of the getData() function? Or should Ireturn` the values? Any help would be appreciated.

Component

  // Third-party imports
  import axios from 'axios'
  // Component imports
  import VideoCard from './components/VideoCard'

  export default {
    name: 'app',
    components: {
      VideoCard
    },
    data () {
      return {
        API: '/static/data.json',
        results: null
      }
    },
    created () {
      this.getData()
    },
    methods: {
      getData: function () {
        // I've even tried return instead of assigning to a variable
        this.results = axios.get(this.API)
          .then(function (response) {
            console.log('then()')
            return response.data.data
          })
          .catch(function (error) {
            console.log(error)
            return error
          })
      }
    }
  }

Test

import Vue from 'vue'
import App from 'src/App'

import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'

let mock = new MockAdapter(axios)

describe('try and load some data from somewhere', () => {
  it('should update the results variable with results', (done) => {
    console.log('test top')
    mock.onGet('/static/data.json').reply(200, {
      data: {
        data: [
          { id: 1, name: 'Mexican keyboard cat' },
          { id: 2, name: 'Will it blend?' }
        ]
      }
    })

    const VM = new Vue(App).$mount

    setTimeout(() => {
      expect(VM.results).to.be.null
      done()
    }, 1000)
  })
})
Lee Davies
  • 313
  • 1
  • 5
  • 9

2 Answers2

7

I am not sure about moxios mock adaptor, but I had a similar struggle. I ended up using axios, and moxios, with the vue-webpack template. My goal was to fake retreiving some blog posts, and assert they were assigned to a this.posts variable.

Your getData() method should return the axios promise like you said you tried - that way, we have some way to tell the test method the promise finished. Otherwise it will just keep going.

Then inside the success callback of getData(), you can assign your data. So it will look like

return axios.get('url').then((response) {
   this.results = response
})

Now in your test something like

it('returns the api call', (done) => {
    const vm = Vue.extend(VideoCard)
    const videoCard = new vm()

    videoCard.getData().then(() => {
        // expect, assert, whatever
    }).then(done, done)
)}

note the use of done(). That is just a guide, you will have to modify it depending on what you are doing exactly. Let me know if you need some more details. I recommend using moxios to mock axios calls.

Here is a good article about testing api calls that helped me.

https://wietse.loves.engineering/testing-promises-with-mocha-90df8b7d2e35#.yzcfju3qv

lmiller1990
  • 925
  • 2
  • 12
  • 22
  • Thanks for the reply! You definitely helped me in the general direction; and I've posted my answer below. Thanks again! – Lee Davies Jan 21 '17 at 13:09
  • glad you got it! Nice job, stubbing the request is definitely the way to go. great job posting your answer too, that'll help others out. you can mark the answer as accepted if you are happy with it (: – lmiller1990 Jan 21 '17 at 16:07
  • Weird, axios-mock-adapter doesn't work for me neither, promises don't seem to get fulfilled. Moxios does work! – Busata Feb 06 '17 at 09:13
5

So massive kudos to xenetics post above, who helped in pointing me in the right direction.

In short, I was trying to access the data incorrectly, when I should have been using the $data property

I also dropped axios-mock-adaptor and went back to using moxios.

I did indeed have to return the promise in my component, like so;

getData: function () {
  let self = this
  return axios.get(this.API)
    .then(function (response) {
      self.results = response.data.data
    })
    .catch(function (error) {
      self.results = error
    })
}

(Using let self = this got around the axios scope "problem")

Then to test this, all I had to do was stub the request (after doing the moxios.install() and moxios.uninstall for the beforeEach() and afterEach() respectively.

it('should make the request and update the results variable', (done) => {
  moxios.stubRequest('./static/data.json', {
    status: 200,
    responseText: {
      data: [
        { id: 1, name: 'Mexican keyboard cat' },
        { id: 2, name: 'Will it blend?' }
      ]
    }
  })

  const VM = new Vue(App)
  expect(VM.$data.results).to.be.null

  VM.getData().then(() => {
    expect(VM.$data.results).to.be.an('array')
    expect(VM.$data.results).to.have.length(2)
  }).then(done, done)
})
tony19
  • 125,647
  • 18
  • 229
  • 307
Lee Davies
  • 313
  • 1
  • 5
  • 9