javascriptvue.jspiniavue-testing-library

Unit Testing Vue 3 Component that uses Pinia with Vue Testing Library


I am struggling to understand how I can test the rendering of items based on the results of a call to a Pina getter in my Vue 3 app (using the Vue Testing Library). An example of what I want to achieve might be something like:

<div v-for="contact in store.getContacts()">
      <p>{{contact.firstName}} {{ contact.lastName }}</p>
</div>

where I want to test that all the names of the contacts are displayed.

My app uses Vitest and @testing-library/vue so in my test spec for the above test I might have:

import { cleanup, getByRole, render, screen } from "@testing-library/vue";
import { describe, it, vi, beforeEach, afterEach } from "vitest";
import MyComponent from "@/components/MyComponent.vue";
import { createTestingPinia } from "@pinia/testing";

describe("MyComponent.vue", () => {

  let getByText: any, getByRole: any;

  beforeEach(() => {
    ({ getByText } = render(MyComponent, {
      global: {
        plugins: [
          createTestingPinia({
            initialState: {
              contacts: [{firstName:"Bill",lastName:"Jones"},{firstName:"Peter",lastName:"Smith"}],
            },
            stubActions: false,
            createSpy: vi.fn,
          }),
        ],
      },
    }));
  });

  afterEach(() => {
    cleanup();
  });
  
  it("should display the first name", () => {
    getByText("Bill Jones");
  });

}); 

in the store I have the following state setup:

interface Student {
  "id": number;
  "firstName": string;
  "lastName": string;
  "house": string;
  "year": number;
  "class": string;
}

interface ContactState {
  contacts: Student[];
}

export const useContactStore = defineStore({
  id: "contact",
  state: ():ContactState => ({
    contacts: [],
}),

and a getter:

getContacts: (state) => {
      return state.contacts;
}

I think I have setup the initial state of the store correctly (??) but the getter does not seem to be working - what else do I need to do here? Do I have to mock the getter or something? Or maybe I am not initialising the store correctly in the test?

(my app is all working fine, it's the test I cannot get to work)


Solution

  • When you create the initial state using createTestingPinia, you also need to state the store id, also called name, which is in your case would be contact as seen in in your defineStore.

    So in this case, I think what you should do is change the current code to this:

    ...
    createTestingPinia({
        initialState: {
            contact: {
                contacts: [{firstName:"Bill",lastName:"Jones"},{firstName:"Peter",lastName:"Smith"}]
            },
         },
         stubActions: false,
         createSpy: vi.fn,
    }),
    ...
    

    This is not very well explained in the documentation, however, this should at least initialize the contacts array for you.