Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests not working since introducing vue-i18n #276

Closed
vsambor opened this issue Jan 13, 2018 · 7 comments
Closed

Unit tests not working since introducing vue-i18n #276

vsambor opened this issue Jan 13, 2018 · 7 comments

Comments

@vsambor
Copy link

vsambor commented Jan 13, 2018

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!

@bost-h
Copy link

bost-h commented Jan 19, 2018

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.

@vsambor
Copy link
Author

vsambor commented Jan 19, 2018

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!

@vsambor vsambor closed this as completed Jan 19, 2018
@zleight1
Copy link

zleight1 commented Feb 9, 2018

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

@alexey2baranov
Copy link

alexey2baranov commented Dec 20, 2019

@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>

@k-slash
Copy link

k-slash commented Apr 24, 2020

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.

@silianpan
Copy link

silianpan commented Jul 23, 2020

Vue.prototype._i18n = i18n must be under the line App.mpType = 'app'

App.mpType = 'app'
Vue.prototype._i18n = i18n

@imapolaris
Copy link

thanks @bost-h, it works for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants