Vue-i18n: Unit tests not working since introducing vue-i18n

Created on 13 Jan 2018  Â·  6Comments  Â·  Source: kazupon/vue-i18n

I included internationalization in my project (I decided to use vue-i18n lib)
The translation works as expected, but when I run my unit tests, I have errors, note: The tests passed before adding vue-i18n.

My vue-i18n configuration (src/i18n/index.js):

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import fr from './fr'
import en from './en'

Vue.use(VueI18n)

export default new VueI18n({
  locale: 'en',
  fallbackLocale: 'en',
  messages: {
    en,
    fr
  }
})

The main.js:

import Vue from 'vue'
import Vuex from 'vuex'
import i18n from './i18n'
import App from './App'
import store from './store'
import router from './router'

Vue.use(Element)
Vue.use(Vuex)

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  i18n,
  store,
  router,
  template: '<App/>',
  components: { App }
})

This my component, which I test (Home.vue):

<template>
  <section class="hero">
    <div class="hero-body">
      <div class="container">
        <h1 class="title">Welcome to Server Client Project (STP)!</h1>
      </div>
      <div style="text-color: black;">{{ $t("general.hello") }}</div>
      or
      <div style="text-color: black;">{{ $i18n.t("general.hello") }}</div>
      or
      <div style="text-color: black;">{{ $i18n.messages.fr.general.hello }}</div>
    </div>
  </section>
</template>

<script>
export default {
  data() {
    return {}
  },
  methods: {}
}
</script>

This is the test (Home.spec.js):

import Vue from 'vue'
import Home from '@/components/Home'

// I've also tried with this 2 lines, but is the same results. :(  #####
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)

describe('Home.vue', () => {
  it('should render correct contents', () => {
    const Constructor = Vue.extend(Home)
    const vm = new Constructor().$mount()
    expect(vm.$el.querySelector('h1').textContent)
      .to.equal('Welcome to Server Client Project (STP)!')
  })
})

The errors I get:

13 01 2018 11:25:21.560:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket ch-UPyobpSLXRsYVAAAA with id 80198143
ERROR LOG: '[Vue warn]: Error in render: "TypeError: undefined is not an object (evaluating 'i18n._t')"

(found in <Root>)'
ERROR LOG: TypeError{stack: 'http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:13162:20
render@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:16593:29
_render@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:5265:26
updateComponent@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:3556:28
get@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:3906:29
Watcher@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:3895:15
mountComponent@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:3563:14
$mount@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:9220:24
$mount@http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:11581:20
http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7:16573:62
callFn@http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4481:25
run@http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4473:13
runTest@http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4969:13
http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:5075:19
next@http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4887:16
http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4897:11
next@http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4821:16
http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:4865:9
timeslice@http://localhost:9876/absolute/Users/vasilesambor/Documents/School/Sem2/Server-Client/server-client-project/node_modules/mocha/mocha.js?8bf1d1adf34e719cca6e8f6915b9cd6eabf83d6b:82:27', line: 13162, sourceURL: 'http://localhost:9876/base/index.js?ef5c3f3eb42f0c73db3ae13d5804bcc7a8a395e7'}

  Home.vue
    ✗ should render correct contents
    undefined is not a constructor (evaluating 'vm.$el.querySelector('h1')')
    webpack:///test/unit/specs/Home.spec.js:10:32 <- index.js:16575:32

PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.072 secs / 0.007 secs)
I looked around for other similar problems, but I couldn't find a clear solution.

Thank you!

Most helpful comment

You need to inject an i18n object when instantiating your component.

Using your example :

import Vue from 'vue'
import Home from '@/components/Home'

import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
const i18n = new VueI18n({});

describe('Home.vue', () => {
  it('should render correct contents', () => {
    const Constructor = Vue.extend(Home)
    const vm = new Constructor({i18n}).$mount()
    expect(vm.$el.querySelector('h1').textContent)
      .to.equal('Welcome to Server Client Project (STP)!')
  })
})

Now it creates a new VueI18n object and pass it to new Constructor.

All 6 comments

You need to inject an i18n object when instantiating your component.

Using your example :

import Vue from 'vue'
import Home from '@/components/Home'

import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
const i18n = new VueI18n({});

describe('Home.vue', () => {
  it('should render correct contents', () => {
    const Constructor = Vue.extend(Home)
    const vm = new Constructor({i18n}).$mount()
    expect(vm.$el.querySelector('h1').textContent)
      .to.equal('Welcome to Server Client Project (STP)!')
  })
})

Now it creates a new VueI18n object and pass it to new Constructor.

I already solve it: https://stackoverflow.com/questions/48238906/vue-project-tests-are-failing-when-i-added-vue-i18n-karma-mocha-phantomjs/48239256#48239256

@bost-h and yes, you are right, I didn't inject the component. Thank you!

Thanks @bost-h saved me a lot of time!

@vsambor hello!
we are testing components without Vue.extends(). Can you explain why this test doesn't work please

import Vue from "vue";

import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
const vueI18n= new VueI18n()
import {mount} from '@vue/test-utils'

import Demo from '../../../src/components/Demo'

it('vue-i18n test', async () => {
    const wrapper = mount(Demo, { 
        vueI18n,
    })
    // mount({ vueI18n,   ...Demo}) not works too

})

As you can see we use mount(component, options) syntax. And get the same error

TypeError: Cannot read property '_t' of undefined



  at Proxy.Vue.$t (node_modules/vue-i18n/dist/vue-i18n.common.js:179:17)
  at Proxy.render (src/components/Demo.vue:17:154)
  at VueComponent.Vue._render (node_modules/vue/dist/vue.runtime.common.dev.js:3532:22)
  at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4048:21)
  at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4459:25)
  at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4448:12)
  at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4055:3)
  at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8386:10)
  at init (node_modules/vue/dist/vue.runtime.common.dev.js:3112:13)
  at createComponent (node_modules/vue/dist/vue.runtime.common.dev.js:5952:9)
  at createElm (node_modules/vue/dist/vue.runtime.common.dev.js:5899:9)
  at VueComponent.patch [as __patch__] (node_modules/vue/dist/vue.runtime.common.dev.js:6449:7)
  at VueComponent.Vue._update (node_modules/vue/dist/vue.runtime.common.dev.js:3927:19)
  at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4048:10)
  at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4459:25)
  at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4448:12)
  at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4055:3)
  at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8386:10)
  at mount (node_modules/@vue/test-utils/dist/vue-test-utils.js:8649:21)
  at Object.<anonymous> (tests/unit/components/VueI18n.spec.js:11:21)
<template>
    <div>
        {{ $t('profile.lastName') }}
    </div>
</template>
<script>
    export default {

    }
</script>

Hi,
This solution works for me:

First, create a js file wich will create your component with all your extensions, for example GenerateComponent.js

import { shallowMount } from '@vue/test-utils'
import i18n from '@/i18n'
import router from '@/router'
import store from '@/store'

module.exports = {
  getRenderedComponent(Component, propsData) {
    let wrapper = null
    return wrapper = shallowMount(Component, { i18n, router, store, ability, propsData })
  }
}

Then, call the function in your testing file

import Upload from '@/components/Upload'
import Component from '../GenerateComponent'

describe('Upload', () => {
  it('should render correct contents', () => {
    const component = Component.getRenderedComponent(Upload)
    expect(component.classes()).toContain('upload')
  })
})

Hope it helps.

_Vue.prototype._i18n = i18n_ must be under the line _App.mpType = 'app'_

App.mpType = 'app'
Vue.prototype._i18n = i18n
Was this page helpful?
0 / 5 - 0 ratings