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

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

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

No branches or pull requests

5 participants