import { test, expect } from './fixtures/auth.fixture'; import { navigateAndWait, assertPageHasContent } from './helpers/nav.helper'; /** * E2E tests for the Identity Providers settings page. * * These tests use the auth fixture which mocks the backend API. * The MockIdentityProviderClient in app.config.ts serves mock data, * so these tests verify UI rendering and interaction without a live backend. */ const sampleLdapProvider = { id: 'e2e-ldap-id', name: 'E2E LDAP', type: 'ldap', enabled: true, configuration: { host: 'ldap.e2e.test', port: '389', bindDn: 'cn=admin,dc=e2e,dc=test', bindPassword: 'secret', searchBase: 'dc=e2e,dc=test', }, description: 'E2E LDAP test provider', healthStatus: 'healthy', createdAt: '2026-02-24T00:00:00Z', updatedAt: '2026-02-24T00:00:00Z', createdBy: 'e2e-admin', updatedBy: 'e2e-admin', }; const sampleSamlProvider = { id: 'e2e-saml-id', name: 'E2E SAML', type: 'saml', enabled: true, configuration: { spEntityId: 'stellaops-e2e-sp', idpEntityId: 'https://idp.e2e.test', idpSsoUrl: 'https://idp.e2e.test/sso', }, description: 'E2E SAML test provider', healthStatus: 'healthy', createdAt: '2026-02-24T00:00:00Z', updatedAt: '2026-02-24T00:00:00Z', createdBy: 'e2e-admin', updatedBy: 'e2e-admin', }; const sampleOidcProvider = { id: 'e2e-oidc-id', name: 'E2E OIDC', type: 'oidc', enabled: false, configuration: { authority: 'https://oidc.e2e.test', clientId: 'stellaops-e2e', clientSecret: 'e2e-secret', }, description: 'E2E OIDC test provider', healthStatus: 'disabled', createdAt: '2026-02-24T00:00:00Z', updatedAt: '2026-02-24T00:00:00Z', createdBy: 'e2e-admin', updatedBy: 'e2e-admin', }; test.describe('Identity Providers Settings Page', () => { test('should load page and display content', async ({ authenticatedPage: page }) => { const errors: string[] = []; page.on('console', (msg) => { if (msg.type() === 'error' && /NG0\d{3,4}/.test(msg.text())) { errors.push(msg.text()); } }); // Mock the identity providers API await page.route('**/api/v1/platform/identity-providers', (route) => { if (route.request().method() === 'GET') { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([sampleLdapProvider, sampleSamlProvider, sampleOidcProvider]), }); } else { route.continue(); } }); await page.route('**/api/v1/platform/identity-providers/types', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([ { type: 'standard', displayName: 'Standard', requiredFields: [], optionalFields: [] }, { type: 'ldap', displayName: 'LDAP / Active Directory', requiredFields: [ { name: 'host', displayName: 'Host', fieldType: 'text', defaultValue: null, description: null }, { name: 'port', displayName: 'Port', fieldType: 'number', defaultValue: '389', description: null }, { name: 'bindDn', displayName: 'Bind DN', fieldType: 'text', defaultValue: null, description: null }, { name: 'bindPassword', displayName: 'Bind Password', fieldType: 'secret', defaultValue: null, description: null }, { name: 'searchBase', displayName: 'Search Base', fieldType: 'text', defaultValue: null, description: null }, ], optionalFields: [], }, { type: 'saml', displayName: 'SAML 2.0', requiredFields: [ { name: 'spEntityId', displayName: 'SP Entity ID', fieldType: 'text', defaultValue: null, description: null }, { name: 'idpEntityId', displayName: 'IdP Entity ID', fieldType: 'text', defaultValue: null, description: null }, ], optionalFields: [], }, { type: 'oidc', displayName: 'OpenID Connect', requiredFields: [ { name: 'authority', displayName: 'Authority', fieldType: 'url', defaultValue: null, description: null }, { name: 'clientId', displayName: 'Client ID', fieldType: 'text', defaultValue: null, description: null }, ], optionalFields: [], }, ]), }); }); await navigateAndWait(page, '/settings/identity-providers', { timeout: 30_000 }); await page.waitForTimeout(2000); await assertPageHasContent(page); expect(errors).toHaveLength(0); }); test('should show empty state with no providers', async ({ authenticatedPage: page }) => { await page.route('**/api/v1/platform/identity-providers', (route) => { if (route.request().method() === 'GET') { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]), }); } else { route.continue(); } }); await page.route('**/api/v1/platform/identity-providers/types', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]), }); }); await navigateAndWait(page, '/settings/identity-providers', { timeout: 30_000 }); await page.waitForTimeout(2000); const emptyState = page.locator('.idp-empty-state'); if (await emptyState.isVisible({ timeout: 5000 }).catch(() => false)) { await expect(emptyState).toContainText('No identity providers'); } }); test('should display provider cards with correct type badges', async ({ authenticatedPage: page }) => { await page.route('**/api/v1/platform/identity-providers', (route) => { if (route.request().method() === 'GET') { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([sampleLdapProvider, sampleSamlProvider, sampleOidcProvider]), }); } else { route.continue(); } }); await page.route('**/api/v1/platform/identity-providers/types', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]), }); }); await navigateAndWait(page, '/settings/identity-providers', { timeout: 30_000 }); await page.waitForTimeout(2000); // Verify provider names are visible const ldapName = page.locator('text=E2E LDAP').first(); const samlName = page.locator('text=E2E SAML').first(); const oidcName = page.locator('text=E2E OIDC').first(); if (await ldapName.isVisible({ timeout: 5000 }).catch(() => false)) { await expect(ldapName).toBeVisible(); } if (await samlName.isVisible({ timeout: 5000 }).catch(() => false)) { await expect(samlName).toBeVisible(); } if (await oidcName.isVisible({ timeout: 5000 }).catch(() => false)) { await expect(oidcName).toBeVisible(); } }); test('should open add provider wizard on button click', async ({ authenticatedPage: page }) => { await page.route('**/api/v1/platform/identity-providers', (route) => { if (route.request().method() === 'GET') { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]), }); } else { route.continue(); } }); await page.route('**/api/v1/platform/identity-providers/types', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([ { type: 'standard', displayName: 'Standard', requiredFields: [], optionalFields: [] }, { type: 'ldap', displayName: 'LDAP', requiredFields: [], optionalFields: [] }, { type: 'saml', displayName: 'SAML', requiredFields: [], optionalFields: [] }, { type: 'oidc', displayName: 'OIDC', requiredFields: [], optionalFields: [] }, ]), }); }); await navigateAndWait(page, '/settings/identity-providers', { timeout: 30_000 }); await page.waitForTimeout(2000); const addButton = page.locator('button:has-text("Add Provider")').first(); if (await addButton.isVisible({ timeout: 5000 }).catch(() => false)) { await addButton.click(); await page.waitForTimeout(1000); // Wizard should be visible const wizard = page.locator('app-add-provider-wizard, .wizard-overlay').first(); if (await wizard.isVisible({ timeout: 5000 }).catch(() => false)) { await expect(wizard).toBeVisible(); } } }); test('should handle enable/disable toggle', async ({ authenticatedPage: page }) => { await page.route('**/api/v1/platform/identity-providers', (route) => { if (route.request().method() === 'GET') { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([sampleLdapProvider]), }); } else { route.continue(); } }); await page.route('**/api/v1/platform/identity-providers/types', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]), }); }); // Mock disable endpoint await page.route('**/api/v1/platform/identity-providers/*/disable', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ ...sampleLdapProvider, enabled: false, healthStatus: 'disabled' }), }); }); await navigateAndWait(page, '/settings/identity-providers', { timeout: 30_000 }); await page.waitForTimeout(2000); // Find disable/enable toggle button const toggleBtn = page.locator('button:has-text("Disable")').first(); if (await toggleBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await toggleBtn.click(); await page.waitForTimeout(1000); } }); test('should handle delete provider', async ({ authenticatedPage: page }) => { await page.route('**/api/v1/platform/identity-providers', (route) => { if (route.request().method() === 'GET') { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([sampleLdapProvider]), }); } else { route.continue(); } }); await page.route('**/api/v1/platform/identity-providers/types', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([]), }); }); // Mock delete endpoint await page.route('**/api/v1/platform/identity-providers/*', (route) => { if (route.request().method() === 'DELETE') { route.fulfill({ status: 204 }); } else { route.continue(); } }); await navigateAndWait(page, '/settings/identity-providers', { timeout: 30_000 }); await page.waitForTimeout(2000); const deleteBtn = page.locator('button:has-text("Delete")').first(); if (await deleteBtn.isVisible({ timeout: 5000 }).catch(() => false)) { await deleteBtn.click(); await page.waitForTimeout(1000); } }); });