eddyerburgh / avoriaz Goto Github PK
View Code? Open in Web Editor NEW๐ฌ a Vue.js testing utility library
Home Page: https://eddyerburgh.gitbooks.io/avoriaz/content/
License: MIT License
๐ฌ a Vue.js testing utility library
Home Page: https://eddyerburgh.gitbooks.io/avoriaz/content/
License: MIT License
Hi,
I am getting errors in code that was working in previous versions. It could be a bug or I need to mount the component in a different way now?
const $route = { path: '/users/:id', params: { id: 4 } };
const globals = { $route };
const wrapper = shallow(AnswerBeat, { globals });
UPD. The real description of the problem is here.
Hi guys, I've just noticed that zIndex
doesn't work with hasStyle
.
I tried also .hasStyle('z-index', '9999')
. Still false
.
What am I doing wrong? Thanks.
Using vue-cli(vue 1.x)
DeviceMaps.vue
<template>
<div class="device_map">
<div id="gmap"></div>
</div>
</template>
<script>
export default {
name: 'DeviceMaps',
props: ['child', 'last_position', 'geoposition_status'],
data () {
return {
map: null,
flagLastPosition: false
}
},
ready () {
this.createMap()
},
methods: {
createMap () {
this.$nextTick(() => {
if (document.getElementById('gmap')) {
this.map = new google.maps.Map(document.getElementById('gmap'), {})
this.flagLastPosition = this.last_position === null ? true : false
}
})
}
}
}
</script>
DeviceMaps.spec.js
import Vue from 'vue' // vue 1.x
import DeviceMaps from 'src/components/device/DeviceMaps'
import { mount } from 'avoriaz'
let child = {
active: true,
born: 1006059600000,
created_at: 1497029891956,
device_uid: 'device_uid',
first_name: 'Dredd',
gender: 'male',
last_name: 'Frd',
owner_uid: 'owner_uid',
person_uid: 'person_uid',
picture: 'picture'
}
let lastPosition = {
accuracy: 58,
latitude: -12.08774909980868,
longitude: -77.00324162067318,
timestamp: 1497284126034
}
let geopositionStatus = 0
describe('DeviceMaps.vue', () => {
let propsData = {
child: child,
last_position: lastPosition,
geoposition_status: geopositionStatus
}
it('has a created hook', () => {
expect(typeof DeviceMaps.created).to.equal('function')
})
it('debe de llamar a la funcion createMap', () => {
const vm = mount(DeviceMaps, { propsData: propsData })
expect(vm.propsData().geoposition_status).to.equal(0)
})
})
Return:
undefined is not an object (evaluating 'vNode.elm')
Hi I just tried out your module and it seems to work very good.
Though I have a question I just made my first setup for a vue ssr app, and I was wondering if doing the tests like this is the best way for a universal app, or do you know of a better way?
I've got some methods that are called on created, mounted events. I can't seem to be able to spy on them properly (or make stubs).
What I tried so far is, is spying on methods of pre mounted element and then checking if the spy was called. This doesn't work even when the actual method was called (tested by adding simple consolel.og)
Example:
it('calls myMethod when mounted', () => {
const spy = sinon.spy(myComponent.methods, 'myMethod')
const wrapper = mount(myComponent, { propsData, store })
expect(spy.called).to.be.true // AssertionError: expected false to be true
})
Using Karma, Mocha and Sinon. I hope this is enough info and appropriate place to ask this.
Firstly, thanks for a small and useful utility wrapper for Vue.js' testing purposes!
I think there's a small bug in Wrapper.js' methods() function? It references $options.method
instead of $options.methods
. When I changed it under dist/Wrapper.js it started working for me. Could you double-check? I could make a PR.
BR,
Andreas
It seems that when I do a dispatch() on a vue-component that is a child element of the component I'm testing, the event is either not fired at all or not caught by the vue event handler.
If I replace the ui-navigation-level component with a simple div, the event is caught.
This is the component (stripped to bare functionality):
<template>
<ul class="ui-navigation">
<ui-navigation-level
:options="options"
@select="handleSelect"
></ui-navigation-level>
</ul>
</template>
<script>
import NavigationLevel from './ui-navigation-level.vue'
export default {
name: 'ui-navigation',
props: {
options: {
type: Array,
required: true,
},
},
components: {
'ui-navigation-level': NavigationLevel,
},
methods: {
handleSelect(option) {
this.$emit('select', option)
},
},
}
</script>
And the test:
it('handles the select event', () => {
const handleSelect = sinon.spy(Navigation.methods, 'handleSelect')
const wrapper = mount(Navigation, {
propsData: {
options: [
/* ... */
],
},
})
wrapper.find('.ui-navigation-level')[0].dispatch('select')
expect(handleSelect).to.be.calledOnce //Result: called 0 times
})
Vue: 2.1.8
here is the code
<!-- Item.vue -->
<template>
<div class="foo">
</div>
</template>
<!-- Foo.vue -->
<template>
<div>
<Foo v-for="item in list" :item="item"></Foo>
</div>
</template>
<script>
export default {
components: {
'Foo': Foo
},
props: ['list']
}
</script>
in Foo.spec.js
//......
it('create Foo', () => {
mount(Foo, {
propsData: {
list: []
}
});
wrapper.vm.list = wrapper.vm.list.concat([{}, {}, {}]);
console.log(wrapper.find('.foo').length); // will print 6, double the actual value
})
//......
I try to debug this, and find that in findAllVNodes
if (vNode.child) {
findAllVNodes(vNode.child._vnode, nodes, false, depth);
}
vNode.child._vnode.elm == vNode.elm
return true, so this element will push to array nodes
twice
it is possible to import .vue files without requiring the extension? I have a huge project and I never use the extension.
In webpack.config.js I have this line, but it seems not working
extensions: ['.js', '.vue'],
Thanks
Hello, I'm trying to use avoriaz with ava using a very basic example, even more basic than your ava example, but it's throwing an error that window is not defined
, referencing sizzle. Any suggestions?
Hi, did avoriaz support slot inside mounted component? How I can test a component with slots?
https://vuejs.org/v2/guide/components.html#Content-Distribution-with-Slots
If I try to mount a component with:
const id = 'hello';
const url = 'bad thing';
const wrapper = mount(Dropzone, {
propsData: {
id,
url,
},
});
It fails to create it, because the component requires props to have a value. If I mount it using:
const getComponentWithProps = (component, propsData) => {
const Ctor = Vue.extend(component);
return new Ctor({
propsData,
});
};
const id = 'hello';
const url = 'bad thang';
const wrapper = getComponentWithProps(Dropzone, { id, url });
The wrapper has the instance of my component created. Any help? =X
Hi,
For my new project I used this project along with jsdom version 11 and results in an error. When using the jsdom version what avoriaz supports (^9.9.1), the error will not occur. Sadly, you cannot use avorias with Nuxt because Nuxt uses version 11.
I'm using node 8.1.2 and npm 5.0.4.
Note: I'm using AVA version 0.19.1 for my tests.
My example component
<template>
<div class="example">
<h1>{{ message }}</h1>
<h2>prop: {{ msg }}</h2>
<button id="change-message" @click="changeMessage">Change message</button>
</div>
</template>
<script>
export default {
name: 'Example',
data () {
return {
message: 'Default message'
}
},
props: ['msg'],
methods: {
changeMessage () {
this.message = 'new message'
}
}
}
</script>
Example test
import test from 'ava'
import { mount } from 'avoriaz'
// Component
import Example from '../../../components/Example.vue'
// Saving mounted instance of component
const wrapper = mount(Example)
test('renders one h1', t => {
t.is(wrapper.find('h1').length, 1)
// results in an error, so I add the following to check if I get HTML:
const html = wrapper.html()
console.log(html)
// results in an error what is a bit clear
})
Error about the .find() function
โ npm run test-unit
> [email protected] test-unit
> ava test/unit/specs/**/*.js
1 failed
renders one h1
node_modules/window/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:330
Error thrown in test
Error:
[TypeError: Cannot use 'in' operator to search for 'nodeType' in undefined]
HTMLDivElementImpl.appendChild (node_modules/window/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:330:22)
HTMLDivElement.appendChild (node_modules/window/node_modules/jsdom/lib/jsdom/living/generated/Node.js:132:57)
VueWrapper.html (node_modules/avoriaz/dist/Wrapper.js:212:11)
Test.fn (test/unit/specs/Example.test.js:11:31)
test/unit/specs/Example.test.js exited with a non-zero exit code: 1
Error about the .html() function
node_modules/window/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:330
if (!("nodeType" in newChild)) {
^
TypeError: Cannot use 'in' operator to search for 'nodeType' in undefined
at HTMLDivElementImpl.appendChild (node_modules/window/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:330:22)
at HTMLDivElement.appendChild (node_modules/window/node_modules/jsdom/lib/jsdom/living/generated/Node.js:132:57)
at VueWrapper.html (node_modules/avoriaz/dist/Wrapper.js:212:11)
at Object.<anonymous> (test/unit/specs/Example.test.js:13:41)
at Module._compile (module.js:569:30)
at extensions.(anonymous function) (node_modules/require-precompiled/index.js:13:11)
at Object.require.extensions.(anonymous function) [as .js] (node_modules/ava/lib/process-adapter.js:100:4)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (node_modules/ava/lib/test-worker.js:49:1)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Function.Module.runMain (module.js:605:10)
at startup (bootstrap_node.js:158:16)
at bootstrap_node.js:575:3
Probably jsdom is breaking avoriaz somehow...
See jsdom/jsdom@58a7028
Is this an expected behaviour? In that case? How can I stub child component without loosing the execution of created hook?
Thank you
I am not sure this is an issue with avoriaz, but this is the error I get when trying to use the Vuex example. It doesn't seem to be working out of the box.
Error:
Actions.vue
โ "before each" hook for "calls store action actionInput when input value is input and an input even is fired"
[vuex] must call Vue.use(Vuex) before creating a store instance.
assert@specs/test.spec.js:6606:55
Store@specs/test.spec.js:6753:9
specs/test.spec.js:39510:41
test.spec.js:
import avoriaz, { mount } from 'avoriaz';
import sinon from 'sinon';
import { expect } from 'chai';
import Vuex from 'vuex';
import 'babel-polyfill';
import Actions from 'app/components/Actions';
avoriaz.use(Vuex);
describe('Actions.vue', () => {
let actions;
let store;
beforeEach(() => {
actions = {
actionClick: sinon.stub(),
actionInput: sinon.stub(),
};
store = new Vuex.Store({
state: {},
actions,
});
});
it('calls store action actionInput when input value is input and an input even is fired', () => {
const wrapper = mount(Actions, { store });
const input = wrapper.find('input')[0];
input.element.value = 'input';
input.simulate('input');
expect(actions.actionInput.calledOnce).to.equal(true);
});
});
Action.js
<template>
<div class="text-align-center">
<input type="text" @input="actionInputIfTrue" />
<button @click="actionClick()">Click</button>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default{
methods: {
...mapActions([
'actionClick',
]),
actionInputIfTrue: function actionInputIfTrue(event) {
const inputValue = event.target.value;
if (inputValue === 'input') {
this.$store.dispatch('actionInput', { inputValue });
}
},
},
};
</script>
Karma.conf.js
const webpack = require('webpack');
module.exports = function (config) {
config.set({
browsers: ['PhantomJS'],
frameworks: ['mocha'],
files: ['./specs/test.spec.js'],
preprocessors: {
'./specs/test.spec.js': ['webpack', 'sourcemap']
},
webpack: {
resolve: {
alias: {
vue: 'vue/dist/vue.common.js'
},
extensions: ['.js', '.vue']
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'stage-2']
}
},
]
},
},
webpackMiddleware: {
noInfo: true,
},
reporters: ['spec'],
});
};
Using Vue as a nested dependency will potentially cause version mismatches between the copy of Vue used by the user's application code.
This would be a breaking change - I'm just keeping a record for the things that we might want to change before we ship the next version.
For the following component the test fails but succeeds when i remove the <router-view></router-view>
<template>
<div class="teams card">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Teams</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="team in teams">
<td>
<span v-show="!team.editing">{{team.name}}</span>
<input type="text" class="form-control" v-model="team.name" v-show="team.editing" />
</td>
<td>
<router-link :to="modalFor(team)">Edit</router-link>
</td>
</tr>
</tbody>
</table>
</div>
<router-view></router-view>
</div>
</template>
<script>
import { Team } from '../../../models/team'
import Modal from '../../../components/Modal'
export default {
components: {Modal},
name: 'teams',
mounted () {
// load all teams
Team.all().then(teams => {
// disable editing mode for all teams
teams.forEach(team => { team.editing = false })
this.teams = teams
})
},
data () {
return {
teams: [],
}
},
methods: {
modalFor (team) {
return '/admin/teams/' + team.id
}
}
}
import Teams from '@/pages/dashboard/admin/Teams'
import { mount } from 'avoriaz'
describe('Teams.vue', () => {
it('should render correct contents', () => {
const wrapper = mount(Teams)
const tableHeader = wrapper.find('.table tr th')[0]
expect(tableHeader.text()).to.equal('Teams')
})
})
<router-view>
inside the component:<router-view>
Say there is a component called dateInput
<template>
<div>
<input type='date' readonly @click="show = true"/>
<Datepicker :show="show" />
</div>
</template>
<script>
export default {
data(){
return { show : false };
}
};
</script>
The DatePicker
itself is attached to root element
<template>
<div v-if="show">...</div>
</template>
<script>
export default {
props: [ 'show' ],
mounted(){
this.$root.$el.appendChild(this.$el);
}
}
</script>
When testing, I need to set attachToDocument:true
for it to work
test('toogle DatePicker', t => {
let wrapper = mount(DateInput, { attachToDocument:true });
wrapper.setData({ show: true });
//cannot find the Datepicker in wrapper.element or document.body
});
I think that the DatePicker
is appended to the node in memory?
Right now because of Vue's built-in error handling, exceptions are logged to console.error
rather than thrown. During test running it will generally make more sense for these errors to fail the tests, but as they are just logged this doesn't happen.
As a stopgap solution Vue.config.errorHandler
can be set at the top of every test, but this is a bit less than ideal and it would be better if this could be configured through Avoriaz.
I have got a component like the following one, and i need to test if it emits the right event .
Could this be supported?
<template>
<button @click="handleClick">
<slot></slot>
</button>
</template>
<script>
export default {
name: 'Button',
methods: {
handleClick(e) {
this.$emit('click', e)
}
}
}
</script>
Given a following component (Bar.vue):
<template>
<div>
<div class="date">{{dateValue2.toISOString()}}</div>
<div class="int">{{intValue2}}</div>
<button @click="change">Change</button>
</div>
</template>
<script>
export default {
props: ['dateValue', 'intValue'],
data(){
return {
dateValue2: this.dateValue,
intValue2: this.intValue
};
},
watch: {
dateValue(newVal, oldVal){
this.dateValue2 = this.dateValue;
},
intValue(newVal, oldVal){
this.intValue2 = this.intValue;
}
},
methods:{
change(){
this.dateValue2 = new Date(
this.dateValue2.getFullYear(),
this.dateValue2.getMonth(),
1
);
this.intValue2 += 1;
}
}
};
</script>
And this test
import { mount } from 'avoriaz'
import Bar from '../src/components/Bar.vue'
var test = require('tape')
test('set date', (t) => {
const wrapper = mount(Bar, {
propsData:{
dateValue: new Date(2017, 5, 21),
intValue: 1
}
});
let date = wrapper.find('.date')[0];
let int = wrapper.find('.int')[0];
t.is(date.text(), new Date(2017, 5, 21).toISOString(), 'dateValue2 before');
t.is(int.text(), '1', 'intValue2 before');
wrapper.find('button')[0].dispatch('click');
t.is(date.text(), new Date(2017, 5, 1).toISOString(), 'dateValue2 after');
t.is(int.text(), '2', 'intValue2 after');
t.end();
});
The test for dateValue2 after
would fail. I found that the dispatch('click')
has somehow triggered the watcher dateValue
thus re-assign the value.
This test would pass for version 1.14.0
, but fail at current 2.4.0
.
I have created the test here:
https://github.com/jackysee/avoriaz-tape-example
Despite what https://vuejs.org/v2/api/#Vue-use says, Vue.use() accepts two parameters.
See spec here: https://github.com/vuejs/vue/blob/master/test/unit/features/global-api/use.spec.js
I found this while trying to initialise the excellent vuex-i18n with avoriaz.use(vuexI18n.plugin, store)
Hey @eddyerburgh,
great library man!
Just upgraded to your latest version while trying out the slots.
I am following the docs from what I understand but addSlots.js
is throwing an exception complaining that slots[key]
should be an Array
of vNodes
.
I don't understand how this should work when the Foo
component in the docs is an Object?
Ref:
https://eddyerburgh.gitbooks.io/avoriaz/content/api/mount/#default-and-named-slots
import { mount } from 'avoriaz';
import { expect } from 'chai';]
import Foo from './Foo.vue';
import Bar from './Bar.vue';
import FooBar from './FooBar.vue';
describe('Foo', () => {
it('renders a div', () => {
const wrapper = mount(Foo, {
slots: {
default: Bar,
fooBar: FooBar // Will match <slot name="FooBar" />
}
});
expect(wrapper.props(div)).to.equal(true);
});
});
Hello guys,
I'm trying to test a method in a component and this method uses this.$route.path
of the component. But I've got some problems to overwrite this object in test.
My component
<template>
</template>
<script>
import modulesConfig from './modules.config'
export default {
data () {
return {
modules: modulesConfig,
activeModule: null
}
},
mounted () {
this.selectDefault()
},
methods: {
selectDefault () {
const route = this.$route.path
.replace('/admin/', '')
const [module] = route.split('/')
this.activeModule = this.modules.find(item => item.slug === module)
},
goToModule (route) {
this.$router.push(route)
}
}
}
</script>
Spec
import avoriaz, { mount } from 'avoriaz'
import sinon from 'sinon'
import { expect } from 'chai'
// Component
import ModuleOptions from '_common/components/modules-options/ModuleOptions.vue'
describe('Module Options component :: ', () => {
it('Receive the current default module', () => {
const $route = { path: '/admin/cms' }
const wrapper = mount(ModuleOptions, {
globals: {
$route
}
})
expect(wrapper.data().activeModule.name).to.be.equal('Webshop CMS')
})
})
But my original method in component returns an undefined object for the $route
What I'm doing wrong? Thanks ๐
First off super awesome stuff on the latest 2.1.0 release and shallow rendering ๐ Been looking forward to that and thanks for all the effort in creating avoriaz!
I just checked out the shallow rendering, and for a case where a child component has some lifecycle hook, it will still get executed during test. For example a child component dispatching a vuex action on mount:
export default {
name: 'SomeChildComponent',
mounted() {
this.$store.dispatch('fetchUsers');
}
};
This is expected, but would it be worth having a way to optionally bypass the lifecycle hooks so that testing the parent doesn't care about any of these potentially side effects?
It would be nice to have a special option for mount (and shallow) to add event listeners to the tested component. This way, we can easily test that our events listeners are emitted.
Currently, I have to do something like this:
test('method: handleClick', () => {
const handler = jest.fn()
const $c = shallow({
render (h) {
return <div>
<Button type="button" onAction={handler}>Click me!</Button>
</div>
},
})
$c.find('button')[0].trigger('click')
expect(handler).toBeCalled()
})
What it could look like:
test('method: handleClick', () => {
const handler = jest.fn()
const $c = shallow(Button, {
on: {
action: handler,
},
})
$c.find('button')[0].trigger('click')
expect(handler).toBeCalled()
})
Is it possible to use avoriaz to test functional components? When I quickly tried it out earlier it gave me an error that the context parameter for the component's render function was undefined.
If I change the mounting to something like this
new Vue({
components: {
Test: component
},
render (h) {
return h('test', options)
}
})
then I don't get the error message, but everything in context.props
is undefined, like this.
{
prop1: undefined,
prop2: undefined
}
Consider a component with template like this:
<div>
<div>
<div v-if="!ready" class="not-ready">not-ready</div>
<div v-else class="ready">ready</div>
</div>
</div>
After ready
change to true
we will not be able to wrapper.find('.ready')
because nested vNodes is not updated (it still will be .not-ready
div). I was debugging it via findAllVNodes
. This function is getting out-dated nested vNodes.
On the other hand wrapper.html()
and wrapper.text()
work correctly.
Given this component:
export default {
props: ['value', 'show'],
data(){
return {
formatted: (this.value || '').toUpperCase()
}
},
watch:{
show(isShow){
if(isShow){
console.log('show watch : ' + this.show + ',' + this.value);
this.formatted = (this.value || '').toUpperCase();
}
}
}
}
When wrapper.setProps({ show: true, value: 'abc' })
, the console log shows show watch : true,
., showing that value
is not the updated one.
So I'm writing a test that does something like:
t.stub($store);
const $router = { push: t.spy() };
const data = { email: '[email protected]', password: 'password' };
const wrapper = mount(Login, { data, globals: { $router, $store } });
t.stub($store, 'getters').value({ isLoggedIn: true });
And while the $store
stub is available on this
in the component the $router
one is not set. I'm assuming there is some special behaviour with the $router
global?
This is a unit test so I'm not installing vue-router
or vuex
in the tests, I'm stubbing them out using Sinon instead.
Is there a way to bypass this exception when component has transitions?
TypeError: Cannot read property 'split' of undefined
getTransitionInfo (node_modules/vue/dist/vue.runtime.common.js:6145:58)
whenTransitionEnds (node_modules/vue/dist/vue.runtime.common.js:6115:13)
Timeout._onTimeout (node_modules/vue/dist/vue.runtime.common.js:6342:11)
Start to ask if you can detail the shallow and mount differences in documentation, it would be great to know exactly what to expect.
I'm getting what I think could be a bug, or something that I'm missing. For the given test, component and result:
Component:
<template>
<div>
<popover ref="popover" :triggerElements="['.input']"></popover>
</div>
</template>
Test:
it.only('onFocus - load failed', done => {
const wrapper = shallow(SelectSearchInput, {
propsData: {
...defaultProps,
loadFailed: true
}
})
const emitStub = sinon.stub(wrapper.vm, '$emit')
// Show options should be false since input field is empty
expect(wrapper.vm.onFocus()).to.be.true
expect(emitStub).to.be.calledWith('startLoading', wrapper.data().inputValue)
emitStub.restore()
done()
})
Error:
ERROR LOG: '[Vue warn]: Error in callback for watcher "triggerElements": "TypeError: undefined is not a constructor (evaluating 'this.$el.querySelector(this.triggerElements[0])')"
found in
---> <Popover> at /resources/assets/js/components/popover.vue <Root>'
Popover component has a watcher on triggerElements prop.
If I replace shallow by mount everything works just fine.
// PROBLEM
Have loved using your your app!
It is throwing me a Vue Warning '[Vue warn]: Cannot find element: #app'
This is because I am mounting this component in a unit test so it obviously won't run the usual main.js set up class. I was wondering if the mount function has a way of putting it into a #app div to stop this annoying warning message. (this feels like a nice to have feature as everything is working fine)
// TEST CODE
import { expect } from 'chai'
import { mount } from 'avoriaz'
import TextInput from '../../../../src/widgets/TextInput.vue'
import {StringField} from 'mutt-forms/src/fields/text'
describe('TextInput.vue', () => {
let wrapper = {}
beforeEach(() => {
// instantiate our model
let test = StringField.new('test_id', "test_name", {"type":"string"}, {"label":"Dr Pookie from group 1"})
// pass model in as a prop to vue component
wrapper = mount(TextInput, {
attachToDocument: true,
propsData: {
field: test
}
})
})
it('renders ok', function() {
expect(wrapper.is('div')).to.equal(true)
})
})
// VUE COMPONENT
Karma tests aren't being run on files in the mount directory of the avoriaz project.
I have tried editing the karma.conf to catch the files with a glob pattern ('../specs/**/*.{vue,js}'), but it was throwing errors.
I don't have much experience with Karma, so if anyone knows how to fix please open a PR!
I use browser stack test IE browser.
When I use
wrapper.find('.classname')[0].trigger('click')
Get Error Message: Object doesn't support this action
.
I want to know how to fix it?
I'd like advice about how best to add tests to this project to test the ability to mount a component who's root template element is one of the valid descendants of <table>
such as ', '<body>
, ', '<tr>
, ', '<td>
.
Is there a better way than adding components to a new folder test/resources/components/table
and adding the tests to the existing mount.spec.js
?
The components that caused me to want to create these tests render fine in Vue 2, but when I try to mount a component with a root element of <tr>
the .html
and .text
portions of avoriaz are not behaving as expected. .html
is returning <!---->
and .text
is returning an empty string. Those functions are working as expected for other components. Adding these tests would help to diagnose if this is related in any way to avoriaz, or if the problem originates with another part of my test tooling.
Is there any way to test the rendering of an element that is contained in a transition?
<template>
<transition name="fade" mode="out-in">
<h1 v-if="showHeading">Herro<h1>
</transition>
</template>
<script>
export default {
data () {
return {
showHeading: false
};
}
};
</script>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
</style>
The following test will fail on the above component unless I remove the transition.
it('renders an h1 when showHeading is true', () => {
wrapper.setData({ showHeading: true });
expect(wrapper.find('h1').length).to.equal(1);
});
Thanks a lot for avoriaz, by the way. I've been using it for the past couple days, and I love it.
In 1.16.0, when we try to test a click event on a child component found using the component object as the selector, the event does not get a target.
The component:
<template>
<div class="ui-button-group">
<ui-button v-for="(option, index) in options"
:key="option.label"
:id="option.value"
@click="handleClick"
>{{ option.label }}</ui-button>
</div>
</template>
<script>
import Button from '../button/ui-button.vue'
export default {
name: 'ui-button-group',
props: {
options: {
type: Array,
required: true,
},
},
components: {
'ui-button': Button,
},
methods: {
handleClick(event) {
const value = event.target.id // Test fails on this line
this.$emit('click', value)
},
},
}
</script>
The test:
it('handles the click event', function () {
const handleClick = sinon.spy(ButtonGroup.methods, 'handleClick')
const wrapper = mount(ButtonGroup, {
propsData: {
options: [
/** ... **/
],
},
})
wrapper.find(Button)[0].element.click() // This works
wrapper.find(Button)[0].trigger('click') // In handleClick this is thrown: "undefined is not an object (evaluating 'event.target')"
expect(handleClick).to.be.calledOnce
})
https://github.com/eddyerburgh/avoriaz#assert-style-is-rendered
That section doesn't make sense. Why are you creating a button
var and then never using it.
I noticed that the example test for testing applied styles ( https://github.com/eddyerburgh/avoriaz-karma-mocha-example ) is testing for inlined styles. But, if you were to move the styles into a <style>
tag, using the single file Vue pattern, the test will break.
Bar.spec.js...
const wrapper = mount(Bar);
const childUl = wrapper.find('.child-ul')[0];
expect(childUl.style().color).to.equal('red');
});
Bar.vue without inlined style...
<template>
<div class="bar">
<ul class="parent-ul">
<li />
<li />
<ul class="child-ul">
<li />
<li />
</ul>
</ul>
</div>
</template>
<script>
export default {
name: 'bar',
};
</script>
<style lang="scss">
.bar {
ul.child-ul {
color: red;
}
}
</style>
edit: Looks like when findMatchingVNodes()
executes, the Vnodes don't have any of the styles applied yet
First of all, thanks for adding shallow
. This is totally cleaning up our tests!
I noticed today (and maybe this is by design, but I wanted to check to make sure), that if you include both mount
and shallow
in a single spec, shallow
seems to take over.
While we've been using shallow
in our new tests for our presentation components, we utilize vue-svg-loader
for loading SVGs and using them as components. This of course requires the use of mount
. What I've noticed is that one you include shallow
in the spec, all uses of mount
also shallow-render.
It's not a huge deal to just use mount
in those specs, but I feel like I may be missing something. Any ideas?
I'd like to test whether an event handler is called. I thought this would work, but it doesn't:
it('handles the input event', () => {
const wrapper = mount(UiInput)
const handleInput = sinon.spy(wrapper.vm, 'handleInput')
wrapper.find('input')[0].dispatch('input')
expect(handleInput).to.be.calledOnce
})
(handleInput is a method on the UiInput component, and is bound by @input="handleInput" on the input element)
It is called 0 times. If I call the handler directly instead of dispatching the event, the expect returns true. Seems the dispatch does not trigger the v-on binding somehow? Any idea why this happens?
I can not call is
on a wrapper made from find
.
Here is the example more or less copy pasted from the doc:
// Foo.spec.js
import { mount } from 'avoriaz';
import Foo from './Foo.vue';
describe('Foo.vue', function () {
it('should contain a div', function () {
const wrapper = mount(Foo);
const div = wrapper.find('div');
expect(div.is('div')).to.equal(true);
});
});
<!-- Foo.vue -->
<template>
<dd><div>dummy</div></dd>
</template>
And the error I get: TypeError: div.is is not a function
component code:
<template>
<div>
{{prop1}}
{{prop2}}
</div>
</template>
<script>
export default {
props: {
prop1: {default: 'default prop1'},
prop2: {default: 'default prop2'}
},
watch: {
prop1 (val) {
this.prop2 = val
}
}
}
</script>
test code:
import { mount } from 'avoriaz'
import test from 'components/test'
describe('test.vue', () => {
it('should update prop2', () => {
const wrapper = mount(test)
const prop1 = 'testest'
wrapper.setProps({prop1})
expect(wrapper.propsData().prop2).to.equal(prop1)
//expected 'default prop2' to equal 'testest'
})
})
I think watch function is not working in avoriaz. Do you have any workaround for this?
When trying to test a computed property using AVA and with Avoriaz, the context of this
is not what is expected. I'm trying to use a computed property that is based on some data from the component.
More details on stackoverflow.
I'm using AVA with Avoriaz. Both on latest version.
If the wrapper tag is a functional component, like <transition>
, Avoriaz throws an error:
Uncaught Exception
TypeError: Cannot read property 'split' of undefined
zn (node_modules/vue/dist/vue.min.js:6:31287)
Vn (node_modules/vue/dist/vue.min.js:6:30990)
Timeout._onTimeout (node_modules/vue/dist/vue.min.js:7:907)
My component:
<template>
<transition name="page-container" appear>
<div class="page-container">
<slot />
</div>
</transition>
</template>
<script>
export default {
name: 'page-container'
}
</script>
My test case:
import test from 'ava'
import { mount } from 'avoriaz'
import PageContainer from './PageContainer.vue'
const wrapper = mount(PageContainer)
test('should have the correct name', t => {
t.is(wrapper.name(), 'page-container')
})
test('should render parent wrapper', t => {
const hasPageWrapper = wrapper.contains('.page-wrapper')
t.is(hasPageWrapper, true)
})
What do you think that could be?
Hello,
First, thank you for creating avoriaz. While using it, I couldn't find a way to test component prop validators. For example, let's say that I have this component:
myComponent.vue
<template>
<div></div>
</template>
<script>
export default {
data() {}
props: {
maxValue: {
type: Number,
default: 10,
validator: function(val) {
return val > 0; // Ensure that max has a positive value
}
}
}
}
</script>
I tried created a test that looked like this:
myComponent.spec.js
import MyComponent from '../src/myComponent.vue';
const sinon = require('sinon');
const consoleWarn = sinon.stub(console, 'warn');
describe(property', () => {
it('should be a positive value', () => {
var wrapper = mount(MyComponent);
wrapper.setProps({maxValue: -1});
expect(consoleWarn.calledOnce).to.equal(true);
});
});
Does avoriaz have a way to test property validators? If not, it seems like this would be a great addition to this project.
We're having an issue with testing a button click handler. I made a simple test component (below) as an example. The stubbed wrapper.vm.clickHandler
is only called if we trigger a click twice. We have not had this problem with change
events; only the click
event. I have not tested other elements besides buttons.
<!-- TestComponent.vue -->
<template>
<button @click="clickHandler">Go</button>
</template>
<script>
export default {
methods: {
clickHandler () {
console.log('Clicked');
}
}
};
</script>
/* TestComponent.spec.js */
/* global describe, it */
import { mount } from 'avoriaz';
import { expect } from 'chai';
import sinon from 'sinon';
import TestComponent from '@/components/TestComponent';
describe('TestComponent.vue', () => {
it('calls clickHandler', () => {
const wrapper = mount(TestComponent);
wrapper.vm.clickHandler = sinon.stub();
wrapper.find('button')[0].trigger('click');
// wrapper.find('button')[0].trigger('click'); // test only passes when uncommented
expect(wrapper.vm.clickHandler.called).to.equal(true);
});
});
Hello again! It seems for my setup that .find()
doesn't find any child nodes and therefore only looks at the parent node, making .find()
the equivalent of .hasClass()
(when used with a class selector). When used with an ID, it gives the error
TypeError: node.elm.getAttribute is not a function
Also, in vNode.js, why is there a check for nodeName === '#text'
(findById, line 32)?
The template of my component:
<template>
<transition name="modal">
<div class="modal-mask" @click="hideModal" transition="modal">
<div class="modal-dialog" @click.stop>
<div class="modal-header">
<a class="btn close" @click="hideModal">
<i class="icon-cross color-darkest-gray large"></i>
</a>
</div>
<div class="modal-body">
<slot name="body">
<p>Default modal content goes here.</p>
</slot>
</div>
</div>
</div>
</transition>
</template>
<script>
import { mapActions } from 'vuex';
export default {
name: 'modal',
methods: {
...mapActions('Modals', [
'hideModal'
])
}
}
</script>
And when running
import { mount } from 'avoriaz';
import { expect } from 'chai';
import Modal from '../src/components/Modal.vue';
describe('Modal.vue', () => {
it('renders a div element with class modal-mask', () => {
const modal = mount(Modal);
expect(modal.is('div')).to.equal(true);
expect(modal.hasClass('modal-mask')).to.equal(true); // Here we can see the component considers this to be its root node
});
it('renders a div element with class modal-mask', () => {
const modal = mount(Modal);
const mask = modal.find('.modal-mask')[0]; // Finds .modal-mask
expect(mask.is('div')).to.equal(true);
});
it('renders a div element with class modal-dialog', () => {
const modal = mount(Modal);
const dialog = modal.find('.modal-dialog')[0];
// .find() returns empty array, dialog equals undefined at this point
// Same happens for any child node
expect(dialog.is('div')).to.equal(true);
});
});
Should I try and replicate this in a fiddle?
Hey,
is it possible to trigger an change event on an input field with a given value?
input.simulate('change', 'value')
and input.simulate('change', { target: 'value' })
doesn't work and I don't find anything in the docs.
Thanks in advance. โ๏ธ
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.