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

Calling setData raises 'Cannot read property '$options' of undefined' #653

Closed
falloutcoder opened this issue May 24, 2018 · 14 comments
Closed

Comments

@falloutcoder
Copy link

Version

1.0.0-beta.16

Reproduction link

https://codesandbox.io/s/6lm4248qjr

Steps to reproduce

In reproduction link, 1.0.0-beta.12 version is selected on which test is passing. Upgrading to any version after 1.0.0-beta.12 causes test to fail with error Cannot read property '$options' of undefined when setData is invoked.

What is expected?

Test should pass on later/latest versions as well.

What is actually happening?

Test is failing on vue-test-utils latest versions(after 1.0.0-beta.12 )


Since this worked fine on version 1.0.0-beta.12, i assume this bug could be side effect of PR #438 merged in version 1.0.0-beta.13, as all ElementUI components used in the sample reproduction link are not functional components, so it should work ok on latest version as well. Links to component's used in this sample are below for reference:

https://github.com/ElemeFE/element/blob/v2.3.8/packages/form/src/form.vue
https://github.com/ElemeFE/element/blob/v2.3.8/packages/form/src/form-item.vue
https://github.com/ElemeFE/element/blob/v2.3.8/packages/input/src/input.vue

@eddyerburgh
Copy link
Member

eddyerburgh commented May 25, 2018

Thanks for the bug report.

This is a problem with how we have implemented synchronous updating. There's a PR open to fix this by adding an async option to Vue—vuejs/vue#8240.

For the moment, the workaround is to set the sync mounting option to false and use Vue.nextTick to await DOM updates:

test('use Vue.nextTick', (done) => {
  const wrapper = mount(TestComponent, { sync: false })
  wrapper.trigger('click')
  Vue.nextTick(() => {
    expect(wrapper.text()).toBe('updated')
    done()
  })
})

@falloutcoder
Copy link
Author

Thank you providing the update on this and suggesting workaround. 👍

@dkblay
Copy link

dkblay commented Jun 14, 2018

I was facing this issue and when i realized a fix was provided, I updated from 1.0.0-beta.16 to 1.0.0-beta.18 and all my tests are breaking. I have a feeling a lot changed especially with the way stubbing is done. Can you please help clarify. Thanks

@eddyerburgh
Copy link
Member

There is a bug where stubs and mocks aren't applied correctly to extended components, including the class component. The fix will be released soon.

The issue here is still unresolved.

@SzNagyMisu
Copy link

I have a very similar case, I don't know, if it should be a separate issue:

When upgrading from 1.0.0-beta.17 (up to 1.0.0-beta.20 I tried), all my components that use vuelidate are unable to reach data(). If I try and test if the initial values are correctly set, I get an error message: Cannot read property 'validations' of undefined.

If I use it like this:

const data = vm.$options.data
expect(data().someValue).toEqual('value')

then I get Cannot read property '$options' of undefined.
If I change to

expect(vm.$options.data().someValue).toEqual('value')

then the error message changes to the one above.

Both worked under 1.0.0-beta.17, and vuelidate didn't change since.

Any ideas?

@eddyerburgh
Copy link
Member

Sorry about this. Can you post a minimal reproduction?

@chandrucrm
Copy link

chandrucrm commented Jun 26, 2018

Steps to reproduce

package.json

{
  "name": "vue-test-utils-jest-example",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "Edd Yerburgh <[email protected]>",
  "scripts": {
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js",
    "lint": "eslint --ext .js,.vue src test",
    "lint:fix": "npm run lint --fix",
    "unit": "jest"
  },
  "dependencies": {
    "@vue/test-utils": "^1.0.0-beta.20",
    "element-ui": "^2.4.2",
    "vue": "^2.5.16",
    "vue-router": "^2.6.0"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-jest": "^23.2.0",
    "babel-loader": "^7.1.1",
    "babel-plugin-module-resolver": "^2.7.1",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chalk": "^2.0.1",
    "connect-history-api-fallback": "^1.3.0",
    "css-loader": "^0.28.0",
    "cssnano": "^3.10.0",
    "eslint": "^3.19.0",
    "eslint-config-standard": "^6.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^3.0.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^2.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^2.0.0",
    "file-loader": "^0.11.1",
    "friendly-errors-webpack-plugin": "^1.1.3",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "^0.17.3",
    "jest": "^23.2.0",
    "jest-serializer-vue": "^2.0.2",
    "opn": "^5.1.0",
    "optimize-css-assets-webpack-plugin": "^2.0.0",
    "ora": "^1.2.0",
    "rimraf": "^2.6.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "url-loader": "^0.5.8",
    "vue-jest": "^2.6.0",
    "vue-loader": "^12.1.0",
    "vue-server-renderer": "^2.5.16",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.16",
    "webpack": "^2.6.1",
    "webpack-bundle-analyzer": "^2.2.1",
    "webpack-dev-middleware": "^1.10.0",
    "webpack-hot-middleware": "^2.18.0",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "vue"
    ],
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
    },
    "snapshotSerializers": [
      "<rootDir>/node_modules/jest-serializer-vue"
    ]
  }
}

Component with ElementUI dropdown and table

<template>
 <div>
  <el-select v-model="value" placeholder="Select">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value">
    </el-option>
  </el-select>
  <br/>
  <el-table
      :data="tableData"
      style="width: 100%">
      <el-table-column
        prop="date"
        label="Date"
        width="180">
      </el-table-column>
      <el-table-column
        prop="name"
        label="Name"
        width="180">
      </el-table-column>
      <el-table-column
        prop="address"
        label="Address">
      </el-table-column>
    </el-table>
 </div>
</template>

<script>
export default {
  name: "dropdown-sample",
  data() {
    return {
      options: [
        {
          value: "Option1",
          label: "Option1"
        },
        {
          value: "Option2",
          label: "Option2"
        }
      ],
      value: "",
      tableData: [
        {
          date: "2016-05-03",
          name: "Tom",
          address: "No. 189, Grove St, Los Angeles"
        },
        {
          date: "2016-05-02",
          name: "Tom",
          address: "No. 189, Grove St, Los Angeles"
        }
      ]
    }
  }
}
</script>

Test

import { mount, createLocalVue } from '@vue/test-utils'
import { createRenderer } from 'vue-server-renderer'
import ElementUI from 'element-ui'
import DropDownSample from '@/components/DropDownSample.vue'

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

describe('DropDownSample.vue', () => {
  it('displays default message', () => {
    const wrapper = mount(DropDownSample, { localVue })
    const renderer = createRenderer()

    renderer.renderToString(wrapper.vm, (err, str) => {
      if (err) throw new Error(err)
      expect(str).toMatchSnapshot()
    })
  })
})

Test Results

 yarn unit
yarn run v1.7.0
warning package.json: No license field
$ jest
 PASS  src/components/__tests__/DropDownSample.spec.js
  DropDownSample.vue
    √ displays default message (140ms)

  console.error node_modules/vue/dist/vue.runtime.common.js:589
    [Vue warn]: Error in callback for watcher "options": "TypeError: Cannot read property 'querySelectorAll' of undefined"

    found in

    ---> <ElSelect>
           <DropdownSample>
             <Root>

  console.error node_modules/vue/dist/vue.runtime.common.js:1739
    TypeError: Cannot read property 'querySelectorAll' of undefined
        at VueComponent.options (C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:8567:29)
        at Watcher.run (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:3231:19)
        at flushSchedulerQueue (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:2979:13)
        at Array.<anonymous> (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1835:12)
        at flushCallbacks (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1756:14)
        at <anonymous>
        at process._tickCallback (internal/process/next_tick.js:188:7)

  console.error node_modules/vue/dist/vue.runtime.common.js:589
    [Vue warn]: Error in nextTick: "TypeError: Cannot read property 'clientWidth' of undefined"

  console.error node_modules/vue/dist/vue.runtime.common.js:1739
    TypeError: Cannot read property 'clientWidth' of undefined
        at TableLayout.updateColumnsWidth (C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:11450:36)
        at VueComponent.updateScrollY (C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:10269:19)
        at C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:10829:26
        at Array.<anonymous> (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1835:12)
        at flushCallbacks (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1756:14)
        at <anonymous>
        at process._tickCallback (internal/process/next_tick.js:188:7)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        2.822s, estimated 3s
Ran all test suites.
Done in 3.89s.

Any idea about this?

@eddyerburgh
Copy link
Member

Can you try setting sync to false and use Vue.nextTick to await DOM updates:

test('use Vue.nextTick', (done) => {
  const wrapper = mount(TestComponent, { sync: false })
  wrapper.trigger('click')
  Vue.nextTick(() => {
    expect(wrapper.text()).toBe('updated')
    done()
  })
})

@chandrucrm
Copy link

I changed the test as below (sync is set to false and Vue.nextTick is used)

But the test results is still the same.

import Vue from "vue"
import { mount, createLocalVue } from "@vue/test-utils"
import { createRenderer } from "vue-server-renderer"
import ElementUI from "element-ui"
import DropDownSample from "@/components/DropDownSample.vue"

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

describe("DropDownSample.vue", () => {
  it("displays default message", () => {
    const wrapper = mount(DropDownSample, { sync: false, localVue })
    const renderer = createRenderer()
    Vue.nextTick(() => {
      renderer.renderToString(wrapper.vm, (err, str) => {
        if (err) throw new Error(err)
        expect(str).toMatchSnapshot()
      })
    })
  })
})

Test Results

PS C:\Projects\Issues\vue-unit-test-starter> yarn unit
yarn run v1.7.0
warning package.json: No license field
$ jest
 PASS  src/components/__tests__/DropDownSample.spec.js
  DropDownSample.vue
    √ displays default message (265ms)

  console.error node_modules/vue/dist/vue.runtime.common.js:589
    [Vue warn]: Error in callback for watcher "options": "TypeError: Cannot read property 'querySelectorAll' of undefined"

    found in

    ---> <ElSelect>
           <DropdownSample>
             <Root>

  console.error node_modules/vue/dist/vue.runtime.common.js:1739
    TypeError: Cannot read property 'querySelectorAll' of undefined
        at VueComponent.options (C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:8567:29)
        at Watcher.run (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:3231:19)
        at flushSchedulerQueue (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:2979:13)
        at Array.<anonymous> (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1835:12)
        at flushCallbacks (C:\Projects\Issues\vue-unit-test-starter\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: "TypeError: Cannot read property 'clientWidth' of undefined"

  console.error node_modules/vue/dist/vue.runtime.common.js:1739
    TypeError: Cannot read property 'clientWidth' of undefined
        at TableLayout.updateColumnsWidth (C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:11450:36)
        at VueComponent.updateScrollY (C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:10269:19)
        at C:\Projects\Issues\vue-unit-test-starter\node_modules\element-ui\lib\element-ui.common.js:10829:26
        at Array.<anonymous> (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1835:12)
        at flushCallbacks (C:\Projects\Issues\vue-unit-test-starter\node_modules\vue\dist\vue.runtime.common.js:1756:14)
        at <anonymous>

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        4.575s
Ran all test suites.
Done in 5.87s.

@eddyerburgh
Copy link
Member

Can you create a full minimal reproduction that I can run (either on code sandbox or GitHub). Please use the least amount of code possible to reproduce the issue. Then open a new issue with the reproduction.

@BartekZienkiewicz
Copy link

@chandrucr maybe you should change Vue.nextTick to localVue.nextTick

@chandrucrm
Copy link

chandrucrm commented Jun 28, 2018

@BartekZienkiewicz
I get same warnings for localVue and Vue.

@eddyerburgh
These warnings are thrown for Jest Snapshots tests only.
Other tests succeed without any warning.

I will create a new issue for this. #770

@SzNagyMisu
Copy link

submitted new issue (#795)

@eddyerburgh
Copy link
Member

The reproduction issue is fixed with the latest version of element-ui—https://codesandbox.io/s/3rvrqrv2vq

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants