iTranslated by AI
Using Vitest for AWS CDK Testing
This is an article for Day 7 of the "AWS CDK Advent Calendar 2024".
Introduction
In this article, I will introduce how to use Vitest for CDK testing and how to write tests using Vitest.
What is Vitest?
Vitest is a next-generation JavaScript testing framework powered by Vite.
Vite is a next-generation frontend tool, but Vitest is not limited to the frontend and can run tests for code written in JavaScript / TypeScript.
In fact, I run all Validation Tests / Fine-grained assertions Tests / Snapshot Tests for my CDK projects using Vitest.
(The following article was helpful regarding the details of each test)
Vitest Installation Steps
You can introduce Vitest to your CDK project using the following steps:
1. Run the installation command
Run the following command to install Vitest:
# npm
npm install -D vitest
# yarn
yarn install -D vitest
# pnpm
pnpm install -D vitest
2. package.json settings
Next, add the test command to the scripts in package.json so that you can run Vitest commands from the terminal.
(Adding it to scripts is not strictly required since it can also be executed with npx vitest.)
{
"scripts": {
+ "test": "vitest",
}
}
3. Create the Vitest configuration file
Next, create vitest.config.ts in the root of your project.
(File extensions other than ts can also be used.)
Here is an example of vitest.config.ts:
import { defineConfig } from "vitest/config";
export default defineConfig({
root: ".",
test: {
root: ".",
globals: true,
environment: "node",
include: ["**/test/**/*.{spec,test}.ts"]
},
});
4. Update tsconfig.json
If you want to use Vitest globally (so you can call global APIs without declarations), you need to modify compilerOptions.types in tsconfig.json to load Vitest type information.
The modification is as follows:
{
"compilerOptions": {
// ...
+ "types": ["vitest/globals"]
},
}
This completes the Vitest setup. From here on, I will introduce how to write Validation Tests / Fine-grained assertions Tests / Snapshot Tests using Vitest.
Validation Test
Validation refers to the process of verifying the validity of values through conditional branching and other methods. In AWS CDK as well, validation logic is sometimes implemented for the properties of props, which are inputs to Stacks and Constructs.
Quote: https://aws.amazon.com/jp/builders-flash/202411/learn-cdk-unit-test/
In this case, we assume a scenario where we validate the RDS database name.
The code on the Construct side is as follows:
interface RdsProps {
readonly databaseName: string;
// ...
}
export class Rds extends Construct {
constructor(scope: Construct, id: string, props: RdsProps) {
super(scope, id);
this.validateDatabaseName(props.databaseName);
this.validateUsername(props.username);
// ...
}
private validateDatabaseName(databaseName: string): void {
if (!this.isSnakeCase(databaseName)) {
throw new Error("データベース名はスネークケースで指定してください。");
}
}
private isSnakeCase(str: string): boolean {
const snakeCasePattern = /^[a-z]+(_[a-z]+)*$/;
return snakeCasePattern.test(str);
}
}
The test code for this validation is as follows:
const createRdsInstance = (databaseName: string): Rds => {
const app = new App();
const stack = new Stack(app, "TestStack");
// ...
return new Rds(stack, "TestRds", {
// ...
databaseName,
});
};
describe("バリデーションテスト", () => {
test("データベース名がスネークケースでない場合はエラー", () => {
const databaseName = "invalid-name";
const errorMessage = "データベース名はスネークケースで指定してください。";
expect(() => createRdsInstance(databaseName)).toThrowError(errorMessage);
});
});
Fine-grained assertions Test
Fine-grained assertions testing in AWS CDK refers to tests that extract a portion of the generated CloudFormation template and perform checks on that part. This allows you to test fine-grained components, such as what specific resources are being created.
Quote: https://aws.amazon.com/jp/builders-flash/202411/learn-cdk-unit-test/
In this case, we assume we are validating the Engine, EngineVersion, and DBInstanceClass of AWS::RDS::DBInstance in the CloudFormation template.
The test code is as follows:
const getTemplate = (): Template => {
const app = new App();
const stack = new BackCdkTrainingStack(app, "TestStack");
return Template.fromStack(stack);
};
describe("RDS Fine-grained assertions tests", () => {
const template = getTemplate();
test("Whether RDS settings are appropriate", () => {
template.hasResourceProperties("AWS::RDS::DBInstance", {
Engine: "mysql",
EngineVersion: "8.0",
DBInstanceClass: "db.t4g.micro",
});
});
});
Snapshot Test
Snapshot testing in AWS CDK refers to tests that output the AWS CloudFormation template synthesized from CDK code and compare it with the template content generated during previous test runs to detect differences in the template.
Quote: https://aws.amazon.com/jp/builders-flash/202411/learn-cdk-unit-test/
When performing a Snapshot Test, we process the serialization of hash values assigned to the CloudFormation template.
This is to handle cases where hash values change with each test execution (such as ECR images).
To perform serialization, we use Vitest's Custom Serializer.
import { SnapshotSerializer } from "vitest";
export default {
/**
* Serialization targets strings only
*/
test(val: unknown) {
return typeof val === "string";
},
/**
* Replace hash values
*/
serialize(val: string) {
return val.replace(/[A-Fa-f0-9]{64}/, "hashed");
},
} satisfies SnapshotSerializer;
Then, add this Serializer to the config file.
import { defineConfig } from "vitest/config";
export default defineConfig({
root: ".",
test: {
root: ".",
globals: true,
environment: "node",
+ snapshotSerializers: ["./plugins/vitestPlugin/customSerializer.ts"],
include: ["**/test/**/*.{spec,test}.ts"]
},
});
The test code is as follows.
const getTemplate = (): Template => {
const config = getConfigStackProps("dev");
const app = new App();
const stack = new BackCdkTrainingStack(app, "BackCdkTraining", config);
return Template.fromStack(stack);
};
test("Snapshot Tests", () => {
const template = getTemplate();
const json = template.toJSON();
expect(json).toMatchSnapshot();
});
Migration from Jest
When you start a JavaScript / TypeScript CDK project using the cdk init command, the Jest testing framework is automatically installed.
Therefore, I believe quite a few CDK users have adopted Jest as their testing framework.
If you are a CDK user already using Jest and are considering migrating to Vitest, please refer to the following documentation:
(Vitest provides Jest-compatible APIs, so you can migrate easily.)
Conclusion
In this article, I introduced how to incorporate Vitest into a CDK project.
I hope this is helpful for anyone considering Vitest or wondering how to write tests with it!
References
Discussion