Vuetify: 1.1.9
Vue: 2.5.2
Vue Test Utils: 1.0.0-beta.23
Browsers: JSDom
OS: High Sierra 10.13.4
Companies.vue
<template>
<div>
<v-container grid-list-md text-xs-center>
<v-layout row wrap>
<v-flex xs12>
<v-card>
<v-data-table
:headers="headers"
:items="items"
:loading="loading"
class="elevation-1"
>
<v-progress-linear slot="progress" color="blue" indeterminate></v-progress-linear>
<template slot="headerCell" slot-scope="props">
<v-tooltip bottom>
<span slot="activator">
{{ props.header.text }}
</span>
<span>
{{ props.header.text }}
</span>
</v-tooltip>
</template>
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td>{{ props.item.contactName }}</td>
<td>{{ props.item.contactEmail }}</td>
<td class="justify-center layout px-0">
<v-icon
small
class="mr-2"
@click="viewItem(props.item)"
>
domain
</v-icon>
<v-icon
small
class="mr-2"
@click="editItem(props.item)"
>
edit
</v-icon>
<v-icon
small
@click="deleteItem(props.item)"
>
delete
</v-icon>
</td>
</template>
<template slot="no-data">
<v-btn color="primary" flat @click="createNewCompany">
Add company
<v-icon right dark>add_box</v-icon>
</v-btn>
</template>
</v-data-table>
</v-card>
</v-flex>
<v-flex xs12>
<v-btn
color="primary"
class="white--text"
@click="createNewCompany"
>
Create New Company
<v-icon right dark>domain</v-icon>
</v-btn>
</v-flex>
</v-layout>
<ConfirmModal ref="Confirm"></ConfirmModal>
</v-container>
</div>
</template>
<script>
import vuetifyToast from 'vuetify-toast';
import { getCompanies, deleteCompany } from '@/services/database/company';
import { ConfirmModal } from '@/components/commons';
export default {
name: 'companies',
data() {
return {
headers: [
{ text: 'Company', align: 'center', value: 'name' },
{ text: 'Contact Name', align: 'center', value: 'contactName' },
{ text: 'Contact Email', align: 'center', value: 'contactEmail' },
{ text: 'Actions', value: 'name', sortable: false },
],
items: [],
loading: false,
selectedItem: null,
};
},
mounted() {
this.loadInfo();
},
methods: {
loadInfo() {
this.items = [];
this.loading = true;
getCompanies()
.then(companies => {
this.items = companies.map(c => ({
id: c.id,
name: c.value.name,
contactName: c.value.contact.name,
contactEmail: c.value.contact.email,
}));
this.loading = false;
})
.catch(() => {
this.loading = false;
vuetifyToast.error('Error getting companies');
});
},
viewItem(item) {
this.$router.push({
name: 'company',
params: { companyId: item.id, originPage: 'companies' },
});
},
editItem(item) {
this.$router.push({
name: 'companyDetail',
params: { companyId: item.id, originPage: 'companies' },
});
},
deleteItem(item) {
this.selectedItem = item;
this.$refs.Confirm.open(
`Are you sure you want to delete company ${this.selectedItem.name}?`,
this.removeCompany,
);
},
removeCompany() {
deleteCompany(this.selectedItem.id)
.then(() => {
vuetifyToast.success(`Company ${this.selectedItem.name} was deleted`);
this.items = this.items.filter(item => item.id !== this.selectedItem.id);
this.selectedItem = null;
})
.catch(() => {
vuetifyToast.error(`Error deleting company ${this.selectedItem.name}`);
});
},
createNewCompany() {
this.$router.push({
name: 'companyDetail',
params: { companyId: 'new', originPage: 'companies' },
});
},
},
components: {
ConfirmModal,
},
};
</script>
Companies.spec.js
import Vue from 'vue';
import Vuetify from 'vuetify';
import VueRouter from 'vue-router';
import flushPromises from 'flush-promises';
import { mount, createLocalVue } from '@vue/test-utils';
import VeeValidate from 'vee-validate';
import * as companiesDatabase from '@/services/database/company';
import Companies from './Companies';
Vue.config.silent = true;
const localVue = createLocalVue();
localVue.use(VueRouter);
localVue.use(Vuetify);
localVue.use(VeeValidate);
describe('Companies', () => {
const routes = [
{ path: '/', name: 'home' },
];
const router = new VueRouter({
routes,
});
let wrapper;
beforeAll(() => {
console.log('version', Vuetify.version);
const { getComputedStyle } = global;
global.getComputedStyle = function getComputedStyleStub(el) {
return {
...getComputedStyle(el),
transitionDelay: '',
transitionDuration: '',
animationDelay: '',
animationDuration: '',
};
};
});
beforeEach(async () => {
companiesDatabase.getCompanies = jest.fn();
companiesDatabase.getCompanies.mockReturnValueOnce(Promise.resolve([
{
id: '1',
value: {
name: 'name',
contact: {
name: 'contact',
email: '[email protected]',
},
},
},
]));
const App = localVue.component('App', {
components: { Companies },
template: `
<div data-app>
<companies />
</div>
`,
});
const mountedApp = mount(App, {
localVue,
attachToDocument: true,
router,
sync: false,
});
wrapper = mountedApp.find(Companies);
});
it('should render the companies', () => {
expect(wrapper.is(Companies)).toBe(true);
});
});
Test should pass
An error appears in the console:
TypeError: Cannot read property 't' of undefined
at VueComponent.listData (node_modules/vuetify/dist/vuetify.js:9433:47)
at Watcher.get (node_modules/vue/dist/vue.runtime.common.js:3140:25)
at Watcher.evaluate (node_modules/vue/dist/vue.runtime.common.js:3247:21)
at VueComponent.computedGetter [as listData] (node_modules/vue/dist/vue.runtime.common.js:3505:17)
at VueComponent.staticList (node_modules/vuetify/dist/vuetify.js:9452:99)
at Watcher.get (node_modules/vue/dist/vue.runtime.common.js:3140:25)
at Watcher.evaluate (node_modules/vue/dist/vue.runtime.common.js:3247:21)
at VueComponent.computedGetter [as staticList] (node_modules/vue/dist/vue.runtime.common.js:3505:17)
at VueComponent.genList (node_modules/vuetify/dist/vuetify.js:9606:29)
at VueComponent.genMenu (node_modules/vuetify/dist/vuetify.js:9662:33)
at VueComponent.genDefaultSlot (node_modules/vuetify/dist/vuetify.js:9592:26)
at VueComponent.genInputSlot (node_modules/vuetify/dist/vuetify.js:6067:22)
at VueComponent.genInputSlot (node_modules/vuetify/dist/vuetify.js:12793:94)
at VueComponent.genControl (node_modules/vuetify/dist/vuetify.js:6011:22)
at VueComponent.genContent (node_modules/vuetify/dist/vuetify.js:6006:49)
at Proxy.render (node_modules/vuetify/dist/vuetify.js:6138:17)
at VueComponent.Vue._render (node_modules/vue/dist/vue.runtime.common.js:4542:22)
at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.js:2786:21)
at Watcher.get (node_modules/vue/dist/vue.runtime.common.js:3140:25)
at new Watcher (node_modules/vue/dist/vue.runtime.common.js:3129:12)
at mountComponent (node_modules/vue/dist/vue.runtime.common.js:2793:3)
at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.js:7997:10)
Looking at the stacktrace the following line in the vuetify.js file is the one having the issue:
noDataText: this.$vuetify.t(this.noDataText),
Thanks in advance for the help
I'm testing with the Vuetify 1.1.12 and the errors can be reproduced though the stacktrace line numbers had changed:
TypeError: Cannot read property 't' of undefined
at VueComponent.listData (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:9453:47)
at Watcher.get (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3140:25)
at Watcher.evaluate (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3247:21)
at VueComponent.computedGetter [as listData] (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3505:17)
at VueComponent.staticList (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:9472:99)
at Watcher.get (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3140:25)
at Watcher.evaluate (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3247:21)
at VueComponent.computedGetter [as staticList] (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3505:17)
at VueComponent.genList (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:9626:29)
at VueComponent.genMenu (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:9682:33)
at VueComponent.genDefaultSlot (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:9612:26)
at VueComponent.genInputSlot (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:6065:22)
at VueComponent.genInputSlot (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:12813:94)
at VueComponent.genControl (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:6009:22)
at VueComponent.genContent (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:6004:49)
at Proxy.render (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vuetify/dist/vuetify.js:6136:17)
at VueComponent.Vue._render (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:4542:22)
at VueComponent.updateComponent (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:2786:21)
at Watcher.get (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3140:25)
at new Watcher (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3129:12)
at mountComponent (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:2793:3)
at VueComponent.Object.<anonymous>.Vue.$mount (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7997:10)
Looks like you need to look at the internationalization instructions again...
import sv from './i18n/vuetify/sv'
Vue.use(Vuetify, {
lang: {
locales: { sv },
current: 'sv'
}
})
The import of locale, you may need to find the path to that file, "en" and a few other languages are supported...
en is set by default, you don't need to change anything if you're just using that.
@martosoler localVue.use(Vuetify)
won't work properly because we access things from Vue.prototype.$vuetify
, see vuejs/vue#8278. You'll have to use VueRouter and Vuetify globally instead, or mock the missing pieces.
Thanks for the feedback though I don't understand how should I do, its a simple unit test what I'm trying to implement :(
You are using _avoriaz_ to do the unit tests and the author of that library is now involved in the official test library for Vue. I hope he can chime in.
Will post here if I found an alternative as many of our components use the table component.
Thanks a lot !!
Simply
Vue.use(VueRouter);
Vue.use(Vuetify);
instead
@KaelWD I have the same issue with Vuetify, that some components like data-table, date-picker cannot really be tested, because of 2 instances of Vue, being in charge.
In webpack it's actually easy to alias vue$
to local vue located in node_modules, but the same work-around doesn't seem to work in Jest:
"moduleNameMapper": {
"@/(.*)$": "<rootDir>/app/javascript/spa/$1",
"^vue$": "<rootDir>/node_modules/vue/dist/vue.js",
".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub"
},
I think the problem is that @vue/test-utils do not set vue
as a peerDependency in package.json and do not set it as external in their build config, so basically vue-test-utils ships with the copy of Vue, that's why there are 2 versions.
In order to make tests working, @vue/test-utils
should use Vue as a external library and do not include source code of Vue in the dist file. Test utils are using lerna as a bundling tool and I am not sure if it's even possible to configure it in a way to treat Vue as external library.
FYI @eddyerburgh
Sorry @eddyerburgh & @KaelWD
I have just found out that @vue/test-utils
is setting vue as external dependency: https://github.com/vuejs/vue-test-utils/blob/dev/packages/test-utils/scripts/build.js#L59 in the rollup config.
So the problem is somewhere else, maybe it's because of Typescript in Vuetify? Not sure :thinking:
I am having the same problem " Cannot read property 't' of undefined" in the same line "noDataText: this.$vuetify.t(this.noDataText)", any fix for that I am including Vuetify in nuxt using '@nuxtjs/vuetify'. Please help me to resolve the problem for me the problem occurs in normal page rendering
Polluting global Vue instance is a terrible idea.
Same problem here. I am getting the same error on normal rendering. What to do?
We kindly ask users to not comment on closed/resolved issues. If you believe that this issue has not been correctly resolved, please create a new issue showing the regression or reach out to us in our Discord community.
Most helpful comment
Polluting global Vue instance is a terrible idea.