diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 2bace40346..ad70912212 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -28,13 +28,13 @@ jobs: - name: Install Playwright browsers run: npx playwright install --with-deps chromium - - name: Build application - run: npm run build - - 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 - name: Upload Playwright report uses: actions/upload-artifact@v7 diff --git a/package-lock.json b/package-lock.json index 1f13a0b54c..fc4926f4bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,8 +83,10 @@ "@vendure/ngx-translate-extract": "^9.4.0", "cypress": "^13.17.0", "eslint": "^9.39.1", + "express": "^5.2.1", "git-describe": "^4.1.1", "htmlhint": "1.9.2", + "http-proxy-middleware": "^3.0.5", "https-proxy-agent": "7.0.6", "husky": "^9.1.7", "jasmine-core": "^4.2.0", @@ -8192,7 +8194,6 @@ "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*" } @@ -13406,8 +13407,7 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", @@ -13993,7 +13993,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=4.0" }, @@ -14915,7 +14914,6 @@ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -14959,7 +14957,6 @@ "integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/http-proxy": "^1.17.15", "debug": "^4.3.6", diff --git a/package.json b/package.json index 870b9d2202..8e3657d62d 100644 --- a/package.json +++ b/package.json @@ -110,8 +110,10 @@ "@vendure/ngx-translate-extract": "^9.4.0", "cypress": "^13.17.0", "eslint": "^9.39.1", + "express": "^5.2.1", "git-describe": "^4.1.1", "htmlhint": "1.9.2", + "http-proxy-middleware": "^3.0.5", "https-proxy-agent": "7.0.6", "husky": "^9.1.7", "jasmine-core": "^4.2.0", diff --git a/playwright.config.ts b/playwright.config.ts index 3c9123f3f1..4336c65b77 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,4 @@ -/** +/** * Copyright since 2025 Mifos Initiative * * This Source Code Form is subject to the terms of the Mozilla Public @@ -88,12 +88,11 @@ export default defineConfig({ ], // Web server configuration - // In CI: builds production bundle (without base-href), then serves it with http-server + // In CI: builds production bundle, then serves it with e2e-server.js + // (Express + http-proxy-middleware for /fineract-provider/* proxy) // Locally: reuses existing ng serve if running webServer: { - command: process.env.CI - ? 'npm run build && npx http-server ./dist/web-app/browser -p 4200 --silent' - : 'npm run start', + command: process.env.CI ? 'npm run build && node playwright/e2e-server.js' : 'npm run start', url: 'http://localhost:4200', reuseExistingServer: !process.env.CI, timeout: 180000, diff --git a/playwright/e2e-server.js b/playwright/e2e-server.js new file mode 100644 index 0000000000..977c844f3f --- /dev/null +++ b/playwright/e2e-server.js @@ -0,0 +1,48 @@ +/** + * Copyright since 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +const express = require('express'); +const { createProxyMiddleware } = require('http-proxy-middleware'); +const path = require('path'); +const fs = require('fs'); + +const FINERACT_API_URL = process.env.FINERACT_API_URL || 'https://demo.mifos.community'; +const PORT = process.env.E2E_PORT || 4200; +const DIST_DIR = path.resolve(__dirname, '..', 'dist', 'web-app', 'browser'); + +if (!fs.existsSync(DIST_DIR)) { + console.error(`Build directory not found: ${DIST_DIR}`); + console.error('Run "npm run build" before starting the E2E server.'); + process.exit(1); +} + +const app = express(); + +// Proxy /fineract-provider/* to the Fineract backend +app.use( + '/fineract-provider', + createProxyMiddleware({ + target: FINERACT_API_URL, + changeOrigin: true, + secure: true, + logger: console + }) +); + +// Serve static files from the Angular build +app.use(express.static(DIST_DIR)); + +// SPA fallback: serve index.html for all non-file routes (Angular hash routing) +app.get('{*path}', (_req, res) => { + res.sendFile(path.join(DIST_DIR, 'index.html')); +}); + +app.listen(PORT, () => { + console.log(`E2E server listening on http://localhost:${PORT}`); + console.log(`Proxying /fineract-provider/* → ${FINERACT_API_URL}`); +}); diff --git a/playwright/tests/login.spec.ts b/playwright/tests/login.spec.ts index c70b2de614..adc25b2022 100644 --- a/playwright/tests/login.spec.ts +++ b/playwright/tests/login.spec.ts @@ -67,9 +67,9 @@ test.describe('Login Page', () => { await expect(loginPage.loginButton).toBeEnabled(); }); - // Skip in CI - requires Fineract backend - test.skip(!!process.env.CI, 'Requires Fineract backend'); test('should successfully login with valid credentials', async () => { + test.skip(!!process.env.CI, 'Production build auth interceptor skips tenant header for absolute URLs'); + // Perform login with valid credentials // This uses the login() method which follows the exact codegen sequence await loginPage.loginAndWaitForDashboard('mifos', 'password'); @@ -98,9 +98,9 @@ test.describe('Login Page', () => { * Simple test that exactly mirrors the codegen script. * This is the baseline test generated from codegen. */ - // Skip in CI - requires Fineract backend - test.skip(!!process.env.CI, 'Requires Fineract backend'); test('codegen baseline: login with mifos credentials', async () => { + test.skip(!!process.env.CI, 'Production build auth interceptor skips tenant header for absolute URLs'); + // This test uses the exact codegen interaction sequence await loginPage.login('mifos', 'password');