Я только что начал новый проект React/Next.js и понял, что не могу имитировать мемоизированные компоненты React так, как я мог это делать в предыдущем проекте. И я не могу понять, почему. Вот минимальный пример моей настройки:
// /src/components/Foo.tsx
import Bar from "./Bar";
const Foo = () => (
<div>
<Bar />
</div>
);
export default Foo;
// /src/components/Bar.tsx
import { memo } from "react";
const Bar = memo(function Bar_() {
return <div>Original</div>;
});
export default Bar;
Теперь я хочу протестировать Foo издевательство Bar.
Вот что я сделал в своем последнем проекте:
// /src/components/Foo.test.tsx
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import Foo from "./Foo";
const barModule = require("./Bar");
jest.replaceProperty(barModule, "default", () => <div>Mocked</div>);
describe("Foo", () => {
it("should mock Bar", () => {
render(<Foo />);
expect(screen.queryByText("Original")).not.toBeInTheDocument();
});
});
Но когда я запускаю тесты, я получаю сообщение об ошибке «Свойство default не объявлено настраиваемым». Как я могу это исправить?
Вот мои конфигурационные файлы:
// jest.config.js
const nextJest = require("next/jest");
/** @type {import('jest').Config} */
const createJestConfig = nextJest({
dir: "./",
});
/** @type {import('jest').Config} */
const config = {
clearMocks: true,
collectCoverage: true,
coverageDirectory: "coverage",
coverageProvider: "v8",
testEnvironment: "jsdom",
};
module.exports = createJestConfig(config);
// tsconfig.json
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
// package.json
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest"
},
"dependencies": {
"next": "14.1.4",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.2",
"@types/jest": "^29.5.12",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "^14.1.4",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"typescript": "^5"
}
}
@morganney, это приводит к той же ошибке: свойство Bar не объявлено настраиваемым.
Вы пробовали вместо этого использовать jest.mock('./Bar')? jestjs.io/docs/mock-functions#mocking-modules
Это не сработает, потому что компонент мемоизирован. См. https://stackoverflow.com/questions/77770830/how-to-mock-a-memoized-react-comComponent-with-jest.
Тогда зачем принимать ответ, используя jest.mock. Лучше читать текущую документацию и примеры, чем регулярно копировать шаблоны из предыдущих проектов. Технические изменения.





Издевайтесь так:
jest.mock('./Bar', () => ({ default: () => 'mocked Bar' }));
Затем я получаю: Ошибка: тип элемента недействителен: ожидалась строка (для встроенных компонентов) или класс/функция (для составных компонентов), но получен: объект. Проверьте метод рендеринга Foo.
Вы уверены, что экспортировали Bar по умолчанию и импортировали по умолчанию? stackoverflow.com/a/36265067/11309214
Да, смотрите код в моем вопросе.
Обратите внимание, что Бар запомнен!
Вероятно, вы можете избежать этого, не используя экспорт по умолчанию. Использование экспорта по умолчанию в модульных системах — это раздражающий антипаттерн, который только причинит вам боль. Используйте полную версию CJS или ESM.