はじめに
お疲れ様です、りつです。
Viteで「React × TypeScript」のプロジェクトを作成し、テストを実装しようとしたところ、表題のエラーに遭遇しました。
問題
jestやReactTestingLibrary導入後、npm run test
実行時に以下のエラーが発生しました。
エラー内容
ターミナルのエラー内容
$ npm run test
> type-class@0.0.0 test
> jest
(node:412914) ExperimentalWarning: CommonJS module /home/ritsu/workspace/type-class/node_modules/jest-util/build/requireOrImportModule.js is loading ES Module /home/ritsu/workspace/type-class/jest.config.js using require().
Support for loading ES Module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
FAIL src/__tests__/App.spec.tsx
● Test suite failed to run
src/App.tsx:3:29 - error TS2307: Cannot find module '@/lib/todo' or its corresponding type declarations.
3 import { GetAllTodos } from "@/lib/todo"
~~~~~~~~~~~~
src/App.tsx:4:22 - error TS2307: Cannot find module '@/domain/todo' or its corresponding type declarations.
4 import { Todo } from "@/domain/todo"
~~~~~~~~~~~~~~~
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 3.834 s
Ran all test suites.
(node:412914) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
ソースコード
src/__tests__/App.spec.tsx
import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
import App from "../App";
import { render, screen } from "@testing-library/react";
describe("App", () => {
it("タイトルがあること", () => {
render(<ChakraProvider value={defaultSystem}><App /></ChakraProvider>);
const title = screen.getByTestId("title");
expect(title).toBeInTheDocument();
});
});
src/App.tsx
import { useEffect, useState } from "react"
import { Table } from "@chakra-ui/react"
import { GetAllTodos } from "@/lib/todo"
import { Todo } from "@/domain/todo"
function App() {
const [todos, setTodos] = useState<Todo[]>([]);
useEffect(() => {
const getAllTodos = async () => {
const todoData = await GetAllTodos();
setTodos(todoData);
}
getAllTodos();
}, [])
return (
<>
<h1 data-testid="title">TODOリスト</h1>
<Table.Root size="sm">
<Table.Header>
<Table.Row>
<Table.ColumnHeader>Title</Table.ColumnHeader>
<Table.ColumnHeader>Done</Table.ColumnHeader>
<Table.ColumnHeader>CreatedAt</Table.ColumnHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{todos.map((todo) => (
<Table.Row key={todo.id}>
<Table.Cell>{todo.title}</Table.Cell>
<Table.Cell>{todo.done ? "TRUE" : "FALSE"}</Table.Cell>
<Table.Cell>{todo.created_at}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
</>
)
}
export default App
tsconfig.app.json
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"]
}
tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"jsx": "react-jsx",
"types": ["node", "jest", "@testing-library/jest-dom"],
}
}
jest.config.js
export default {
preset: "ts-jest",
testEnvironment: "jsdom",
setupFilesAfterEnv: ["./jest.setup.ts"],
transform: {
"^.+\\.(ts|tsx)$": "ts-jest",
},
moduleNameMapper: {
"\\.(css|less)$": "identity-obj-proxy"
},
};
原因
Chakra UIを導入した際、tsconfig.app.json
にパスのエイリアスを設定しています。
tsconfig.app.json(一部省略)
{
"compilerOptions": {
// 省略
"paths": {
"@/*": ["./src/*"]
}
},
// 省略
}
App.tsx
などでimportする時にエイリアスの@
を使用してパスを記載しているのですが、それがうまく認識されていないようです。
解決方法
-
tsconfig.json
にpaths
を追加{ "files": [], "references": [ { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" } ], "compilerOptions": { "jsx": "react-jsx", "types": ["node", "jest", "@testing-library/jest-dom"], + "paths": { + "@/*": ["./src/*"] + } } }
-
jest.config.js
のmoduleNameMapper
に追記jest.config.jsexport default { preset: "ts-jest", testEnvironment: "jsdom", setupFilesAfterEnv: ["./jest.setup.ts"], transform: { "^.+\\.(ts|tsx)$": "ts-jest", }, moduleNameMapper: { "\\.(css|less)$": "identity-obj-proxy", + "^@/(.*)$": "<rootDir>/src/$1" }, };
おわりに
上記の修正で、無事テストが通るようになりました。
参考