Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue-test-utils > 1.0.0-beta.12 fails with vee-validate #1267

Closed
SwannLV opened this issue Apr 18, 2018 · 35 comments
Closed

vue-test-utils > 1.0.0-beta.12 fails with vee-validate #1267

SwannLV opened this issue Apr 18, 2018 · 35 comments
Labels
☔ has workaround this issue has a workaround 🙏 help wanted issues needing contribution

Comments

@SwannLV
Copy link

SwannLV commented Apr 18, 2018

Versions:

  • VueJs: 2.5.13
  • Vee-Validate: 2.0.6
  • vue/cli-plugin-unit-jest: 3.0.0-beta.6
  • vue/cli-service: 3.0.0-beta.6
  • vue/test-utils: 1.0.0-beta.10

Description:

Hi. I am having some trouble mounting a component which validate a custom component with Jest and Vee-Validate. When I am not unit testing, the components and validations work great.
Having those errors when running my test:

[Vue warn]: Error in config.errorHandler: "TypeError: Cannot set property '_error' of undefined"
console.error node_modules\vue\dist\vue.runtime.common.js:1739
     RangeError: Maximum call stack size exceeded

(more details at the end)

Thank you very much in advance for your help.

Steps To Reproduce:

Here is the component I am unit testing, Step1.vue :

<template>
  <div class="step1">
    <test name="POD"  v-model="testData" v-validate="'required'"></test>
    <p v-show="errors.has('POD')" class="is-error">{{ errors.first('POD') }}</p>
  </div>
</template>

<script>
  import test from "./test.vue"

  export default {
    data() {
      return {
        testData: "test"
      }
    },
    components: {
      test
    }
  }
</script>

Here is the custom component under vee-validation, test.vue :

<template>
  <div>
    <p>{{currentValue}}</p><button @click="RemoveLetters">Remove letters</button>
  </div>
</template>

<script>
  export default {
    name: "test",
    props: ["value"],
    data() {
      return {
        currentValue: this.value,
      }
    },
    methods: {
      RemoveLetters: function () {
        this.currentValue = this.currentValue.substring(0, this.currentValue.length -2)
        this.$emit("input", this.currentValue)
      }
    }
  }
</script>

And here is my Step1.spec.js :

import { mount, createLocalVue  } from "@vue/test-utils"
import Component from "./Step1.vue"
import VeeValidate from 'vee-validate'

let localVue = createLocalVue()
localVue.use(VeeValidate)

describe("Step1.vue", () => {
  it("renders to a nice snapshot", () => {
    const wrapper = mount(Component, { localVue })
    expect(wrapper.html()).toMatchSnapshot()
  })
})

Error message:

PASS  app\components\views\Step1\__tests__\Step1.spec.js
  ● Console

    console.error node_modules\vue\dist\vue.runtime.common.js:589
      [Vue warn]: Error in config.errorHandler: "TypeError: Cannot set property '_error' of undefined"
    console.error node_modules\vue\dist\vue.runtime.common.js:1739
      TypeError: Cannot set property '_error' of undefined
          at errorHandler (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\@vue\test-utils\dist\vue-test-utils.js:4446:13)
          at globalHandleError (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:1725:34)
          at handleError (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:1719:3)
          at Array.<anonymous> (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:1837:9)
          at flushCallbacks (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:1756:14)
          at <anonymous>
    console.error node_modules\vue\dist\vue.runtime.common.js:589
      [Vue warn]: Error in nextTick: "RangeError: Maximum call stack size exceeded"
    console.error node_modules\vue\dist\vue.runtime.common.js:1739
      RangeError: Maximum call stack size exceeded
          at Watcher.cleanupDeps (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3183:11)
          at Watcher.get (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3154:10)
          at Watcher.run (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3217:22)
          at Watcher.update (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3205:10)
          at Dep.notify (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:695:13)
          at VueComponent.reactiveSetter [as $attrs] (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:1012:11)
          at updateChildComponent (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:2836:13)
          at prepatch (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:4142:5)
          at patchVnode (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:5923:7)
          at updateChildren (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:5820:9)
          at patchVnode (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:5934:29)
          at VueComponent.patch [as __patch__] (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:6094:9)
          at VueComponent.Vue._update (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:2668:19)
          at VueComponent.updateComponent (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:2786:10)
          at Watcher.get (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3140:25)
          at Watcher.run (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3217:22)
          at Watcher.update (D:\MUST\branches\11.0\SPAs\BookingOneStep\node_modules\vue\dist\vue.runtime.common.js:3205:10)
@SwannLV
Copy link
Author

SwannLV commented Apr 18, 2018

If I remove the name attribut from <test />, I don't have the error anymore.
Having just v-model and v-validate as attributs does not show the error.

But, if i add anything as an attribut, for instance:

<test 
    aaaa
    v-model="testData"
    v-validate="'required'"></test>

Then I have the same error.

@logaretm
Copy link
Owner

There is no place in the source code where _errors prop is being used, so I suspect this isn't related to vee-validate. also, the stack trace does not show if vee-validate is triggering an infinite loop.

It could be some weird interaction between vee-validate and other plugin or the test environment but your test seems very similar to the ones being used in this repo except that they do not fail.

I will try few things and report back if it can be fixed.

@Akaryatrh
Copy link

Having the exact same issue! (except on my side It's a route component, so I don't have any custom attributes) Any progress on this @SwannLV?

@SwannLV
Copy link
Author

SwannLV commented May 7, 2018

No not yet sorry, I was not working since then. If I do find I would post the solution.

@logaretm logaretm added the 🙏 help wanted issues needing contribution label May 7, 2018
@cesalberca
Copy link

I have the same issue after updating @vue/cli dependencies from beta.6 to beta.9. When removing the prop v-validate the errors goes away. Needless to say that the validation stops working. Any progress on this?

@Akaryatrh
Copy link

I have the same issue after updating dependencies from beta.6 to beta.9

@cesalberca Seems you talk about vue-test-utils version? Vee-validate current version is 2.0.9

@cesalberca
Copy link

No, I meant @vue/cli. We also tried reverting @vue/test-utils to beta.10 but no luck. The only way we've found to avoid the message is to add to the mount options stubs: ['<YOUR_COMPONENT>'].

@Akaryatrh
Copy link

@cesalberca Weird, on my side I just got rid of the error by downgrading @vue/test-utils from 1.0.0-beta.15 to 1.0.0-beta.10. Can you check again that you used the exact version on your package.json?

My tests are still failing, but I also made a big migration from quasar 0.14.x to 0.15.x so i need to investigate.

Finally, I'm not really sure that vee-validate is linked to our issue.

@Akaryatrh
Copy link

Akaryatrh commented May 9, 2018

OK, finally @logaretm even vee-validate tests fails with vue-test-utils 1.0.0-beta.15. I just cloned your repo, installed deps, launched tests and same error occured (maximum call stack exceeded).

And actually even by forcing version to 1.0.0-beta.10 your tests are failing (but without the stack overflow error), so that would be great to see what dependencies are making tests failing.

@cesalberca
Copy link

@Akaryatrh yeah, for some reason the version didn't downgrade. I fixed that and I reverted to @vue/test-utils 1.0.0-beta.10, which got rid of the error, but now other tests are failing so I'd rather (for the moment being) use the stubs until this issue is solved.

@cesalberca
Copy link

It seems this issue is likely related to this one: vuejs/vue-test-utils#382 as we are using TypeScript and we need to use Vue.extend.

@logaretm
Copy link
Owner

logaretm commented May 10, 2018 via email

@Akaryatrh
Copy link

Akaryatrh commented May 10, 2018

@logaretm Well, I can't find the differences between your setup and mine, but I can't make your tests pass with test utils beta 10. I even used fixed versions on the package.json file, but no luck: 8 tests are failing (with both npm test and yarn test and same version of node).

@logaretm
Copy link
Owner

logaretm commented May 10, 2018 via email

@logaretm
Copy link
Owner

logaretm commented May 13, 2018

I installed @vue/test-utils 1.0.0-beta.16 and I got the same errors locally.

However, I tried running the tests/integration tests individually and the results were:

  • aliases: Fails but it should fail since the test case is invalid (no .initial modifier used).
  • classes: passes.
  • dynamicRules: passes.
  • events: passes.
  • flags: passes.
  • initial: passes.
  • inject: passes.
  • lifecycle: passes.
  • model: fails but it shouldn't.
  • name: fails with the max stack error.
  • scopes: fails with the max stack error.
  • snapshots: passes.
  • target: fails with the max stack error.
  • types: passes.
  • validity: passes.
  • valueResolvers: fails with the max stack error.

We can safely say that the upgrade of vue-test-utils is what caused these tests to fail, after investigating those the model and aliases, they should pass but aliases test was a botched test, it shouldn't have passed in previous versions. It now its corrected and should pass when using the .initial modifier in Aliases.vue component.

The models.js should pass, but it doesn't because for some reason the watcher doesn't fire when the model value changes from null to empty string, changing the value to an intermediate value then back to an empty string fixed the test. But again it shouldn't fail unless I'm missing a critical change in how Vue compares initial values and what constitutes a change in model value.

Now with the "should pass" tests out of the way, while valueResolvers pass, it produces the error reported by @SwannLV and demonstrates the strange behavior of using any props on the template, for example using data-vv-name on the custom component triggers this error, but it isn't reproducible in real-world tests.

At this point I ran out of ideas, and I suspect fixing vuejs/vue-test-utils#532 would address this issue. Feel free to post any updates you may come across.

@Akaryatrh
Copy link

Great investigation, thx @logaretm

@logaretm logaretm removed the wutface label May 13, 2018
@logaretm
Copy link
Owner

as of 1.0.18 this is not yet fixed

@Akaryatrh
Copy link

Issue won't be resolved before Vue 2.6 anyway as said here: vuejs/vue-test-utils#676

@logaretm logaretm changed the title Unit testing | "TypeError: Cannot set property '_error' of undefined" when validating a custom component with Jest vue-test-utils > 1.0.0-beta.12 fails with vee-validate Jun 26, 2018
@logaretm logaretm added the ☔ has workaround this issue has a workaround label Jun 26, 2018
@mkhanal
Copy link

mkhanal commented Jun 29, 2018

I had a similar issue with jest+vue-test-utils+vee-validator.

Downgrading vue-test-utils did not work as suggested in various forums. I had to downgrade vee-validate to 2.0.9 to make it work.

@logaretm
Copy link
Owner

@mkhanal the beta releases had bugs due to the huge rewrite, Depending on what you are testing you could see different results between the betas and the latest stable version. Beta.5 should be passing though as the main reactivity issue was resolved.

@aldarund
Copy link
Contributor

for me tests works with beta.5 and 1.0.0-beta.12

@constantm
Copy link

constantm commented Sep 28, 2018

If you need setValue() in your tests (which was only added in Beta 17 - although I can only get it working in Beta 18), vee-validate testing works for me with test utils 1.0.0-beta.18. I've needed to use a mixture of sync:false on mount, running tests with async, as well as the flushPromises package.

@chriszrc
Copy link

chriszrc commented Dec 3, 2018

@constantm thank you!!! I can confirm that with all the latest versions of everything:

vue/cli 3.2.0
vue 2.5.17
vee-validate 2.1.3
vue/test-utils: 1.0.0-beta.20

That adding the sync:false to the mount/shallowMount config, running the tests with async, and adding:

await flushPromises();

after the mount call, that the tests are working and not producing any errors.

I created a sample app using the cli and added the minimal amount to reproduce the errors and the solution here:

https://github.com/chriszrc/vue-veevalidate-jest-fail/tree/master/myapp
https://github.com/chriszrc/vue-veevalidate-jest-fail/blob/master/myapp/tests/unit/example.spec.ts

The first test that doesn't use the above fixes fails with dozens of RangeError: Maximum call stack size exceeded, while the second with the fixes succeeds-

@bglaz
Copy link

bglaz commented Dec 12, 2018

Hello, I tried using your example with the fixes as a guide, but I am still getting the Maximum call stack size exceeded error. Here is my test:

it('should call the login action with correct params when form submitted', async () => {
    wrapper = mount(Login, { store, localVue, sync: false });

    await flushPromises();

    const email = wrapper.find('input[name="email"]');
    email.value = 'test@test.com';
    email.trigger('input');
    const password = wrapper.find('input[name="password"]');
    password.value = 'password';
    password.trigger('input');

    await flushPromises();

    wrapper.find('form').trigger('submit');

    await flushPromises();

    expect(userLoginAction).to.have.been.called; // eslint-disable-line
  });

This part may or may not be relevant?

const localVue = createLocalVue();

localVue.use(BootstrapVue, Vuex);
localVue.use(VeeValidate, { inject: true, fieldsBagName: 'veeFields' });

@chriszrc
Copy link

chriszrc commented Dec 12, 2018

@bglaz all looks good to me, hopefully one of the experts on here can pick this up, I don't have any other ideas. Are you sure you're using all the same dependency versions?

vue/cli 3.2.0
vue 2.5.17
vee-validate 2.1.3
vue/test-utils: 1.0.0-beta.20

@bglaz
Copy link

bglaz commented Dec 12, 2018

@chriszrc My versions are just slightly different, so maybe that has something to do with it?

vue/cli 3.1.3
vue 2.5.2
vee-validate 2.1.3
vue/test-utils: 1.0.0-beta.27

@chriszrc
Copy link

Fwiw, I upgraded test-utils to 1.0.0.-beta.27 and it's still working-

@chriszrc
Copy link

Oh, did you try clearing the jest cache:

package.json

"test:unit": "jest --clearCache && vue-cli-service test:unit",

@bglaz
Copy link

bglaz commented Dec 12, 2018

I realized my issue was that I had a previous test that was NOT using sync: false and flushPromise, and that was causing all the errors.

@chriszrc
Copy link

@bglaz hahahaha I totally did that to myself too, lol, should have mentioned that, glad you got it solved-

@agcty
Copy link

agcty commented Jan 22, 2019

I use vue-test-utils 1.0.0.-beta.28 and i don't get the max stack error when using sync: false, however, I have this problem: #1177 even though I test as described here: https://github.com/baianat/vee-validate/blob/master/tests/integration/model.js#L13

@constantm
Copy link

@agcty I've not been able to successfully test anything using vee-validate without having sync set to true. The reason for this is that there are promises that have not yet returned errors before the test finishes, hence the need for using sync: true and await flushPromises().

@chriszrc
Copy link

@agcty with sync set to false, you might need to wait for the nextTick() to complete before checking veevalidate, since it's an asynchronous operation:

await wrapper.vm.$nextTick()

after you've changed values, but before you expect to see something vee-validate related change-

@agcty
Copy link

agcty commented Jan 23, 2019

@chriszrc Nope still doesn't work, my code looks like this:

test("validates form", async () => {
    const wrapper = mount(LoginForm, {
      store,
      localVue,
      sync: false,
      attachToDocument: true
    });
    await wrapper.vm.$nextTick();
    expect(wrapper.vm.errors.count()).toBe(0);
    wrapper.setData({
      authData: { username: "somevalue", password: "HelloHello1!" }
    });
    await wrapper.vm.$nextTick();
    expect(wrapper.vm.errors.has("email")).toBe(true); //always false
    expect(wrapper.vm.errors.count()).toBe(0); //always 0

  });

I also tried using await flushPromises() instead of await nextTick() but it makes no difference 🤔

EDIT: Need to mention that the data property is called username but the input name is email and the username should be formatted as an email so errors.has("email") should be true after setting username to "somevalue"

@logaretm
Copy link
Owner

The vue-test-utils have decided to drop the sync behavior since it causes more problems than its worth, which means flushPromsies is now required to do Vue testing, regardless if vee-validate is involved or not.

I added a testing guide to the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
☔ has workaround this issue has a workaround 🙏 help wanted issues needing contribution
Projects
None yet
Development

No branches or pull requests

10 participants