testing-library / vue-testing-library

🦎 Simple and complete Vue.js testing utilities that encourage good testing practices.
http://testing-library.com/vue
MIT License
1.08k stars 109 forks source link

Testing with vue-18n and script setup #302

Open Explicit12 opened 1 year ago

Explicit12 commented 1 year ago

I use vue-i18n in my component, which is written using script setup syntax. When I try to render component in my test I'm getting the error TypeError: $setup.t is not a function

The test:

import { describe, test } from "vitest";
import { render } from "@testing-library/vue";
import { createI18n } from "vue-i18n";

import TheHeader from "@/components/TheHeader.vue";

const i18n = createI18n({
  legacy: false,
  locale: "en",
  messages: { ... }
});

describe("TheHeader", () => {
  test("Toggles the search input", async () => {
    const wrapper = render(TheHeader, {
      global: {
        plugins: [i18n],
      },
    });
  });
});

I've solved this problem in another test by this way:

const i18n = createI18n({
  legacy: false,
  locale: "en",
  messages: {
    en: {
      error: "Error",
    },
    uk: {
      error: "Помилка",
    },
    ru: {
      error: "Ошибка",
    },
  },
});

const wrapper = render(
  {
    ...TheError,
    $setup() {
      const { t } = useI18n();
      return { t };
    },
  },
  {
    props: { message },
    global: {
      plugins: [i18n],
    },
  },
);

But It doesn't work in this case. I've seen same problem in stack overflow several times, but no answers , so I consider it as bug. Component I try to test: https://github.com/Explicit12/utube/blob/main/src/components/TheHeader.vue

fabio984 commented 1 year ago

I'm using Vue 3 with script setup (Single File Component) and Jest.

my_i18n_lib_path/i18n.ts:

import { I18n, createI18n } from 'vue-i18n';

const i18n: I18n = createI18n({
    legacy: false,
    locale: 'en',
    messages: {},
    missing: (locale, key) =>
        console.error('Translation not found! Locale:', locale, 'translation key:', key),
});

the SFC myComponent.vue file:

import { useI18n } from 'vue-i18n';

<script setup lang="ts">
const { t } = useI18n();

then the test:

import { shallowMount } from '@vue/test-utils';
import { i18n } from 'my_i18n_lib_path/i18n';

describe('myComponent.vue', () => {
    it('Should eat onions like apples', () => {
        // Arrange
        const wrapper = shallowMount(myComponent, {
            global: {
                plugins: [i18n],
                mocks: { t: (key: string) => key },
            },
        });
    });
});

Hope this helps someone, or if it can be improved, just share.

Korny666 commented 1 year ago

Has anyone a solution yet? - Struggling with the same problem

PanDymitr commented 1 year ago

Vitest setup files to the rescue:

// vite.config.ts
export default defineConfig({
  test: {
    root: './src/',
    setupFiles: ['./setup.ts'],
  }
})
// src/plugins/i18n.ts
import { createI18n } from 'vue-i18n';

export default createI18n({
  // ...
});
// src/setup.ts
import i18n from '@/plugins/i18n';
import { config } from '@vue/test-utils';

// @ts-expect-error type
if (!globalThis.defined) {
  config.global.plugins = [i18n];
  // @ts-expect-error type
  globalThis.defined = true;
}
cbush06 commented 8 months ago

I added config.global.plugins = [VueI18n] to setup.ts.

Then, I used this in my test:

        const { getByTestId } = render({
            ...ResultsForAttemptVue,
            setup() {
                return { t: useI18n().t };
            },
        });

This seems very hackish, but nothing else would work.

isimehmeti-bga commented 6 months ago

if anyone still having the issue

import { vi } from 'vitest';

vi.mock('vue-i18n', () => ({
  useI18n: () => ({
    t: (key: string) => key,
    d: (key: string) => key,
  }),
}));

fond solution from here

Dygerydoo commented 4 months ago

I don't know why, but in my case this was happening because I use pinia. Once I set pinia as plugin everything worked. So if anyones struggling with this. Try it

import { createTestingPinia } from '@pinia/testing'

render(MessagesList, {
    props,
    global: {
      stubs: [
        'router-view',
        'vue-i18n',
      ],
      plugins: [
        createTestingPinia(),
        [plugin, defaultConfig],
      ],
    },
  }),