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: Mocking not working when setup() is defined #1869

Closed
Roywcm opened this issue Nov 16, 2022 · 17 comments · Fixed by #1871
Closed

Bug: Mocking not working when setup() is defined #1869

Roywcm opened this issue Nov 16, 2022 · 17 comments · Fixed by #1871
Labels
bug Something isn't working

Comments

@Roywcm
Copy link

Roywcm commented Nov 16, 2022

Describe the bug
I'm trying to mock the vuei18n $t. But this is not working when using the setup composition api.
When disabling the setup, it works as expected. I also tried with other function names like $test.
Strange thing is, when using a name without the dollar sign, it also works just normal.

To Reproduce

index.vue

<template>
    <div> {{ $t('hello') }}</div>
</template>
<script>
  export default {
    setup(){
        return {} // will not work
    },
  }
</script>

test file

import { config, mount } from '@vue/test-utils'
import Index from './index'

config.global = {
    mocks: {
        $t: (msg) => msg
    }
}

describe ('Index Tests', () => {
     it ('should mount without crashing', () => {
         const wrapper = mount(Index)
         expect(wrapper).toBeTruthy();
     })
});

Expected behavior
Should also works when using the composition api.

Related information:

  • @vue/test-utils version: 2.2.3
  • Vue version: 3.2.45
  • node version: v18.2.0
  • npm (or yarn) version: 8.10.0
@Roywcm Roywcm added the bug Something isn't working label Nov 16, 2022
@simonvizzini
Copy link

Facing the exact same issue with test-utils 2.2.3

I think bug was introduced in one of the recent patch version, will try to downgrade to 2.2.2 or 2.2.1 in the meantime

@cexbrayat
Copy link
Member

Yes, this comes from internal changes in Vue core v3.2.45, which we try to workaround in VTU but some cases are tricky, as Vue no longer allows to modify the internal state of a setup component.
I may have an idea to fix this use-case, stay tuned.

In the meantime, you can downgrade to Vue v3.2.44

@simonvizzini
Copy link

Oh that interesting, because we are still using Vue v3.2.41 and this issue appeared after updating test-utils to v2.2.3. I just did a downgrade to v2.2.1 and the error is now gone.

cexbrayat added a commit to cexbrayat/vue-test-utils-next that referenced this issue Nov 16, 2022
cexbrayat added a commit to cexbrayat/vue-test-utils-next that referenced this issue Nov 16, 2022
@cexbrayat
Copy link
Member

I may have found a way to make this use-case work with Vue v3.2.45
Once #1871 is merged and released, you should be able to upgrade to the latest version of Vue and VTU

@JeremCafeyn
Copy link

JeremCafeyn commented Nov 21, 2022

Hey @cexbrayat,
Thanks for the fix! It helps a lot.
In order to not add the global mocks in each .spec files, I tried to add it in the setup file of vitest but it doesn't work.
Do you know if it's related to Vitest?
Here is my code:

import matchers from '@testing-library/jest-dom/matchers';
import { config } from '@vue/test-utils';
import { expect } from 'vitest';

config.global.mocks = {
  $t: (key: string) => key, // just return translation key
};
expect.extend(matchers);

@cexbrayat
Copy link
Member

@JeremCafeyn Happy to hear that 👍

For global mocks, can you provide us a small repro online using https://stackblitz.com/edit/vitest-dev-vitest-qoiwy3?file=package.json&initialPath=__vitest__ ? I'll take a look to check if this is a VTU issue.

@stefanlivens
Copy link

we still have the same error. downgrading to 2.2.2 fixes it immediately... using a combination of options api and composition api in our project. and since 2.2.3 we get this problem: global mocks just disappear (in our case, we 'enhanced' the mount/shallowMount with mocks for all vue-i18n methods, so all our mount/shallowMount have this mocked vue-i18n methods, even adding a mocked $router just ... disappears...)
But we're using vue 3.2.45 in both cases!
If i try vue3.2.41 and vtu 2.2.4 i get the errors too.

@cexbrayat
Copy link
Member

@JeremCafeyn
Copy link

@JeremCafeyn Happy to hear that 👍

For global mocks, can you provide us a small repro online using https://stackblitz.com/edit/vitest-dev-vitest-qoiwy3?file=package.json&initialPath=__vitest__ ? I'll take a look to check if this is a VTU issue.

Sure! and thanks for your reply. Here you go:
https://stackblitz.com/edit/vitest-dev-vitest-f3omsf?file=components/AsAsync.vue

I included a setup file in the test folder to change the global config, and change also the vitest.config.
I added a $t in the AsAsync component and now it failed.

@cexbrayat
Copy link
Member

@JeremCafeyn If you use "@vue/test-utils": "2.2.4", in package.json, then the tests succeed (Stackblitz uses v2.2.3 in your example I think)

@stefpb
Copy link

stefpb commented Dec 7, 2022

Remove the $ in all global properties names and mocks helps us in this situation.

config.global.mocks['$localStorage'] = useLocalStorage();
config.global.mocks['$event'] = mitt();

to

config.global.mocks['localStorage'] = useLocalStorage();
config.global.mocks['event'] = mitt();

and

app.config.globalProperties.$localStorage = useLocalStorage();
app.config.globalProperties.$event = mitt();

to

app.config.globalProperties.localStorage = useLocalStorage();
app.config.globalProperties.event = mitt();

and wrapper.vm.$event to wrapper.vm.event and so on

@renatodeleao
Copy link
Contributor

renatodeleao commented Dec 31, 2022

Have the exact same scenario as #1869 (comment), have mixed options API component with a setup() function. In these mixed components $ prefixed mocks are ignored (including $route/$router), renaming them without $ makes them work 🤯

Cannot reproduce with a bare vitest stackblitz, so must be something on my dev environment?! :/ @stefanlivens appreciate if you have more info on it

Cheers 👋

Stack

jest@29.3.1"
@vue/vue3-jest@29.2.2
@vue/test-utils@2.2.6
@vue@3.2.45
@vue/compat@3.2.45

EDIT: screenshots from running on my env with a patched @vue/test-utils 🦆

fig1. fig.2
fig 1 fig 2

EDIT2: I can also confirm that downgrading to VTU@2.2.2 while maintaining vue@3.2.45 makes everything work as expected. From VTU@^2.2.3 it starts to fail 🤷

@renatodeleao
Copy link
Contributor

renatodeleao commented Jan 3, 2023

@cexbrayat it seems that the patch introduced at 2.2.3 to make VTU mocks work on <script setup> also catches options API components with a setup() hook and breaks it somehow. I could not yet find a way to reproduce within @vue/test-utils test suite (I've forked and created a test myself) neither with a plain new vitest setup.

That being said, I can reproduce it using latest jest + vue-jest. I don't know how the test-running setup is affecting the output but here's the reproduction example: https://stackblitz.com/edit/vitejs-vite-giabcm?file=test/App.test.js (npm run test)

Any help is appreciated! Cheers 👋

@cexbrayat
Copy link
Member

Hmm that's strange. I'm not surprised that having a component with both composition and options API has a weird behavior, as the VTU codebase now distinguishes the 2 cases. More than that, I'm surprised that this can only be reproduced with Jest. If we don't have a way to reproduce this in the VTU test suite, this is going to be hard even to just take a look.

Ideally, you should try to move to a component with only a setup or a component with plain Option API. Trying to fix this "mix component case" in VTU is going to add even more complexity to something that is already quite tricky I'm afraid.

@renatodeleao
Copy link
Contributor

renatodeleao commented Jan 3, 2023

Ideally, you should try to move to a component with only a setup or a component with plain Option API.

At the scale of the app I'm working that's not doable ATM. Also setup() is a perfectly valid component option for Options API at the time of writing, so I don't think I have a strong argument to present to my team for enforcing that style. Unless vue docs explicitly mention "do not use setup() with other options besides props/name/inheritAttrs.." I can't go down that path.

Trying to fix this "mix component case" in VTU is going to add even more complexity to something that is already quite tricky I'm afraid.

With that, I fully agree. You're already relying on devtoolsRawSetupState internal property to make the 2.2.3 patch and from my limited understanding of vue core codebase and investigation, the only way to make this work would be to rely on another internal prop __isScriptSetup. Not seeing any other way.

Another weird part: the reason you add the if block in the first place was to avoid a Proxy set error, but on my end patching the VTU@2.2.6 and code and remove the if (hasSetupState(this)) block altogether makes it work with no warnings or errors for both options API, "mixed" and <script setup> components 🤷, but I don't know what specific context trigger you to add that change.

test-utils/src/mount.ts

Lines 481 to 485 in a48712d

// we need to differentiate components that are or not not `script setup`
// otherwise we run into a proxy set error
// due to https://github.com/vuejs/core/commit/f73925d76a76ee259749b8b48cb68895f539a00f#diff-ea4d1ddabb7e22e17e80ada458eef70679af4005df2a1a6b73418fec897603ceR404
// introduced in Vue v3.2.45
if (hasSetupState(this)) {

Edit

I've patched my fork of test-utils as shown bellow and all tests pass. I know that it's increasing complexity/hackery, but on the other hand, we were already accessing internals anyways. Of course that before making a PR, I would like to add a test case to the codebase where the previous code failed but haven't got any success with that.

- if (hasSetupState(this)) { }
+ if (hasSetupState(this) && this.$.setupState.__isScriptSetup) { }

@stefanlivens
Copy link

hi guys, i simply could not reproduce it in the stackblitz setup. and i missed your call to help, my bad

However, i can confirm v2.2.7 fixed the issue for me!

@renatodeleao
Copy link
Contributor

Hey @stefanlivens no worries about that! You already helped a lot by demonstrating that I was not the only one with the issue! That's what drove me to find a solution, otherwise, I would just give up and accept as a fact that the problem was with my setup!

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

Successfully merging a pull request may close this issue.

7 participants