I’ve been trying to mock a custom hook but continuously face the same error. I think I am probably missing a fundamental concept about named exports and default exports here.
Consider the following custom hook with pseudo code:
const usePiece = (gameMode: string) => {
const [piece, setPiece] = useState<Piece>({
position: { x: 0, y: 0 },
tetromino: TETROMINOES[0].shape,
collided: false,
});
// Rotates the tetromino
const rotate = (matrix: TetrominoShape, direction: number) => {
// Code to rotate the matrix
};
// Piece rotate
const pieceRotate = (stage: StageType, direction: number) => {
// Code to rotate the piece
};
// Updates the position of the piece to the received
// parameters
const updatePiecePosition = ({
x,
y,
collided,
}: {
x: number;
y: number;
collided: boolean;
}) => {
setPiece((prev) => ({
...prev,
position: { x: prev.position.x + x, y: prev.position.y + y },
tetromino: prev.tetromino,
collided,
}));
};
// Resets the piece state. Callback doesn't depend on
// anything because the function is only called once
const resetPiece = useCallback(
(tetromino: TetrominoShape | null) => {
// Code to reset the piece
},
[gameMode]
);
return {
piece,
updatePiecePosition,
resetPiece,
pieceRotate,
};
};
export default usePiece;
My attempt at mocking this hook:
describe("Example test", () => {
beforeEach(() => {
// Mocking usePiece to control the piece's initial position and movement
vi.mock('@hooks/usePiece', () => {
const TEST_STAGE_WIDTH = 6;
return {
default: vi.fn().mockReturnValue({
piece: {
// An 4[] piece on the stage has x position at TEST_STAGE_WIDTH - 2 (as tetromino is a 2X2 matrix)
position: { x: TEST_STAGE_WIDTH - 2, y: 0 },
tetromino: [
[0, 'I'],
[0, 'I'],
],
collided: false,
},
updatePiecePosition: vi.fn(),
resetPiece: vi.fn(),
pieceRotate: vi.fn(),
}),
};
}); });
afterEach(() => {
cleanup;
// vi.clearAllMocks();
vi.restoreAllMocks();
});
})
I continuously receive this error.
Error – *Cannot destructure property ‘piece’ of ‘default(…)’ as it is undefined.*
- How to mock this custom hook?
- What is the difference between the two mock implementations shown below:
Implementation one
import * as usePiece from '@hooks/usePiece';
vi.mock('@hooks/usePiece');
beforeEach(() => {
usePiece.default = vi.fn().mockReturnValue({
piece: {
// A piece on the stage has x position at TEST_STAGE_WIDTH - 2 (as tetromino is a 2X2 matrix)
position: { x: TEST_STAGE_WIDTH - 2, y: 0 },
tetromino: [
[0, 'I'],
[0, 'I'],
],
collided: false,
},
updatePiecePosition: vi.fn(),
resetPiece: vi.fn(),
pieceRotate: vi.fn(),
});
})
and, implementation two
vi.mock('@hooks/usePiece', () => {
const TEST_STAGE_WIDTH = 6;
return {
default: vi.fn().mockReturnValue({
piece: {
// An 4[] piece on the stage has x position at TEST_STAGE_WIDTH - 2 (as tetromino is a 2X2 matrix)
position: { x: TEST_STAGE_WIDTH - 2, y: 0 },
tetromino: [
[0, 'I'],
[0, 'I'],
],
collided: false,
},
updatePiecePosition: vi.fn(),
resetPiece: vi.fn(),
pieceRotate: vi.fn(),
}),
};
});
- When to use either of the two mock implementations? Would be great, if you can give examples.
- What is the meaning of factory in
If factory is defined, all imports will return its result. Vitest calls factory only once and caches results for all subsequent imports until vi.unmock or vi.doUnmock is called.
Quote taken from vitest docs