[AWS CDK] Arrayのテストで順序を無視したアサーションをする (TypeScript)

TypeScriptでCDKスタックとテストを書いていた際、 Match.arrayWith() を使って配列に複数の要素が含まれていることを確認したかったがうまくいかなかった。

うまくいかない例↓

import * as cdk from "aws-cdk-lib";
import { Match, Template } from "aws-cdk-lib/assertions";

let app: cdk.App;
let stack: MyStack;
let template: Template;

beforeAll(() => {
  app = new cdk.App();
  stack = new MyStack(app, "MyTestStack");
  template = Template.fromStack(stack);
});

test("Cognito UserPoolClient Created", () => {
  template.hasResourceProperties("AWS::Cognito::UserPoolClient", {
        // code, implicitの順番はどうでもいい
    AllowedOAuthFlows: Match.arrayWith(["code", "implicit"]),
  });
});

ドキュメントにも書いてあるが、 Match.arrayWith() は要素の順序が揃っている必要がある。
例示されているコードはほとんど単一要素しか書かれていないため、若干ひっかけポイントになっていた。
エラーメッセージとしては下記のように表示される。

Template has 1 resources with type AWS::Cognito::UserPoolClient, but none match as expected.
The 1 closest matches:
UserPoolConsoleClient7A1A759F :: {
  "Properties": {
    "AccessTokenValidity": 60,
    "AllowedOAuthFlows": [
      "implicit",
!!     arrayWith pattern 0 matched here
      "code"
!!     Could not match arrayWith pattern 1. No more elements to try
      
    ],
    "AllowedOAuthFlowsUserPoolClient": true,
    "AllowedOAuthScopes": [ ... ],
    "AuthSessionValidity": 3,
    "CallbackURLs": [ { "Fn::Join": [ ... ] } ],
    "ClientName": "ConsoleClient",
    "EnableTokenRevocation": true,
    "ExplicitAuthFlows": [ ... ],
    "GenerateSecret": false,
    "IdTokenValidity": 60,
    "LogoutURLs": [],
    "PreventUserExistenceErrors": "LEGACY",
    "ReadAttributes": [ "email" ],
    "RefreshTokenValidity": 43200,
    "SupportedIdentityProviders": [ "COGNITO" ],
    "TokenValidityUnits": { ... },
    "UserPoolId": { "Ref": "UserPool21F2907E" },
    "WriteAttributes": [ "email" ]
  },
  "Type": "AWS::Cognito::UserPoolClient"
}

解決策

jestのネイティブ機能である expect.arrayContaining() を使うようにする。
そのために一度 Capture で取り出して、個別にアサーションをした。

import * as cdk from "aws-cdk-lib";
import { Capture, Template } from "aws-cdk-lib/assertions";

let app: cdk.App;
let stack: MyStack;
let template: Template;

beforeAll(() => {
  app = new cdk.App();
  stack = new MyStack(app, "MyTestStack");
  template = Template.fromStack(stack);
});

test("Cognito UserPoolClient Created", () => {
  // Captureインスタンスを作成
  const AllowedOAuthFlows = new Capture();
  template.hasResourceProperties("AWS::Cognito::UserPoolClient", {
    // 一旦Captureをあてて抽出
    AllowedOAuthFlows: AllowedOAuthFlows,
  });
  // ここで本命のアサーション
  expect(AllowedOAuthFlows.asArray()).toEqual(
    expect.arrayContaining(["code", "implicit"])
  );
});

コメント

タイトルとURLをコピーしました