Home > other >  Why can't I mock `crypto.createHash`?
Why can't I mock `crypto.createHash`?

Time:02-11

I'm trying to test a function which makes use of Node's crypto.createHash function. However, when I try to mock it using jest.mock('crypto', () => ({ createHash: … })), the mock doesn't seem to work.

The unit under test uses both Hash#update and Hash#digest, so I'm trying to add those to the createHash mock, but when the unit runs, createHash returns undefined.

src/hash.ts

import { createHash } from 'crypto';

export function hash(input: string | Uint8Array): Uint8Array {
  return new Uint8Array(createHash('sha512').update(input).digest().buffer);
}

src/__test__/hash.test.ts

import { createHash } from 'crypto';

import { hash } from '../hash-node.js';

const mockDigest = jest.fn();

jest.mock('crypto', () => ({
  createHash: jest.fn().mockReturnValue({
    update: jest.fn().mockReturnThis(),
    digest: mockDigest,
  }),
}));

describe('hash', () => {
  it('uses SHA512', () => {
    hash('foo');

    expect(createHash).toHaveBeenCalledWith(
      expect.stringMatching(/sha512/i),
    );
  });
});

Output

    TypeError: Cannot read properties of undefined (reading 'update')

      3 |
      4 | export function hash(input: string | Uint8Array): Uint8Array {
    > 5 |   return new Uint8Array(createHash('sha512').update(input).digest().buffer);
        |                         ^
      6 | }
      7 |

      at hash (src/hash.ts:4:25)
      at Object.<anonymous> (src/__test__/hash.test.ts:16:5)

As you can see, createHash is clearly returning undefined, as though .mockReturnValue hadn't been called.

What am I doing wrong? How can I get this module mock to work?

CodePudding user response:

I came back to this and was able to figure it out; it's a result of configuring Jest to reset mocks between tests. Once I moved the mockReturnValue call on createHash to inside a beforeEach block, it all started working as expected.

import { type Hash, createHash } from 'crypto';

import { hash } from '../hash.js';

const mockDigest = jest.fn();

jest.mock('crypto', () => ({
  createHash: jest.fn(),
}));

describe('hash', () => {
  beforeEach(() => {
    (createHash as jest.MockedFunction<typeof createHash>).mockReturnValue({
      update: jest.fn().mockReturnThis(),
      digest: jest.fn(),
    } as unknown as Hash);
  });

  it('uses SHA512', () => {
    hash('foo');

    expect(createHash).toHaveBeenCalledWith(
      expect.stringMatching(/sha512/i),
    );
  });
});
  • Related