hosting-frontend/__tests__/deployment.test.ts
Alexis Bruneteau 33272327d8 fix(tests): fix CI test failures - improve test helpers and configuration
## Changes
- Updated jest.config.js to exclude utility test files from test execution
- Enhanced test-helpers with flexible auth context mocking
- Support for authenticated and unauthenticated test states
- Fixed landing page tests to use unauthenticated state
- Fixed navbar tests to handle multiple identical elements
- Fixed portfolio dashboard tests for status indicators
- Improved .gitignore with .env file exclusions

## Test Status
- Passing: 310/338 tests (92%)
- Failing: 28 tests (8%)
- Main issues: Multiple element matching, async validation

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 23:34:21 +02:00

217 lines
8.1 KiB
TypeScript

/**
* Deployment & Infrastructure Tests
* Tests for Docker, CI/CD, and deployment configuration
*/
import fs from 'fs'
import path from 'path'
describe('Deployment Configuration', () => {
describe('Dockerfile', () => {
it('should have valid Dockerfile', () => {
const dockerfilePath = path.join(process.cwd(), 'Dockerfile')
expect(fs.existsSync(dockerfilePath)).toBe(true)
})
it('should use Alpine base image', () => {
const dockerfilePath = path.join(process.cwd(), 'Dockerfile')
const content = fs.readFileSync(dockerfilePath, 'utf-8')
expect(content).toContain('alpine')
})
it('should have health check configured', () => {
const dockerfilePath = path.join(process.cwd(), 'Dockerfile')
const content = fs.readFileSync(dockerfilePath, 'utf-8')
expect(content).toContain('HEALTHCHECK')
})
it('should run as non-root user', () => {
const dockerfilePath = path.join(process.cwd(), 'Dockerfile')
const content = fs.readFileSync(dockerfilePath, 'utf-8')
expect(content).toContain('USER nextjs')
expect(content).toContain('addgroup')
expect(content).toContain('adduser')
})
it('should expose port 3000', () => {
const dockerfilePath = path.join(process.cwd(), 'Dockerfile')
const content = fs.readFileSync(dockerfilePath, 'utf-8')
expect(content).toContain('EXPOSE 3000')
})
it('should use multi-stage build', () => {
const dockerfilePath = path.join(process.cwd(), 'Dockerfile')
const content = fs.readFileSync(dockerfilePath, 'utf-8')
expect(content).toContain('FROM node:20-alpine AS builder')
expect(content).toContain('FROM node:20-alpine')
expect(content.match(/FROM node:20-alpine/g)!.length).toBe(2)
})
})
describe('Environment Configuration', () => {
it('should have .env.production file', () => {
const envPath = path.join(process.cwd(), '.env.production')
expect(fs.existsSync(envPath)).toBe(true)
})
it('should have .env.test file', () => {
const envPath = path.join(process.cwd(), '.env.test')
expect(fs.existsSync(envPath)).toBe(true)
})
it('should have production API URL configured', () => {
const envPath = path.join(process.cwd(), '.env.production')
const content = fs.readFileSync(envPath, 'utf-8')
expect(content).toContain('NEXT_PUBLIC_API_URL')
expect(content).toContain('NODE_ENV=production')
})
it('should not expose sensitive data in .env files', () => {
const envPath = path.join(process.cwd(), '.env.production')
const content = fs.readFileSync(envPath, 'utf-8')
expect(content).not.toContain('SECRET')
expect(content).not.toContain('PRIVATE_KEY')
expect(content).not.toContain('PASSWORD')
})
})
describe('CI/CD Workflows', () => {
it('should have test and validate workflow', () => {
const workflowPath = path.join(process.cwd(), '.gitea/workflows/test-and-validate.yml')
expect(fs.existsSync(workflowPath)).toBe(true)
})
it('should have production deployment workflow', () => {
const workflowPath = path.join(process.cwd(), '.gitea/workflows/deploy-prod.yml')
expect(fs.existsSync(workflowPath)).toBe(true)
})
it('test workflow should run tests', () => {
const workflowPath = path.join(process.cwd(), '.gitea/workflows/test-and-validate.yml')
const content = fs.readFileSync(workflowPath, 'utf-8')
expect(content).toContain('npm run test:ci')
expect(content).toContain('npm run build')
})
it('test workflow should check coverage', () => {
const workflowPath = path.join(process.cwd(), '.gitea/workflows/test-and-validate.yml')
const content = fs.readFileSync(workflowPath, 'utf-8')
expect(content).toContain('coverage')
expect(content).toContain('90')
})
it('production workflow should deploy with kubectl', () => {
const workflowPath = path.join(process.cwd(), '.gitea/workflows/deploy-prod.yml')
const content = fs.readFileSync(workflowPath, 'utf-8')
expect(content).toContain('kubectl')
expect(content).toContain('Deploy to Production')
})
})
describe('Build Configuration', () => {
it('should have next.config.js', () => {
const nextConfigPath = path.join(process.cwd(), 'next.config.js')
expect(fs.existsSync(nextConfigPath)).toBe(true)
})
it('should have tsconfig.json', () => {
const tsconfigPath = path.join(process.cwd(), 'tsconfig.json')
expect(fs.existsSync(tsconfigPath)).toBe(true)
})
it('should have jest.config.js', () => {
const jestConfigPath = path.join(process.cwd(), 'jest.config.js')
expect(fs.existsSync(jestConfigPath)).toBe(true)
})
it('should have package.json with build script', () => {
const packageJsonPath = path.join(process.cwd(), 'package.json')
const content = fs.readFileSync(packageJsonPath, 'utf-8')
const packageJson = JSON.parse(content)
expect(packageJson.scripts).toHaveProperty('build')
expect(packageJson.scripts.build).toContain('next build')
})
})
describe('Documentation', () => {
it('should have deployment guide', () => {
const docPath = path.join(process.cwd(), 'docs/DEPLOYMENT.md')
expect(fs.existsSync(docPath)).toBe(true)
})
it('should have README.md', () => {
const readmePath = path.join(process.cwd(), 'README.md')
expect(fs.existsSync(readmePath)).toBe(true)
})
it('deployment guide should include troubleshooting', () => {
const docPath = path.join(process.cwd(), 'docs/DEPLOYMENT.md')
const content = fs.readFileSync(docPath, 'utf-8')
expect(content).toContain('Troubleshooting')
expect(content).toContain('Health Check')
})
})
describe('Security Configuration', () => {
it('should have .dockerignore file', () => {
const dockerignorePath = path.join(process.cwd(), '.dockerignore')
expect(fs.existsSync(dockerignorePath)).toBe(true)
})
it('.dockerignore should exclude node_modules', () => {
const dockerignorePath = path.join(process.cwd(), '.dockerignore')
const content = fs.readFileSync(dockerignorePath, 'utf-8')
expect(content).toContain('node_modules')
})
it('should have .gitignore file', () => {
const gitignorePath = path.join(process.cwd(), '.gitignore')
expect(fs.existsSync(gitignorePath)).toBe(true)
})
it('.gitignore should exclude .env files', () => {
const gitignorePath = path.join(process.cwd(), '.gitignore')
const content = fs.readFileSync(gitignorePath, 'utf-8')
expect(content).toContain('.env')
})
})
describe('Build Optimization', () => {
it('package.json should have build optimization scripts', () => {
const packageJsonPath = path.join(process.cwd(), 'package.json')
const content = fs.readFileSync(packageJsonPath, 'utf-8')
const packageJson = JSON.parse(content)
expect(packageJson.scripts).toHaveProperty('build')
expect(packageJson.scripts).toHaveProperty('start')
expect(packageJson.scripts).toHaveProperty('dev')
})
it('should have proper npm dependencies', () => {
const packageJsonPath = path.join(process.cwd(), 'package.json')
const content = fs.readFileSync(packageJsonPath, 'utf-8')
const packageJson = JSON.parse(content)
// Production dependencies
expect(packageJson.dependencies).toHaveProperty('next')
expect(packageJson.dependencies).toHaveProperty('react')
expect(packageJson.dependencies).toHaveProperty('react-dom')
// Dev dependencies
expect(packageJson.devDependencies).toHaveProperty('typescript')
expect(packageJson.devDependencies).toHaveProperty('jest')
})
})
describe('Kubernetes Configuration', () => {
it('should have k3s deployment manifests', () => {
const k3sDir = path.join(process.cwd(), 'deploy/k3s/prod')
expect(fs.existsSync(k3sDir)).toBe(true)
})
it('should have kustomization.yml', () => {
const kustomizePath = path.join(process.cwd(), 'deploy/k3s/prod/kustomization.yml')
expect(fs.existsSync(kustomizePath)).toBe(true)
})
})
})