ElemeFE / element

A Vue.js 2.0 UI Toolkit for Web
https://element.eleme.io/
MIT License
54.13k stars 14.64k forks source link

[Bug Report] vue/test-util cannot mount "ElSelectDropdown" #12634

Closed matthieuHanne closed 6 years ago

matthieuHanne commented 6 years ago

Element UI version

2.4.6

OS/Browsers version

mac os

Vue version

2.5.17

Reproduction Link

https://github.com/valterbarros/trackthings

Steps to reproduce

try to mount a component with el-select inside throw :

---> <ElSelectDropdown>
       <Transition>
         <ElSelect>
           <ElFormItem>
             <ElForm>
               <Anonymous>
                 <Root>

TypeError: Cannot read property '$el' of undefined at VueComponent.mounted (/Users/mhanne/src/report-builder/viewer/node_modules/element-ui/lib/element-ui.common.js:9131:54) at callHook (/Users/mhanne/src/report-builder/viewer/node_modules/vue/dist/vue.runtime.common.js:2919:21) at Object.insert (/Users/mhanne/src/report-builder/viewer/node_modules/vue/dist/vue.runtime.common.js:4156:7) at invokeInsertHook (/Users/mhanne/src/report-builder/viewer/node_modules/vue/dist/vue.runtime.common.js:5958:28)

What is Expected?

Mount le select input

What is actually happening?

test crash. with jest or ava same issues

JaekwanLee commented 6 years ago

We face the same issue and tried to locate the culprit. And I found that the problematic line in ElSelectDropdown is the line it accessing $ref in mounted() as below.

mounted() {
...
this.referenceElm = this.$parent.$refs.reference.$el;
...
}

The Vue official documents for $ref usage specifies.

An important note about the ref registration timing: because the refs themselves are created as a result of the render function, you cannot access them on the initial render - they don’t exist yet! $refs is also non-reactive, therefore you should not attempt to use it in templates for data-binding.

As per document, the this.$parent.$refs does not contain child references on mounted. This seems quite clear.

matthieuHanne commented 6 years ago

@JaekwanLee Have you find a solution ?

JaekwanLee commented 6 years ago

@matthieuHanne Not really. Just testing it with shallowMount for now. It is weird that it seems working when it runs on browser though.

GenevievePlantin commented 6 years ago

Hi, is there any development @JaekwanLee ? or @matthieuHanne have found some kind of solution ? I'm currently adding some unit tests with Mocha to my Vue project and I have the same issue.

Thank you :)

vladra commented 6 years ago

We've also encountered exactly same issue in tests

a-kriya commented 6 years ago

@ziyoung @wacky6 Any ideas what is to be done here?

wacky6 commented 6 years ago

As far as I know, Element requires the page to be render in a real browser.

referenceElm is used by Popper mixin to show popup according to this reference element's position.


What to be done? Maybe, set referenceElm to null, hope vue-popper does not throw and mounts the dropdown (or you won't be able to select the option).

I think there is modifications going on in vue-popper for next branch. You have to ask @ziyoung for details. That part of Element is out of my expertise.


My recommendation for testing applications with Vue/Element (in fact any MVVM framework applications, such as those built with React) is to use a state management library.

Then, assume UI library's implementation is correct, test the states / data (of state management libraries) are correct (through mutations / setState), instead of performing MVVM component-level tests.

ziyoung commented 6 years ago

I write a simple demo https://github.com/ziyoung/vue-test-with-jest All test cases pass.

 PASS  src/components/__tests__/hello-world.test.js
 PASS  src/components/Select/__tests__/select.test.js
  ● Console

    console.log src/components/Select/select.vue:18
      HTMLParagraphElement {}

Maybe it's not a bug of Element.

a-kriya commented 6 years ago

@ziyoung Here's a patch to your vue-test-with-jest that will allow you to reproduce the issue: ref.txt

huihao commented 6 years ago

https://vue-test-utils.vuejs.org/api/components/

import { config } from '@vue/test-utils' config.stubs.transition = false

This may solve this problem.

The built-in transition component has property named abstract, but transitionStub does not.

vue/src/core/instance/lifecycle.js

export function initLifecycle (vm: Component) {
  const options = vm.$opti

  // locate first non-abstract parent
  let parent = options.parent
  if (parent && !options.abstract) {
    while (parent.$options.abstract && parent.$parent) {
      parent = parent.$parent
    }
    parent.$children.push(vm)
  }
 ...
} 

This causes the child component to have the wrong parent component.

ziyoung commented 6 years ago

Thank you @huihao. @matthieuHanne @syn-zeta it should work for you. https://github.com/ziyoung/vue-test-with-jest/blob/master/src/components/__tests__/hello-world.test.js

hengkx commented 5 years ago

Thank you @huihao. @matthieuHanne @syn-zeta it should work for you. https://github.com/ziyoung/vue-test-with-jest/blob/master/src/components/__tests__/hello-world.test.js

This is the same mistake. image

psaren commented 5 years ago

@huihao Thank you for your solution!

yuanalina commented 5 years ago

@huihao Thank you

jpenna commented 5 years ago

We face the same issue and tried to locate the culprit. And I found that the problematic line in ElSelectDropdown is the line it accessing $ref in mounted() as below.

mounted() {
...
this.referenceElm = this.$parent.$refs.reference.$el;
...
}

I couldn't find where this this.referenceElm is used. What is this variable for? I commented it out and both the tests and browser view worked fine.

half-shell commented 5 years ago

@ziyoung I would like to ask if this issue could be reopened. I am still having that same exact error, and huihao's answer

import { config } from '@vue/test-utils';
config.stubs.transition = false;

doesn't solve it. Did anyone find a workaround or a working solution?

TheJaredWilcurt commented 2 years ago

Heads up for anyone Googling this in the future, the work around is no longer needed in Vue Test Utils 1.3.1

PetersonLian commented 4 months ago

Heads up for anyone Googling this in the future, the work around is no longer needed in Vue Test Utils 1.3.1

Thanks a thousand times