Maronato / vue-toastification

Vue notifications made easy!
https://vue-toastification.maronato.dev
MIT License
3.03k stars 139 forks source link

[Vue warn]: A plugin must either be a function or an object with an "install" function. Vue test utils #341

Open SoetZombie opened 1 year ago

SoetZombie commented 1 year ago

Versions

-2.0.5-rc

Describe the bug

Testing components using vueTestUtills on Vite, errors out on not being able to resolve the plugin.

Expected behavior

import VueToastificationPlugin from 'vue-toastification';

const wrapper = mount(InvoiceView, {
      props: { invoiceId: '2B8B364A-A45E-4922-85CF-0334EC5D4354' },
      global: {
        plugins: [store, VueToastificationPlugin],
      },
    });

should work just fine, instead vue displays warning: [Vue warn]: A plugin must either be a function or an object with an "install" function. Vue test utils and the test errors out on TypeError: __vite_ssr_import_16__.useToast is not a function

Steps to reproduce

jmaltis commented 1 year ago

Same issue here

pstieger92 commented 1 year ago

Same issue using render function of vue testing library

or2e commented 1 year ago

+1 NuxtRC9

arjenprogramic commented 1 year ago

I got the same error, also using vite and vitest. In the normal aplication it works, but during tests it failed. Mocking with vi.mock('vue-toastification', ...); unfortunately didn't seem to do anything either.

What I did to solve the problem for now was writing a custom (wrapped) useToast function in a separate file:

src/plugins/toasts/index.ts:

import { useToast as useToastOriginal, ...} from 'vue-toastification';
//...
export const useToast = (): ReturnType<typeof useToastOriginal> => {
  return useToastOriginal();
};
//...

And in the file that you want to use it replace import { useToast } from 'vue-toastification'; with import { useToast } from '@/plugins/toasts'; Or something similar.

In case you wanted to test for a toast notification to be triggered you can place a spy:

const wrapperVm = wrapper.vm as unknown as typeof RootComponent;
const toastSuccessSpy = vi.spyOn(wrapperVm.toast, 'success');

expect(toastSuccessSpy).not.toHaveBeenCalled();

await new Promise(resolve => setTimeout(resolve, 500)); // Just for testing purposes :P

expect(toastSuccessSpy).toHaveBeenCalled();

I hope this helps anyone running into this problem.

GradeyCullins commented 1 year ago

Similar issue here when running vitest + vue test utils.

@arjenprogramic 's solution worked for me

MerzoukeMansouri commented 1 year ago

+1 thanks for the workaround @arjenprogramic

gbyesiltas commented 1 year ago

I'm also having the same issue using Vitest + Vue3

samuelpoudroux commented 1 year ago

+1 Same issue with vite, we had to add our custom hooks :/

tim-kilian commented 1 year ago

Same issue :(

BayBreezy commented 1 year ago

Same for NuxtRC12

pavloniym commented 1 year ago

NuxtRC12, same issue... Fixed by more explicit import

// ./plugins/vue-toastification.ts

import Toast from "vue-toastification/dist/index.mjs";
import "vue-toastification/dist/index.css";

export default defineNuxtPlugin(nuxtApp => {
    nuxtApp.vueApp.use(Toast)
});
imrim12 commented 1 year ago

I have the same issue while using vue-toasted, it seems like this is a @vue/test-utils bug which cannot inject plugins functions to the tested instance using @vue/test-utils mount options

I get the cannot read 'error' of undefined when use vm?.$toasted.error() as $toasted is not injected, same things happen with my other plugins

https://replit.com/join/rrjrziigds-bittermeatball

My test file:

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

import App from "./App.vue";

describe("App", () => {
  it("should be mounted normally", () => {
    const wrapper = mount(App, {
      global: {
        mocks: {},
        plugins: [ToastPlugin]
      }
    });

    expect(wrapper.vm).toBeTruthy();
  });
});
KosekiDev commented 1 year ago

Same here, using vitest + vuejs3

kokamvd commented 1 year ago

Same for Nuxt 3.0.0 Plugin init (plugins/toastification.js):

mport { defineNuxtPlugin } from 'nuxt/app'
import Toast from 'vue-toastification'

export default defineNuxtPlugin((nuxtApp) => {
  const toastOptions = {
    closeButton: false,
    timeout: 3000,
  }

  nuxtApp.vueApp.use(Toast, toastOptions)
})
victor-ponamariov commented 1 year ago

Same here, cannot use it as a plugin

meiyerDev commented 1 year ago

same issue, vuejs 3 + vite + vitest + @testing-library/vue

michal-stachura commented 1 year ago

https://github.com/Maronato/vue-toastification/issues/341#issuecomment-1295504287 this helps. Also if you want get rid of IDE warnings with import Toast this way, you can simply add // @ts-ignore before import.

// @ts-ignore
import Toast from "vue-toastification/dist/index.mjs";
import "vue-toastification/dist/index.css";

export default defineNuxtPlugin(nuxtApp => {
  nuxtApp.vueApp.use(Toast)
})
zwsaile commented 4 months ago

I am trying to manually instantiate a component and it is giving me this same warning, '[Vue warn]: A plugin must either be a function or an object with an "install" function", for the line where I am trying to pass in my Pinia store.

import { useStore } from '../store/chartStore';

legendGroup = createApp({
        render () {
            return h(LegendGroup, {
                indicators: indicators.map(i => i.params),
                isUpper: panel.isUpper,
                panelUid: panel.params.uid,
                activeLegends
            });
        }
});
legendGroup.use(store);
legendGroup.mount(legendElement, true);