Combine vue-gettext with unit tests (Vuejs) - unit-testing

Combining unit-tests and vue-gettext I get this error when running the tests:
ERROR LOG: '[Vue warn]: Error in render function: "TypeError:
undefined is not a constructor (evaluating
'Number.isNaN(parseInt(n))')"
found in
---> < Translate >
< Root >'
I am not sure how to combine these two to work together.
Reduced example looks like this:
Home.vue
<template>
<div>
<h1>
<translate tag="h1">Homepage</translate>
</h1>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
Home.vue.spec.js
import Vue from 'vue'
import Home from '#views/Home'
describe('Home.vue', () => {
it('should render correct contents', () => {
const Constructor = Vue.extend(Home)
const vm = new Constructor().$mount()
expect(vm.$el.querySelector('div h1').textContent)
.to.equal('Homepage')
})
})

Related

How to access Vue-test-util console error

I am using Jest to test this Vue component:
import { mount } from '#vue/test-utils'
import ExampleComponent from '../Components/Example.vue'
describe("Test", () => {
it('shows no errors', () => {
jest.spyOn(global.console, 'error');
jest.spyOn(global.console, 'warn');
mount(ExampleComponent)
expect(console.warn).not.toHaveBeenCalled()
expect(console.error).not.toHaveBeenCalled()
})
})
I am expecting this test to Fail since I have this component:
Example.vue
<template>
<div>
{{ number }}
</div>
</template>
<script>
export default {}
</script>
as you can see number is not defined, and if opened this component using the browser it will show me:
[Vue warn]: Property or method "number" is not defined on the instance but referenced during render.
but if I test it, the test will pass. How can If the Vue component has warnings or errors?

Vue warn: property or method 'processLogout' is not defined on the instance but defined during render

I'm having an issue with Vue. At this point I've read things like this detailing this error occurring when you try to define a method on the root instance, then reference it in local scope.
My issue is slightly different because it is defined in local scope, so I'm not sure what to make of this error. I've also looked at this, and this.
Here is my App.vue:
<template>
<div id="app">
<router-link to="/Home">home</router-link>
<router-link to="/Login">login</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
console.log('app.vue loading')
</script>
My main.js:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import store from './store'
import router from './router'
import Home from './components/Home'
import Login from './components/Login'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App, Home, Login },
template: '<App/>'
})
console.log('main js loading');
The component the issue is coming from:
<template>
<div class="login">
<head>
<title>{{title}}</title>
</head>
<form for="login" id="loginMain">
<label for="username">Username:</label>
<input type="text" id="username"></input>
<label for="password">Password:</label>
<input type="password"></input><br/><br/>
<button for="login" #click="processLogin">LOGIN</button>
<button for="logout" #click="processLogout">LOGOUT</button>
</form>
<p> Your login status: {{ loginStatus }} </login></p>
</div>
</template>
<script>
import Vue from 'vue'
import { mapGetters, mapActions, Vuex } from 'vuex'
import store from '#/store'
const Login = {
delimiters: [ '[{','}]'],
data () {
title: 'Foo',
msg: 'Bar'
}
name: 'Login',
props: {
// worry about this later
},
methods: {
...mapActions({
processLogin : 'LOGIN_ACTION',
processLogout : 'LOGOUT_ACTION'
})
},
computed: {
...mapGetters({
title: 'GET_TITLE',
loginStatus: 'GET_LOGIN_STATUS'
}),
}
}
console.log('Login loading');
export default Login
And although I'm unsure if it is related, but my store:
import Vue from 'vue'
import Vuex from 'vuex'
import Home from './components/Home'
import Login from './components/Login'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
title: 'My Custom Title',
loggedIn: false
},
mutations: {
MUT_LOGIN: (state) => {
state.loggedIn = true
},
MUT_LOGOUT: (state) => {
state.loggedIn = false
}
},
actions: {
LOGIN_ACTION ({ commit }){
store.commit('MUT_LOGIN')
},
LOGOUT_ACTION ({ commit, state }) {
store.commit('MUT_LOGOUT')
}
},
getters: {
GET_LOGIN_STATUS: state => {
return state.loggedIn
},
GET_TITLE: state => {
return state.title
}
}
})
console.log('store loading');
export default store
I know that I had some of these errors at one point and got rid of them by revisiting each import statement and making some corrections to how I had things hooked up. The only other difference between now and then is that I am running all of these files through Webpack and serving them with Django in a template. (The reason for all the consoles, making sure all the files got in there via Webpack.)
The image below is a couple of the specific things it is barking about.
Because of the link from the devtools error, I have looked at this and also experimented with adding local data () properties to the component itself.
Changing
data () {
title: 'Foo',
msg: 'Bar',
},
to
data () {
return {
title: 'Foo',
msg: 'Bar',
}
},
will fix the "title" error.
As for the issue with the actions nothing is jumping out at me. Can you try mapGetters and see if you have access to the getters?

Why my custom directive does not appear in my vue element?

In my App?vue template , I have a custom directive ( v-noise )
//App.vue
<template>
<div id="app" class="container" v-noise="'brown'">
<...>
</div>
</template>
Testing my plugin, I don't see the directive in the console.log
import Vue from 'vue'
import App from '#/App'
import VueNoiseGeneratorPlugin from '#/plugins/VueNoiseGeneratorPlugin'
import sinon from 'sinon'
import { mount } from 'avoriaz'
Vue.use(VueNoiseGeneratorPlugin)
...
describe('VueNoiseGeneratorPlugin', () => {
let wrapper
let audioContext = sinon.mock(new (window.AudioContext || window.webkitAudioContext)())
beforeEach(() => {
wrapper = mount(App)
})
it('should start noise', () => {
console.log('WRAPPER.VM.$EL: ', wrapper.vm.$el)
Vue.noise.start()
audioContext.expects('resume').once()
})
})
no v-noise directive
'WRAPPER.VM.$EL: ', <div data-v-ee77fb84="" id="app" class="container">
<h2 data-v-ee77fb84=""><span data-v-ee77fb84="">POMODORO </span>
<span data-v-c15acdbe="" data-v-ee77fb84=""><button data-v-c15acdbe="">
....
I want to be able to change the directive (changing the colour of the noise )
feedback welcome

Using Jest to mock a component which has other components as properties

I'm trying to mock react-bootstrap <Modal> component with jest. <Modal> contains some "sub-components" as properties, for example <Modal.Header>. I'm trying to find out the correct way to mock this kind of components using Jest.
Here's a simple component using <Modal>:
// mymodal.js
import React from 'react'
import {Modal, Button} from 'react-bootstrap'
const MyModal = ({ visible, hide, title, onOk }) =>
<Modal show={visible} onHide={hide}>
<div className='simple-modal'>
<Modal.Header closeButton>{title}</Modal.Header>
<Modal.Body>
<div>I'm body</div>
</Modal.Body>
<Modal.Footer>
<Button className='invert-primary' onClick={hide}>
Cancel
</Button>
<Button bsStyle='primary' onClick={onOk}>
Ok
</Button>
</Modal.Footer>
</div>
</Modal>
export default MyModal
And here's basic snapshot test for it:
// mymodal.test.js
import renderer from 'react-test-renderer'
import * as React from 'react'
import MyModal from './mymodal'
jest.mock('react-bootstrap', () => {
function Modal(props) {
return <div>{props.children}</div>
}
Modal.Header = 'Modal.Header'
Modal.Body = 'Modal.Body'
Modal.Footer = 'Modal.Footer'
return({
Modal: Modal,
Button: 'Button',
})
})
describe('MyModal component', () => {
test('should render a modal', () => {
const modal = renderer.create(<MyModal
visible={true}
hide={() => ''}
onOk={() => ''}
title='Title' />)
expect(modal.toJSON()).toMatchSnapshot()
})
})
And here's snapshot:
// Jest Snapshot v1
exports[`MyModal component should render a modal 1`] = `
<div>
<div
className="simple-modal"
>
<Modal.Header
closeButton={true}
>
Title
</Modal.Header>
<Modal.Body>
<div>
I'm body
</div>
</Modal.Body>
<Modal.Footer>
<Button
className="invert-primary"
onClick={[Function]}
>
Cancel
</Button>
<Button
bsStyle="primary"
onClick={[Function]}
>
Ok
</Button>
</Modal.Footer>
</div>
</div>
`;
I'm quite happy with the snapshot result, but I'd like to get better output for the <Modal> component itself so that the snapshot would contain also component's name (currenlty <div>) and props (currently no props shown).
How should the mocking be done to achieve this?
I couldn't find way to achieve this with jest mocking. Finally I went with enzyme shallow rendering, which handles the basic mocking out of box. To do spanshot matching, I serialized the enzyme wrappers using enzyme-to-json npm package.

"Failed to resolve directive: transition" when trying to use a transition with vue-router

I've got a vue app in which I'm using the vue-router.
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let router = new VueRouter()
// Components
import App from './App.vue'
import Mapper from './components/Mapper/mapper.vue'
import ToDos from './components/Todos/ToDoApp.vue'
import Punchlist from './components/Punchlist/punchlist.vue'
// Transitions
Vue.transition('slide',{
enterClass: 'slideInRight',
leaveClass: 'slideOutRight'
})
// Redirects
router.redirect({
'*': 'punchlist'
})
// Mappings
router.map({
'/mapper': {
component: Mapper
},
'/todos': {
component: ToDos
},
'/punchlist': {
component: Punchlist
}
})
router.start(App, '#app')
I have a specific transition registered called slide that I would like to use when navigating between routes. In my App component I added the v-transition and transition-mode directives to the route-view:
<template>
<div class="container">
<h1>Component Gallery</h1>
<p>
<a class='btn btn-primary' v-link="{ path: '/punchlist' }">Punchlist</a>
<a class='btn btn-primary' v-link="{ path: '/todos' }">Todos</a>
<a class='btn btn-primary' v-link="{ path: '/mapper' }">Mapper</a>
</p>
<router-view v-transition="slide" transition-mode="out-in" :google-maps-api-key="googleMapsApiKey"></router-view>
</div>
</template>
When I try to run it, I get the console error:
[Vue warn]: Failed to resolve directive: transition (found in component: )
I've been reading through the docs and looking at examples but I can't figure out why it's erroring out when trying to resolve the binding.
Any ideas?
Transition is an attribute, not a directive. No v-:
<router-view transition="slide">