unplugin / unplugin-vue-components

📲 On-demand components auto importing for Vue
https://www.npmjs.com/package/unplugin-vue-components
MIT License
3.82k stars 351 forks source link

`<anonymous-stub>` when running in Vitest + Vue 3 + Vue test utils `{ shallow: true }` #429

Open Neophen opened 2 years ago

Neophen commented 2 years ago

Issue

When using single/multiple stubs option with vue test utils it renders the whole inner html of the component, like so:

import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';

import SomeComponent from './SomeComponent.vue';

test('stubs component', () => {
  const wrapper = mount(SomeComponent, {
    global: {
      stubs: {
        SomeComponent: true
      }
    }
  })

  console.log(wrapper.html())
  **Expected**
  /*
    <some-component-header-stub></some-component-header-stub>
    <h1>Welcome to Vue.js 3</h1>
  */

  **Actual**
  /*
    <div class="text-2xl font-bold">This header should be stubbed</div>
    <h1>Welcome to Vue.js 3</h1>
  */

  expect(wrapper.html()).toContain('Welcome to Vue.js 3')
})

When using with shallow mount the children component names become anonymous-stub:

test('shallow stubs out all child components', () => {
  const wrapper = mount(ComplexComponent, {
    shallow: true
  })

  console.log(wrapper.html())
  **Expected**
  /*
    <h1>Welcome to Vue.js 3</h1>
    <complex-a-stub></complex-a-stub>
    <complex-b-stub></complex-b-stub>
    <complex-c-stub></complex-c-stub>
  */

  **Actual**
  /*
    <h1>Welcome to Vue.js 3</h1>
    <anonymous-stub></anonymous-stub>
    <anonymous-stub></anonymous-stub>
    <anonymous-stub></anonymous-stub>
  */
})

both cases are wrong, is there a way to make this work?

Use Case

When using tailwind you can catch style changes with snapshot tests. which I assume are much faster, than cypress component tests.

And you only want to see the styles of the current component under test, so as not to make tests fail when the child element styles update. to avoid flaky tests.

as a workaround you can import components directly, without using unplugin-vue-components and it works, but that obviously defeats the purpose of this plugin.

Thank you

This plugin saves a ton of time and boilerplate would be awesome to get this little bit to work :)

I'd give it a show with a PR if you could just point me in the direction

TadasMil commented 2 years ago

I'm facing the same issue here

ady642 commented 2 years ago

Can we see the ComplexComponent please ?

Neophen commented 2 years ago
<script setup>
</script>
<template>
   <h1>Welcome to Vue.js 3</h1>
   <ComplexA />
   <ComplexB />
   <ComplexC />
</template>
Neophen commented 2 years ago

Where the Complex[x] components are auto imported by unplugin vue components

fvanwijk commented 2 years ago

When unplugin-vue-components is used, it is impossible to us the stubs feature of Vue Test Utils. This makes unplugin-vue-components practically unusable with Vitest.

Here is an example repo created with npm create vite@latest (vue-ts) + @testing-library/vue + vitest + unplugin-vue-components.

(It also fails with Vue Test Utils instead of Testing library)

I'm not certain this is related to the first comment but at least there seems to be anything wrong with stubbing.

hershelh commented 2 years ago

I've opened a pr to solve this.

cadriel commented 2 years ago

Is this a similar issue in Vue 2 components? I'm seeing vuecomponent-stub entries for all Vuetify related components when shallow mounting.

The PR above only applies to Vue3 - and not test utils for Vue2.

cadriel commented 2 years ago

I've resolved my issue, but it may be relevant here.

For a Vue 2.7 project - running Vitest and shallow mounting caused all Vuetify components to be returned as <vuecomponent-stub>. None of the slots rendered either.

To fix this, I had to disable unplugin-vue-components in the test environment, and instead import the entire Vuetify lib.

This was pretty easy;

In your vitest.config.ts

export default defineConfig((configEnv) => ({
  ...,
  plugins: [
    vue2(),
    Components({
      resolvers: (configEnv.mode !== 'test') ? [VuetifyResolver()] : [],
      ...
  ]

Then in your vitest.setup.ts make sure you import Vuetify from 'vuetify' and Vue.use(Vuetify).

hershelh commented 2 years ago

Is this a similar issue in Vue 2 components? I'm seeing vuecomponent-stub entries for all Vuetify related components when shallow mounting.

The thing is when stubbing a component that uses both <script setup> syntax and unplugin-vue-components, test utils won't do it correctly, which has been solved by the PR.

I'm not sure if Vuetify uses <script setup> syntax or not, and the PR only applies to the test utils for Vue3.