Giter Club home page Giter Club logo

Comments (31)

eddyerburgh avatar eddyerburgh commented on September 26, 2024 13

What do people think about adding it as an option to mount:

mount(Component, {
  use: [plugin]
})

use would take an array of plugins and use it in a scoped Vue instance.

from vue-test-utils.

yyx990803 avatar yyx990803 commented on September 26, 2024 12

It should work by using an extended constructor with empty options:

const FreshVue = Vue.extend()

FreshVue.use(plugin)

const testedVM = new FreshVue({ ... })

Let me know if there are practical issues with this.

from vue-test-utils.

blocka avatar blocka commented on September 26, 2024 6

from vue-test-utils.

cristijora avatar cristijora commented on September 26, 2024 3

@blocka I think people find very useful using global mixins, plugins and components. For me personally injecting $apollo like you said seems more straight forward than a HOC. In my tests I can replace that with a mock very easily if I want to so I don't have to care too much about it's implementation.
After all I don't think you can stop people from using such a feature which is very widespread in Vue and used by many of vue developers.

from vue-test-utils.

jackmellis avatar jackmellis commented on September 26, 2024 2

What I thought about doing with Vuenit was to have an install method that exposed the scoped vue object before mounting the component:

mount(Component, {
  install : function(ScopedVue){
    ScopedVue.use('blahblah');
  }
});

I don't know if that is the way to go, it means you don't have to account for the entire Vue api within the mount config.

from vue-test-utils.

codebryo avatar codebryo commented on September 26, 2024 2

@eddyerburgh alright, I get your point and yes it was a concern of mine as well. Probably better to omit some automagic by default.
As the approach with the CleanVue Instance is optional I think we should be good, as Vue.use(Vuex) would still work for users who prefer it that way.
The API seems pretty clean so we should be good, agreed. :)

from vue-test-utils.

posva avatar posva commented on September 26, 2024 1

Are you referring to

Be able to Vue.use(plugin) without it polluting the global environment and leaking between tests. Some sort of isolated Vue constructor perhaps?

?

We could provide a wrapper that tracks the calls to global components, directives, filters and that can later be called again to uninstall everything. This is however limited to serialised tests. The isolated constructor is interesting, I wonder if we cannot get a hacky version working without touching core

from vue-test-utils.

yyx990803 avatar yyx990803 commented on September 26, 2024 1

@jackmellis it seems to work: https://jsfiddle.net/yyx990803/b5a1zh6u/

from vue-test-utils.

chrisvfritz avatar chrisvfritz commented on September 26, 2024 1

For 1 & 2, how about createLocalVue, the verb reminding users that it's a function? Then the option could be called localVue, making it clear that it expects the result of createLocalVue. The "local" part serves to remind people not to use or pollute the global Vue.

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024 1

@kazupon I'm happy to make a PR 👍

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024 1

This has been solved by createLocalVue

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024 1

You can see an example in the createLocalVue code—https://github.com/vuejs/vue-test-utils/blob/dev/packages/test-utils/src/create-local-vue.js

You can omit the errorHandler

from vue-test-utils.

jackmellis avatar jackmellis commented on September 26, 2024

I like that, it's neat. Should we also account for configuration options?

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

Yeah I think if we go this route we'll need to add all of the global API to mount. Which will be a reasonable amount of work.

mount(Component, {
  use: ['plugin'],
  config: {
     ignoredElements: ['my-custom-web-component', 'another-web-component']
  }
})

Another option is to have a ScopedVue object (although with a better name!) -

import { ScopedVue } from 'vue-test-utils'

const scopedVue = new ScopedVue
scopedVue.use(plugin)
scopedVue.mixin('my-directive', function () {})

mount(Component, {
  instance: scopedVue
})

from vue-test-utils.

jackmellis avatar jackmellis commented on September 26, 2024

I should also add that I found that an extended Vue object didn't work with mixins, directives, and components. So doing:

const Extended = Vue.extend(Component);
Extended.component('some-component', definition);

const vm = new Extended.$mount();

This did not use some-component registered with the extended component, it would always go back to the base Vue object for globally-registered stuff.

from vue-test-utils.

jackmellis avatar jackmellis commented on September 26, 2024

@yyx990803 well in that case I stand corrected!

You can see the original discussion on this matter: https://forum.vuejs.org/t/vue-component-inheritence/9387

Perhaps the issue I had was that I was creating an extended vue, then registering a global component, then I was extending that extended vue again. I had assumed that it would go up the inheritence chain until it found what it was looking for, but maybe it just looks on the current class, then jumps straight to the base class?

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

The proposed API for options.use is problematic.

For example, Vuex must be installed before you can create a store, so this is not possible:

const store = new Vuex.Store({...})
mount(Component, { use: [Vuex] })

An alternative could be this pattern:

const CleanVue = Vue.extend()
CleanVue.use(Plugin)
mount(Component, { instance: CleanVue })

But there are also problems calling use on a vue.extend instance.

An extended instance doesn't have a version, which vuex relies on.

I'll look into this more over the next couple days

from vue-test-utils.

blocka avatar blocka commented on September 26, 2024

@yyx990803 I know that provide/inject did not exist at the time vuex was created, but if it used provide/inject, this would be less of a problem, as vuex can provide it's own mock provider, or creating a one is pretty trivial, and there would be no need to globally clobber ever vue instance.

from vue-test-utils.

jackmellis avatar jackmellis commented on September 26, 2024

@eddyerburgh that is one of several reasons I wrote mock-vuex, because Vuex has some test-unfriendly rules about instantiating and useing

from vue-test-utils.

codebryo avatar codebryo commented on September 26, 2024

@eddyerburgh so, why not inject the store in the wrapper as well? That would make specs even cleaner and that's the approach I took for Revue.

mount(Component, {use: [Vuex], store: storeObject}

Or we make it even implicit, but that of course can be trcky if people wanne use a different store type.

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

@codebryo I don't think we should add options for specific plugins.

store is already used by Vuez. ), right now a store passed to mount will be passed as component options - which means Vuex and Vue can both be tested. If we treat all option.store as Vuex, we make it impossible to test a Vuez store. Unless we also make an exception for that. But then another plugin might require a store option. I think it's a bad road to go down.

Although maybe we could add some kind of options specifically for vue-router and Vuex as they are official libraries. If we did we'd have to be explicit in the options that they are for Vuex and vue-router

mount(Component, {use: [Vuex], vuexStore , vueRouter }

Overall, I'm in favor of this API -

const CleanVue = Vue.extend()
CleanVue.use(Vuex)
const store = new Vuex.Store({...})

mount(Component, { instance: CleanVue, store })

It means we don't have to write code for specific plugins.

It also means we avoid adding options for everything you can pass to a Vue instance, like component, mixin, directive etc.

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

Oops, accidentally closed 😛

Ok great, I'll start working on it and get it added 👍

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

I've added a function that returns an extended Vue instance with some props that Vuex and Vue-router use (like version and config)

This way you can pass it to mount using the instance option, and mount will use the extended class as a base class.

So you can add components, mixins, and install components without polluting the global vue base class.

import { scopedVue, mount } from 'vue-test-utils'

const baseClass = scopedVued()
baseClass.use(Vuex)
const wrapper = mount(Component, {
  instance: baseClass
})
wrapper.vm.$store // is defined

const freshWrapper = mount(Component)
wrapper.vm.$store // is undefined

Some things I'd like input on:

  1. I don't think scopedVue is very clear, can anyone think of a better name? extendedVue, freshVue, cleanVue?
  2. the option to pass a Vue class is named instance. I think this should be renamed, but am not sure what to. I would love some input.
  3. Vuex can't be installed on two instances. It uses the same Vue class each install - https://github.com/vuejs/vuex/blob/dev/src/store.js#L6. I'm not sure how to resolve this

from vue-test-utils.

ktsn avatar ktsn commented on September 26, 2024
  1. Vuex can't be installed on two instances. It uses the same Vue class each install

I guess we should add an install option to allow overwriting previous Vue instance like forceInstall: true in Vuex.

from vue-test-utils.

gkatsanos avatar gkatsanos commented on September 26, 2024

Just did this:

import { mount, createLocalVue } from 'vue-test-utils';
import Vuetify from 'vuetify';

const localVue = createLocalVue();
localVue.use(Vuetify);

describe('Question.spec.js', () => {
  let cmp;
  let template;
  
  beforeEach(() => {
    cmp = mount(Question, {
      localVue,
      propsData: {
        question: {},
        id: "/questions/6673",
      store,
    });
    template = cmp.html();
  });

And I get


    TypeError: Cannot set property 'installed' of undefined

      at Function.instance.use (node_modules/vue-test-utils/dist/vue-test-utils.js:1253:30)
      at Object.<anonymous> (src/components/Question/Question.spec.js:8:10)
          at Generator.next (<anonymous>)
          at Promise (<anonymous>)
          at Generator.next (<anonymous>)
          at <anonymous>

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

Thanks for the bug report, can you please make a new issue?

I see you did. Thanks :)

from vue-test-utils.

gkatsanos avatar gkatsanos commented on September 26, 2024

from vue-test-utils.

lsimone avatar lsimone commented on September 26, 2024

@yyx990803 I tried in your fiddle what you suggested in this thread

const FreshVue = Vue.extend()
FreshVue.use(plugin)
const testedVM = new FreshVue({ ... })

but it seems to use the global Vue and it does not recognise $t method (error in console)

from vue-test-utils.

eddyerburgh avatar eddyerburgh commented on September 26, 2024

Hi @lsimone . The solution to this issue was to add a createLocalVue function. This needs to be used with a localVue option.

You can see examples in the docs—https://vue-test-utils.vuejs.org/en/api/createLocalVue.html 😀

from vue-test-utils.

lsimone avatar lsimone commented on September 26, 2024

Thanks @eddyerburgh but how to do it without importing createLocalVue from '@vue/test-utils'?
the code I quoted doesn't work as expected in the fiddle I linked

from vue-test-utils.

lsimone avatar lsimone commented on September 26, 2024

ok, thanks @eddyerburgh I will try this way.
So the code suggested by Evan here is definitely not enough to avoid Vue.use polluting global Vue instance.

Do you think that cloning Vue would have a big impact on performance? (I am using it in server side rendering)

from vue-test-utils.

Related Issues (20)

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.