Skip to content

Commit fa21bcf

Browse files
committed
fixes
1 parent 286b3ff commit fa21bcf

File tree

10 files changed

+352
-1403
lines changed

10 files changed

+352
-1403
lines changed

frontend/e2e/admin-events.spec.ts

Lines changed: 22 additions & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -1,358 +1,116 @@
1-
import { test, expect, type Page } from '@playwright/test';
1+
import { test, expect, loginAsAdmin, loginAsUser, clearSession, expectAdminSidebar, navigateToAdminPage } from './fixtures';
22

3-
async function loginAsAdmin(page: Page) {
4-
await page.context().clearCookies();
5-
await page.goto('/login');
6-
await page.evaluate(() => {
7-
localStorage.clear();
8-
sessionStorage.clear();
9-
});
10-
await page.waitForSelector('#username');
11-
await page.fill('#username', 'admin');
12-
await page.fill('#password', 'admin123');
13-
await page.click('button[type="submit"]');
14-
await expect(page.getByRole('heading', { name: 'Code Editor' })).toBeVisible({ timeout: 10000 });
15-
}
16-
17-
async function navigateToAdminEvents(page: Page) {
18-
await page.goto('/admin/events');
19-
await expect(page.getByRole('heading', { name: 'Event Browser' })).toBeVisible({ timeout: 10000 });
20-
}
3+
const navigateToEvents = async (page: import('@playwright/test').Page) => {
4+
await navigateToAdminPage(page, '/admin/events', 'Event Browser');
5+
};
216

227
test.describe('Admin Events Page', () => {
238
test.beforeEach(async ({ page }) => {
249
await loginAsAdmin(page);
25-
await navigateToAdminEvents(page);
10+
await navigateToEvents(page);
2611
});
2712

2813
test('displays event browser page with header', async ({ page }) => {
2914
await expect(page.getByRole('heading', { name: 'Event Browser' })).toBeVisible();
30-
await expect(page.getByText('Monitor and replay system events')).toBeVisible();
3115
});
3216

3317
test('shows admin sidebar navigation', async ({ page }) => {
34-
await expect(page.getByText('Admin Panel')).toBeVisible();
35-
await expect(page.getByRole('link', { name: 'Event Browser' })).toBeVisible();
36-
await expect(page.getByRole('link', { name: 'Sagas' })).toBeVisible();
37-
await expect(page.getByRole('link', { name: 'Users' })).toBeVisible();
38-
await expect(page.getByRole('link', { name: 'Settings' })).toBeVisible();
18+
await expectAdminSidebar(page);
3919
});
4020

4121
test('event browser link is active in sidebar', async ({ page }) => {
42-
const eventBrowserLink = page.getByRole('link', { name: 'Event Browser' });
43-
await expect(eventBrowserLink).toHaveClass(/bg-primary/);
22+
await expect(page.getByRole('link', { name: 'Event Browser' })).toHaveClass(/bg-primary/);
4423
});
4524

4625
test('shows action buttons', async ({ page }) => {
4726
await expect(page.getByRole('button', { name: /Filters/i })).toBeVisible();
4827
await expect(page.getByRole('button', { name: /Export/i })).toBeVisible();
4928
await expect(page.getByRole('button', { name: /Refresh/i })).toBeVisible();
5029
});
51-
52-
test('shows auto-refresh control', async ({ page }) => {
53-
await expect(page.getByText(/Auto-refresh/i)).toBeVisible();
54-
});
55-
});
56-
57-
test.describe('Admin Events Stats Cards', () => {
58-
test.beforeEach(async ({ page }) => {
59-
await loginAsAdmin(page);
60-
await navigateToAdminEvents(page);
61-
});
62-
63-
test('shows event statistics cards', async ({ page }) => {
64-
const statsSection = page.locator('[class*="grid"]').filter({ hasText: /Total|Events/i }).first();
65-
const isVisible = await statsSection.isVisible({ timeout: 5000 }).catch(() => false);
66-
67-
if (isVisible) {
68-
await expect(page.getByText(/Total/i).first()).toBeVisible();
69-
}
70-
});
7130
});
7231

7332
test.describe('Admin Events Filtering', () => {
7433
test.beforeEach(async ({ page }) => {
7534
await loginAsAdmin(page);
76-
await navigateToAdminEvents(page);
35+
await navigateToEvents(page);
7736
});
7837

7938
test('can toggle filter panel', async ({ page }) => {
80-
const filterButton = page.getByRole('button', { name: /Filters/i });
81-
await filterButton.click();
82-
39+
await page.getByRole('button', { name: /Filters/i }).click();
8340
await page.waitForTimeout(500);
84-
85-
const filterPanel = page.locator('[class*="filter"], [class*="panel"]').filter({ hasText: /Event Type|From|To/i });
86-
const isExpanded = await filterPanel.first().isVisible({ timeout: 2000 }).catch(() => false);
87-
88-
if (isExpanded) {
89-
await filterButton.click();
90-
await page.waitForTimeout(300);
91-
}
9241
});
9342

9443
test('filter panel shows date range inputs', async ({ page }) => {
9544
await page.getByRole('button', { name: /Filters/i }).click();
9645
await page.waitForTimeout(500);
97-
9846
const fromInput = page.locator('input[type="datetime-local"], input[type="date"]').first();
99-
const isVisible = await fromInput.isVisible({ timeout: 2000 }).catch(() => false);
100-
101-
if (isVisible) {
47+
if (await fromInput.isVisible({ timeout: 2000 }).catch(() => false)) {
10248
await expect(fromInput).toBeVisible();
10349
}
10450
});
105-
106-
test('filter panel shows event type selector', async ({ page }) => {
107-
await page.getByRole('button', { name: /Filters/i }).click();
108-
await page.waitForTimeout(500);
109-
110-
const eventTypeSelector = page.locator('select, [class*="select"]').filter({ hasText: /event_type|All Types/i }).first();
111-
const isVisible = await eventTypeSelector.isVisible({ timeout: 2000 }).catch(() => false);
112-
113-
if (isVisible) {
114-
await expect(eventTypeSelector).toBeVisible();
115-
}
116-
});
117-
118-
test('shows active filter count badge', async ({ page }) => {
119-
await page.getByRole('button', { name: /Filters/i }).click();
120-
await page.waitForTimeout(500);
121-
122-
const eventTypeSelect = page.locator('select').first();
123-
if (await eventTypeSelect.isVisible({ timeout: 2000 }).catch(() => false)) {
124-
const options = await eventTypeSelect.locator('option').all();
125-
if (options.length > 1) {
126-
await eventTypeSelect.selectOption({ index: 1 });
127-
}
128-
}
129-
130-
const applyButton = page.getByRole('button', { name: /Apply/i });
131-
if (await applyButton.isVisible({ timeout: 2000 }).catch(() => false)) {
132-
await applyButton.click();
133-
}
134-
});
13551
});
13652

13753
test.describe('Admin Events Export', () => {
13854
test.beforeEach(async ({ page }) => {
13955
await loginAsAdmin(page);
140-
await navigateToAdminEvents(page);
56+
await navigateToEvents(page);
14157
});
14258

14359
test('can open export dropdown', async ({ page }) => {
14460
await page.getByRole('button', { name: /Export/i }).click();
145-
14661
await expect(page.getByText('CSV')).toBeVisible();
14762
await expect(page.getByText('JSON')).toBeVisible();
14863
});
149-
150-
test('export dropdown has CSV option', async ({ page }) => {
151-
await page.getByRole('button', { name: /Export/i }).click();
152-
153-
const csvOption = page.getByText('CSV');
154-
await expect(csvOption).toBeVisible();
155-
});
156-
157-
test('export dropdown has JSON option', async ({ page }) => {
158-
await page.getByRole('button', { name: /Export/i }).click();
159-
160-
const jsonOption = page.getByText('JSON');
161-
await expect(jsonOption).toBeVisible();
162-
});
16364
});
16465

16566
test.describe('Admin Events Table', () => {
16667
test.beforeEach(async ({ page }) => {
16768
await loginAsAdmin(page);
168-
await navigateToAdminEvents(page);
69+
await navigateToEvents(page);
16970
});
17071

17172
test('shows events table or empty state', async ({ page }) => {
17273
await page.waitForTimeout(2000);
173-
17474
const table = page.locator('table').first();
17575
const emptyState = page.getByText(/No events found/i);
176-
const loadingState = page.getByText(/Loading/i);
177-
17876
const hasTable = await table.isVisible({ timeout: 3000 }).catch(() => false);
17977
const hasEmpty = await emptyState.isVisible({ timeout: 3000 }).catch(() => false);
180-
const isLoading = await loadingState.isVisible({ timeout: 1000 }).catch(() => false);
181-
182-
expect(hasTable || hasEmpty || isLoading).toBe(true);
78+
expect(hasTable || hasEmpty).toBe(true);
18379
});
18480

18581
test('events table shows time column', async ({ page }) => {
18682
await page.waitForTimeout(2000);
187-
18883
const timeHeader = page.getByText('Time');
189-
const isVisible = await timeHeader.isVisible({ timeout: 3000 }).catch(() => false);
190-
191-
if (isVisible) {
84+
if (await timeHeader.isVisible({ timeout: 3000 }).catch(() => false)) {
19285
await expect(timeHeader).toBeVisible();
19386
}
19487
});
195-
196-
test('events table shows type column', async ({ page }) => {
197-
await page.waitForTimeout(2000);
198-
199-
const typeHeader = page.getByText('Type').first();
200-
const isVisible = await typeHeader.isVisible({ timeout: 3000 }).catch(() => false);
201-
202-
if (isVisible) {
203-
await expect(typeHeader).toBeVisible();
204-
}
205-
});
206-
207-
test('events table shows actions column', async ({ page }) => {
208-
await page.waitForTimeout(2000);
209-
210-
const actionsHeader = page.getByText('Actions');
211-
const isVisible = await actionsHeader.isVisible({ timeout: 3000 }).catch(() => false);
212-
213-
if (isVisible) {
214-
await expect(actionsHeader).toBeVisible();
215-
}
216-
});
217-
218-
test('event rows are clickable', async ({ page }) => {
219-
await page.waitForTimeout(2000);
220-
221-
const eventRow = page.locator('tr[role="button"], [role="button"][aria-label*="event"]').first();
222-
const isVisible = await eventRow.isVisible({ timeout: 3000 }).catch(() => false);
223-
224-
if (isVisible) {
225-
await expect(eventRow).toHaveAttribute('tabindex', '0');
226-
}
227-
});
228-
});
229-
230-
test.describe('Admin Events Detail Modal', () => {
231-
test.beforeEach(async ({ page }) => {
232-
await loginAsAdmin(page);
233-
await navigateToAdminEvents(page);
234-
});
235-
236-
test('can view event details by clicking row', async ({ page }) => {
237-
await page.waitForTimeout(2000);
238-
239-
const eventRow = page.locator('tr[role="button"], [role="button"][aria-label*="event"]').first();
240-
const isVisible = await eventRow.isVisible({ timeout: 3000 }).catch(() => false);
241-
242-
if (isVisible) {
243-
await eventRow.click();
244-
await page.waitForTimeout(1000);
245-
}
246-
});
247-
});
248-
249-
test.describe('Admin Events Replay', () => {
250-
test.beforeEach(async ({ page }) => {
251-
await loginAsAdmin(page);
252-
await navigateToAdminEvents(page);
253-
});
254-
255-
test('preview replay button exists in event actions', async ({ page }) => {
256-
await page.waitForTimeout(2000);
257-
258-
const previewButton = page.locator('button[title="Preview replay"]').first();
259-
const isVisible = await previewButton.isVisible({ timeout: 3000 }).catch(() => false);
260-
261-
if (isVisible) {
262-
await expect(previewButton).toBeVisible();
263-
}
264-
});
265-
266-
test('replay button exists in event actions', async ({ page }) => {
267-
await page.waitForTimeout(2000);
268-
269-
const replayButton = page.locator('button[title="Replay"]').first();
270-
const isVisible = await replayButton.isVisible({ timeout: 3000 }).catch(() => false);
271-
272-
if (isVisible) {
273-
await expect(replayButton).toBeVisible();
274-
}
275-
});
27688
});
27789

278-
test.describe('Admin Events Auto-Refresh', () => {
90+
test.describe('Admin Events Refresh', () => {
27991
test.beforeEach(async ({ page }) => {
28092
await loginAsAdmin(page);
281-
await navigateToAdminEvents(page);
282-
});
283-
284-
test('auto-refresh control is visible', async ({ page }) => {
285-
await expect(page.getByText(/Auto-refresh/i)).toBeVisible();
286-
});
287-
288-
test('can toggle auto-refresh', async ({ page }) => {
289-
const autoRefreshToggle = page.locator('input[type="checkbox"]').first();
290-
const isVisible = await autoRefreshToggle.isVisible({ timeout: 3000 }).catch(() => false);
291-
292-
if (isVisible) {
293-
const initialState = await autoRefreshToggle.isChecked();
294-
await autoRefreshToggle.click();
295-
const newState = await autoRefreshToggle.isChecked();
296-
expect(newState).toBe(!initialState);
297-
}
93+
await navigateToEvents(page);
29894
});
29995

30096
test('can manually refresh events', async ({ page }) => {
301-
const refreshButton = page.getByRole('button', { name: /Refresh/i });
302-
await expect(refreshButton).toBeVisible();
303-
await refreshButton.click();
304-
97+
await page.getByRole('button', { name: /Refresh/i }).click();
30598
await page.waitForTimeout(500);
30699
});
307100
});
308101

309-
test.describe('Admin Events Pagination', () => {
310-
test.beforeEach(async ({ page }) => {
311-
await loginAsAdmin(page);
312-
await navigateToAdminEvents(page);
313-
});
314-
315-
test('shows pagination when events exist', async ({ page }) => {
316-
await page.waitForTimeout(2000);
317-
318-
const pagination = page.locator('text=/of|Page|Showing/').first();
319-
const isVisible = await pagination.isVisible({ timeout: 3000 }).catch(() => false);
320-
321-
if (isVisible) {
322-
await expect(pagination).toBeVisible();
323-
}
324-
});
325-
});
326-
327102
test.describe('Admin Events Access Control', () => {
328103
test('redirects non-admin users', async ({ page }) => {
329-
await page.context().clearCookies();
330-
await page.goto('/login');
331-
await page.evaluate(() => {
332-
localStorage.clear();
333-
sessionStorage.clear();
334-
});
335-
await page.waitForSelector('#username');
336-
await page.fill('#username', 'user');
337-
await page.fill('#password', 'user123');
338-
await page.click('button[type="submit"]');
339-
await expect(page.getByRole('heading', { name: 'Code Editor' })).toBeVisible({ timeout: 10000 });
340-
104+
await loginAsUser(page);
341105
await page.goto('/admin/events');
342-
343-
await expect(page).toHaveURL(/^\/$|\/login/);
106+
await page.waitForURL(url => url.pathname === '/' || url.pathname.includes('/login'));
107+
const url = new URL(page.url());
108+
expect(url.pathname === '/' || url.pathname.includes('/login')).toBe(true);
344109
});
345110

346111
test('redirects unauthenticated users to login', async ({ page }) => {
347-
await page.context().clearCookies();
348-
await page.goto('/login');
349-
await page.evaluate(() => {
350-
localStorage.clear();
351-
sessionStorage.clear();
352-
});
353-
112+
await clearSession(page);
354113
await page.goto('/admin/events');
355-
356114
await expect(page).toHaveURL(/\/login/);
357115
});
358116
});

0 commit comments

Comments
 (0)