Search code examples
javascriptvue.jstestingjasmine

Testing Vue.js With Jasmine Not Using JS Modules


I've been asked to research unit testing Javascript on a legacy app that does not use JS modules (import/export). The app has JS object/prototypes in external .js files that are included via script src and more recently some Vue 2 components in .vue files using PHP include('mycomponent.vue').

All the examples for various unit testing frameworks assume JS modules are used. Can Vue be tested without modules?

I'm a bit lost and I am looking for direction, advice, and/or code examples of tests.

Thanks. Your help is much appreciated.

Here is a sample component:

PHP view (.phtml)

<?php include 'mycomponent.vue' ?>

<script type="text/javascript">
    Vue.use(Vuex);
    Vue.use(BootstrapVue);
    Vue.component('v-select', VueSelect.VueSelect);

    const i18n = new VueI18n({
        locale: 'en',
        dateTimeFormats: {
            en: {
                long: {
                    year: 'numeric', month: 'long', day: 'numeric',
                    hour: 'numeric', minute: 'numeric',
                    timezone: 'EST',
                },
            },
        },
        messages: {
            en: <?= json_encode([
                'messages' => 'etc'
            ]) ?>,
        }
    });

    const store = new Vuex.Store({
        state: {
            //etc
        }
    });

    new Vue({
        el: '#wrapper',
        store,
        i18n,
        data() {
            return <?= json_encode([
                'something' = [
                bits: 'Bob'
                ]
            ]) ?>;
        },
    });
</script>

<div id="wrapper" v-cloak>
    <mycomponent
        :something="something"
    ></mycomponent>
</div>

mycomponent.vue

<template id="mycomponent_tmpl">
  <div>
    {{currentMessage}}
  </div>
</template>



<script>
Vue.component('mycomponent', {
  template: '#mycomponent_tmpl',

  props: {
    something: {
      type: Object,
      required: true,
    }
  },

  data() {
    return {
        this.message = 'Hello World'
    }
  },

  created() {
    
  },

  mounted() {

  },

  watch: {

  },

  computed: {
    currentMessage() {
        return this.message + ' ' + this.something.bits;
    }
  },

  methods: {
    
  }
});
</script>

Solution

  • So I eventually answered my own question here. Hope this helps someone else that is adding vue into a legacy app and wants to do some testing. It's not perfect as calling methods in the test doesn't seem to update the outerHTML at expect time although if I output the vue instance to the browser console the outHTML is updated then. Not sure how to access the changes during the tests yet but this is a decent start.

    hello-world.vue

    <template id="hello_world_tmpl">
      <div>{{getMessage}}</div>
    </template>
    
    <script>
    Vue.component('HelloWorld', {
      template: '#hello_world_tmpl',
      props: {
        message: {
          type: String,
          required: true,
        }
      },
      data() {
        return {
          msg: this.message
        };
      },
      computed: {
        getMessage() {
          return this.msg;
        }
      },
      methods: {
        newMessage(msg) {
          this.msg = msg;
        }
      }
    });
    </script>
    

    I used php include in the Jasmine SpecRunner to add the vue file

    Spec file

    it('HelloWorld should not be null', function() {
        let vm = new Vue({
            template: `<HelloWorld message="Hi There!"></HelloWorld>`
        }).$mount();
    
        expect('<div>Hi There!</div>').toEqual(vm.$el.outerHTML);
    
        vm.$children[0].newMessage('Test');
        expect('Test').toEqual(vm.$children[0].msg);
    });