Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing HTTP request with Vue, Axios, and Mocha

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)
  })
})
like image 840
Lee Davies Avatar asked Jan 20 '17 21:01

Lee Davies


2 Answers

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

like image 80
lmiller1990 Avatar answered Sep 18 '22 14:09

lmiller1990


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)
})
like image 41
Lee Davies Avatar answered Sep 18 '22 14:09

Lee Davies