Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 31 additions & 74 deletions .github/workflows/backend-ci-cd.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
name: Backend CI/CD Pipeline

on:
push:
branches:
- develop
- main
tags:
- "v*"
paths:
- "backend/**"
- ".github/workflows/backend-ci-cd.yml"
pull_request:
branches:
- develop
- main
paths:
- "backend/**"

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}/backend
name: backend-dist

jobs:
# ============================================================================
# TEST: Unit Tests
# ============================================================================
test:
e2e:
runs-on: ubuntu-latest
name: Test
name: E2E
needs: build

services:
postgres:
image: postgres:16
env:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: nestera_test
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U user -d nestera_test"
--health-interval=10s
--health-timeout=5s
--health-retries=5

redis:
image: redis:7
ports:
- 6379:6379

steps:
- name: Checkout code
Expand All @@ -46,50 +43,10 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run unit tests
run: cd backend && pnpm run test

- name: Generate coverage report
run: cd backend && pnpm run test:cov

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./backend/coverage/coverage-final.json
flags: unittests
fail_ci_if_error: false

# ============================================================================
# BUILD: Ensure the NestJS project compiles cleanly
# ============================================================================
build:
runs-on: ubuntu-latest
name: Build
needs: test

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
cache-dependency-path: "**/pnpm-lock.yaml"

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: cd backend && pnpm run build

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: backend-dist
path: backend/dist
retention-days: 7
- name: Run backend E2E tests
env:
NODE_ENV: test
DATABASE_URL: postgresql://user:pass@localhost:5432/nestera_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: super-secret-key-for-testing-purposes-must-be-long-enough
run: cd backend && pnpm run test:e2e
22 changes: 22 additions & 0 deletions backend/docs/E2E_TEST_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Backend E2E Test Plan

Critical E2E paths:
1. Authentication flow
2. Wallet linking lifecycle
3. Savings subscription lifecycle
4. Withdrawal process
5. Governance proposal + voting
6. Transaction processing

## Test environment
- PostgreSQL test database (`DATABASE_URL`)
- Redis test instance (`REDIS_URL`)
- Stellar testnet/soroban endpoints (or mocked adapters)

## Coverage target
- Minimum 80% of defined critical-path scenarios.

## Implementation notes
- Reuse `backend/test/factories/e2e.factory.ts` for deterministic test data.
- Keep tests independent and idempotent.
- Use database cleanup hooks between suites.
20 changes: 20 additions & 0 deletions backend/test/factories/e2e.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const E2EFactory = {
authPayload: () => ({
email: `e2e_${Date.now()}@example.com`,
password: 'StrongPass123!',
firstName: 'E2E',
lastName: 'User',
}),
walletLinkPayload: () => ({
address: 'GBRPYHIL2C2YJ7Y3A4YQ7QO6FSVUIZXHTU2JZ5XW5ITQMRWJQN6M5J7N',
signature: 'test-signature',
nonce: `nonce-${Date.now()}`,
}),
savingsSubscriptionPayload: (productId: string) => ({ productId, amount: 100 }),
withdrawalPayload: (subscriptionId: string) => ({ subscriptionId, amount: 50 }),
governanceProposalPayload: () => ({
title: 'E2E Governance Proposal',
description: 'Proposal created by e2e tests',
}),
votePayload: () => ({ support: true }),
};