🎪

Jestのスナップショットテストで特定の値をマスクする

2024/04/16に公開

CDK でインフラを管理しているプロジェクトでは、CDK やライブラリなどの変更・更新に伴う出力の変化を検知するためにスナップショットテストを用意しておくと便利です。

https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/testing.html#testing_snapshot

AWS のサンプル通りに実装すると、スナップショットには合成された CloudFormation テンプレートが丸っと記録されることになります。
自分の携わっていたプロジェクトでは、一部のシークレット値を Git 管理しているコード外から取得して SSM Parameter として作成するようになっています。
(スナップショットに載せなくても実際の CloudFormation テンプレートには含まれるため、そもそも CloudFormation 自体に含まれないようにした方がいいというのはありつつ) こうした値はスナップショットとしてコミットに含めるのは望ましくありません。

Jest ではスナップショットの作成処理を扱うプラグインを導入できるため、特定の値をマスクするプラグインを書いてみました。

参考:
https://dev.classmethod.jp/articles/aws-cdk-unit-test-ignore-assets-using-jest-snapshot-serializer/

実装例

下記の実装は、 AWS::SSM::Parameter が String の場合にマスクするプラグインの例です。
(SnapshotSerializer 用の型が外部公開されていなったため、 addSnapshotSerializer 関数の引数から無理やり取得しています)

プラグインの test 関数でマスク済みかどうかを判定しないと無限ループになるので注意が必要です。

mask-ssm-parameter-plugin.ts
import { JestExpect } from "@jest/expect";

type SnapshotSerializerPlugin = Parameters<
  JestExpect["addSnapshotSerializer"]
>[0];

const MASKED_VALUE = "[***MASKED***]";

type CfnParameterElement = {
  Type: "AWS::SSM::Parameter";
  Properties: {
    Type: "String";
    Name: string;
    Value: string;
  };
};

const plugin: SnapshotSerializerPlugin = {
  test(value) {
    return (
      value?.Type === "AWS::SSM::Parameter" &&
      value?.Properties?.Type === "String" &&
      value?.Properties?.Value !== MASKED_VALUE
    );
  },
  serialize(
    value: CfnParameterElement,
    config,
    indentation,
    depth,
    refs,
    printer,
  ) {
    value.Properties.Value = MASKED_VALUE;
    return printer(value, config, indentation, depth, refs);
  },
};

export default plugin;

テストファイル内で expect.addSnapshotSerializer に渡すことで利用できます (jest.config.js でも可)。

cdk.test.ts
import snapshotPlugin from "./mask-ssm-parameter-plugin";

expect.addSnapshotSerializer(snapshotPlugin);

Discussion