- 投稿日:
以下のようなコードを書いたときに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');
});
- 投稿日:
条件分岐でコンポーネントの出し分けをしている時に正しくコンポーネントが出ているかどうかに使えるやつ
UIロジックのリグレッションテストで使える
分岐結果の出力を見てるだけなのでテストとして壊れづらく、運用しやすいと考えている
確認環境
Next.jsで確認してるけど素のReactでも同じだと思う
Env | Ver |
---|---|
@swc/core | 1.2.133 |
@swc/jest | 0.2.17 |
jest | 27.4.7 |
next | 12.0.8 |
react | 17.0.2 |
react-dom | 17.0.2 |
react-test-renderer | 17.0.2 |
typescript | 4.5.4 |
テスト対象
テストのためにコンポーネントを細かくexport
すると名前空間が汚染されるのが悩み…
type BaseProps = {
id: string;
};
type SwitchExampleProps = BaseProps & {
display: 'Foo' | 'Bar';
};
export const Foo = (props: BaseProps) => {
return (
<div id={props.id}>
<p>Foo</p>
</div>
);
};
export const Bar = (props: BaseProps) => {
return (
<div id={props.id}>
<p>Bar</p>
</div>
);
};
export const SwitchExample = (props: SwitchExampleProps) => {
if (props.display === 'Foo') {
return <Foo id={props.id} />;
} else {
return <Bar id={props.id} />;
}
};
テストコード
react-testing-libraryの.toHaveAttribute()
や.toHaveDisplayValue()
を書き連ねるより圧倒的に楽で保守性も良いと思う
import TestRenderer from 'react-test-renderer';
import { Bar, Foo, SwitchExample } from './SwitchExample';
type TestCase = {
name: string;
param: Parameters<typeof SwitchExample>[0];
actual: JSX.Element;
};
describe('SwitchExample', () => {
const testCaseItems: TestCase[] = [
{
name: 'Foo',
param: {
id: 'hoge',
display: 'Foo',
},
actual: <Foo id={'hoge'} />,
},
{
name: 'Bar',
param: {
id: 'piyo',
display: 'Bar',
},
actual: <Bar id={'piyo'} />,
},
];
testCaseItems.forEach((item) => {
// eslint-disable-next-line jest/valid-title
it(`switched condition ${item.name}`, () => {
const result = TestRenderer.create(
<SwitchExample id={item.param.id} display={item.param.display} />
);
const actual = TestRenderer.create(<>{item.actual}</>);
expect(result.toJSON()).toStrictEqual(actual.toJSON());
});
});
});
参考記事
- 投稿日:
確認環境
Env | Ver |
---|---|
next | 11.1.2 |
typescript | 4.3.4 |
サンプルコード
__mocks__/next/router.ts
export const useRouter = () => {
return {
route: '/',
pathname: '',
query: '',
asPath: '',
push: jest.fn(),
replace: jest.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
},
beforePopState: jest.fn(() => null),
prefetch: jest.fn(() => null),
};
};
- 投稿日:
基本出来ないのでwindow.location.href
を操作するためのラッパーを作って、それをjest.spyOn()
して解決する
理由はjsdomが対応していないため
- 投稿日:
global.navigator
をモックにする方法- モックというか書き換えてるだけ
jest
のモック機能はプロパティのモックが出来ないので、実オブジェクトを強制的に書き換えて実施する
サンプルコード
Object.defineProperty()
を利用して実装value
, プロパティが返す値configurable
, 再定義可能かどうか、設定しないと再実行でコケる
- 実際の使用ではユーティリティ関数を作っておき、
afterAll()
でnavigator.userAgent
を初期値に戻すのが望ましい
Object.defineProperty(global.navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
configurable: true,
});