jestjs / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
44.06k stars 6.44k forks source link

[Bug]: #14456

Closed EvandrooViegas closed 1 year ago

EvandrooViegas commented 1 year ago

Version

29.6.3

Steps to reproduce

  1. Clone my repo: https://github.com/EvandrooViegas/valorant-agents
  2. cd to client: cd client
  3. run: npm run test

Expected behavior

I expected the load function from home.page.test.ts file to be mocked properly

Actual behavior

jest.mock("./+page.server", () => {
    const originalModule = jest.requireActual("./+page.server") as {}
    return {
        __esModule: true,
        ...originalModule,
        load: jest.fn(() => ({
            agents: [
                { uuid: "", displayName: "a", description: "", displayIcon: "", fullPortrait: "", background: "", role: { displayName: "", displayIcon: "" }, abilities: [] },
                { uuid: "", displayName: "b", description: "", displayIcon: "", fullPortrait: "", background: "", role: { displayName: "", displayIcon: "" }, abilities: [] },
                { uuid: "", displayName: "c", description: "", displayIcon: "", fullPortrait: "", background: "", role: { displayName: "", displayIcon: "" }, abilities: [] },
            ]
        }))
    };
})

import { describe, jest } from "@jest/globals";
import { render, screen } from "@testing-library/svelte";
import Page from "./+page.svelte";
import * as loadModule from "./+page.server";

describe("testing the home page", () => {
    it("should load and render all agents on the page", () => {
        render(Page)
        expect(loadModule.load).toBeCalled()
        expect(screen.getAllByTestId("agent-a")).toHaveLength(1)
        expect(screen.getAllByTestId("agent-b")).toHaveLength(1)
        expect(screen.getAllByTestId("agent-c")).toHaveLength(1)

    })
})

this is the test, here I'm mocking a function return. When i try to run the test I get this:

expect(received).toBeCalled()

    Matcher error: received value must be a mock or spy function    

    Received has type:  function
    Received has value: [Function load]

Additional context

This project is built with sveltekit and typescript, the function that I'm trying to mock is the load function, it is responsible to provide the data to the page. What I'm trying to do at the code above is mocking the load function to return dummy data, and I'm expecting to this function be called and the items returned from this function to be rendered correctly on the page.

Environment

System:
    OS: Windows 10 10.0.19045
    CPU: (4) x64 Intel(R) Core(TM) i5-3350P CPU @ 3.10GHz
  Binaries:
    Node: 18.12.1 - C:\Program Files\nodejs\node.EXE   
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD     
    npm: 8.19.2 - C:\Program Files\nodejs\npm.CMD      
  npmPackages:
    jest: ^29.6.3 => 29.6.3
EvandrooViegas commented 1 year ago

btw this is my jest config:

{
    "preset": "ts-jest",
    "transform": {
        "^.+\\.svelte$": [
            "svelte-jester",
            {
                "preprocess": true
            }
        ],
        "^.+\\.ts$": [
            "ts-jest",
            {
                "useESM": true
            }
        ]
    },

    "moduleFileExtensions": ["js", "ts", "svelte"],
    "extensionsToTreatAsEsm": [".svelte", ".ts"],
    "testEnvironment": "jsdom",
    "moduleNameMapper": {
        "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/mocks/fileMock.js"
    }
}
mrazauskas commented 1 year ago

See the Module mocking in ESM section in the ECMAScript Modules guide.

The thing is that jest.mock() and jest.requireActual() will work only for CJS modules. For details on mocking ESM modules check the link above.

EvandrooViegas commented 1 year ago

Thanks! It actually worked. This is the solved code if anyone needs it:

import { describe, jest } from "@jest/globals";
import { render, screen } from "@testing-library/svelte";
import Page from "./+page.svelte";
jest.unstable_mockModule("./+page.server", () => {

    return {
        __esModule: true,
        load: jest.fn(() => Promise.resolve(({
            agents: [
                { uuid: "", displayName: "a", description: "", displayIcon: "", fullPortrait: "", background: "", role: { displayName: "", displayIcon: "" }, abilities: [] },
                { uuid: "", displayName: "b", description: "", displayIcon: "", fullPortrait: "", background: "", role: { displayName: "", displayIcon: "" }, abilities: [] },
                { uuid: "", displayName: "c", description: "", displayIcon: "", fullPortrait: "", background: "", role: { displayName: "", displayIcon: "" }, abilities: [] },
            ],
        })))
    };
})

const { load } = await import("./+page.server")

describe("testing the home page", () => {
    it("should load and render all agents on the page", () => {
        render(Page)
        expect(load).toBeCalled()
        expect(screen.getAllByTestId("agent-a")).toHaveLength(1)
        expect(screen.getAllByTestId("agent-b")).toHaveLength(1)
        expect(screen.getAllByTestId("agent-c")).toHaveLength(1)

    })
})
mrazauskas commented 1 year ago

Glad it work.

By the way, you can skip __esModule: true. If I remember it right, Babel is adding that prop for code transformed from ESM to CJS. That is needed for some interop (default imports, perhaps?). You don’t transform between ESM and CJS, so just skip that.

github-actions[bot] commented 11 months ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.