Skip to content
Open
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
97 changes: 84 additions & 13 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
name: Playwright E2E Tests
name: E2E Tests (Playwright + Fineract)

on:
push:
branches: [main, dev, dev-angular-19]
branches: [main, dev]
pull_request:
branches: [main, dev, dev-angular-19]
branches: [main, dev]

concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true

jobs:
playwright:
name: Run Playwright Tests
e2e:
name: Playwright E2E
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 45

env:
CI: true
E2E_BASE_URL: http://localhost:4200
E2E_FINERACT_URL: https://localhost:8443
E2E_USERNAME: mifos
E2E_PASSWORD: password
E2E_TENANT_ID: default
NODE_TLS_REJECT_UNAUTHORIZED: '0'

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

- name: Use Node.js 22x
- name: Use Node.js 24
uses: actions/setup-node@v6
with:
node-version: '24.14.0'
Expand All @@ -28,13 +41,65 @@ jobs:
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium

- name: Start E2E infrastructure
run: docker compose -f docker-compose.e2e.yml up -d --build

- name: Wait for PostgreSQL
run: |
timeout 60 bash -c '
until docker exec e2e-postgres pg_isready -U postgres 2>/dev/null; do
sleep 2
done
'
echo "✅ PostgreSQL ready"

- name: Wait for Fineract backend
run: |
timeout 300 bash -c '
until docker ps --filter "health=healthy" --filter "name=e2e-fineract" | grep -q healthy; do
echo " … Fineract not healthy yet"
sleep 10
done
'
curl -fk --retry 30 --retry-all-errors --connect-timeout 10 --retry-delay 10 \
https://localhost:8443/fineract-provider/actuator/health
echo ""
echo "✅ Fineract ready"

- name: Verify Fineract initialization complete
run: |
AUTH_HEADER=$(echo -n "${E2E_USERNAME}:${E2E_PASSWORD}" | base64 | tr -d '\n')
timeout 120 bash -c "
until curl -fsk \
-H 'Fineract-Platform-TenantId: ${E2E_TENANT_ID}' \
-H 'Authorization: Basic ${AUTH_HEADER}' \
https://localhost:8443/fineract-provider/api/v1/offices 2>/dev/null | grep -q 'Head Office'; do
echo ' … waiting for seed data'
sleep 5
done
"
echo "✅ Fineract initialization complete"

- name: Wait for web-app
run: |
curl -f --retry 20 --retry-all-errors --connect-timeout 5 --retry-delay 5 \
http://localhost:4200 > /dev/null 2>&1
echo "✅ Web-app ready"

- name: Run Playwright tests
run: npx playwright test --reporter=html,github
env:
CI: true
FINERACT_API_URL: https://demo.mifos.community
E2E_USERNAME: mifos
E2E_PASSWORD: password
run: npx playwright test --reporter=html,github --workers=1

- name: Dump Docker logs on failure
if: failure()
run: |
echo "=== Fineract ==="
docker logs e2e-fineract --tail 100 2>&1 || true
echo "=== PostgreSQL ==="
docker logs e2e-postgres --tail 50 2>&1 || true
echo "=== Web-App ==="
docker logs e2e-web-app --tail 50 2>&1 || true
echo "=== Memory ==="
docker stats --no-stream || true

- name: Upload Playwright report
uses: actions/upload-artifact@v7
Expand All @@ -51,3 +116,9 @@ jobs:
name: test-results
path: test-results/
retention-days: 7

- name: Tear down E2E infrastructure
if: always()
run: |
docker compose -f docker-compose.e2e.yml down -v --remove-orphans
docker system prune -f
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ src/environments/.env.ts
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ ENV PATH=/usr/src/app/node_modules/.bin:$PATH
ENV PUPPETEER_DOWNLOAD_HOST=$PUPPETEER_DOWNLOAD_HOST_ARG
ENV PUPPETEER_CHROMIUM_REVISION=$PUPPETEER_CHROMIUM_REVISION_ARG
ENV PUPPETEER_SKIP_DOWNLOAD=$PUPPETEER_SKIP_DOWNLOAD_ARG
ENV CYPRESS_INSTALL_BINARY=0
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1

COPY ./ /usr/src/app/

Expand Down
40 changes: 40 additions & 0 deletions config/e2e/fineract.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Fineract E2E Environment — PostgreSQL-only

# ── Spring Profiles ──
SPRING_PROFILES_ACTIVE=test,diagnostics

# ── PostgreSQL Connection (Docker service: "db") ──
FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.postgresql.Driver
FINERACT_HIKARI_JDBC_URL=jdbc:postgresql://db:5432/fineract_tenants
FINERACT_HIKARI_USERNAME=postgres
# Well-known Fineract E2E password — intentionally committed, not a secret.
FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca

# ── Tenant Database ──
FINERACT_DEFAULT_TENANTDB_HOSTNAME=db
FINERACT_DEFAULT_TENANTDB_PORT=5432
FINERACT_DEFAULT_TENANTDB_UID=postgres
FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
FINERACT_DEFAULT_TENANTDB_NAME=fineract_default

# ── SSL & HTTP ──
FINERACT_SERVER_SSL_ENABLED=true
FINERACT_INSECURE_HTTP_CLIENT=true

# ── Node Identity ──
FINERACT_NODE_ID=1

# ── External Events (no ActiveMQ in E2E) ──
FINERACT_EXTERNAL_EVENTS_ENABLED=false

# ── HikariCP Pool (tuned for E2E) ──
FINERACT_HIKARI_MINIMUM_IDLE=3
FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10

# ── Data Seeding ──
# INITIALIZATION_ENABLED is NOT a Fineract server env var (it belongs to
# fineract-e2e-tests-runner's Gradle Cucumber runner). Do not set it here.
#
# Liquibase auto-seeds: Head Office, default tenant config, schema.
# Domain data (products, GL accounts, clients) must be seeded via the
# FineractApiClient fixture in test beforeAll hooks.
25 changes: 25 additions & 0 deletions config/e2e/nginx-e2e.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
server {
listen 80;
server_name _;

root /usr/share/nginx/html;
index index.html;

# ${E2E_PROXY_TARGET} is replaced by envsubst; $host/$scheme etc. are
# safe because NGINX_ENVSUBST_FILTER restricts to ^(FINERACT_|MIFOS_|...).
location /fineract-provider/ {
proxy_pass ${E2E_PROXY_TARGET}/fineract-provider/;
proxy_ssl_verify off;
proxy_connect_timeout 30s;
proxy_read_timeout 120s;
}

location / {
try_files $uri $uri/ /index.html;
}

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
11 changes: 11 additions & 0 deletions config/e2e/postgresql-init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
# Creates the two databases Fineract requires at first boot.
# POSTGRES_USER (postgres) is the default superuser — no CREATE USER needed.
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE DATABASE fineract_tenants;
CREATE DATABASE fineract_default;
EOSQL

echo "✓ E2E databases created: fineract_tenants, fineract_default"
95 changes: 95 additions & 0 deletions docker-compose.e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
services:
db:
image: postgres:18.3-alpine
container_name: e2e-postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: skdcnwauicn2ucnaecasdsajdnizucawencascdca
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./config/e2e/postgresql-init.sh:/docker-entrypoint-initdb.d/01-init.sh:ro
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 5s
timeout: 5s
retries: 10
ports:
- '5432:5432'
mem_limit: 768m
shm_size: 256m
tmpfs:
- /var/lib/postgresql/data
command: >
postgres
-c shared_buffers=128MB
-c work_mem=4MB
-c maintenance_work_mem=64MB

fineract:
image: apache/fineract:latest
container_name: e2e-fineract
depends_on:
db:
condition: service_healthy
env_file:
- ./config/e2e/fineract.env
environment:
JAVA_TOOL_OPTIONS: >-
-Xmx1536m -Xms512m
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
-Djava.security.egd=file:/dev/./urandom
healthcheck:
test:
[
'CMD-SHELL',
'wget -qO- --no-check-certificate https://localhost:8443/fineract-provider/actuator/health || exit 1'
]
interval: 10s
timeout: 10s
retries: 60
start_period: 120s
ports:
- '8443:8443'
mem_limit: 2g

web-app:
build:
context: .
dockerfile: Dockerfile
args:
PUPPETEER_SKIP_DOWNLOAD_ARG: 'true'
container_name: e2e-web-app
depends_on:
fineract:
condition: service_healthy
environment:
# Nginx proxy target (internal docker DNS)
E2E_PROXY_TARGET: https://fineract:8443

# Angular app configuration (resolved by host browser via proxy)
FINERACT_API_URLS: ''
FINERACT_API_URL: ''

FINERACT_API_PROVIDER: /fineract-provider/api
FINERACT_API_VERSION: /v1
FINERACT_PLATFORM_TENANT_IDENTIFIER: default
MIFOS_DEFAULT_LANGUAGE: en-US
MIFOS_SUPPORTED_LANGUAGES: en-US
MIFOS_PRELOAD_CLIENTS: 'false'
MIFOS_DEFAULT_CHAR_DELIMITER: ','
NGINX_ENVSUBST_FILTER: '^(FINERACT_|MIFOS_|ENABLE_|EXTERNAL_|E2E_PROXY_TARGET)'
volumes:
- ./config/e2e/nginx-e2e.conf.template:/etc/nginx/templates/default.conf.template:ro
ports:
- '4200:80'
mem_limit: 256m
# Override CMD: Dockerfile's /bin/sh CMD causes the nginx entrypoint to
# skip template processing (it checks $1 == "nginx"). Process both
# templates explicitly. Only substitute $E2E_PROXY_TARGET in the nginx
# template so $host, $scheme, $uri etc. are left for nginx.
command: >-
/bin/sh -c "
envsubst '$$E2E_PROXY_TARGET' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf &&
envsubst < /usr/share/nginx/html/assets/env.template.js > /usr/share/nginx/html/assets/env.js &&
nginx -g 'daemon off;'
"
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
"playwright:ui": "playwright test --ui",
"playwright:headed": "playwright test --headed",
"playwright:debug": "playwright test --debug",
"playwright:ci": "playwright test --reporter=html,github --workers=1",
"e2e:docker": "bash scripts/e2e-docker.sh",
"e2e:docker:up": "docker compose -f docker-compose.e2e.yml up -d --build",
"e2e:docker:down": "docker compose -f docker-compose.e2e.yml down -v --remove-orphans",
"e2e:docker:logs": "docker compose -f docker-compose.e2e.yml logs -f",
"headers:check": "node scripts/check-file-headers.js",
"headers:add": "node scripts/add-file-headers.js"
},
Expand Down Expand Up @@ -69,7 +74,7 @@
"jspdf": "^4.2.1",
"jspdf-autotable": "^5.0.2",
"lightgallery": "^2.9.0",
"lodash": "4.17.23",
"lodash": "4.18.1",
"minimatch": "^3.1.4",
"moment": "^2.29.4",
"ngx-mat-select-search": "^8.0.2",
Expand Down
Loading
Loading