TypeError: Cannot read properties of undefined (reading 'getRandomValues')
に対応したメモ。
前提
- Jestでテストをする
- Crypto.getRandomValues() という乱数を生成するメソッドがある。
乱数文字列を生成する関数
function getRandom() { const S = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const N = 64; const str = Array.from(window.crypto.getRandomValues(new Uint8Array(N))) .map((n) => S[n % S.length]) .join(''); return str; } ... function foo() { const rand = getRandom(); ... }
fooのテストコード
describe('foo', () => { test('success', async () => { const result = foo(); expect(result).toEqual(...); }); });
テストを実行すると以下のようになる。
yarn test yarn run v1.22.22 FAIL xxx.test.ts foo ✕ success ● foo › success TypeError: Cannot read properties of undefined (reading 'getRandomValues') 12 | const S = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 13 | const N = 64; > 14 | const str = Array.from(window.crypto.getRandomValues(new Uint8Array(N))) | ^ 15 | .map((n) => S[n % S.length]) 16 | .join(''); 17 | return str;
ステップ1
当該テストの中で、getRandomValuesをmockにする。
fooのテストコード
describe('foo', () => { test('success', async () => { const mGetRandomValues = jest .fn() .mockReturnValueOnce([ 23, 52, 227, 35, 236, 241, 244, 212, 231, 189, 171, 160, 70, 146, 227, 90, 99, 2, 161, 45, 164, 115, 254, 138, 146, 243, 55, 107, 31, 87, 0, 235, 96, 216, 125, 200, 88, 119, 205, 209, 224, 185, 235, 101, 168, 202, 134, 70, 38, 175, 41, 5, 1, 102, 60, 2, 46, 216, 212, 17, 176, 231, 233, 167, ]); Object.defineProperty(window, 'crypto', { value: { getRandomValues: mGetRandomValues }, }); const result = foo(); expect(result).toEqual(...); }); });
これでも動作はするが、
- テストケース毎にmockを記述するのは煩雑になる
- foo
のテストケースで、内部で呼び出している関数のmock追加することに違和感を感じる。認知負荷が高い気がする。
ステップ2
- fooのテストはそのままにしたい。
- テストケース毎にmockををするのではなく、設定を一箇所にしたい
前提
jest.config.js
/** @type {import('jest').Config} */ const config = { ... "setupFiles": [ "<rootDir>/src/jest/jest.polyfills", ], ...
改善
src/jest/jest.polyfills.js
... const crypto = require('crypto'); Object.defineProperty(globalThis, 'crypto', { value: { getRandomValues: arr => crypto.randomBytes(arr.length) } }); ...
セットアップで、mockの設定をすることで個別のテストケースではmockしないようにする。