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

Computed ref unwrapping is different than in vue #2196

Closed
stam opened this issue Aug 1, 2023 · 7 comments · Fixed by #2356 or Enterprise-CMCS/cmcs-eregulations#1321
Closed

Computed ref unwrapping is different than in vue #2196

stam opened this issue Aug 1, 2023 · 7 comments · Fixed by #2356 or Enterprise-CMCS/cmcs-eregulations#1321
Labels
bug Something isn't working

Comments

@stam
Copy link

stam commented Aug 1, 2023

Subject of the issue

Hey, I'm working on a codebase where we use computed refs outside of vue components.
A store class has a computed ref (store.count in the stackblitz environment), an instance of this class is passed as prop to a vue component.

In Vue itself, store.count is a ComputedRefImpl, where you still need .value to access the value.
In Vue-test-utils store.count already is the value itself, and store.count.value will be undinefed

Steps to reproduce

I have created a stackblitz environment
When viewing the ui, App.storeValue is 3, and store.count is a ComputedRefImpl
If you kill the devserver and npm test App.storeValue is NaN, because store.count is the value itself, so store.count.value is undefined

Expected behaviour

store.count should be a computedRefImpl which still needs .value to access the value

Actual behaviour

store.count immediately contains the value, unlike in vue itself

Possible Solution

?

@stam stam changed the title Computed ref unwrapping is different then in vue Computed ref unwrapping is different than in vue Aug 1, 2023
@lmiller1990 lmiller1990 transferred this issue from vuejs/vue-test-utils Sep 24, 2023
@lmiller1990
Copy link
Member

I think this is the wrong repo, moving to @vue/test-utils

@cexbrayat
Copy link
Member

This one slipt my radar as it was transferred from test-utils v1, but this indeed looks like an issue.

I made a simpler repro, to ensure this was not something related to the Options API or the class usage.
But I do reproduce with the Composition API and simple objects.

See https://stackblitz.com/edit/github-ff6icg?file=src%2Fcomponents%2FHelloWorld.vue,src%2Fcomponents%2F__tests__%2FHelloWorld.spec.ts,src%2FApp.vue

<template>
  <div id="app">
    {{ storeValue }}
  </div>
</template>

<script setup lang="ts">
import { computed, Ref } from 'vue';

const props = defineProps<{ store: { count: Ref<number> } }>();
const storeValue = computed(() => props.store.count.value + 1);
</script>
import { mount } from '@vue/test-utils';
import { ref } from 'vue';
import { describe, it, expect } from 'vitest';
import HelloWorld from '../HelloWorld.vue';

describe('HelloWorld', () => {
  it('can access the nested computed value', async () => {
    const wrapper = mount(HelloWorld, {
      props: {
        store: {
          count: ref(2),
        },
      },
    });

    expect(wrapper.get('#app').text()).toBe('3'); // fails
    expect(wrapper.vm.storeValue).toBe(3); // fails
  });
});

The issue goes away if we drop the store level in the props:

<template>
  <div id="app">
    {{ storeValue }}
  </div>
</template>

<script setup lang="ts">
import { computed, Ref } from 'vue';

const props = defineProps<{ count: Ref<number> }>();
const storeValue = computed(() => props.count.value + 1);
</script>
describe('HelloWorld', () => {
  it('can access the nested computed value', async () => {
    const wrapper = mount(HelloWorld, {
      props: {
        count: ref(2),
      },
    });

    expect(wrapper.get('#app').text()).toBe('3'); // succeeds
    expect(wrapper.vm.storeValue).toBe(3); // succeeds
  });
});

So there is an issue with nested refs inside objects that we need to take a look at.

@cexbrayat cexbrayat added the bug Something isn't working label Oct 3, 2023
@tommasogangemi
Copy link

I am still having this issue as of today, are there any updates? Passing an object that contains a nested ref or computed ref as a prop directly unwraps the reactive nodes in the component's mounted instance.

@lmiller1990
Copy link
Member

I am not sure why this happens, but it looks like we grab all of the props you pass to mount and wrap it in reactive. I wonder if that is related, if so, we might need some logic around there.

@lsimone
Copy link

lsimone commented Feb 8, 2024

I am experiencing the same problem and unfortunately this is blocking for most of my tests: any update about it?

@lmiller1990
Copy link
Member

Not right now, would you like to take a look and try to fix it? I am not able to do it right now.

@Evobaso-J
Copy link
Contributor

@lmiller1990 hi there! I gave it a shot in this PR. It seems that the issue was due to the mount method not checking deeply whether a prop contains a ref or not, but just on the first level. However mount looks quite complex, I really hope I did not mess anything up 😅
Please let me know what you think ✌🏻

lmiller1990 pushed a commit that referenced this issue Mar 13, 2024
* fix: allow access to nested computed values

* fix: remove useless access to vm
scmmishra added a commit to chatwoot/chatwoot that referenced this issue Jul 31, 2024
The issue is highlighted here: vuejs/test-utils#2196
Solution was made but only works for vue 3: vuejs/test-utils#2196

Skipping it for now, tested in manually
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment