UnitTestPlan.md
February 21, 2026 ยท View on GitHub
๐งช Unit Test Plan for CIA Compliance Manager
๐ Comprehensive Unit Testing Strategy
๐ Secure Development Policy ยท Vulnerability Management
๐ ISMS Alignment: This unit test plan implements Secure Development Policy Section 4.3.1 - Unit Testing Requirements.
1. Overview
This document outlines the unit testing strategy for the CIA Compliance Manager application. The application is built using React with TypeScript, and unit tests are implemented using Vitest.
ISMS Compliance Requirements
Per Hack23 AB's Secure Development Policy, this project maintains:
| ๐ฏ Requirement | ๐ Target | โ Current | ๐ ISMS Reference |
|---|---|---|---|
| Line Coverage | โฅ80% | 83% | Section 4.3.1.1 |
| Branch Coverage | โฅ75% (v1.0) | 75.39% | Section 4.3.1.2 |
| Test Execution | Every commit | โ Automated | Section 4.3.1.3 |
| Public Reporting | Required | โ Published | Section 4.3.1.4 |
Evidence Links:
See Also: ISMS Implementation Guide - Testing Strategy
2. Testing Framework
- Primary framework: Vitest
- Test environment: JSDOM
- Coverage tool: V8 (via Vitest)
- Target coverage: 80% line coverage minimum
3. Test Organization
3.1 File Structure
Unit tests should be placed alongside their implementation files with the .test.tsx or .test.ts extension:
src/
โโโ components/
โ โโโ Component.tsx
โ โโโ Component.test.tsx
โโโ utils/
โ โโโ helper.ts
โ โโโ helper.test.ts
3.2 Test Categories
- Component tests: Test React components in isolation with mocked dependencies
- Utility tests: Test utility functions, hooks, and services
- Integration tests: Test small groups of components working together
4. Testing Standards
4.1 Component Testing
- Test rendering without crashing
- Test all component props and variations
- Test state changes and user interactions
- Test conditional rendering logic
- Mock external dependencies and services
4.2 Test Doubles
- Use mocks for external services and dependencies
- Use test fixtures for complex data structures
- Use fake timers for time-dependent functions
5. Code Coverage Requirements
- Statements: 80% minimum
- Branches: 75% minimum (v1.0 release target)
- Functions: 80% minimum
- Lines: 80% minimum
5.1 Branch Coverage Strategies
Branch coverage ensures that all conditional paths in the code are tested. To achieve and maintain 75%+ branch coverage:
5.1.1 Conditional Logic Testing
Test all branches of conditional statements:
// Function with conditional logic
export function getStatusVariant(level: string): StatusType {
const normalizedLevel = level.toLowerCase();
if (normalizedLevel === "none") return "error";
if (normalizedLevel === "low") return "warning";
if (normalizedLevel === "moderate") return "info";
if (normalizedLevel === "high") return "success";
if (normalizedLevel === "very high") return "purple";
return "neutral";
}
// Tests covering all branches
describe("getStatusVariant", () => {
it("returns error for none level", () => {
expect(getStatusVariant("none")).toBe("error");
});
it("returns warning for low level", () => {
expect(getStatusVariant("low")).toBe("warning");
});
// ... test each branch
it("returns neutral for unknown levels", () => {
expect(getStatusVariant("unknown")).toBe("neutral");
});
});
5.1.2 Error Handling Paths
Test both success and error paths:
// Test error handling branches
it("handles Error objects", () => {
const error = new Error("Test error");
expect(toErrorObject(error)).toBe(error);
});
it("handles null/undefined", () => {
expect(toErrorObject(null)).toBeInstanceOf(Error);
expect(toErrorObject(undefined)).toBeInstanceOf(Error);
});
it("handles string errors", () => {
const result = toErrorObject("String error");
expect(result.message).toBe("String error");
});
5.1.3 Null/Undefined Checks
Test optional chaining and nullish coalescing:
// Function with fallback
export function getValue(level: SecurityLevel): number {
return levelValues[level] || defaultValue;
}
// Test both branches
it("returns value for valid level", () => {
expect(getValue("High")).toBe(1);
});
it("returns default for invalid level", () => {
expect(getValue("Unknown" as any)).toBe(defaultValue);
});
5.1.4 Boolean Logic
Test all combinations of && and || operators:
// Test complex conditions
it("validates all conditions", () => {
expect(isValid(true, true)).toBe(true); // Both true
expect(isValid(true, false)).toBe(false); // First true
expect(isValid(false, true)).toBe(false); // Second true
expect(isValid(false, false)).toBe(false); // Both false
});
5.1.5 Switch Statements
Test all cases including default:
describe("switch statement coverage", () => {
it("handles case A", () => { /* test */ });
it("handles case B", () => { /* test */ });
it("handles default case", () => { /* test */ });
});
5.1.6 Ternary Operators
Test both branches of conditional expressions:
// Function with ternary
const color = isActive ? "green" : "gray";
// Tests
it("returns green when active", () => {
expect(getColor(true)).toBe("green");
});
it("returns gray when inactive", () => {
expect(getColor(false)).toBe("gray");
});
5.2 Coverage Enforcement
The project enforces coverage thresholds in vite.config.ts:
coverage: {
thresholds: {
statements: 80,
branches: 75, // v1.0 release requirement
functions: 80,
lines: 80,
},
}
CI builds will fail if coverage falls below these thresholds.
6. Running Tests
- Development:
npm run test - CI/CD:
npm run test:ci - Coverage report:
npm run test:coverage
7. Pull Request Requirements
All pull requests must:
- Include tests for new features and bug fixes
- Not decrease the overall code coverage
- Pass all existing tests
8. Common Test Patterns
8.1 Component Test Example
import { render, screen, fireEvent } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import Component from "./Component";
describe("Component", () => {
it("renders correctly", () => {
render(<Component />);
expect(screen.getByText("Expected Text")).toBeInTheDocument();
});
it("handles click events", () => {
const handleClick = vi.fn();
render(<Component onClick={handleClick} />);
fireEvent.click(screen.getByRole("button"));
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
8.2 Utility Function Test Example
import { describe, it, expect } from "vitest";
import { formatData } from "./utils";
describe("formatData", () => {
it("formats data correctly", () => {
const input = { key: "value" };
const expected = { formattedKey: "VALUE" };
expect(formatData(input)).toEqual(expected);
});
it("handles empty input", () => {
expect(formatData({})).toEqual({});
});
});