Coder Social home page Coder Social logo

eddyerburgh / avoriaz Goto Github PK

View Code? Open in Web Editor NEW
761.0 761.0 62.0 945 KB

๐Ÿ”ฌ a Vue.js testing utility library

Home Page: https://eddyerburgh.gitbooks.io/avoriaz/content/

License: MIT License

JavaScript 87.67% Vue 9.38% Shell 0.57% TypeScript 2.38%
avoriaz test-driven-development testing testing-tools tests vue vue-test vue-test-utilities vue-test-utils vue-testing vue-testing-framework vue-testing-tools vue-testing-utilities vuejs vuejs2 vuesjs2-testing

avoriaz's People

Contributors

alex-sokolov avatar atilacamurca avatar austindebruyn avatar beliolfa avatar ciceropablo avatar eddyerburgh avatar eugeneherasymchuk avatar hypermkt avatar jacekkarczmarczyk avatar joezimjs avatar johnfraney avatar jraller avatar korri avatar lmiller1990 avatar m-zuber avatar mj111 avatar morkro avatar nekosaur avatar pangxie1991 avatar patrickdavey avatar pearofducks avatar philefstat avatar philstavri avatar riophae avatar rjfranco avatar stephane avatar tatyshev avatar umzegher avatar usagi-f avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

avoriaz's Issues

Router is not mounted after upgrading to 2.4.0

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 });

Error vNode: elm

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')

ssr

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?

Spy or stub methods before mount

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.

Methods utility

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

Event not being caught on child component?

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
})

`find` returns vue component twice

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

import .vue files without extension

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

Sizzle throws error that window is not defined

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?

Cant mount component with required: true props

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

avoriaz cannot upgrade jsdom to ^11.0.0

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

[vuex] must call Vue.use(Vuex) Error

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'],
  });
};

Vue should be made a peerDependency

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.

Test fails when <router-view></router-view> is an element inside the component

For the following component the test fails but succeeds when i remove the <router-view></router-view>

Teams.vue

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

Teams.spec.js

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')
  })
})

The test result with the <router-view> inside the component:

image

The test result without the <router-view>

image

Cannot locate component appended to vm.$root.$el

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?

Exceptions are logged instead of thrown

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.

Support for vue events

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>

Watcher of date type being triggered when dispatch/trigger

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

Slots throw vNode array exception

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);
  });
});

Globals injector not overwrite $route object mount

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

screen shot 2017-05-17 at 2 49 09 pm

What I'm doing wrong? Thanks ๐Ÿ˜„

Shallow render - bypass lifecycle hooks

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?

Ability to test Vue events

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()
})

Functional components

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
}

Nested vNodes are out of sync

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.


[email protected]/2.2.1
[email protected]

Watcher only update self value

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.

Can't stub $router in unit tests

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.

Shallow transitions

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)

Mount and shallow behaviour

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.

[Vue warn]: Cannot find element: #app

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

<script> import LabelWidget from './helpers/Label.vue' import ErrorWidget from './helpers/Error.vue' import HelpWidget from './helpers/Help.vue' import {WidgetProxy, DataProxy} from '../utils' export default { name: 'mutt-text', props: ['field'], components: { LabelWidget, ErrorWidget, HelpWidget }, created: function() { this.field.widget = this }, data: DataProxy, methods: WidgetProxy } </script>

Karma tests not running on /test/unit/specs/mount/**/*.js

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!

#trigger() method not support IE10/IE9?

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?

adding tests for tables built of multiple components

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.

How to test for elements within a transition

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.

Target not set on click event when finding by component

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
})

Test for Applied Styles breaks if styles are not inlined, as example shows

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

Using both `shallow` and `mount` in a test causes everything to shallow render

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?

Testing whether an event handler is called

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?

div.is is not a function

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's watch function not working

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?

Testing of computed properties

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.

Error when <transition> is the tag wrapper

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?

Testing Prop Validator

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.

Have to trigger click twice for click handler to be called

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);
  });
});

findAllVNodes doesn't look through children

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?

Trigger change event on input field

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. โœŒ๏ธ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.