Skip to content
New issue

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

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

Already on GitHub? # to your account

Bug: Props in child component defined in mixin are missing with shallowMount on @vue/compat #2333

Open
cody-collins opened this issue Feb 9, 2024 · 5 comments
Assignees
Labels
bug Something isn't working

Comments

@cody-collins
Copy link

cody-collins commented Feb 9, 2024

Describe the bug
With shallowMount on Vue 3 + @vue/compat, properties of a child component are undefined when using them through a mixin.

If the property is moved from the mixin directly to the component, then the property is defined.

Also if the shallowMount is switched to mount, the property is defined.

To Reproduce

I created a demo repo where this issue can be reproduced, with tags for various working and not working states. It includes the following important files:

git clone https://github.com/cody-collins/vue-compat-mixin-demo.git
cd vue-compat-mixin-demo
npm install
npm test

And the following tags:

Expected behavior
The second assertion should pass in the broken case

@cody-collins cody-collins added the bug Something isn't working label Feb 9, 2024
@cexbrayat
Copy link
Member

Hi @cody-collins

Thanks for the repros. compat mode is the realm of @xanf , so let's ping him

@lmiller1990
Copy link
Member

I do not doubt this is a bug, but I suspect fixing this will be quite complex. It may be a good time to attempt to move your test to use mount, which is a lot less complexity and more in parity with both Test Utils v1 and production in general.

@vidal7
Copy link

vidal7 commented Nov 21, 2024

Any news for this issue? We are migrating a large repo from Vue 2 + VTU 1 to Vue 3 + VTU 2 + @vue/compat and we have hundreds of falling tests because of this.

I don't think using mount instead of shallowMount is a good fix for us because of performance.

@xanf
Copy link
Collaborator

xanf commented Nov 21, 2024 via email

@vidal7
Copy link

vidal7 commented Nov 21, 2024

I found a workaround for now that solve some of my issues but I am not sure if is a good fix or not. I am still experiencing, but the idea is to merge the mixin props with the component props something like it. @xanf , @lmiller1990 , if it a valid solution, it might not be that hard afterall.

export const createStub = ({
  name,
  type,
  renderStubDefaultSlot
}: StubOptions) => {
  const anonName = 'anonymous-stub'
  const tag = name ? `${hyphenate(name)}-stub` : anonName

  const componentOptions = type
    ? unwrapLegacyVueExtendComponent(type) || {}
    : {}

  const props = {}
  // Add mixins props
  componentOptions.mixins?.forEach((mixin: ComponentOptions) => {
     Object.assign(props, mixin.props);
  });
  // Add component props
  Object.assign(props, component.props);

  const stub = defineComponent({
    name: name || anonName,
    props
    // fix #1550 - respect old-style v-model for shallow mounted components with @vue/compat
    // @ts-expect-error
    model: componentOptions.model,
    setup(props, { slots }) {
      return () => {
        // https://github.com/vuejs/test-utils/issues/1076
        // Passing a symbol as a static prop is not legal, since Vue will try to do
        // something like `el.setAttribute('val', Symbol())` which is not valid and
        // causes an error.
        // Only a problem when shallow mounting. For this reason we iterate of the
        // props that will be passed and stringify any that are symbols.
        // Also having function text as attribute is useless and annoying so
        // we replace it with "[Function]""
        const stubProps = normalizeStubProps(props)
        // if renderStubDefaultSlot is true, we render the default slot
        if (renderStubDefaultSlot && slots.default) {
          // we explicitly call the default slot with an empty object
          // so scope slots destructuring works
          return h(tag, stubProps, slots.default({}))
        }
        return h(tag, stubProps)
      }
    }
  })

  const { __asyncLoader: asyncLoader } = type as ComponentOptions
  if (asyncLoader) {
    asyncLoader().then(() => {
      registerStub({
        source: (type as ComponentOptions).__asyncResolved,
        stub
      })
    })
  }

  return stub
}

I am using config.plugins.createStubs to override the default createStub function in src/vnodeTransformers/stubComponentsTransformer.ts

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants