nuxt / test-utils

🧪 Test utilities for Nuxt
http://nuxt.com/docs/getting-started/testing
MIT License
323 stars 84 forks source link

setProps with array concats newItems and oldItems value #876

Closed tomoki1207 closed 5 months ago

tomoki1207 commented 5 months ago

Environment

Reproduction

https://stackblitz.com/edit/nuxt-starter-ncxs25?file=components%2FTest.spec.ts

Describe the bug

I called setProps on Component has an Array type prop. However, the resulting prop value is a concatenation of the new array value and the old array value.

const wrapper = await mountSuspended(Test, {
    props: {
      users: [
        { id: 0, name: 'John' },
        { id: 1, name: 'Kate' },
      ],
    },
  });
expect(wrapper.html()).toContain('John'); // props contain John and Kate
await wrapper.setProps({ users: [{ id: 2, name: 'Bob' }] });
expect(wrapper.html()).not.toContain('John');  // !! props contain Bob, John and Kate

This issue occurs when using Wrapper from mountSuspended, but it does not occur when using @vue/test-utils's mount.

What could be the cause of this behavior?

Additional context

No response

Logs

No response

dosubot[bot] commented 5 months ago

Hey @tomoki1207! 👋 I'm here to help you with your bug, answer your questions, and assist you in becoming a contributor. Let's work together to solve the issue you're facing.

The cause of the setProps method resulting in the prop value being a concatenation of the new array value and the old array value when using mountSuspended is due to the use of Object.assign in the __setProps method. This method merges the new properties into the existing setProps object, which can lead to arrays being concatenated rather than replaced.

Here is the relevant code snippet:

(vm as unknown as AugmentedVueInstance).__setProps = (props: Record<string, unknown>) => {
  Object.assign(setProps, props)
}

To fix this issue, you should replace the entire setProps object with the new properties instead of merging them. You can do this by using a shallow copy:

(vm as unknown as AugmentedVueInstance).__setProps = (props: Record<string, unknown>) => {
  for (const key in setProps) {
    delete setProps[key]
  }
  Object.assign(setProps, props)
}

This ensures that the setProps object is reset before applying the new properties, preventing the concatenation of array values [1].

To continue talking to Dosu, mention @dosu.