Files
cluster/deploy/dev/configurations/TESTING.md
2025-08-15 18:59:10 -04:00

7.4 KiB

Testing Guide for Zitadel Configurator

This document explains the testing approach and methodology used in the Zitadel Configurator project, which uses CDKTF (Cloud Development Kit for Terraform) to manage Zitadel infrastructure.

Overview

The project uses unit testing with Jest to test Infrastructure as Code (IaC) definitions. Tests verify that the synthesized Terraform configuration contains the expected resources and properties without creating actual cloud resources.

Testing Framework

Core Technologies

  • Jest: JavaScript testing framework
  • ts-jest: TypeScript support for Jest
  • CDKTF Testing: Built-in testing utilities for CDKTF applications
  • TypeScript: Primary language for both implementation and tests

Configuration Files

  • jest.config.js: Jest configuration with TypeScript support
  • setup.js: CDKTF-specific Jest setup that enables testing matchers
  • package.json: Test scripts and dependencies

Test Structure

Directory Organization

zitadel-configurator/
├── __tests__/           # Test files directory
│   └── main.test.ts     # Main test suite
├── main.ts              # Implementation to be tested
├── jest.config.js       # Jest configuration
└── setup.js            # CDKTF Jest setup

Test File Naming

  • Tests are located in the __tests__/ directory
  • Test files follow the pattern: *.test.ts
  • Alternative patterns supported: *.spec.ts

Running Tests

Available Commands

# Run all tests once
npm test

# Run tests in watch mode (auto-rerun on file changes)
npm run test:watch

Test Output

Tests provide clear feedback about:

  • Resource creation verification
  • Property validation
  • Synthesized Terraform configuration structure

Testing Approach

Unit Testing Philosophy

The project follows a unit testing approach where:

  • Tests validate the synthesized Terraform configuration
  • No actual cloud resources are created during testing
  • Fast execution with immediate feedback
  • Focus on infrastructure definition correctness

Test Categories

1. Resource Existence Tests

Verify that expected resources are created in the Terraform configuration:

it("should create an organization resource", () => {
  const app = Testing.app();
  const stack = new ZitadelStack(app, "test-stack");
  
  // Test that the stack contains an Org resource
  expect(Testing.synth(stack)).toHaveResource(Org);
});

2. Resource Property Tests

Validate that resources have the correct properties:

it("should create organization with name 'makers'", () => {
  const app = Testing.app();
  const stack = new ZitadelStack(app, "test-stack");
  
  // Test the synthesized terraform to ensure it contains the expected resource properties
  expect(Testing.synth(stack)).toHaveResourceWithProperties(Org, {
    name: "makers"
  });
});

3. Public Interface Tests

Verify that the stack exposes the expected outputs:

it("should create organization with name 'makers'", () => {
  const app = Testing.app();
  const stack = new ZitadelStack(app, "test-stack");
  
  // Verify the organization was created and stored
  expect(stack.createdOrg).toBeDefined();
});

CDKTF Testing Utilities

Key Testing Methods

Testing.app()

Creates a CDKTF app instance for testing purposes.

Testing.synth(stack)

Synthesizes the stack into Terraform JSON configuration for testing.

toHaveResource(ResourceClass)

Custom Jest matcher that checks if the synthesized configuration contains a specific resource type.

toHaveResourceWithProperties(ResourceClass, properties)

Custom Jest matcher that validates both resource existence and specific property values.

Setup Requirements

The setup.js file is crucial as it:

const cdktf = require("cdktf");
cdktf.Testing.setupJest();

This enables CDKTF-specific Jest matchers and testing utilities.

Best Practices

1. Test Structure

  • Use descriptive test suite names (describe blocks)
  • Write clear, specific test case descriptions
  • Group related tests logically

2. Test Isolation

  • Each test creates its own app and stack instance
  • Tests are independent and don't share state
  • Use fresh instances for each test case

3. Comprehensive Coverage

  • Test resource creation
  • Validate resource properties
  • Verify public interfaces and outputs
  • Test different configuration scenarios

4. Meaningful Assertions

  • Test both existence and correctness
  • Use specific matchers for clear error messages
  • Validate the actual synthesized configuration

Example Test Implementation

import "cdktf/lib/testing/adapters/jest"; // Load types for expect matchers
import { Testing } from "cdktf";
import { ZitadelStack } from "../main";
import { Org } from "../.gen/providers/zitadel/org";

describe("Zitadel Configurator", () => {
  describe("Unit testing using assertions", () => {
    it("should create an organization resource", () => {
      const app = Testing.app();
      const stack = new ZitadelStack(app, "test-stack");
      
      // Test that the stack contains an Org resource
      expect(Testing.synth(stack)).toHaveResource(Org);
    });

    it("should create organization with name 'makers'", () => {
      const app = Testing.app();
      const stack = new ZitadelStack(app, "test-stack");
      
      // Verify the organization was created and stored
      expect(stack.createdOrg).toBeDefined();
      
      // Test the synthesized terraform to ensure it contains the expected resource properties
      expect(Testing.synth(stack)).toHaveResourceWithProperties(Org, {
        name: "makers"
      });
    });
  });
});

Benefits of This Testing Approach

1. Fast Feedback

  • Tests run quickly without cloud API calls
  • Immediate validation of infrastructure definitions
  • Suitable for continuous integration

2. Cost-Effective

  • No cloud resources created during testing
  • No API rate limits or costs
  • Safe for frequent execution

3. Reliable

  • Tests are deterministic and repeatable
  • No dependency on external services during testing
  • Consistent results across different environments

4. Development-Friendly

  • Supports test-driven development (TDD)
  • Watch mode for rapid iteration
  • Clear error messages for debugging

Extending Tests

Adding New Test Cases

When adding new resources or modifying existing ones:

  1. Test Resource Creation: Verify the new resource type exists
  2. Test Properties: Validate all important configuration properties
  3. Test Relationships: Verify resource dependencies and references
  4. Test Public Interface: Ensure any exposed outputs are accessible

Advanced Testing Scenarios

Consider adding tests for:

  • Error conditions and validation
  • Different configuration environments
  • Resource dependencies and relationships
  • Complex property calculations

Troubleshooting

Common Issues

Missing CDKTF Setup

If you see errors about missing matchers, ensure setup.js is properly configured in jest.config.js.

TypeScript Compilation Errors

Ensure all necessary type definitions are imported:

import "cdktf/lib/testing/adapters/jest"; // Load types for expect matchers

Resource Import Issues

Verify that generated provider resources are properly imported:

import { Org } from "../.gen/providers/zitadel/org";

This testing approach ensures robust, reliable infrastructure definitions while maintaining development velocity and cost-effectiveness.