ci: add Gitea Actions workflow for automated testing
- 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:
126
tests/gitea-workflow.spec.ts
Normal file
126
tests/gitea-workflow.spec.ts
Normal 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');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user