Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js - Testing asynchronously returned data

I have the following example:

<!DOCTYPE html>
<html>
  <head>
    <title>Mocha</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="mocha.css" />
  </head>
  <body>
    <div id="mocha"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/3.1.2/mocha.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.5.0/chai.min.js"></script>

    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.0.3/vue-resource.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/1.15.4/sinon.js"></script>

    <script>mocha.setup('bdd');</script>
    <script>
     "use strict";
     var assert = chai.assert;
     var should = chai.should();

     var vm = new Vue({
     data: {
         message: "Hello"
     },

     methods: {
         loadMessage: function() {
         this.$http.get("/get").then(
             function(value) {
             this.message = value.body.message;
             });
         },
     }
     });
     describe('getMessage', function() {
     let server;
     beforeEach(function () {
         server = sinon.fakeServer.create();
     });

     it("should get the message", function(done) {
         server.respondWith([200, { 'Content-Type': 'application/json' },
                 JSON.stringify({message: "Test"})]);

         vm.message.should.equal("Hello");
         vm.loadMessage();
         server.respond();
         setTimeout(function() {
         // This one works, but it's quirky and a possible error is not well represented in the HTML output.
         vm.message.should.equal("Test");
         done();
         }, 100);

         // This one doesn't work
         //vm.message.should.equal("Test");
     });
     });
    </script>
    <script>
      mocha.run();
    </script>
  </body>
</html>

I want to test that Vue asynchronously gets data from the server. Though, I mock out the actual HTTP request with Sinon FakeServer.

Naturally, directly after the call to loadMessage, the message is not yet set. I could use a timeout function for the test, but I believe there should be a better method. I've looked into respondImmediately, but it did not change. Also, there is the possibility to call a done() function. However, as I understand this, this done would need to be called within the loadMessage function, hence modifying the code under test.

What is the correct approach to handle this problem?

Edit: I have found at least a partial solution, but it seems to be still messy: call the done() function in the mocha unit test. When the assertion fails, it is at least shown in the HTML output. However, the assertion message is not as clear as in a normal test. Also, the technique still seems messy to me.

like image 816
Maximilian Matthé Avatar asked Nov 08 '22 06:11

Maximilian Matthé


1 Answers

Since updating of vue component is done asynchronously you would need to use

// Inspect the generated HTML after a state update
  it('updates the rendered message when vm.message updates', done => {
    const vm = new Vue(MyComponent).$mount()
    vm.message = 'foo'
    // wait a "tick" after state change before asserting DOM updates
    Vue.nextTick(() => {
      expect(vm.$el.textContent).toBe('foo')
      done()
    })
  })

Taken from official docs.

like image 73
peaceman Avatar answered Nov 15 '22 11:11

peaceman