import { describe, it, expect } from 'vitest'; import { readFileSync, existsSync } from 'fs'; import { resolve } from 'path'; import { parse as parseYaml } from 'yaml'; describe('Gitea Workflow CI - Phase 9.4', () => { const workflowPath = resolve(process.cwd(), '.gitea/workflows/ci.yml'); const securityPath = resolve(process.cwd(), 'SECURITY.md'); const apiKeysPath = resolve(process.cwd(), 'docs/API_KEYS.md'); let workflowContent: string; let workflowYaml: any; let securityContent: string; let apiKeysContent: string; // Load files once if (existsSync(workflowPath)) { workflowContent = readFileSync(workflowPath, 'utf-8'); workflowYaml = parseYaml(workflowContent); } if (existsSync(securityPath)) { securityContent = readFileSync(securityPath, 'utf-8'); } if (existsSync(apiKeysPath)) { apiKeysContent = readFileSync(apiKeysPath, 'utf-8'); } // Test 1: Workflow file exists it('should have .gitea/workflows/ci.yml file', () => { expect(existsSync(workflowPath)).toBe(true); }); // Test 2: Contains lint job it('should contain job: lint', () => { expect(workflowYaml?.jobs?.lint).toBeDefined(); expect(workflowYaml.jobs.lint.steps).toBeDefined(); }); // Test 3: Contains test-backend job it('should contain job: test-backend', () => { expect(workflowYaml?.jobs?.['test-backend']).toBeDefined(); expect(workflowYaml.jobs['test-backend'].steps).toBeDefined(); }); // Test 4: Contains test-frontend job it('should contain job: test-frontend', () => { expect(workflowYaml?.jobs?.['test-frontend']).toBeDefined(); expect(workflowYaml.jobs['test-frontend'].steps).toBeDefined(); }); // Test 5: Contains test-e2e job it('should contain job: test-e2e', () => { expect(workflowYaml?.jobs?.['test-e2e']).toBeDefined(); expect(workflowYaml.jobs['test-e2e'].steps).toBeDefined(); }); // Test 6: E2E job depends on backend and frontend tests it('test-e2e should have needs: [test-backend, test-frontend]', () => { const needs = workflowYaml?.jobs?.['test-e2e']?.needs; expect(Array.isArray(needs) || typeof needs === 'string').toBe(true); const needsArray = Array.isArray(needs) ? needs : [needs]; expect(needsArray).toContain('test-backend'); expect(needsArray).toContain('test-frontend'); }); // Test 7: E2E uses Gitea Secrets for API keys it('test-e2e should use Gitea Secrets for API keys', () => { const env = workflowYaml?.jobs?.['test-e2e']?.env; expect(env).toBeDefined(); // Check for secret references const envStr = JSON.stringify(env); expect(envStr).toContain('secrets.IGDB_CLIENT_ID'); expect(envStr).toContain('secrets.IGDB_CLIENT_SECRET'); expect(envStr).toContain('secrets.RAWG_API_KEY'); expect(envStr).toContain('secrets.THEGAMESDB_API_KEY'); }); // Test 8: E2E includes yarn test:install step it('test-e2e should include yarn test:install step', () => { const steps = workflowYaml?.jobs?.['test-e2e']?.steps || []; const testInstallStep = steps.some( (step: any) => step.run && typeof step.run === 'string' && step.run.includes('yarn test:install') ); expect(testInstallStep).toBe(true); }); // Test 9: Has triggers on push and pull_request it('should have triggers on push and pull_request', () => { const on = workflowYaml?.on; expect(on).toBeDefined(); expect(on?.push || on?.['push']).toBeDefined(); expect(on?.pull_request || on?.['pull_request']).toBeDefined(); }); // Test 10: Installs Node.js and caches yarn (lint job) it('should install Node.js and cache yarn in lint job', () => { const steps = workflowYaml?.jobs?.lint?.steps || []; const hasNodeSetup = steps.some((step: any) => step.uses && step.uses.includes('setup-node')); const hasYarnCache = steps.some( (step: any) => step.uses && step.uses.includes('setup-node') && step.with?.cache === 'yarn' ); expect(hasNodeSetup).toBe(true); expect(hasYarnCache).toBe(true); }); // Test 11: SECURITY.md mentions Gitea Secrets setup it('SECURITY.md should mention Gitea Secrets setup', () => { expect(securityContent).toBeDefined(); expect(securityContent.toLowerCase()).toContain('gitea'); expect(securityContent.toLowerCase()).toContain('secret'); }); // Test 12: SECURITY.md has instructions for CI/CD secrets it('SECURITY.md should have CI/CD secrets instructions', () => { expect(securityContent).toBeDefined(); expect(securityContent.toLowerCase()).toContain('ci/cd'); expect(securityContent).toContain('IGDB_CLIENT_ID'); expect(securityContent).toContain('RAWG_API_KEY'); }); });