Testing and debugging CloudFront Functions deployed via simulated CloudFormation

Here’s a minimal CDK app that deploys a CloudFront Function:

import * as cdk from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";

const app = new cdk.App();
const stack = new cdk.Stack(app, "TestStack", {
  env: { account: "111111111111", region: "eu-west-2" },
});

new s3.CfnBucket(stack, "SiteBucket", {
  bucketName: "cdk-cff-source-site-bucket",
});

const fooFunction = new cloudfront.CfnFunction(stack, "FooFunction", {
  name: "cdk-source-rewrite-function",
  autoPublish: true,
  functionConfig: {
    comment: "Rewrite function",
    runtime: "cloudfront-js-2.0",
  },
  functionCode: cloudfront.FunctionCode.fromFile({
    filePath: "path/to/handler.cff.js",
  }).render(),
});

new cloudfront.CfnDistribution(stack, "SiteDistribution", {
  distributionConfig: {
    enabled: true,
    origins: [
      {
        id: "SiteOrigin",
        domainName: "cdk-cff-source-site-bucket.s3.amazonaws.com",
        s3OriginConfig: {},
      },
    ],
    defaultCacheBehavior: {
      targetOriginId: "SiteOrigin",
      viewerProtocolPolicy: "allow-all",
      functionAssociations: [
        {
          eventType: "viewer-request",
          functionArn: fooFunction.attrFunctionArn,
        },
      ],
    },
  },
});

app.synth();

You can deploy that stack via simulated CloudFormation for local dev and testing like this:

import { SimAws } from "@kensio/yulin";

const simAws = new SimAws();

const stack = await simAws.cloudFormation().deployTemplateFile({
  templatePath: "cdk.out/TestStack.template.json",
});

await stack.waitForDeployComplete();

That will use the CloudFront Function handler source code embedded in the template. It runs this via the Node.js vm module internally.

That works fine, but what if you want to step through the CloudFront Function handler in a debugger, or to gather test coverage metrics for it?

You can use the bindings property for the deployTemplateFile() method to swap in the real runtime handler function in the same process as the simulated system:

import { SimAws } from "@kensio/yulin";
import { fooFunctionHandler } from "../path/to/cff/foo-function.cff.js";

const simAws = new SimAws();

const stack = await simAws.cloudFormation().deployTemplateFile({
  templatePath: "cdk.out/TestStack.template.json",
  bindings: [
      {
        logicalId: "FooFunction",
        handler: fooFunctionHandler,
      },
    ],
});

await stack.waitForDeployComplete();

Now the real handler function is used at runtime in the simulated system in the same process as everything else, so you can step through it in a debugger and gather test coverage metrics for it.


View post: Testing and debugging CloudFront Functions deployed via simulated CloudFormation