UNPKG

@ordojs/cli

Version:

Command-line interface for OrdoJS framework

257 lines (215 loc) 9.73 kB
/** * @fileoverview Tests for the Docker generator */ import { beforeEach, describe, expect, it } from 'vitest'; import type { DeploymentConfig } from './adapter-interface.js'; import { DockerGenerator } from './docker-generator.js'; describe('DockerGenerator', () => { let dockerGenerator: DockerGenerator; let mockDeploymentConfig: DeploymentConfig; beforeEach(() => { dockerGenerator = new DockerGenerator(); mockDeploymentConfig = { outputDir: 'dist', isStatic: false, includeServerFunctions: true, env: { NODE_ENV: 'production', PORT: '3000' } }; }); describe('generateDockerfile', () => { it('should generate multi-stage Dockerfile by default', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig); expect(dockerfile).toContain('FROM node:18-alpine AS base'); expect(dockerfile).toContain('FROM base AS builder'); expect(dockerfile).toContain('FROM node:18-alpine AS production'); expect(dockerfile).toContain('RUN pnpm install --frozen-lockfile'); expect(dockerfile).toContain('RUN pnpm run build'); expect(dockerfile).toContain('EXPOSE 3000'); expect(dockerfile).toContain('CMD ["node", "dist/server.js"]'); }); it('should generate simple Dockerfile when multiStage is false', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig, { multiStage: false }); expect(dockerfile).toContain('FROM node:18-alpine'); expect(dockerfile).not.toContain('AS base'); expect(dockerfile).not.toContain('AS builder'); expect(dockerfile).not.toContain('AS production'); expect(dockerfile).toContain('RUN pnpm install --frozen-lockfile'); expect(dockerfile).toContain('RUN pnpm run build'); }); it('should include environment variables', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig, { environment: { NODE_ENV: 'production', API_KEY: 'secret' } }); expect(dockerfile).toContain('ENV NODE_ENV=production'); expect(dockerfile).toContain('ENV API_KEY=secret'); }); it('should include health check when enabled', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig, { healthCheck: true, port: 3000 }); expect(dockerfile).toContain('HEALTHCHECK'); expect(dockerfile).toContain('curl -f http://localhost:3000/health'); }); it('should not include health check when disabled', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig, { healthCheck: false }); expect(dockerfile).not.toContain('HEALTHCHECK'); }); it('should use custom Node.js version', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig, { nodeVersion: '20' }); expect(dockerfile).toContain('FROM node:20-alpine'); }); it('should use custom port', () => { const dockerfile = dockerGenerator.generateDockerfile(mockDeploymentConfig, { port: 8080 }); expect(dockerfile).toContain('EXPOSE 8080'); }); }); describe('generateDockerCompose', () => { it('should generate docker-compose.yml with basic configuration', () => { const dockerCompose = dockerGenerator.generateDockerCompose(mockDeploymentConfig); expect(dockerCompose).toContain('version: \'3.8\''); expect(dockerCompose).toContain('ordojs-app:'); expect(dockerCompose).toContain('build:'); expect(dockerCompose).toContain('context: .'); expect(dockerCompose).toContain('dockerfile: Dockerfile'); expect(dockerCompose).toContain('ports:'); expect(dockerCompose).toContain('- "3000:3000"'); expect(dockerCompose).toContain('restart: unless-stopped'); }); it('should include environment variables', () => { const dockerCompose = dockerGenerator.generateDockerCompose(mockDeploymentConfig, { environment: { NODE_ENV: 'production', DATABASE_URL: 'postgres://localhost:5432/mydb' } }); expect(dockerCompose).toContain('environment:'); expect(dockerCompose).toContain('- NODE_ENV=production'); expect(dockerCompose).toContain('- DATABASE_URL=postgres://localhost:5432/mydb'); }); it('should include volumes when specified', () => { const dockerCompose = dockerGenerator.generateDockerCompose(mockDeploymentConfig, { volumes: ['./logs:/app/logs', './data:/app/data'] }); expect(dockerCompose).toContain('volumes:'); expect(dockerCompose).toContain('- ./logs:/app/logs'); expect(dockerCompose).toContain('- ./data:/app/data'); }); it('should include health check configuration', () => { const dockerCompose = dockerGenerator.generateDockerCompose(mockDeploymentConfig, { port: 3000 }); expect(dockerCompose).toContain('healthcheck:'); expect(dockerCompose).toContain('test: ["CMD", "curl", "-f", "http://localhost:3000/health"]'); expect(dockerCompose).toContain('interval: 30s'); expect(dockerCompose).toContain('timeout: 10s'); expect(dockerCompose).toContain('retries: 3'); }); }); describe('generateDockerignore', () => { it('should generate comprehensive .dockerignore file', () => { const dockerignore = dockerGenerator.generateDockerignore(); expect(dockerignore).toContain('node_modules'); expect(dockerignore).toContain('.git/'); expect(dockerignore).toContain('.env'); expect(dockerignore).toContain('dist/'); expect(dockerignore).toContain('*.log'); expect(dockerignore).toContain('coverage'); expect(dockerignore).toContain('.vscode/'); expect(dockerignore).toContain('*.test.js'); expect(dockerignore).toContain('*.test.ts'); }); }); describe('generateKubernetesManifests', () => { it('should generate Kubernetes deployment manifest', () => { const manifests = dockerGenerator.generateKubernetesManifests(mockDeploymentConfig); expect(manifests.deployment).toContain('apiVersion: apps/v1'); expect(manifests.deployment).toContain('kind: Deployment'); expect(manifests.deployment).toContain('name: ordojs-app'); expect(manifests.deployment).toContain('replicas: 3'); expect(manifests.deployment).toContain('containerPort: 3000'); expect(manifests.deployment).toContain('livenessProbe:'); expect(manifests.deployment).toContain('readinessProbe:'); }); it('should generate Kubernetes service manifest', () => { const manifests = dockerGenerator.generateKubernetesManifests(mockDeploymentConfig); expect(manifests.service).toContain('apiVersion: v1'); expect(manifests.service).toContain('kind: Service'); expect(manifests.service).toContain('name: ordojs-app-service'); expect(manifests.service).toContain('type: ClusterIP'); expect(manifests.service).toContain('port: 80'); expect(manifests.service).toContain('targetPort: 3000'); }); it('should generate Kubernetes ingress manifest', () => { const manifests = dockerGenerator.generateKubernetesManifests(mockDeploymentConfig); expect(manifests.ingress).toContain('apiVersion: networking.k8s.io/v1'); expect(manifests.ingress).toContain('kind: Ingress'); expect(manifests.ingress).toContain('name: ordojs-app-ingress'); expect(manifests.ingress).toContain('host: ordojs-app.local'); }); it('should generate ConfigMap for non-secret environment variables', () => { const manifests = dockerGenerator.generateKubernetesManifests(mockDeploymentConfig, { environment: { NODE_ENV: 'production', API_URL: 'https://api.example.com', DB_PASSWORD: 'secret' } }); expect(manifests.configMap).toContain('apiVersion: v1'); expect(manifests.configMap).toContain('kind: ConfigMap'); expect(manifests.configMap).toContain('NODE_ENV: "production"'); expect(manifests.configMap).toContain('API_URL: "https://api.example.com"'); expect(manifests.configMap).not.toContain('DB_PASSWORD'); }); it('should generate Secret for sensitive environment variables', () => { const manifests = dockerGenerator.generateKubernetesManifests(mockDeploymentConfig, { environment: { NODE_ENV: 'production', DB_PASSWORD: 'secret', API_SECRET: 'very-secret' } }); expect(manifests.secret).toContain('apiVersion: v1'); expect(manifests.secret).toContain('kind: Secret'); expect(manifests.secret).toContain('type: Opaque'); expect(manifests.secret).toContain('DB_PASSWORD:'); expect(manifests.secret).toContain('API_SECRET:'); expect(manifests.secret).not.toContain('NODE_ENV'); }); it('should not generate Secret when no sensitive variables', () => { const manifests = dockerGenerator.generateKubernetesManifests(mockDeploymentConfig, { environment: { NODE_ENV: 'production', API_URL: 'https://api.example.com' } }); expect(manifests.secret).toBe(''); }); }); describe('error handling', () => { it('should throw CLIError when Dockerfile generation fails', () => { // Mock a scenario that would cause generation to fail const invalidConfig = { ...mockDeploymentConfig, outputDir: null as any }; expect(() => { dockerGenerator.generateDockerfile(invalidConfig); }).toThrow(); }); }); });