- 投稿日:
依存ライブラリの関係でESLint v9への移行はできていないが、取り合えずFlat configに移行した。ESLintは7.9.0から8.57.0に更新している。
確認環境
Flat configになってからeslint:recommended
は@eslint/jsに移った模様。
Env | Ver |
---|---|
@eslint/js | 9.2.0 |
@lycolia/eslint-config | 0.9.1 |
@swc/jest | 0.2.31 |
@types/jest | 29.5.11 |
@types/node | 20.11.5 |
eslint | 8.57.0 |
eslint-plugin-jest | 28.5.0 |
jest | 29.7.0 |
prettier | 3.2.5 |
typescript | 5.4.5 |
typescript-eslint | 7.8.0 |
元の設定
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/style",
"plugin:jest/recommended",
"@lycolia/eslint-config",
"prettier"
],
"plugins": [
"@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
}
}
やったこと
ESLintなど必要ライブラリのアップデート
npm i -D eslint @eslint/js eslint-plugin-jest jest prettier typescript typescript-eslint @lycolia/eslint-config
新設定の作成
eslint.config.js
を作成
extendsの設定
今までextends
に書いていたものはrequire
でモジュールを参照してmodule.exports = []
の配列の中に書いた。typescript-eslintとeslint-plugin-jestの対応が何とも言えない。なお、この状態だとtypescript-eslintが正常に動かない。
const eslint = require("@eslint/js");
const eslintTypeScript = require("typescript-eslint");
const eslintJest = require("eslint-plugin-jest");
const eslintLycolia = require("@lycolia/eslint-config");
module.exports = [
eslint.configs.recommended,
eslintTypeScript.configs.recommended[0],
eslintJest.configs["flat/style"],
eslintJest.configs["flat/recommended"],
eslintLycolia,
];
設定が競合して都合が悪かったので、この時にPrettierの設定を削除しているが、Flat config化とは特に関係ないので無視してよい。
@lycolia/eslint-configは私が作っているカスタム設定だが、これは特に何もせずとも使えた。
.eslintignore対応
extendsしたオブジェクトの次にオブジェクトを記述し、そこにignores: []
を追加し、その中に同じことを書いた。恐らく根っこの配列はESLintの設定オブジェクトの羅列で、最終的に後勝ちでマージされる様に出来ているのだろう。
const eslint = require("@eslint/js");
const eslintTypeScript = require("typescript-eslint");
const eslintJest = require("eslint-plugin-jest");
const eslintLycolia = require("@lycolia/eslint-config");
module.exports = [
eslint.configs.recommended,
eslintTypeScript.configs.recommended[0],
eslintJest.configs["flat/style"],
eslintJest.configs["flat/recommended"],
eslintLycolia,
{
ignores: [
'dist/*',
'coverage/*',
'**/*.d.ts',
'/src/public/',
'/src/type',
'*.config.js'
],
}
];
TypeScript対応
eslintTypeScript.config()
でESLintの設定配列全体を引数としてラップし、languageOptions
の中身を移植した。旧設定にあったplugins
は公式のドキュメントを見る限り不要になっている模様。
const eslint = require('@eslint/js');
const eslintTypeScript = require('typescript-eslint');
const eslintJest = require('eslint-plugin-jest');
const eslintLycolia = require('@lycolia/eslint-config');
module.exports = eslintTypeScript.config(
eslint.configs.recommended,
...eslintTypeScript.configs.recommended,
eslintJest.configs['flat/style'],
eslintJest.configs['flat/recommended'],
eslintLycolia,
{
ignores: [
'dist/*',
'coverage/*',
'**/*.d.ts',
'/src/public/',
'/src/type',
'*.config.js'
],
languageOptions: {
parser: eslintTypeScript.parser,
parserOptions: {
project: './tsconfig.json'
}
}
}
);
旧設定の削除
.eslintrc
と.eslintignore
を消した。
ESLint v9対応
typescript-eslintが対応していないため、現時点ではできなかった。
変更差分まとめ
-{
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:jest/style",
- "plugin:jest/recommended",
- "@lycolia/eslint-config",
- "prettier"
- ],
- "plugins": [
- "@typescript-eslint"
- ],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "project": "./tsconfig.json"
+const eslint = require('@eslint/js');
+const eslintTypeScript = require('typescript-eslint');
+const eslintJest = require('eslint-plugin-jest');
+const eslintLycolia = require('@lycolia/eslint-config');
+
+module.exports = eslintTypeScript.config(
+ eslint.configs.recommended,
+ ...eslintTypeScript.configs.recommended,
+ eslintJest.configs['flat/style'],
+ eslintJest.configs['flat/recommended'],
+ eslintLycolia,
+ {
+ ignores: [
+ 'dist/*',
+ 'coverage/*',
+ '**/*.d.ts',
+ '/src/public/',
+ '/src/type',
+ '*.config.js'
+ ],
+ rules: {
+ semi: ['error', 'always']
+ },
+ languageOptions: {
+ parser: eslintTypeScript.parser,
+ parserOptions: {
+ project: './tsconfig.json'
+ }
+ }
}
-}
+);
- 投稿日:
関数の仮引数にthis
が入っているタイプの奴。FastifyのsetErrorHandlerに渡す関数のテストをする時に詰まったので書いておく。滅多に遭遇しないケースだと思う。
確認環境
Env | Ver |
---|---|
jest | 29.7.0 |
typescript | 5.3.3 |
実装コード
export class HogeServer {
constructor() {
console.log();
}
}
interface HogeServerInstance {
setErrorHandler(
handler: (
this: HogeServer,
error: unknown,
callback: (code: number) => void
) => void
): HogeServer;
}
// 型定義にthisが入っていてテスト時に上手くいかない
// const handle: (this: HogeServer, error: unknown, callback: (code: number) => void) => void
type HandlerFunc = Parameters<HogeServerInstance['setErrorHandler']>[0];
export const handle: HandlerFunc = (err, cb) => {
if (err instanceof Error) {
cb(500);
} else {
cb(200);
}
};
export const fuga = (s: HogeServerInstance) => {
s.setErrorHandler(handle);
};
テストコード
import { HogeServer, handle } from '.';
describe('handle', () => {
it('errがErrorインスタンスの時', () => {
const thisMock = {} as unknown as HogeServer;
const err = new Error('error-hoge');
const cbFn = jest.fn();
// .call()を使うことでthis付きで呼び出せる
handle.call(thisMock, err, cbFn);
expect(cbFn).toHaveBeenCalledWith(500);
});
it('errがErrorインスタンスではない時', () => {
const thisMock = {} as unknown as HogeServer;
const err = 1234;
const cbFn = jest.fn();
handle.call(thisMock, err, cbFn);
expect(cbFn).toHaveBeenCalledWith(200);
});
});
- 投稿日:
親クラスをモックして子クラスの単体テストをしたいときに
確認環境
Env | Ver |
---|---|
@swc/cli | 0.1.65 |
@swc/core | 1.3.105 |
@swc/jest | 0.2.31 |
@types/jest | 29.5.11 |
jest | 29.7.0 |
typescript | 5.3.3 |
サンプルコード
コードのフルセットは以下
https://github.com/Lycolia/typescript-code-examples/tree/main/mocking-base-class-with-extension-class-swc-ts
ディレクトリ構成
src
├─BaseClass
│ └─index.ts
└─ChildrenClass
├─index.ts
└─index.spec.ts
src/BaseClass/index.ts
親クラス。この例は抽象クラスだが別に具象クラスでも何でもいいと思う
export abstract class BaseClass {
constructor(
private baseValue: string,
private ctx: { [key: string]: unknown }
) {}
public hoge<ResultT>(payload: { [key: string]: unknown }) {
// テスト走行時には全て無効な値を流し込むため
// それらの影響で落ちないことの確認のために、オブジェクトの子を意図的に書いている
console.log(this.baseValue, this.ctx.hoge, payload.piyo);
// サンプルコードなので戻り値はスタブ
return {} as ResultT;
}
}
src/ChildrenClass/index.ts
子クラス
import { BaseClass } from '../BaseClass';
export class ChildrenClass extends BaseClass {
constructor(baseValue: string, ctx: { [key: string]: unknown }) {
super(baseValue, ctx);
}
public piyo<ResultT>(payload: { [key: string]: unknown }) {
try {
// このsuper.hoge()をモックして、
// catchの中に流れるかどうかを確認するのが目的
return super.hoge<ResultT>(payload);
} catch (err) {
// 実際はロガーが動くような部分だが、サンプルコードのためconsole.logで代用する
console.log(err);
throw err;
}
}
}
src/ChildrenClass/index.spec.ts
子クラスのテスト
import { ChildrenClass } from '.';
import { BaseClass } from '../BaseClass';
describe('fetch', () => {
it('親のfetchが呼ばれ、親の戻り値が返ってくること', () => {
// 子が正しくreturnしてくるかどうかを確認するための値
const expected = { code: 200 };
// Class.prototypeとやるとモック出来る
const spiedSuperFetch = jest
.spyOn(BaseClass.prototype, 'hoge')
.mockReturnValue(expected);
// 親クラスの処理はモックするので適当な値を入れておく
// この内容が実行されていればテストが落ちるのでテストコードが間違っていることの検証に使える
const inst = new ChildrenClass('aaaa', {} as { [key: string]: unknown });
const actual = inst.piyo({ foo: 123 });
// 親クラスのメソッドが正しい引数で呼ばれたことの確認
expect(spiedSuperFetch).toHaveBeenCalledWith({ foo: 123 });
// 子クラスのメソッドの戻り値が正しいことの確認
expect(actual).toStrictEqual(expected);
});
it('親のfetchで例外が出たときに、ログ出力とリスローがされること', () => {
const expected = Error('ERR');
// 親クラスのメソッドが例外をスローするケースを作る
jest.spyOn(BaseClass.prototype, 'hoge').mockImplementation(() => {
throw expected;
});
// catch句の中でロガーが動いているかどうかの検査用
const spiedConsoleLog = jest.spyOn(console, 'log');
const inst = new ChildrenClass('aaaa', {} as { [key: string]: unknown });
// 例外がリスローされていることを確認
expect(() => {
inst.piyo({ foo: 123 });
}).toThrow(expected);
// ロガーが動いていることを確認
expect(spiedConsoleLog).toHaveBeenCalled();
});
});
- 投稿日:
Node.jsとGoogle Chrome, Microsoft Edgeを用いて、try-catchとif文でエラー処理にかかる時間がどのくらい違うのかを調べた。
計測手法
次の4パターンを100万回実行した結果を記載している。
- Result型としてエラーオブジェクトをreturnし、if文で判定する方式
- Result型としてエラーインスタンスをreturnし、if文で判定する方式
- エラーオブジェクトをthrowし、try-catchで判定する方式
- エラーインスタンスをthrowし、try-catchで判定する方式
確認に使用したコード:https://gist.github.com/Lycolia/304bc9e825e821c2d582f3ef9f700817
計測結果
CPUによって処理速度がかなり変動するが、いずれの環境でも処理速度の速さは以下の通り。
- Result型としてエラーオブジェクトをreturnし、if文で判定する方式
- エラーオブジェクトをthrowし、try-catchで判定する方式
- Result型としてエラーインスタンスをreturnし、if文で判定する方式
- エラーインスタンスをthrowし、try-catchで判定する方式
計測に使用したCPU
CPU | コア | スレッド | クロック | L2キャッシュ | L3キャッシュ |
---|---|---|---|---|---|
Intel Core i7 13700 | 16 | 24 | 5.20GHz | 24.00MB | 30.00MB |
Intel Core i7 1265U | 10 | 12 | 4.80GHz | 6.50MB | 12.00MB |
AMD Ryzen 5 5600G | 6 | 12 | 3.90GHz | 3.00MB | 16.00MB |
Intel Core i7 13700端末
16C24T, 5.20GHz, L2 24.00MB, L3 30.00MB。ミドルタワーPC。
Node.js v16.20.2
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 13700 |
OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 802 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 5,942 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 1,847 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 6,527 |
Node.js v18.19.1
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 13700 |
OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 887 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 5,826 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,006 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 6,464 |
Node.js v20.11.1
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 13700 |
OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 720 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 5,375 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 1,690 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 5,978 |
Microsoft Edge 121.0.2277.128
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 13700 |
OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 4,246 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 12,329 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 11,985 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 14,105 |
Google Chrome 122.0.6261.58
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 13700 |
OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 3,507 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 10,793 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 10,482 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 12,452 |
Intel Core i7 1265U端末
10C12T, 4.80GHz, L2 6.50MB, L3 12.00MB。ノートPC。
Node.js v16.20.2
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 1265U |
OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 972 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,416 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,288 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 13,993 |
Node.js v18.19.1
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 1265U |
OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,102 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,333 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,441 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 12,827 |
Node.js v20.11.1
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 1265U |
OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 888 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 10,881 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,269 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 12,254 |
Microsoft Edge 121.0.2277.128
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 1265U |
OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 7,526 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 34,761 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 39,005 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 65,752 |
Google Chrome 122.0.6261.58
処理環境
Env | Ver |
---|---|
CPU | Intel Core i7 1265U |
OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 6,303 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 16,460 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 17,979 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 23,378 |
AMD Ryzen 5 5600G端末
6C12T, 3.90GHz, L2 3.00MB, L3 16.00MB。ミニタワーPC。
この端末はOSがUbuntuであるため、これまでのWindows環境との単純比較はできない。
Node.js v16.20.2
処理環境
Env | Ver |
---|---|
CPU | AMD Ryzen 5 5600G |
OS | Ubuntu 22.04.3 LTS |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,786 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,242 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 3,880 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 12,716 |
Node.js v18.19.1
処理環境
Env | Ver |
---|---|
CPU | AMD Ryzen 5 5600G |
OS | Ubuntu 22.04.3 LTS |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,933 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,094 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 3,839 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 12,767 |
Node.js v20.11.1
処理環境
Env | Ver |
---|---|
CPU | AMD Ryzen 5 5600G |
OS | Ubuntu 22.04.3 LTS |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,714 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 10,741 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 3,444 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 11,978 |
Microsoft Edge 121.0.2277.128
処理環境
Env | Ver |
---|---|
CPU | AMD Ryzen 5 5600G |
OS | Ubuntu 22.04.3 LTS |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 4,348 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 21,584 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 15,543 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 23,119 |
Google Chrome 122.0.6261.57
これだけバージョンが合わなかった。
処理環境
Env | Ver |
---|---|
CPU | AMD Ryzen 5 5600G |
OS | Ubuntu 22.04.3 LTS |
処理結果
処理方式 | 処理時間(ms) |
---|---|
Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 4,842 |
Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 16,607 |
エラーオブジェクトをthrowし、try-catchで判定する方式 | 15,051 |
エラーインスタンスをthrowし、try-catchで判定する方式 | 18,095 |
全体サマリ表
凡例
- Result型としてエラーオブジェクトをreturnし、if文で判定する方式
- Result型としてエラーインスタンスをreturnし、if文で判定する方式
- エラーオブジェクトをthrowし、try-catchで判定する方式
- エラーインスタンスをthrowし、try-catchで判定する方式
CPUによってかなり差が出ているが、Intel CPUの13700と1265Uを比較した場合、例外を作らない1, 3のケースでは処理に大きな差がないが、例外を作る2, 4のケースでは有意な差が認められるので、モバイル向けとデスクトップ向けでCPUの処理効率に差があることがわかる。
AMD CPUと比較した場合、Node.js環境で例外を作らないケースではIntel CPUに大きく引けを取るが、ブラウザ上でのそれではパフォーマンスは高い。また例外を作るケースでもNode.js・ブラウザ共にIntel CPUと比較した場合のパフォーマンスが比較的よいという、面白い結果になっている。但しOSが違うことの影響もあるため、単純比較はできないが…。
あとがき
ひとまずtry-catchを使うと遅くなるということが確かめられたので良かったし、環境によって劇的遅くなるケースがあるというのは思わない収穫だった。
これを試そうと思った切欠はtry-catchが乱用されているコードを見てパフォーマンス劣化に繋がっているのではないかという疑問を抱いたからだ。try-catchでパフォーマンスの劣化が起きることは知識としても経験としても知っていたのだが、ちゃんとレポートしたことがなかったので今回まとめてみた。
try-catchの利用によりパフォーマンスの劣化が起きるというのは、古い時代にあった開発のお作法を知っている人であれば、それなりに常識だとは思うが、最近は知られていないか、知られていても意識していないことが少なくないと思われるので、今回記事にしてみた感じだ。
100万回の実行なので細かい話になるとは思うがパフォーマンスチューニングは細かいことの積み重ねでもあるので、むやみやたらに例外を使わないことは重要だと思う。そもそも例外は制御しづらいので、可能な限りif文で処理を書くことが望ましいだろう。
処理が遅延する原因としては二つあると考えていて、一つは例外生成時に顕著であることからスタックトレースの生成を初めとしたエラーオブジェクトの生成に時間がかかっているのと、もう一つはcatchでも遅延が出ることから、コールスタックから最寄りのcatchを辿るのに時間を取られていると思われる。今回の検証では特に出してないが、以前確認した時の記憶が確かであれば、catchに入らない限り、tryだけで顕著に処理が遅延することはなかったと思う。
あと、どうでもいいことだがconsole.log()
で結果を出したときにEdgeだけObjectのKeyの順序が他と違ったので転記しているときに微妙に不便だった。何回やっても同じだったので恐らくEdgeだけキーをソートするアルゴリズムが違うのだと思う。まぁObjectとかHashとかMapとかDictionaryみたいなやつは順序が保証されないので別にいいっちゃいいんだけど、まさか実装によってソート方式が違うというのは思いもしなかった。
EdgeとChromeで処理結果が優位に違うのも、恐らくこれが原因なのだろう。分からないが多分JSのエンジンの実装が違う気がする。
それとLinuxのEdgeにはマウスジェスチャー機能がないという悲しいことも分かった。
参考
- 投稿日:
以下のようなコードを書いたときにmockFnにイベント引数が渡らないが、これをどうにかして取る方法。結論から言うとまともに取れないが、試行錯誤した時のログとして残しておく
const mockFn = jest.fn();
render(<input onChange={mockFn} />);
fireEvent.change(inputElement, { target: { value: 'aaa' } });
確認環境
Env | Ver |
---|---|
@swc/core | 1.3.66 |
@swc/jest | 0.2.26 |
@testing-library/jest-dom | 5.16.5 |
@testing-library/react | 14.0.0 |
jest | 29.5.0 |
react | 18.2.0 |
サンプルコード
これは以下のように書くとfireEvent
の第二引数で指定したtarget.value
の部分だけは一応取れる。
理由としてはfireEvent
がelement.dispatchEvent
を読んでいると思われるためだ。余り深くは追っていないが、react-testing-libraryの実装上は多分そうなっていると思われる。
import { fireEvent, render } from '@testing-library/react';
it('test', () => {
const mockFn = jest.fn((ev) => {
console.log(ev);
});
const { container } = render(<input id="hoge" onChange={mockFn} value={'a'} />);
const element = container.querySelector('input');
if (element === null) throw new Error();
element.dispatchEvent = jest.fn();
fireEvent.change(element, {
target: {
value: 'bbb'
}
});
expect(element.dispatchEvent.mock.instances[0].value).toBe('bbb');
});