vuejs / vue-jest

Jest Vue transformer
MIT License
748 stars 156 forks source link

Inlining functional Components breaks mounting #498

Closed Gbeschbacher closed 1 year ago

Gbeschbacher commented 2 years ago

Problem Statement: Inlining a functional Component in a SFC and mounting it in a spec breaks the SFC because it is also marked as functional.

Versions in use:

"vue": "2.6.10",
"@vue/vue2-jest": "28"
"@vue/test-utils": "^1.3.0",
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.3",
...

Code to reproduce:

// SFC Issue.vue

<template>
  <div><VNode /></div>
</template>

<script>
const VNode = {
  name: "VNode",
  props: {
    node: { type: Object },
  },
  functional: true,
  render(h) {
    return h("div");
  },
};

export default {
  name: "Issue",
  components: {
    VNode,
  },
};
</script>

With the following spec file:

// Issue.spec.js

import { mount, createLocalVue } from "@vue/test-utils";
import Issue from "./Issue";

const localVue = createLocalVue();

console.log(Issue);

describe("issue", () => {
  it("does not mount correctly", () => {
    const a = mount(Issue, { localVue });

    expect(true).toBe(true);
  });
});

This produces the followinig Output:

  issue
    ✕ does not mount correctly (26 ms)

  ● issue › does not mount correctly

    TypeError: Cannot read property '$createElement' of null
      at render (/usr/app/components/Issue.vue:36:16)
      at createFunctionalComponent (node_modules/vue/dist/vue.runtime.common.dev.js:3052:30)
      at createComponent (node_modules/vue/dist/vue.runtime.common.dev.js:3225:12)
      at _createElement (node_modules/vue/dist/vue.runtime.common.dev.js:3421:13)
      at createElement (node_modules/vue/dist/vue.runtime.common.dev.js:3347:10)
      at vm.$createElement (node_modules/vue/dist/vue.runtime.common.dev.js:3481:54)
      at Proxy.parentComponentOptions.render (node_modules/@vue/test-utils/dist/vue-test-utils.js:2670:12)
      at VueComponent.Vue._render (node_modules/vue/dist/vue.runtime.common.dev.js:3532:22)
      at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4048:21)
      at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4459:25)
      at new Watcher (node_modules/vue/dist/vue.runtime.common.dev.js:4448:12)
      at mountComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4055:3)
      at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.dev.js:8386:10)
      at mount (node_modules/@vue/test-utils/dist/vue-test-utils.js:14057:21)
      at Object.<anonymous> (/usr/app/components/issue.spec.js:8:15)

with my console log printing:

    {
      name: 'Issue',
      components: {
        VNode: {
          name: 'VNode',
          props: [Object],
          functional: true,
          render: [Function: render]
        }
      },
      render: [Function: render] { _withStripped: true },
      staticRenderFns: [],
      functional: true,
      _compiled: true
    }

Here you can see the Issue, that my SFC-parent component got marked as functional, even though it should not be and i guess that's the main problem. Setting Issue.functional = false in my spec also makes my spec work but this leads me to this package thinking that parsing my SFC with inlined functional component is broken.

Do you have any suggestions or hints i can follow to address this error?

vano20 commented 2 years ago

I've opened #497. Maybe it was because of this. I will check if it was marked as functional too

kevinoe commented 2 years ago

I have found a hack to work around this:

const functionalKey = "functional";

// Later, in the component def:
{
  [functionalKey]: true,
  // Other component bits.
}