How to set up mocks for a test in a separate file with Vitest/Jest and Testing Library?
Asked Answered
C

1

9

I have the following files in a React app with Vitest (which has the same API as Jest):

// hooks/useEntities/useEntities.ts

return useEntities() {
    // this hooks send api requests so I will mock it in the test file.
}
// SomeComponent.tsx
import useEntities from 'hooks/useEntities/useEntities'

function SomeComponent () {
    const entities = useEntities()

    return <div>...</div>
}
// SomeComponent.test.tsx

vi.mock('hooks/useEntities/useEntities', () => ({ // this mocking seems to work
    default: [...]
}))

describe(...) {
    it(...) {
        render(<SomeComponent />)
    }
}

Because I mock a lot of hooks this way. I want to separate the mocking part to a different file, so it can be reused. I've tried to following ways without a success:

// init.ts

vi.mock('hooks/useEntities/useEntities', () => ({
    default: [...]
}))
// SomeComponent.test.tsx => this mocking seems to work

await init()

describe(...) {
    it(...) {
        render(<SomeComponent />)
    }
}

also tried this way:

// init.ts

vi.mock('hooks/useEntities/useEntities', () => ({
    default: [...]
}))
// SomeComponent.test.tsx => this mocking seems to work

describe(...) {
    beforeAll(async () => {
        await init()
        await init(vi) // tried the same thing with passing the vi instance to the init function in the separate file
    })
    it(...) {
        render(<SomeComponent />)
    }
}
Cesar answered 15/12, 2022 at 15:46 Comment(3)
Have you tried creating another __mocks__ folder? - jestjs.io/docs/manual-mocks - vitest.dev/guide/mocking.html#automocking-algorithmPercent
yes and it didn't work @PercentCesar
do you happen to be using any Mock Service Workers? As MSWs could be intercepting your mocked data within each test.Percent
T
1

You can use setup.ts along with the vi.mocked() to specify the return value of your mock and avoid code duplication.

// setup.ts

vi.mock("hooks/useEntities", async () => {
  // import original module and mock only the pieces that you have to
  const originalModule = await vi.importActual("hooks/useEntities");

  return {
    ...originalModule,
    useEntities: vi.fn(),
  };
});

// utils.ts

// import original function
import useEntities from "hooks/useEntities";

const mockUseEntities = (data: ReturnTypeOfUseEntities) => {
  // of course provide your own valid return type
  vi.mocked(useEntities).mockReturnValue(data); // or use mockResolvedValue if it returns Promise
};
// SomeComponent.test.tsx

describe(..., () => {
  it(..., () => {
    mockUseEntities(...) // your desired return value
    render(<SomeComponent />)
  })
})

This approach works great for me. Remember to include setup.ts in your vite.config.ts file.

https://vitest.dev/config/#setupfiles

However, when it comes to mocking external APIs I would highly suggest you to checkout msw and @mswjs/data.

https://mswjs.io/docs

https://github.com/mswjs/data

Terti answered 13/7 at 13:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.