- smartauth-login.spec.ts: Google Sign-In button presence, MFA challenge not shown initially - smartauth-mfa-settings.spec.ts: MFA status, setup/disable flows with API mocking - smartauth-security-dashboard.spec.ts: stats cards, login events table, suspicious filter - smartauth-devices.spec.ts: device list, trust badges, revoke all button - smartauth-passkeys.spec.ts: passkey list, add button, empty state, device type labels
131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('SmartAuth: Security Dashboard', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/login');
|
|
await page.evaluate(() => {
|
|
localStorage.setItem('admin_access_token', 'mock-token');
|
|
localStorage.setItem('admin_refresh_token', 'mock-refresh');
|
|
localStorage.setItem(
|
|
'admin_auth_user',
|
|
JSON.stringify({
|
|
email: 'admin@example.com',
|
|
name: 'Admin User',
|
|
role: 'super_admin',
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
test('security dashboard page loads', async ({ page }) => {
|
|
await page.route('**/api/auth/security/overview', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
totalUsers: 42,
|
|
mfaAdoptionPercent: 67,
|
|
providerDistribution: { password: 30, google: 10, microsoft: 2 },
|
|
activeSessions: 15,
|
|
suspiciousEvents24h: 3,
|
|
}),
|
|
});
|
|
});
|
|
await page.route('**/api/auth/login-events**', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify([]),
|
|
});
|
|
});
|
|
await page.goto('/ops/security');
|
|
await expect(page.getByText('Security Dashboard')).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test('shows stats cards with overview data', async ({ page }) => {
|
|
await page.route('**/api/auth/security/overview', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
totalUsers: 42,
|
|
mfaAdoptionPercent: 67,
|
|
providerDistribution: {},
|
|
activeSessions: 15,
|
|
suspiciousEvents24h: 0,
|
|
}),
|
|
});
|
|
});
|
|
await page.route('**/api/auth/login-events**', async route => {
|
|
await route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
|
});
|
|
await page.goto('/ops/security');
|
|
await expect(page.getByText('42')).toBeVisible({ timeout: 10000 });
|
|
await expect(page.getByText('67%')).toBeVisible();
|
|
await expect(page.getByText('15')).toBeVisible();
|
|
});
|
|
|
|
test('shows login events table', async ({ page }) => {
|
|
await page.route('**/api/auth/security/overview', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
totalUsers: 1,
|
|
mfaAdoptionPercent: 0,
|
|
providerDistribution: {},
|
|
activeSessions: 1,
|
|
suspiciousEvents24h: 0,
|
|
}),
|
|
});
|
|
});
|
|
await page.route('**/api/auth/login-events**', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify([
|
|
{
|
|
id: 'evt-1',
|
|
eventType: 'login_success',
|
|
method: 'password',
|
|
ip: '192.168.1.1',
|
|
userAgent: 'Chrome',
|
|
riskScore: 10,
|
|
riskFactors: [],
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
]),
|
|
});
|
|
});
|
|
await page.goto('/ops/security');
|
|
await expect(page.getByText('Recent Login Events')).toBeVisible({ timeout: 10000 });
|
|
await expect(page.getByText('192.168.1.1')).toBeVisible();
|
|
});
|
|
|
|
test('suspicious filter toggle works', async ({ page }) => {
|
|
let requestedUrl = '';
|
|
await page.route('**/api/auth/security/overview', async route => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
totalUsers: 1,
|
|
mfaAdoptionPercent: 0,
|
|
providerDistribution: {},
|
|
activeSessions: 1,
|
|
suspiciousEvents24h: 0,
|
|
}),
|
|
});
|
|
});
|
|
await page.route('**/api/auth/login-events**', async route => {
|
|
requestedUrl = route.request().url();
|
|
await route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
|
});
|
|
await page.goto('/ops/security');
|
|
await page.getByRole('button', { name: /show suspicious/i }).click();
|
|
// Wait for re-fetch
|
|
await page.waitForTimeout(500);
|
|
expect(requestedUrl).toContain('suspicious=true');
|
|
});
|
|
});
|