Node.js組み込みテストランナーとJest比較メモ

Node.js組み込みのテストランナーとJestの比較メモ

確認環境

Env ver
Node.js 20.8.0
Jest 29.7

Node.jsの組み込みテストランナーとは

英語圏ではNode.js built-in test runnerとか呼ばれている存在で、Node.jsの組み込みテストランナーのこと。恐らくDenoのテストランナーに対抗して生まれた気配がする(Node.jsはDenoに機能追加があると真似する傾向があるため

Node.jsの組み込みテストランナーは機能が二分されており、テストランナーアサートに分かれている。

Jestみたいにエコシステムが発達しておらず、標準ではdescribeなどはimportする必要がある。TypeScriptをテストする場合は間にレジスター1を嚙ます必要があるが、本項では扱わない。

Jest関数との比較リスト

個人的にdescribe/it辺りは違和感がなかったが、それ以外は軒並み互換性がないので書き換えが必要だと感じた。便利なMatcherは完膚なきまでに全滅している

describe/it

たぶんJestそのままでimportすれば使える。testもあるのでtest派の人も安心だ

import { describe, it } from 'node:test';

describe('hoge', () => {
  it('hoge', () => {
    // ここにテストコード
  });

  it.todo('piyo');
});

.toBe(), .not.toBe()

  • assert.strictEqual(actual, expected[, message])
  • assert.notStrictEqual(actual, expected[, message])
import { describe, it } from 'node:test';
import assert from 'node:assert';

describe('test', () => {
  it('test', () => {
    const actual = 123;

    assert.deepStrictEqual(actual, 123);
  });
});

.toStrictEqual(), .not.toStrictEqual()

  • assert.deepStrictEqual(actual, expected[, message])
  • assert.notDeepStrictEqual(actual, expected[, message])
import { describe, it } from 'node:test';
import assert from 'node:assert';

describe('test', () => {
  it('test', () => {
    const actual = {
      hoge: {
        piyo: {
          id: 1,
          value: 'one',
        },
      },
      fuga: [[123, 456], 'ABC', 'EFG'],
    };

    assert.deepStrictEqual(actual, {
      hoge: {
        piyo: {
          id: 1,
          value: 'one',
        },
      },
      fuga: [[123, 456], 'ABC', 'EFG'],
    });
  });
});

.toBeInstanceOf()

  • assert.ok(value[, message])
  • 否定版は不明
  • 結果がTruthyであればなんでもpassするので注意
import { describe, it } from 'node:test';
import assert from 'node:assert';

describe('test', () => {
  it('test', () => {
    const actual = new Error('hoge');

    assert.ok(actual instanceof Error);
  });
});

jest.spyOn()

node:testからmockをimportして使う

import { describe, it, mock } from 'node:test';
import assert from 'node:assert';

describe('test', () => {
  it('test', () => {
    const mockedInfo = mock.method(console, 'info');
  });
});

.toHaveBeenCalled(), .toHaveBeenCalledTimes()

assert.strictEqual()でモックから生えてるやつを調べる

import { describe, it, mock } from 'node:test';
import assert from 'node:assert';

describe('test', () => {
  it('test', () => {
    const mockedInfo = mock.method(console, 'info');
    console.info('test');
    assert.deepStrictEqual(mockedInfo.mock.calls.length, 1);
  });
});

.toHaveBeenCalledWith()

assert.strictEqual()でモックから生えてるやつを調べる。Jestでは.toEqual()処理されるがNode.jsの組み込みテストランナーの場合、厳密比較ができる

import { describe, it, mock } from 'node:test';
import assert from 'node:assert';

describe('test', () => {
  it('test', () => {
    const mockedInfo = mock.method(console, 'info');
    console.info('test');
    assert.deepStrictEqual(mockedInfo.mock.calls[0].arguments[0], 'test');
  });
});

jest.fn()

  • mock.fn([original[, implementation]][, options])
import { describe, it, mock } from 'node:test';
import assert from 'node:assert';

// 動作確認用の関数
const testTarget = (
  cbParam: string,
  callbackFn: (param: string) => number
) => {
  return callbackFn(cbParam);
};

describe('test', () => {
  it('test', () => {
    // jest.fn()相当のモック関数の作成
    const mockFn = mock.fn((_: string) => {
      return 5;
    });
    const actual = testTarget('hoge', mockFn);

    // 期待した引数が設定されていることを確認
    assert.deepStrictEqual(mockFn.mock.calls[0].arguments[0], 'hoge');
    // コールバック関数の戻り値が関数から戻されることを確認
    assert.deepStrictEqual(actual, 5);
  });
});

  1. 標準出力にトランスパイルした結果を出力してくれるもの