This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { createRequire } from 'node:module';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
||||
const e2eTmp = process.env.E2E_TMP;
|
||||
if (!e2eTmp) throw new Error('E2E_TMP must be set by playwright.config.ts');
|
||||
const dbPath = resolve(e2eTmp, 'e2e.db');
|
||||
|
||||
type SeedRepository = {
|
||||
ensureLocalUser: () => void;
|
||||
createUser: (input: Record<string, unknown>) => { id: string };
|
||||
createSpace: (input: Record<string, unknown>) => Promise<{ id: string }>;
|
||||
createLocalTask: (input: Record<string, unknown>) => Promise<{ id: number }>;
|
||||
recordEvent: (input: Record<string, unknown>) => { id: number };
|
||||
createNotificationItem: (input: Record<string, unknown>) => { id: string };
|
||||
createAgentReminder: (input: Record<string, unknown>) => { id: string };
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
const openRepository = (): SeedRepository => {
|
||||
const { Repository } = require(resolve(repoRoot, 'dist/db/repository.js')) as {
|
||||
Repository: new (path: string) => SeedRepository;
|
||||
};
|
||||
const repository = new Repository(dbPath);
|
||||
// The notification_items recipient FK must not depend on the web server
|
||||
// having completed its no-auth bootstrap before this fixture runs.
|
||||
repository.ensureLocalUser();
|
||||
return repository;
|
||||
};
|
||||
|
||||
test('notification bell shows unread inbox and opens the notification center', async ({ page }) => {
|
||||
const title = `E2E未読通知-${Date.now()}`;
|
||||
const repo = openRepository();
|
||||
try {
|
||||
const space = await repo.createSpace({ kind: 'case', title: `E2E通知-${Date.now()}`, ownerId: 'local', visibility: 'private' });
|
||||
const task = await repo.createLocalTask({ title, body: '', ownerId: 'local', spaceId: space.id });
|
||||
const event = repo.recordEvent({
|
||||
eventType: 'task.failed', resourceType: 'task', resourceId: `e2e-${Date.now()}`,
|
||||
result: 'failed', dedupeKey: crypto.randomUUID(), correlationId: crypto.randomUUID(),
|
||||
});
|
||||
repo.createNotificationItem({
|
||||
eventId: event.id, recipientUserId: 'local', category: 'failed', title,
|
||||
summary: 'E2E notification summary', spaceId: space.id,
|
||||
resourceType: 'job', resourceId: `e2e-${event.id}`, occurredAt: new Date().toISOString(),
|
||||
metadata: { localTaskId: task.id },
|
||||
});
|
||||
} finally {
|
||||
repo.close();
|
||||
}
|
||||
|
||||
await page.goto('/ui');
|
||||
const seededInbox = await page.request.get('/api/notifications/inbox?limit=5');
|
||||
expect(seededInbox.ok()).toBeTruthy();
|
||||
expect((await seededInbox.json() as { items: Array<{ title: string }> }).items.map(item => item.title)).toContain(title);
|
||||
const bell = page.getByTestId('notification-bell-trigger');
|
||||
await expect(bell).toBeVisible();
|
||||
await expect(page.getByTestId('notification-bell-badge')).toBeVisible();
|
||||
await bell.click();
|
||||
const panel = page.getByTestId('notification-bell-panel');
|
||||
await expect(panel).toBeVisible();
|
||||
await expect(panel.getByRole('button', { name: new RegExp(title) })).toBeVisible();
|
||||
await panel.getByRole('button', { name: /すべて表示|View all/ }).click();
|
||||
|
||||
await expect(page).toHaveURL(/[?&]page=notifications(&|$)/);
|
||||
await expect(page.getByRole('heading', { name: /通知センター|Notification center/ })).toBeVisible();
|
||||
const row = page.getByRole('button', { name: new RegExp(title) });
|
||||
await expect(row).toBeVisible();
|
||||
await expect(row.getByText(/未読|Unread/)).toBeAttached();
|
||||
await row.click();
|
||||
await expect(page).toHaveURL(/[?&]space=[^&]+.*[?&]chat=\d+/);
|
||||
await expect(page.getByTestId('notification-bell-badge')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('upcoming reminders show only reminders assigned to the current user', async ({ page }) => {
|
||||
const mine = `E2E本人の予定-${Date.now()}`;
|
||||
const other = `E2E他人の予定-${Date.now()}`;
|
||||
const repo = openRepository();
|
||||
try {
|
||||
const otherUser = repo.createUser({
|
||||
email: `other-reminder-${crypto.randomUUID()}@example.test`, name: 'Other reminder owner',
|
||||
role: 'user', status: 'active',
|
||||
});
|
||||
repo.createAgentReminder({ ownerId: 'local', title: mine, body: mine, dueAt: '2099-01-02T03:04:00.000Z', timezoneId: 'UTC' });
|
||||
repo.createAgentReminder({ ownerId: otherUser.id, title: other, body: other, dueAt: '2099-01-02T04:04:00.000Z', timezoneId: 'UTC' });
|
||||
} finally {
|
||||
repo.close();
|
||||
}
|
||||
|
||||
await page.goto('/ui?page=notifications¬ificationTab=upcoming');
|
||||
await expect(page.getByRole('tab', { name: /予定|Upcoming/ })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(page.getByText(mine, { exact: true })).toBeVisible();
|
||||
await expect(page.getByText(other, { exact: true })).toHaveCount(0);
|
||||
|
||||
const response = await page.request.get('/api/notifications/upcoming');
|
||||
expect(response.ok()).toBeTruthy();
|
||||
const body = await response.json() as { items: Array<{ title: string }> };
|
||||
expect(body.items.map(item => item.title)).toContain(mine);
|
||||
expect(body.items.map(item => item.title)).not.toContain(other);
|
||||
});
|
||||
Reference in New Issue
Block a user