Closed1

VitestのカスタムマッチャでTRPCErrorをテストする

catnosecatnose

やりたいこと

trpcのrouterにおいて発生させたTRPCErrorをvitestでテストしたい。

やったこと

テストケースが多いので、Vitestのカスタムマッチャを使って効率化することにした。

https://vitest.dev/guide/extending-matchers.html

vitest.setup.tsx
...
import { TRPCError } from '@trpc/server';
import { vi, expect } from 'vitest';

// TRPCのエラーコードを推論したかったがexportされていなかったのでクラスから取り出す
type TRPCErrorCode = ConstructorParameters<typeof TRPCError>[0]['code'];

// 発生したエラーのコードとメッセージをテストできるようにする
type ThrowTrpcErrorParams = { code: TRPCErrorCode; message?: string };

expect.extend({
  // TRPCErrorのテスト用マッチャー
  toThrowTrpcError(received: ThrowTrpcErrorParams, expected) {
    const { isNot } = this;

    const pass =
      received instanceof TRPCError &&
      received.code === expected.code &&
      expected.message ? received.message === expected.message : true

    return {
      pass,
      message: () => {
        return `${JSON.stringify(received)} is${isNot ? ' not' : ''} ${JSON.stringify(expected)}`;
      },
    };
  },
});

合わせてマッチャの型定義を追加しておく。

interface CustomMatchers<R = unknown> {
  toThrowTrpcError(params: ThrowTrpcErrorParams): R;
}

declare module 'vitest' {
  interface Assertion<T = any> extends CustomMatchers<T> {}
  interface AsymmetricMatchersContaining extends CustomMatchers {}
}

実際のテストコード

describe('get', async () => {
  test('未ログインだとエラーになること', async () => {
    const caller = createTrpcCaller({ session: null });

    expect(caller.post.get({ id: 1 }))
       .rejects.toThrowTrpcError({
          code: 'UNAUTHORIZED',
          message: 'ログインしてください',
       });
  });
});
このスクラップは2023/08/28にクローズされました