0

I'm trying to write a jest unit test by replacing react-native-randombytes as it uses some NativeModules.

My error message:

Test suite failed to run

TypeError: Cannot read property 'seed' of undefined

> 1 | const RandomBytes = jest.genMockFromModule('react-native-randombytes');
    |                          ^
  2 | 
  3 | const randomBytes = (l) => {
  4 |   let uint8 = new Uint8Array(l);

  at seed (node_modules/react-native-randombytes/index.js:15:21)
  at Object.init (node_modules/react-native-randombytes/index.js:57:1)
  at Object.genMockFromModule (__mocks__/react-native-randombytes.js:1:26)

I place a file react-native-randombytes inside __mocks__ folder beside node_modules

const RandomBytes = jest.genMockFromModule('react-native-randombytes');

const randomBytes = (l) => {
  let uint8 = new Uint8Array(l);
  uint8 = uint8.map(() => Math.floor(Math.random() * 90)+10);
  return uint8;
};

const seed = randomBytes(4096);

RandomBytes.randomBytes = randomBytes;
RandomBytes.seed = seed;

export default RandomBytes;

I opened up the library I would like to mock and I found that instead of a class, it has the following section of code get executed at the end of it's index.js file. link

function init () {
  if (RNRandomBytes.seed) {
    let seedBuffer = toBuffer(RNRandomBytes.seed)
    addEntropy(seedBuffer)
  } else {
    seedSJCL()
  }
}

It seems that using jest.genMockFromModule will trigger the init function so the whole mocking failed. What are the considerations that I should have to choose which ways of mocking methods to use? In the documentation, it lists out various methods, but when to do which methods is not clearly recommended.

Should I use jest.fn()?

Please advice.

UPDATE 1:

I tried the following out in test file

jest.mock('react-native-randombytes');
const randomBytes = jest.fn().mockImplementation((l) => {
    let uint8 = new Uint8Array(l);
    uint8 = uint8.map(() => Math.floor(Math.random() * 90)+10);
    return uint8;
  });

result: it doesn't work. It had same error.

UPDATE 2: change my file inside mock as followed

const R = jest.genMockFromModule('react-native-randombytes');

R.randomBytes = (l) => {
  let uint8 = new Uint8Array(l);
  uint8 = uint8.map(() => Math.floor(Math.random() * 90)+10);
  return uint8;
};

R.init = () => {};

export default R;

result: same error message. It still goes to original react-native-randombytes.

UPDATE 3: just like update 1 but with some twist inspired by this post

jest.genMockFromModule('react-native-randombytes');
// eslint-disable-next-line import/first
import randomBytes from 'react-native-randombytes';

randomBytes.mockImplementation((l) => {
    let uint8 = new Uint8Array(l);
    uint8 = uint8.map(() => Math.floor(Math.random() * 90)+10);
    return uint8;
  });

result: same error message.

Hami
  • 335
  • 1
  • 7
  • 22

1 Answers1

2

Please refer to my suggestions first if you are a jest newbie.

There are many node_modules modules that depend on react-native-randombytes. You will go crazy running after each of them. Instead, you should find an upper level module and mock it and if it is only one function, just function mock. Example as shown below.

And I would suggest using a manual mock since these modules located at node_modules

Example 1:

jest.mock('react-native-securerandom', (size) => {
  return {
    generateSecureRandom: jest.fn(() => {
      let uint8 = new Uint8Array(size);
      uint8 = uint8.map(() => Math.floor(Math.random() * 90)+10);
      return uint8;
    }),
  };
});

Example 2:

'use strict';

const bip39 = jest.mock('react-native-bip39'); // genMockFromModule causes problem

bip39.generateMnemonic = jest.fn((l) => [
  'furth',
  'edessa',
  'injustices',
  'frankston',
  'serjeant',
  'khazar',
  'sihanouk',
  'longchamp',
  'stags',
  'pogroms',
  'coups',
  'upperparts',
  'endpoints',
  'infringed',
  'nuanced',
  'summing',
  'humorist',
  'pacification',
  'ciaran',
  'jamaat',
  'anteriorly',
  'roddick',
  'springboks',
  'faceted'
  ].slice(0, l));

bip39.validateMnemonic = jest.fn((_) => true);

bip39.mnemonicToSeed = jest.fn((_) => 'I am a mnemonic seed');

export default bip39;
Hami
  • 335
  • 1
  • 7
  • 22
  • 1
    note that `Math.random()` is **not** a **secure** source of randomness (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)) – Cédric Van Rompay Apr 02 '20 at 14:35
  • just an illustration, you can always choose to use more secure source of randomness. Thanks for the suggestion. – Hami Jul 30 '22 at 11:03