Is there a way to simulate Pinia and vue-i18n simultaneously?

Exploring Vue 3's Composition API with a twist:

The store.ts file

import { ref, Ref } from 'vue';
import { defineStore } from 'pinia';

export const useStore = defineStore('store', () => {
  const isLoading: Ref<boolean> = ref(true);

  function initialize() {
    isLoading.value = true;
    setTimeout(() => (isLoading.value = false), 3000);
  }

  return {
    initialize,
    isLoading,
  };
});

Inside the Component.vue file

<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { useStore } from './store';

const { t } = useI18n();
const store = useStore();
const { isLoading } = storeToRefs(store);
</script>

<template>
  <wb-button @click="store.initialize()">{{ t('initialize') }}</wb-button>
  <p>Loading: {{ isLoading ? 'Yes' : 'No' }}</p>
</template>

Everything seems fine during implementation, but it gets complicated when testing. To simplify things, I mock vue-i18n globally like this:

Creating testSetup.ts file

import { vi } from 'vitest';

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

Unfortunately, things get messy when attempting to mock the store simultaneously as demonstrated in Component.test.ts:

Testing Component.vue

import { it, expect, vi } from 'vitest';
import { mount} from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import Component from './Component.vue';

const options = {
  global: {
    plugins: [
      createTestingPinia({
        createSpy: vi.fn(),
        initialState: {
          items: [],
        },
      }),
    ],
  },
};

it('tests are functioning', () => {
  const wrapper = mount(Component, options);
  expect(wrapper.findComponent(Component)).toBeTruthy();
});

Upon introducing Pinia mocking to the plugin configuration, the vue-i18n mock fails and triggers an error stating

TypeError: $setup.t is not a function
. Various attempts such as using config.global.mocks or config.global.plugins have also failed after implementing Pinia mocking in the tests. It appears that the behavior of the config.global object is somehow altered by @pinia/testing, making it difficult to troubleshoot.

Package dependencies listed in package.json:

"@pinia/testing": "0.0.16",
"@types/jsdom": "21.1.1",
"@types/node": "18.16.2",
"@vue/test-utils": "2.3.2",
"jsdom": "21.1.1"
"typescript": "~4.8.4",
"vite": "4.3.3",
"vitest": "0.30.1",

Answer №1

The problem arises when the createSpy property is given a call instead of a function. To resolve this, simply change vi.fn() to vi.fn and everything will function as intended.

createTestingPinia({
  createSpy: vi.fn, <--
  ...
})

Source:

Answer №2

There's an error message indicating that the mounted component is missing a t function. This issue arises because VueI18n has not been included as a plugin in the mounting options:

import { it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createPinia } from 'pinia'
import Component from './Component.vue'
import { createI18n } from 'vue-i18n'

const options = {
  global: {
    plugins: [
      createPinia(),
      createI18n({
        legacy: false,
        locale: 'en-US',
        messages: {
          'en-US': {
            init: 'Initialize'
          }
        }
      })
    ]
  }
}

it('does work', () => {
  const wrapper = mount(Component, options)
  expect(wrapper.findComponent(Component)).toBeTruthy()
})

To clarify, global.plugins requires a Vue plugins array (objects or class instances with an install() function). It functions similarly to app.use(somePlugin).
All necessary plugins for the tested component (and its children, if not shallow-mounted) should be included here. Unit tests are conducted independently of the actual app environment.

In essence, this issue mimics what would occur if you attempted to use VueI18n without using .use(VueI18n) on the app.


To streamline test file setup, consider exporting a mountingOptions from test.utils.ts:

import { createPinia } from 'pinia'
import { createI18n } from 'vue-i18n'

export const mountingOptions = {
  global: {
    plugins: [
      createPinia(),
      createI18n({
        legacy: false,
        locale: 'en-US',
        messages: {
          'en-US': {
            init: 'Initialize'
          }
        }
      })
    ]
  }
}

Ideally, mountingOptions should encompass all plugins added to the app in the main file.

Subsequently, in any test scenario:

import { mountingOptions } from '../test.utils'
//...
const wrapper = mount(Component, mountingOptions)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the most effective method to implement a toggle function using only JavaScript, without any reliance on jQuery?

Recently, I had a navigation bar in the form of an unordered list (ul) with multiple list items (li), and the last li element was labeled 'more' which had its own sub-menu in the form of another ul. To toggle this sub-menu between visible and hid ...

jquery to create a fading effect for individual list items

I have a group of items listed, and I would like them to smoothly fade out while the next one fades in seamlessly. Below is the code I've been working on: document.ready(function(){ var list_slideshow = $("#site_slideshow_inner_text"); ...

A new sub-schema has been created in the JSON schema specifically tailored to a certain property

I needed to create a JSON schema with 3 fields: num, key1, and key2. The fields num and key1 are required, while the field key2 is only mandatory if key1 has a value of 'abc'. Below is the schema structure I came up with: schema = { type: &ap ...

Track the number of views each month using PHP and MySQL to generate dynamic jQuery charts

I am currently utilizing jQuery with chart.js to display the view counter based on month using PHP and MySql. Each page view is inserted into MySql in the following format : | id | ip | page | date(timestamp) | | 1 | 138.86.20.20 | test.p ...

Maximizing the efficiency of a personalized hook that facilitates data sharing in React

I have developed a unique Custom Hook that looks like the following: import { useEffect, useState } from 'react'; import axios from 'axios'; const myCustomHook = () => { const [countries, setCountries] = useState([]); const [i ...

Extracting user login details from a Java script-based web browser for a RASA chatbot

Our website integrates a web bot using Javascript. When users log in, they can access the chatbot icon. Currently, the chatbot starts without collecting user data. However, having user data is important as we plan to trigger actions based on user ID. If ...

Sinon Stub generates varying values with each invocation

I'm pretty new to TypeScript and JavaScript, but I've managed to create a functioning VScode extension that I'm really happy with. However, I'm running into some issues with my Mocha tests. Here's a snippet of the code I'm str ...

Execute Function on Double-Click with Flot.js

Is there a way to run a function when the mouse double-clicks while using flot? Currently, I am only able to trap the single click with the following code: $(graph).bind('plotclick', function(event, pos, item) { if (item) { .... ...

Having trouble getting NPM to install on my personal computer

Here are the specifications listed below. Node Version : v16.13.0 Npm Version : 8.1.2 Below is a record of the commands I attempted one at a time. npm cache clean npm install --no-bin-links npm install --save Subsequently, I encountered an error indica ...

Does the positive Z axis move inward in threejs? The behavior of camera.near and camera.far seems strange

My goal is to display only a slice of my 3D object. I have tried setting the orthographic camera's camera.near to 2.0 and camera.far to 1.5, then iterating with values of camera.near = 1.5 and camera.far = 1.0. However, this approach is not yielding t ...

expanding the expressjs res feature

I am currently working on implementing an error and notification feature for my expressjs app. My approach was to add a function by calling: app.use(function (req, res, next) { res.notice = function (msg) { res.send([Notice] ' + msg); } }); ...

Converting an Array of Objects into a single Object in React: A Tutorial

AccessData fetching information from the database using graphql { id: '', name: '', regions: [ { id: '', name: '', districts: [ { id: '', ...

Oops! Looks like there was an issue with assigning to a reference or variable: Error: Uncaught (in promise)

I seem to be struggling with an issue that I believe may have been addressed before, but after reviewing other solutions, I am unable to pinpoint the error in my code. Any assistance in identifying my mistake would be greatly appreciated. <div class="j ...

Align the headers of columns to the right in the AgGrid widget

Is there a way to align the column headers to the right in AgGrid without having to implement a custom header component? It seems like a lot of work for something that should be simple. You can see an example here: https://stackblitz.com/edit/angular-ag-g ...

Troubleshooting Typescript Compilation Error in React - Cannot assign type 'Element' to type 'FunctionComponent<{}>'

The code snippet originally utilized - import { Create } from '@material-ui/icons'; <DroppableFolder count={draftsCount} sidebarOpen={open} folderId={FolderType.Drafts} Icon={Create} name="Dr ...

Error: The variable <something> has not been defined

Within my GitHub project, an error stating Uncaught ReferenceError: breakpoints is not defined is appearing in the Chrome console. This issue should be resolved by including breakpoints.min.js, but it seems that webpack is somehow causing interference. I ...

when webpack loads the bundle.js file, the mime type is converted to text/html

I'm currently working on implementing server side rendering for an application using react-redux and express for the server. We are also utilizing webpack to bundle our assets. To get started, I referred to the following documentation: https://redux ...

What is the best way to transfer a variable from jQuery to a PHP script?

While I am aware that similar questions have been asked in the past, I am facing a unique challenge in trying to create a table with distinct links and pass the id of the link to a PHP page. Here is what I have so far: echo("<p>To reser ...

What steps can be taken to troubleshoot issues with the jquery mask plugin?

I am using the jQuery Mask Plugin available at to apply masks to input fields on my website. Currently, I am trying to implement a mask that starts with +38 (0XX) XXX-XX-XX. However, I am facing an issue where instead of mandating a zero in some places, ...

Assign a complete object to the v-model of a Vuetify v-select

My vuetify select component looks like this: <v-select class="ml-4" v-model="selectedProjects" :items="projects" item-text="name" item-value="id" chips :menu-pro ...