自分の作ったChrome拡張にテストを組み込む(2) テスト追加編
JestとReact-Testing-Libraryを使って単体テストをやりたい
このメモの続きです。
対象レポジトリ
テストケース用のディレクトリを追加する
__tests__
というディレクトリ内にテスト用のファイルを追加していく。
$ tree -d src
src
├── Component
├── Container
├── FunctionalButton
├── Functions
├── Section
│ └── ShortCutLinks
└── scss
※ディレクトリ構成が気持ち悪いのは許してください…
関数を切り出しているのはFunctionsディレクトリなのでそこにテストケース用のディレクトリを追加する。
$ mkdir -p src/Functions/__tests__
テストケースの作成
配列の要素をユニークにする関数を置いているので、期待した動きをするかどうかのテストケースを書いていく。
参考: JavaScriptのArrayでuniqする8つの方法(と、その中で最速の方法) - Qiita
その前に、Jestのドキュメントを見ながら書き方を確認。
参考: Getting Started · Jest
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
なるほど。 test('説明', () => expect(関数(引数)).toBe(期待する値));
みたいな構文なのね?というのがわかる。
早速書いてみる。
import { unique } from '../Unique';
test('remove duplicate element', () => {
const input = ['A', 'B', 'AA', 'B'];
const expected = ['A', 'B', 'AA'];
expect(unique(input)).toBe(expected);
});
テストしてみる
テストケースを書いたので早速テストしてみる。
$ npm run test
> short-cut-extension@1.3.2 test
> npx jest
FAIL src/Functions/__tests__/Unique.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/satoshie/git/chrome-extension-study/src/Functions/__tests__/Unique.ts:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { unique } from '../Unique';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1796:14)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.562 s
Ran all test suites.
ダメじゃん!!
jest.config.tsの修正
TypeScriptのファイルはちゃんとJestの設定で変換の指定を指定してあげないといけない。
jest.config.ts に transform の指定を追加する。
const config: Config = {
verbose: true,
+ transform: {
+ '^.+\\.ts$': 'ts-jest',
+ },
};
追加した状態で再度テストを実行してみる。
$ npm run test
> short-cut-extension@1.3.2 test
> npx jest
FAIL src/Functions/__tests__/Unique.ts
● Test suite failed to run
Unable to process '/Users/satoshie/git/chrome-extension-study/src/Functions/__tests__/Unique.ts', please make sure that `outDir` in your tsconfig is neither `''` or `'.'`. You can also configure Jest config option `transformIgnorePatterns` to inform `ts-jest` to transform /Users/satoshie/git/chrome-extension-study/src/Functions/__tests__/Unique.ts
at TsCompiler.getCompiledOutput (node_modules/ts-jest/dist/legacy/compiler/ts-compiler.js:165:27)
at TsJestCompiler.getCompiledOutput (node_modules/ts-jest/dist/legacy/compiler/ts-jest-compiler.js:13:39)
at TsJestTransformer.processWithTs (node_modules/ts-jest/dist/legacy/ts-jest-transformer.js:232:37)
at TsJestTransformer.process (node_modules/ts-jest/dist/legacy/ts-jest-transformer.js:161:24)
at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:619:31)
at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:765:40)
at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:822:19)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 1.585 s
Ran all test suites.
エラーの内容が変わった。
please make sure that
outDir
in your tsconfig is neither''
or'.'
.
tsconfig内の outDir
の設定が ''
か '.'
になっていないか確認してください。とのことだけど、 outDir
の設定はそうはなっていないのでここではなさそう。
トランスパイル周りな気がするんだよなぁ。
そう言えばテストにばかり注意を向けていたけど、本体のビルドは影響ないのか?と思っていざビルドしてみると…
$ npm run build
(省略)
ERROR in /Users/satoshie/git/chrome-extension-study/tsconfig.json
/Users/satoshie/git/chrome-extension-study/tsconfig.json
[tsl] ERROR
TS6059: File '/Users/satoshie/git/chrome-extension-study/jest.config.ts' is not under 'rootDir' '/Users/satoshie/git/chrome-extension-study/src'. 'rootDir' is expected to contain all source files.
The file is in the program because:
Root file specified for compilation
1 error has detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.
jest.config.ts
をルートディレクトリに置いてしまっていたせいで発生していたので src/
配下に移動した。
移動したら既存のコードのビルドは通るようになった。
気を取り直してこの状態でテスト実行してみる。
$ npm run test
> short-cut-extension@1.3.2 test
> npx jest
FAIL src/Functions/__tests__/Unique.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/satoshie/git/chrome-extension-study/src/Functions/__tests__/Unique.ts:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { unique } from '../Unique';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1796:14)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.541 s
Ran all test suites.
振り出しに戻ってる…。
公式ドキュメント見ると --config
で設定ファイルを指定してね!って書いてあったので package.json
の test
の設定を修正。
"test": "npx jest --config src/jest.config.ts",
そして再度テスト実行してみる。
$ npm run test
> short-cut-extension@1.3.2 test
> npx jest --config src/jest.config.ts
FAIL src/Functions/__tests__/Unique.ts
✕ remove duplicate element (5 ms)
● remove duplicate element
expect(received).toBe(expected) // Object.is equality
If it should pass with deep equality, replace "toBe" with "toStrictEqual"
Expected: ["A", "B", "AA"]
Received: serializes to the same string
5 | const expected = ['A', 'B', 'AA'];
6 | expect(unique(input)).toBe(expected);
> 7 | });
| ^
8 |
at Object.<anonymous> (Functions/__tests__/Unique.ts:7:41)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.772 s
Ran all test suites.
おおおおおお!ちゃんとテスト出来てる!
これは異なるオブジェクト同士をEqualsで比較しようとしたからFailedになったんだね!
これはテストケースが正しくないから書き換える。
Use .toStrictEqual to test that objects have the same types as well as structure.
Differences from .toEqual:
Keys with undefined properties are checked. e.g. {a: undefined, b: 2} does not match {b: 2} when using .toStrictEqual.
Array sparseness is checked. e.g. [, 1] does not match [undefined, 1] when using .toStrictEqual.
Object types are checked to be equal. e.g. A class instance with fields a and b will not equal a literal object with fields a and b.
今度こそ!
早速テストコードを書き換えてみる。
import { unique } from '../Unique';
test('remove duplicate element', () => {
const input = ['A', 'B', 'AA', 'B'];
const expected = ['A', 'B', 'AA'];
expect(unique(input)).toStrictEqual(expected);
});
$ npm run test
> short-cut-extension@1.3.2 test
> npx jest --config src/jest.config.ts
PASS src/Functions/__tests__/Unique.ts
✓ remove duplicate element (2 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.754 s, estimated 2 s
Ran all test suites.
無事テストも通るようになりました 🥰
次は react-testing-library を導入していきます!
Discussion