From 49e1c90f378a3e1bbf04ca384bf9f06db2e009d5 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 3 Feb 2026 23:23:27 +0100 Subject: [PATCH] docs(09): create phase plan Phase 09: CI Pipeline Hardening - 4 plan(s) in 3 wave(s) - Wave 1: Infrastructure setup (09-01) - Wave 2: Tests in parallel (09-02, 09-03) - Wave 3: CI integration (09-04) - Ready for execution Co-Authored-By: Claude Opus 4.5 --- .planning/ROADMAP.md | 11 +- .planning/phases/09-ci-pipeline/09-01-PLAN.md | 182 +++++++++++++++ .planning/phases/09-ci-pipeline/09-02-PLAN.md | 211 +++++++++++++++++ .planning/phases/09-ci-pipeline/09-03-PLAN.md | 219 ++++++++++++++++++ .planning/phases/09-ci-pipeline/09-04-PLAN.md | 218 +++++++++++++++++ 5 files changed, 837 insertions(+), 4 deletions(-) create mode 100644 .planning/phases/09-ci-pipeline/09-01-PLAN.md create mode 100644 .planning/phases/09-ci-pipeline/09-02-PLAN.md create mode 100644 .planning/phases/09-ci-pipeline/09-03-PLAN.md create mode 100644 .planning/phases/09-ci-pipeline/09-04-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 489b51f..34ff708 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -106,11 +106,13 @@ Plans: 3. Pipeline fails before Docker build when unit tests fail 4. Pipeline fails before Docker build when type checking fails 5. E2E tests run in pipeline using Playwright Docker image -**Plans**: TBD +**Plans**: 4 plans Plans: -- [ ] 09-01: Vitest setup and unit test structure -- [ ] 09-02: Pipeline integration with fail-fast behavior +- [ ] 09-01-PLAN.md — Test infrastructure setup (Vitest + browser mode) +- [ ] 09-02-PLAN.md — Unit and component test suite with coverage +- [ ] 09-03-PLAN.md — E2E test suite with database fixtures +- [ ] 09-04-PLAN.md — CI pipeline integration with fail-fast behavior ## Progress @@ -127,13 +129,14 @@ Phases execute in numeric order: 7 -> 8 -> 9 | 6. Deployment | v1.0 | 2/2 | Complete | 2026-02-01 | | 7. GitOps Foundation | v2.0 | 2/2 | Complete ✓ | 2026-02-03 | | 8. Observability Stack | v2.0 | 0/3 | Planned | - | -| 9. CI Pipeline Hardening | v2.0 | 0/2 | Not started | - | +| 9. CI Pipeline Hardening | v2.0 | 0/4 | Planned | - | --- *Roadmap created: 2026-01-29* *v2.0 phases added: 2026-02-03* *Phase 7 planned: 2026-02-03* *Phase 8 planned: 2026-02-03* +*Phase 9 planned: 2026-02-03* *Depth: standard* *v1.0 Coverage: 31/31 requirements mapped* *v2.0 Coverage: 17/17 requirements mapped* diff --git a/.planning/phases/09-ci-pipeline/09-01-PLAN.md b/.planning/phases/09-ci-pipeline/09-01-PLAN.md new file mode 100644 index 0000000..2630172 --- /dev/null +++ b/.planning/phases/09-ci-pipeline/09-01-PLAN.md @@ -0,0 +1,182 @@ +--- +phase: 09-ci-pipeline +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - package.json + - vite.config.ts + - vitest-setup-client.ts + - src/lib/utils/filterEntries.test.ts +autonomous: true + +must_haves: + truths: + - "npm run test:unit executes Vitest and reports pass/fail" + - "Vitest browser mode runs component tests in real Chromium" + - "Vitest node mode runs server/utility tests" + - "SvelteKit modules ($app/*) are mocked in test environment" + artifacts: + - path: "vite.config.ts" + provides: "Multi-project Vitest configuration" + contains: "projects:" + - path: "vitest-setup-client.ts" + provides: "SvelteKit module mocks for browser tests" + contains: "vi.mock('$app/" + - path: "package.json" + provides: "Test scripts" + contains: "test:unit" + - path: "src/lib/utils/filterEntries.test.ts" + provides: "Sample unit test proving setup works" + min_lines: 15 + key_links: + - from: "vite.config.ts" + to: "vitest-setup-client.ts" + via: "setupFiles configuration" + pattern: "setupFiles.*vitest-setup" +--- + + +Configure Vitest test infrastructure with multi-project setup for SvelteKit. + +Purpose: Establish the test runner foundation that all subsequent test plans build upon. This enables unit tests (node mode) and component tests (browser mode) with proper SvelteKit module mocking. + +Output: Working Vitest configuration with browser mode for Svelte 5 components and node mode for server code, plus a sample test proving the setup works. + + + +@/home/tho/.claude/get-shit-done/workflows/execute-plan.md +@/home/tho/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phases/09-ci-pipeline/09-RESEARCH.md + +@vite.config.ts +@package.json +@playwright.config.ts + + + + + + Task 1: Install Vitest dependencies and configure multi-project setup + package.json, vite.config.ts + +Install Vitest and browser mode dependencies: +```bash +npm install -D vitest @vitest/browser vitest-browser-svelte @vitest/browser-playwright @vitest/coverage-v8 +npx playwright install chromium +``` + +Update vite.config.ts with multi-project Vitest configuration: +- Import `playwright` from `@vitest/browser-playwright` +- Add `test` config with `coverage` (provider: v8, include src/**/*, thresholds with autoUpdate: true initially) +- Configure two projects: + 1. `client`: browser mode with Playwright provider, include `*.svelte.{test,spec}.ts`, setupFiles pointing to vitest-setup-client.ts + 2. `server`: node environment, include `*.{test,spec}.ts`, exclude `*.svelte.{test,spec}.ts` + +Update package.json scripts: +- Add `"test": "vitest"` +- Add `"test:unit": "vitest run"` +- Add `"test:unit:watch": "vitest"` +- Add `"test:coverage": "vitest run --coverage"` + +Keep existing scripts (test:e2e, test:e2e:docker) unchanged. + + +Run `npm run test:unit` - should execute (may show "no tests found" initially, but Vitest runs without config errors) +Run `npx vitest --version` - confirms Vitest is installed + + Vitest installed with multi-project config. npm run test:unit executes without configuration errors. + + + + Task 2: Create SvelteKit module mocks in setup file + vitest-setup-client.ts + +Create vitest-setup-client.ts in project root with: + +1. Add TypeScript reference directives: + - `/// ` + - `/// ` + +2. Mock `$app/navigation`: + - goto: vi.fn returning Promise.resolve() + - invalidate: vi.fn returning Promise.resolve() + - invalidateAll: vi.fn returning Promise.resolve() + - beforeNavigate: vi.fn() + - afterNavigate: vi.fn() + +3. Mock `$app/stores`: + - page: writable store with URL, params, route, status, error, data, form + - navigating: writable(null) + - updated: { check: vi.fn(), subscribe: writable(false).subscribe } + +4. Mock `$app/environment`: + - browser: true + - dev: true + - building: false + +Import writable from 'svelte/store' and vi from 'vitest'. + +Note: Use simple mocks, do NOT use importOriginal with SvelteKit modules (causes SSR issues per research). + + +File exists at vitest-setup-client.ts with all required mocks. +TypeScript compilation succeeds: `npx tsc --noEmit vitest-setup-client.ts` (or no TS errors shown in editor) + + SvelteKit module mocks created. Browser-mode tests can import $app/* without errors. + + + + Task 3: Write sample test to verify infrastructure + src/lib/utils/filterEntries.test.ts + +Create src/lib/utils/filterEntries.test.ts as a node-mode unit test: + +1. Import { describe, it, expect } from 'vitest' +2. Import filterEntries function from './filterEntries' +3. Read filterEntries.ts to understand the function signature and behavior + +Write tests for filterEntries covering: +- Empty entries array returns empty array +- Filter by tag returns matching entries +- Filter by search term matches title/content +- Combined filters (tag + search) work together +- Type filter (task vs thought) works if applicable + +This proves the server/node project runs correctly. + +Note: This is a real test, not just a placeholder. Aim for thorough coverage of filterEntries.ts functionality. + + +Run `npm run test:unit` - filterEntries tests execute and pass +Run `npm run test:coverage` - shows coverage report including filterEntries.ts + + Sample unit test passes. Vitest infrastructure is verified working for node-mode tests. + + + + + +1. `npm run test:unit` executes without errors +2. `npm run test:coverage` produces coverage report +3. filterEntries.test.ts tests pass +4. vite.config.ts contains multi-project test configuration +5. vitest-setup-client.ts contains $app/* mocks + + + +- CI-01 requirement satisfied: Vitest installed and configured +- Multi-project setup distinguishes client (browser) and server (node) tests +- At least one unit test passes proving the infrastructure works +- Coverage reporting functional (threshold enforcement comes in Plan 02) + + + +After completion, create `.planning/phases/09-ci-pipeline/09-01-SUMMARY.md` + diff --git a/.planning/phases/09-ci-pipeline/09-02-PLAN.md b/.planning/phases/09-ci-pipeline/09-02-PLAN.md new file mode 100644 index 0000000..8030956 --- /dev/null +++ b/.planning/phases/09-ci-pipeline/09-02-PLAN.md @@ -0,0 +1,211 @@ +--- +phase: 09-ci-pipeline +plan: 02 +type: execute +wave: 2 +depends_on: ["09-01"] +files_modified: + - src/lib/utils/highlightText.test.ts + - src/lib/utils/parseHashtags.test.ts + - src/lib/components/SearchBar.svelte.test.ts + - src/lib/components/TagInput.svelte.test.ts + - src/lib/components/CompletedToggle.svelte.test.ts + - vite.config.ts +autonomous: true + +must_haves: + truths: + - "All utility functions have passing tests" + - "Component tests run in real browser via Vitest browser mode" + - "Coverage threshold is enforced (starts with autoUpdate baseline)" + artifacts: + - path: "src/lib/utils/highlightText.test.ts" + provides: "Tests for text highlighting utility" + min_lines: 20 + - path: "src/lib/utils/parseHashtags.test.ts" + provides: "Tests for hashtag parsing utility" + min_lines: 20 + - path: "src/lib/components/SearchBar.svelte.test.ts" + provides: "Browser-mode test for SearchBar component" + min_lines: 25 + - path: "src/lib/components/TagInput.svelte.test.ts" + provides: "Browser-mode test for TagInput component" + min_lines: 25 + - path: "src/lib/components/CompletedToggle.svelte.test.ts" + provides: "Browser-mode test for toggle component" + min_lines: 20 + key_links: + - from: "src/lib/components/SearchBar.svelte.test.ts" + to: "vitest-browser-svelte" + via: "render import" + pattern: "import.*render.*from.*vitest-browser-svelte" +--- + + +Write unit tests for utility functions and initial component tests to establish testing patterns. + +Purpose: Create comprehensive tests for pure utility functions (easy wins for coverage) and establish the component testing pattern using Vitest browser mode. This proves both test project configurations work. + +Output: All utility functions tested, 3 component tests demonstrating the browser-mode pattern, coverage baseline established. + + + +@/home/tho/.claude/get-shit-done/workflows/execute-plan.md +@/home/tho/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/phases/09-ci-pipeline/09-RESEARCH.md +@.planning/phases/09-ci-pipeline/09-01-SUMMARY.md + +@src/lib/utils/highlightText.ts +@src/lib/utils/parseHashtags.ts +@src/lib/components/SearchBar.svelte +@src/lib/components/TagInput.svelte +@src/lib/components/CompletedToggle.svelte +@vitest-setup-client.ts + + + + + + Task 1: Write unit tests for remaining utility functions + src/lib/utils/highlightText.test.ts, src/lib/utils/parseHashtags.test.ts + +Read each utility file to understand its behavior, then write comprehensive tests: + +**highlightText.test.ts:** +- Import function and test utilities from vitest +- Test: Returns original text when no search term +- Test: Highlights single match with mark tag +- Test: Highlights multiple matches +- Test: Case-insensitive matching +- Test: Handles special regex characters in search term +- Test: Returns empty string for empty input + +**parseHashtags.test.ts:** +- Import function and test utilities from vitest +- Test: Extracts single hashtag from text +- Test: Extracts multiple hashtags +- Test: Returns empty array when no hashtags +- Test: Handles hashtags at start/middle/end of text +- Test: Ignores invalid hashtag patterns (e.g., # alone, #123) +- Test: Removes duplicates if function does that + +Each test file should have describe block with descriptive test names. +Use `it.each` for data-driven tests where appropriate. + + +Run `npm run test:unit -- --reporter=verbose` - all utility tests pass +Run `npm run test:coverage` - shows improved coverage for src/lib/utils/ + + All 3 utility functions (filterEntries, highlightText, parseHashtags) have comprehensive test coverage. + + + + Task 2: Write browser-mode component tests for 3 simpler components + src/lib/components/SearchBar.svelte.test.ts, src/lib/components/TagInput.svelte.test.ts, src/lib/components/CompletedToggle.svelte.test.ts + +Create .svelte.test.ts files (note: .svelte.test.ts NOT .test.ts for browser mode) for three simpler components. + +**Pattern for all component tests:** +```typescript +import { render } from 'vitest-browser-svelte'; +import { page } from '@vitest/browser/context'; +import { describe, expect, it } from 'vitest'; +import ComponentName from './ComponentName.svelte'; +``` + +**SearchBar.svelte.test.ts:** +- Read SearchBar.svelte to understand props and behavior +- Test: Renders input element +- Test: Calls onSearch callback when user types (if applicable) +- Test: Shows clear button when text entered (if applicable) +- Test: Placeholder text is visible + +**TagInput.svelte.test.ts:** +- Read TagInput.svelte to understand props and behavior +- Test: Renders tag input element +- Test: Can add a tag (simulate user typing and pressing enter/adding) +- Test: Displays existing tags if passed as prop + +**CompletedToggle.svelte.test.ts:** +- Read CompletedToggle.svelte to understand props +- Test: Renders toggle in unchecked state by default +- Test: Toggle state changes on click +- Test: Calls callback when toggled (if applicable) + +Use `page.getByRole()`, `page.getByText()`, `page.getByPlaceholder()` for element selection. +Use `await button.click()` for interactions. +Use `flushSync()` from 'svelte' after external state changes if needed. +Use `await expect.element(locator).toBeInTheDocument()` for assertions. + + +Run `npm run test:unit` - component tests run in browser mode (you'll see Chromium launch) +All 3 component tests pass + + Browser-mode component testing pattern established with 3 working tests. + + + + Task 3: Configure coverage thresholds with baseline + vite.config.ts + +Update vite.config.ts coverage configuration: + +1. Set initial thresholds using autoUpdate to establish baseline: +```typescript +thresholds: { + autoUpdate: true, // Will update thresholds based on current coverage +} +``` + +2. Run `npm run test:coverage` once to establish baseline thresholds + +3. Review the auto-updated thresholds in vite.config.ts + +4. If coverage is already above 30%, manually set thresholds to a reasonable starting point (e.g., 50% of current coverage) with a path toward 80%: +```typescript +thresholds: { + global: { + statements: [current - 10], + branches: [current - 10], + functions: [current - 10], + lines: [current - 10], + }, +} +``` + +5. Add comment noting the target is 80% coverage (CI-01 decision) + +Note: Full 80% coverage will be achieved incrementally. This plan establishes the enforcement mechanism. + + +Run `npm run test:coverage` - shows coverage percentages +Coverage thresholds are set in vite.config.ts +Future test runs will fail if coverage drops below threshold + + Coverage thresholds configured. Enforcement mechanism in place for incremental coverage improvement. + + + + + +1. `npm run test:unit` runs all tests (utility + component) +2. Component tests run in Chromium browser (browser mode working) +3. `npm run test:coverage` shows coverage for utilities and tested components +4. Coverage thresholds are configured in vite.config.ts +5. All tests pass + + + +- All 3 utility functions have comprehensive tests +- 3 component tests demonstrate browser-mode testing pattern +- Coverage thresholds configured (starting point toward 80% goal) +- Both Vitest projects (client browser, server node) verified working + + + +After completion, create `.planning/phases/09-ci-pipeline/09-02-SUMMARY.md` + diff --git a/.planning/phases/09-ci-pipeline/09-03-PLAN.md b/.planning/phases/09-ci-pipeline/09-03-PLAN.md new file mode 100644 index 0000000..53db962 --- /dev/null +++ b/.planning/phases/09-ci-pipeline/09-03-PLAN.md @@ -0,0 +1,219 @@ +--- +phase: 09-ci-pipeline +plan: 03 +type: execute +wave: 2 +depends_on: ["09-01"] +files_modified: + - playwright.config.ts + - tests/e2e/fixtures/db.ts + - tests/e2e/user-journeys.spec.ts + - tests/e2e/index.ts +autonomous: true + +must_haves: + truths: + - "E2E tests run against the application with seeded test data" + - "User journeys cover create, edit, search, organize, and delete workflows" + - "Tests run on both desktop and mobile viewports" + - "Screenshots are captured on test failure" + artifacts: + - path: "playwright.config.ts" + provides: "E2E configuration with multi-viewport and screenshot settings" + contains: "screenshot: 'only-on-failure'" + - path: "tests/e2e/fixtures/db.ts" + provides: "Database seeding fixture using drizzle-seed" + contains: "drizzle-seed" + - path: "tests/e2e/user-journeys.spec.ts" + provides: "Core user journey E2E tests" + min_lines: 100 + - path: "tests/e2e/index.ts" + provides: "Custom test function with fixtures" + contains: "base.extend" + key_links: + - from: "tests/e2e/user-journeys.spec.ts" + to: "tests/e2e/fixtures/db.ts" + via: "test import with seededDb fixture" + pattern: "import.*test.*from.*fixtures" +--- + + +Create comprehensive E2E test suite with database fixtures and multi-viewport testing. + +Purpose: Establish E2E tests that verify full user journeys work correctly. These tests catch integration issues that unit tests miss and provide confidence that the deployed application works as expected. + +Output: E2E test suite covering core user workflows, database seeding fixture for consistent test data, multi-viewport testing for desktop and mobile. + + + +@/home/tho/.claude/get-shit-done/workflows/execute-plan.md +@/home/tho/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/phases/09-ci-pipeline/09-RESEARCH.md +@.planning/phases/09-ci-pipeline/09-01-SUMMARY.md + +@playwright.config.ts +@tests/docker-deployment.spec.ts +@src/lib/server/db/schema.ts +@src/routes/+page.svelte + + + + + + Task 1: Update Playwright configuration for E2E requirements + playwright.config.ts + +Update playwright.config.ts with E2E requirements from user decisions: + +1. Set `testDir: './tests/e2e'` (separate from existing docker test) +2. Set `fullyParallel: false` (shared database) +3. Set `workers: 1` (avoid database race conditions) +4. Configure `reporter`: + - `['html', { open: 'never' }]` + - `['github']` for CI annotations + +5. Configure `use`: + - `baseURL: process.env.BASE_URL || 'http://localhost:5173'` + - `trace: 'on-first-retry'` + - `screenshot: 'only-on-failure'` (per user decision: screenshots, no video) + - `video: 'off'` + +6. Add two projects: + - `chromium-desktop`: using `devices['Desktop Chrome']` + - `chromium-mobile`: using `devices['Pixel 5']` + +7. Configure `webServer`: + - `command: 'npm run build && npm run preview'` + - `port: 4173` + - `reuseExistingServer: !process.env.CI` + +Move existing docker-deployment.spec.ts to tests/e2e/ or keep in tests/ with separate config. + + +Run `npx playwright test --list` - shows test files found +Configuration is valid (no syntax errors) + + Playwright configured for E2E with desktop/mobile viewports, screenshots on failure, single worker for database safety. + + + + Task 2: Create database seeding fixture + tests/e2e/fixtures/db.ts, tests/e2e/index.ts + +First, install drizzle-seed: +```bash +npm install -D drizzle-seed +``` + +Create tests/e2e/fixtures/db.ts: +1. Import test base from @playwright/test +2. Import db from src/lib/server/db +3. Import schema from src/lib/server/db/schema +4. Import seed and reset from drizzle-seed + +Create a fixture that: +- Seeds database with known test data before test +- Provides seeded entries (tasks, thoughts) with predictable IDs and content +- Cleans up after test using reset() + +Create tests/e2e/index.ts: +- Re-export extended test with seededDb fixture +- Re-export expect from @playwright/test + +Test data should include: +- At least 5 entries with various states (tasks vs thoughts, completed vs pending) +- Entries with tags for testing filter/search +- Entries with images (if applicable to schema) +- Entries with different dates for sorting tests + +Note: Read the actual schema.ts to understand the exact model structure before writing seed logic. + + +TypeScript compiles without errors +Fixture can be imported in test file + + Database fixture created. Tests can import { test, expect } from './fixtures' to get seeded database. + + + + Task 3: Write E2E tests for core user journeys + tests/e2e/user-journeys.spec.ts + +Create tests/e2e/user-journeys.spec.ts using the custom test with fixtures: + +```typescript +import { test, expect } from './index'; +``` + +Write tests for each user journey (per CONTEXT.md decisions): + +**Create workflow:** +- Navigate to home page +- Use quick capture to create a new entry +- Verify entry appears in list +- Verify entry persists after page reload + +**Edit workflow:** +- Find an existing entry (from seeded data) +- Click to open/edit +- Modify content +- Save changes +- Verify changes persisted + +**Search workflow:** +- Use search bar to find entry by text +- Verify matching entries shown +- Verify non-matching entries hidden +- Test search with tags filter + +**Organize workflow:** +- Add tag to entry +- Filter by tag +- Verify filtered results +- Pin an entry (if applicable) +- Verify pinned entry appears first + +**Delete workflow:** +- Select an entry +- Delete it +- Verify entry removed from list +- Verify entry not found after reload + +Use `test.describe()` to group related tests. +Each test should use `seededDb` fixture for consistent starting state. +Use page object pattern if tests get complex (optional - can keep simple for now). + + +Run `npm run test:e2e` with app running locally (or let webServer start it) +All E2E tests pass +Screenshots are generated in test-results/ for any failures + + E2E test suite covers all core user journeys. Tests run on both desktop and mobile viewports. + + + + + +1. `npm run test:e2e` executes E2E tests +2. Tests run on both chromium-desktop and chromium-mobile projects +3. Database is seeded with test data before each test +4. All 5 user journeys (create, edit, search, organize, delete) have tests +5. Screenshots captured on failure (can test by making a test fail temporarily) +6. Tests pass consistently (no flaky tests) + + + +- CI-04 requirement satisfied: E2E tests ready for pipeline +- User journeys cover create/edit/search/organize/delete as specified in CONTEXT.md +- Multi-viewport testing (desktop + mobile) per CONTEXT.md decision +- Database fixtures provide consistent, isolated test data +- Screenshot on failure configured (no video per CONTEXT.md decision) + + + +After completion, create `.planning/phases/09-ci-pipeline/09-03-SUMMARY.md` + diff --git a/.planning/phases/09-ci-pipeline/09-04-PLAN.md b/.planning/phases/09-ci-pipeline/09-04-PLAN.md new file mode 100644 index 0000000..31ac613 --- /dev/null +++ b/.planning/phases/09-ci-pipeline/09-04-PLAN.md @@ -0,0 +1,218 @@ +--- +phase: 09-ci-pipeline +plan: 04 +type: execute +wave: 3 +depends_on: ["09-02", "09-03"] +files_modified: + - .gitea/workflows/build.yaml +autonomous: false + +user_setup: + - service: slack + why: "Pipeline failure notifications" + env_vars: + - name: SLACK_WEBHOOK_URL + source: "Slack App settings -> Incoming Webhooks -> Create new webhook -> Copy URL" + dashboard_config: + - task: "Create Slack app with incoming webhook" + location: "https://api.slack.com/apps -> Create New App -> From scratch -> Add Incoming Webhooks" + +must_haves: + truths: + - "Pipeline runs type checking before Docker build" + - "Pipeline runs unit tests with coverage before Docker build" + - "Pipeline runs E2E tests before Docker build" + - "Pipeline fails fast when tests or type checking fail" + - "Slack notification sent on pipeline failure" + - "Test artifacts (coverage, playwright report) are uploaded" + artifacts: + - path: ".gitea/workflows/build.yaml" + provides: "CI pipeline with test jobs" + contains: "npm run check" + - path: ".gitea/workflows/build.yaml" + provides: "Unit test step" + contains: "npm run test:coverage" + - path: ".gitea/workflows/build.yaml" + provides: "E2E test step" + contains: "npm run test:e2e" + key_links: + - from: ".gitea/workflows/build.yaml" + to: "package.json scripts" + via: "npm run commands" + pattern: "npm run (check|test:coverage|test:e2e)" + - from: "build job" + to: "test job" + via: "needs: test" + pattern: "needs:\\s*test" +--- + + +Integrate tests into Gitea Actions pipeline with fail-fast behavior and Slack notifications. + +Purpose: Ensure tests run automatically on every push/PR and block deployment when tests fail. This is the final piece that makes the test infrastructure actually protect production. + +Output: Updated CI workflow with test job that runs before build, fail-fast on errors, and Slack notification on failure. + + + +@/home/tho/.claude/get-shit-done/workflows/execute-plan.md +@/home/tho/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/phases/09-ci-pipeline/09-RESEARCH.md +@.planning/phases/09-ci-pipeline/09-02-SUMMARY.md +@.planning/phases/09-ci-pipeline/09-03-SUMMARY.md + +@.gitea/workflows/build.yaml +@package.json + + + + + + Task 1: Add test job to CI pipeline + .gitea/workflows/build.yaml + +Update .gitea/workflows/build.yaml to add a test job that runs BEFORE build: + +1. Add new `test` job at the beginning of jobs section: +```yaml +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run type check + run: npm run check -- --output machine + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: Run unit tests with coverage + run: npm run test:coverage + + - name: Run E2E tests + run: npm run test:e2e + env: + CI: true + + - name: Upload test artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-results + path: | + coverage/ + playwright-report/ + test-results/ + retention-days: 7 +``` + +2. Modify existing `build` job to depend on test: +```yaml + build: + needs: test + runs-on: ubuntu-latest + # ... existing steps ... +``` + +This ensures build only runs if tests pass (fail-fast behavior). + + +YAML syntax is valid: `python3 -c "import yaml; yaml.safe_load(open('.gitea/workflows/build.yaml'))"` +Build job has `needs: test` dependency + + Test job added to pipeline. Build job depends on test job (fail-fast). + + + + Task 2: Add Slack notification on failure + .gitea/workflows/build.yaml + +Add a notify job that runs on failure: + +```yaml + notify: + needs: [test, build] + runs-on: ubuntu-latest + if: failure() + steps: + - name: Notify Slack on failure + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + run: | + curl -X POST -H 'Content-type: application/json' \ + --data "{\"text\":\"Pipeline failed for ${{ gitea.repository }} on ${{ gitea.ref }}\"}" \ + $SLACK_WEBHOOK_URL +``` + +Note: Using direct curl to Slack webhook rather than a GitHub Action for maximum Gitea compatibility (per RESEARCH.md recommendation). + +The SLACK_WEBHOOK_URL secret must be configured in Gitea repository settings by the user (documented in user_setup frontmatter). + + +YAML syntax is valid +Notify job has `if: failure()` condition +Notify job depends on both test and build + + Slack notification configured for pipeline failures. + + + + Complete CI pipeline with test job, fail-fast behavior, artifact upload, and Slack notification + +1. Review the updated .gitea/workflows/build.yaml file structure +2. Verify the job dependency chain: test -> build -> (notify on failure) +3. Confirm test job includes all required steps: + - Type checking (svelte-check) + - Unit tests with coverage (vitest) + - E2E tests (playwright) +4. If ready to test in CI: + - Push a commit to trigger the pipeline + - Monitor Gitea Actions for the test job execution + - Verify build job waits for test job to complete +5. (Optional) Set up SLACK_WEBHOOK_URL secret in Gitea to test failure notifications + + Type "approved" to confirm CI pipeline is correctly configured, or describe any issues found + + + + + +1. .gitea/workflows/build.yaml has test job with: + - Type checking step + - Unit test with coverage step + - E2E test step + - Artifact upload step +2. Build job has `needs: test` (fail-fast) +3. Notify job runs on failure with Slack webhook +4. YAML is valid syntax +5. Pipeline can be triggered on push/PR + + + +- CI-02 satisfied: Unit tests run in pipeline before build +- CI-03 satisfied: Type checking runs in pipeline +- CI-04 satisfied: E2E tests run in pipeline +- CI-05 satisfied: Pipeline fails fast on test/type errors (needs: test) +- Slack notification on failure (per CONTEXT.md decision) +- Test artifacts uploaded for debugging failed runs + + + +After completion, create `.planning/phases/09-ci-pipeline/09-04-SUMMARY.md` +