Some checks are pending
Go Benchmark / Performance Regression Check (push) Waiting to run
Cerberus Integration / Cerberus Security Stack Integration (push) Waiting to run
Upload Coverage to Codecov / Backend Codecov Upload (push) Waiting to run
Upload Coverage to Codecov / Frontend Codecov Upload (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (go) (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Waiting to run
CrowdSec Integration / CrowdSec Bouncer Integration (push) Waiting to run
Docker Build, Publish & Test / build-and-push (push) Waiting to run
Docker Build, Publish & Test / Security Scan PR Image (push) Blocked by required conditions
Quality Checks / Auth Route Protection Contract (push) Waiting to run
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Waiting to run
Quality Checks / Backend (Go) (push) Waiting to run
Quality Checks / Frontend (React) (push) Waiting to run
Rate Limit integration / Rate Limiting Integration (push) Waiting to run
Security Scan (PR) / Trivy Binary Scan (push) Waiting to run
Supply Chain Verification (PR) / Verify Supply Chain (push) Waiting to run
WAF integration / Coraza WAF Integration (push) Waiting to run
418 lines
13 KiB
TypeScript
Executable File
418 lines
13 KiB
TypeScript
Executable File
/**
|
|
* Multi-Feature Workflows E2E Tests
|
|
*
|
|
* Tests for complex workflows that span multiple features,
|
|
* testing real-world usage scenarios and feature interactions.
|
|
*
|
|
* Test Categories (11-14 tests):
|
|
* - Group A: Complete Host Setup Workflow (5 tests)
|
|
* - Group C: Certificate + DNS Workflow (4 tests)
|
|
* - Group D: Admin Management Workflow (5 tests)
|
|
*
|
|
* These tests verify end-to-end user journeys across features.
|
|
*/
|
|
|
|
import { test, expect, loginUser, TEST_PASSWORD } from '../fixtures/auth-fixtures';
|
|
import { generateProxyHost } from '../fixtures/proxy-hosts';
|
|
import { generateAccessList, generateAllowListForIPs } from '../fixtures/access-lists';
|
|
import { generateCertificate } from '../fixtures/certificates';
|
|
import { generateDnsProvider } from '../fixtures/dns-providers';
|
|
import {
|
|
waitForToast,
|
|
waitForLoadingComplete,
|
|
waitForAPIResponse,
|
|
waitForModal,
|
|
clickAndWaitForResponse,
|
|
waitForResourceInUI,
|
|
} from '../utils/wait-helpers';
|
|
|
|
/**
|
|
* Selectors for multi-feature workflows
|
|
*/
|
|
const SELECTORS = {
|
|
// Navigation
|
|
sideNav: '[data-testid="sidebar"], nav, .sidebar',
|
|
proxyHostsLink: 'a[href*="proxy-hosts"], button:has-text("Proxy Hosts")',
|
|
accessListsLink: 'a[href*="access-lists"], button:has-text("Access Lists")',
|
|
certificatesLink: 'a[href*="certificates"], button:has-text("Certificates")',
|
|
dnsProvidersLink: 'a[href*="dns"], button:has-text("DNS")',
|
|
securityLink: 'a[href*="security"], button:has-text("Security")',
|
|
settingsLink: 'a[href*="settings"], button:has-text("Settings")',
|
|
|
|
// Common Actions
|
|
addButton: 'button:has-text("Add"), button:has-text("Create")',
|
|
saveButton: 'button:has-text("Save"), button[type="submit"]',
|
|
deleteButton: 'button:has-text("Delete")',
|
|
editButton: 'button:has-text("Edit")',
|
|
cancelButton: 'button:has-text("Cancel")',
|
|
|
|
// Status Indicators
|
|
activeStatus: '.badge:has-text("Active"), [data-testid="status-active"]',
|
|
errorStatus: '.badge:has-text("Error"), [data-testid="status-error"]',
|
|
pendingStatus: '.badge:has-text("Pending"), [data-testid="status-pending"]',
|
|
|
|
// Common Elements
|
|
table: 'table, [data-testid="data-table"]',
|
|
modal: '.modal, [data-testid="modal"], [role="dialog"]',
|
|
toast: '[data-testid="toast"], .toast, [role="alert"]',
|
|
loadingSpinner: '[data-testid="loading"], .loading, .spinner',
|
|
};
|
|
|
|
async function navigateToDnsProviders(page: import('@playwright/test').Page): Promise<void> {
|
|
const providersResponse = waitForAPIResponse(page, /\/api\/v1\/dns-providers/);
|
|
await page.goto('/dns/providers');
|
|
await providersResponse;
|
|
await waitForLoadingComplete(page);
|
|
}
|
|
|
|
async function navigateToCertificates(page: import('@playwright/test').Page): Promise<void> {
|
|
const certsResponse = waitForAPIResponse(page, /\/api\/v1\/certificates/);
|
|
await page.goto('/certificates');
|
|
await certsResponse;
|
|
await waitForLoadingComplete(page);
|
|
}
|
|
|
|
test.describe('Multi-Feature Workflows E2E', () => {
|
|
// ===========================================================================
|
|
// Group A: Complete Host Setup Workflow (5 tests)
|
|
// ===========================================================================
|
|
test.describe('Group A: Complete Host Setup Workflow', () => {
|
|
test('should complete full proxy host setup with all features', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Step 1: Create access list for the host', async () => {
|
|
const acl = generateAllowListForIPs(['192.168.1.0/24']);
|
|
await testData.createAccessList(acl);
|
|
|
|
await page.goto('/access-lists');
|
|
await waitForResourceInUI(page, acl.name);
|
|
});
|
|
|
|
await test.step('Step 2: Create proxy host', async () => {
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
await page.goto('/proxy-hosts');
|
|
await waitForResourceInUI(page, proxy.domain);
|
|
});
|
|
|
|
await test.step('Step 3: Verify dashboard shows the host', async () => {
|
|
await page.goto('/');
|
|
await waitForLoadingComplete(page);
|
|
const content = page.locator('main, .content, h1').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should create proxy host with SSL certificate', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Create proxy host', async () => {
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
await page.goto('/proxy-hosts');
|
|
await waitForResourceInUI(page, proxy.domain);
|
|
});
|
|
|
|
await test.step('Navigate to certificates', async () => {
|
|
await page.goto('/certificates');
|
|
await waitForLoadingComplete(page);
|
|
const content = page.locator('main, .content').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should create proxy host with access restrictions', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Create access list', async () => {
|
|
const acl = generateAccessList();
|
|
await testData.createAccessList(acl);
|
|
|
|
await page.goto('/access-lists');
|
|
await waitForResourceInUI(page, acl.name);
|
|
});
|
|
|
|
await test.step('Create proxy host', async () => {
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
await page.goto('/proxy-hosts');
|
|
await waitForResourceInUI(page, proxy.domain);
|
|
});
|
|
});
|
|
|
|
test('should update proxy host configuration end-to-end', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
await test.step('Navigate to proxy hosts', async () => {
|
|
await page.goto('/proxy-hosts');
|
|
await waitForResourceInUI(page, proxy.domain);
|
|
});
|
|
|
|
await test.step('Verify proxy host is editable', async () => {
|
|
const row = page.getByText(proxy.domain).locator('..').first();
|
|
await expect(row).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should delete proxy host and verify cleanup', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
await test.step('Verify proxy host exists', async () => {
|
|
await page.goto('/proxy-hosts');
|
|
await waitForResourceInUI(page, proxy.domain);
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// ===========================================================================
|
|
// Group C: Certificate + DNS Workflow (4 tests)
|
|
// ===========================================================================
|
|
test.describe('Group C: Certificate + DNS Workflow', () => {
|
|
test('should setup DNS provider for certificate validation', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
const dnsProvider = generateDnsProvider();
|
|
|
|
await test.step('Create DNS provider', async () => {
|
|
await testData.createDNSProvider({
|
|
name: dnsProvider.name,
|
|
providerType: dnsProvider.provider_type,
|
|
credentials: dnsProvider.credentials,
|
|
});
|
|
});
|
|
|
|
await test.step('Verify DNS provider appears in list', async () => {
|
|
await navigateToDnsProviders(page);
|
|
await waitForResourceInUI(page, dnsProvider.name);
|
|
});
|
|
});
|
|
|
|
test('should request certificate with DNS challenge', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
const dnsProvider = generateDnsProvider();
|
|
|
|
await test.step('Create DNS provider first', async () => {
|
|
await testData.createDNSProvider({
|
|
name: dnsProvider.name,
|
|
providerType: dnsProvider.provider_type,
|
|
credentials: dnsProvider.credentials,
|
|
});
|
|
});
|
|
|
|
await test.step('Confirm DNS provider is available', async () => {
|
|
await navigateToDnsProviders(page);
|
|
await waitForResourceInUI(page, dnsProvider.name);
|
|
});
|
|
|
|
await test.step('Navigate to certificates', async () => {
|
|
await navigateToCertificates(page);
|
|
await expect(page.getByRole('main')).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should apply certificate to proxy host', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Create proxy host', async () => {
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
const proxiesResponse = waitForAPIResponse(page, /\/api\/v1\/proxy-hosts/);
|
|
await page.goto('/proxy-hosts');
|
|
await proxiesResponse;
|
|
await waitForLoadingComplete(page);
|
|
await waitForResourceInUI(page, proxy.domain);
|
|
});
|
|
|
|
await test.step('Navigate to certificates', async () => {
|
|
await navigateToCertificates(page);
|
|
await expect(page.getByRole('main')).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should verify certificate renewal workflow', async ({
|
|
page,
|
|
adminUser,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Navigate to certificates', async () => {
|
|
await navigateToCertificates(page);
|
|
});
|
|
|
|
await test.step('Verify certificate management page', async () => {
|
|
await expect(page.getByRole('main')).toBeVisible();
|
|
});
|
|
});
|
|
});
|
|
|
|
// ===========================================================================
|
|
// Group D: Admin Management Workflow (5 tests)
|
|
// ===========================================================================
|
|
test.describe('Group D: Admin Management Workflow', () => {
|
|
test('should complete user management workflow', async ({
|
|
page,
|
|
adminUser,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Navigate to user management', async () => {
|
|
await page.goto('/settings/account-management');
|
|
await waitForLoadingComplete(page);
|
|
});
|
|
|
|
await test.step('Verify user management page', async () => {
|
|
const content = page.locator('main, .content, table').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should configure system settings', async ({
|
|
page,
|
|
adminUser,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Navigate to settings', async () => {
|
|
await page.goto('/settings');
|
|
await waitForLoadingComplete(page);
|
|
});
|
|
|
|
await test.step('Verify settings page', async () => {
|
|
const content = page.locator('main, .content').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should view audit logs for all operations', async ({
|
|
page,
|
|
adminUser,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Navigate to security dashboard', async () => {
|
|
await page.goto('/security');
|
|
await waitForLoadingComplete(page);
|
|
});
|
|
|
|
await test.step('Verify security page', async () => {
|
|
const content = page.locator('main, table, .content').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should perform system health check', async ({
|
|
page,
|
|
adminUser,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
await test.step('Navigate to dashboard', async () => {
|
|
await page.goto('/dashboard');
|
|
await waitForLoadingComplete(page);
|
|
});
|
|
|
|
await test.step('Verify dashboard loads', async () => {
|
|
await page.goto('/');
|
|
await waitForLoadingComplete(page);
|
|
const content = page.locator('main, .content, h1').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('should complete backup before major changes', async ({
|
|
page,
|
|
adminUser,
|
|
testData,
|
|
}) => {
|
|
await loginUser(page, adminUser);
|
|
|
|
// Create some data first
|
|
const proxyInput = generateProxyHost();
|
|
const proxy = await testData.createProxyHost({
|
|
domain: proxyInput.domain,
|
|
forwardHost: proxyInput.forwardHost,
|
|
forwardPort: proxyInput.forwardPort,
|
|
});
|
|
|
|
await test.step('Navigate to backups', async () => {
|
|
await page.goto('/tasks/backups');
|
|
await waitForLoadingComplete(page);
|
|
});
|
|
|
|
await test.step('Verify backup page loads', async () => {
|
|
const content = page.locator('main, .content').first();
|
|
await expect(content).toBeVisible();
|
|
});
|
|
});
|
|
});
|
|
});
|