ci: add Gitea Actions workflow for automated testing
Some checks failed
CI / lint (push) Failing after 11s
CI / test-backend (push) Has been skipped
CI / test-frontend (push) Has been skipped
CI / test-e2e (push) Has been skipped

- Create .gitea/workflows/ci.yml with 4 sequential jobs
  - lint: Run ESLint on root configuration
  - test-backend: Run backend Vitest tests with SQLite
  - test-frontend: Run frontend Vitest tests
  - test-e2e: Run Playwright E2E tests (bloqueante)
- E2E job automates server startup + Playwright test execution
- Configure Gitea Secrets for IGDB, RAWG, TheGamesDB API keys
- Add artifact upload for Playwright reports on failure
- Update SECURITY.md with CI/CD Secrets setup instructions
- Update docs/API_KEYS.md with production Gitea workflow guide
- Add tests/gitea-workflow.spec.ts with 12 validation tests
- Workflow triggers on push/PR to main and develop branches
This commit is contained in:
2026-02-12 20:43:15 +01:00
parent 907d3042bc
commit ce54db38d9
7 changed files with 321 additions and 87 deletions

View File

@@ -0,0 +1,126 @@
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');
});
});