Files
awoooi/apps/web/tests/e2e/phase4-timeline.spec.ts
OG T 9bff46a1b0 feat: integrate Sentry + fix CI/CD issues
Sentry Integration (補強 SignOz):
- Add @sentry/nextjs for frontend error tracking + session replay
- Add sentry-sdk[fastapi] for backend error tracking
- Create sentry.client/server/edge.config.ts
- Integrate with next.config.js + instrumentation.ts
- Add Sentry exception capture in FastAPI error handler
- Create deployment scripts for Self-Hosted @ 192.168.0.110

CI/CD Fixes:
- Fix F821 Undefined name 'Field' in incidents.py
- Add NEXT_PUBLIC_API_URL env var to CI build step
- Add build-arg to Docker build verification

E2E Test Improvements:
- Fix strict mode violations in dashboard-acceptance tests
- Add timeout increase for Phase 4 demo tests
- Make tests more resilient to UI variations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-24 15:19:52 +08:00

110 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect } from '@playwright/test';
/**
* Phase 4: Action Timeline 完整流程驗證
* =====================================
* 模擬: AI 提案 ➡️ DevOps 被拒絕 ➡️ CTO 成功批准
*/
test('Phase 4: Full Action Timeline Demo Flow', async ({ page }) => {
// 增加超時到 60 秒 (互動式 demo 需要更長時間)
test.setTimeout(60000)
// Set larger viewport
await page.setViewportSize({ width: 1920, height: 1200 });
// Navigate to demo page (使用相對路徑baseURL 由 playwright.config.ts 控制)
await page.goto('/zh-TW/demo');
await page.waitForTimeout(4000);
// Screenshot 1: Initial state
await page.screenshot({ path: 'test-results/phase4-01-initial.png', fullPage: true });
// Step 1: Trigger a CRITICAL alert (AI Decision) - use Chinese text
console.log('Step 1: Triggering CRITICAL alert...');
// The button says "+ 嚴重" in Chinese
const criticalButton = page.locator('button:has-text("嚴重")').first();
await criticalButton.click({ timeout: 5000 });
await page.waitForTimeout(4000); // Wait for AI thinking animation
// Screenshot 2: After AI decision
await page.evaluate(() => window.scrollTo(0, 400));
await page.waitForTimeout(500);
await page.screenshot({ path: 'test-results/phase4-02-ai-decision.png' });
// Scroll to see approval cards
await page.evaluate(() => window.scrollTo(0, 500));
await page.waitForTimeout(1000);
// Screenshot 3: Approval cards visible
await page.screenshot({ path: 'test-results/phase4-03-approval-cards.png' });
// Step 2: Try to approve as DevOps (should be denied)
console.log('Step 2: DevOps attempting to sign CRITICAL...');
// Look for the hold-to-approve button
const approveButton = page.locator('button:has-text("長按批准")').first();
// Try to click and hold
if (await approveButton.isVisible()) {
const box = await approveButton.boundingBox();
if (box) {
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
await page.mouse.down();
await page.waitForTimeout(2500); // Hold for 2.5 seconds
await page.mouse.up();
}
}
await page.waitForTimeout(500);
// Screenshot 4: Access Denied modal (should be visible)
await page.screenshot({ path: 'test-results/phase4-04-access-denied.png' });
// Close the modal if visible
const closeButton = page.locator('button:has-text("了解,返回")');
if (await closeButton.isVisible()) {
await closeButton.click();
await page.waitForTimeout(500);
}
// Step 3: Switch to CTO role
console.log('Step 3: Switching to CTO role...');
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(500);
const ctoButton = page.locator('button:has-text("CTO")');
await ctoButton.click();
await page.waitForTimeout(500);
// Screenshot 5: Role switched to CTO
await page.screenshot({ path: 'test-results/phase4-05-cto-role.png' });
// Scroll back to approval cards
await page.evaluate(() => window.scrollTo(0, 500));
await page.waitForTimeout(500);
// Step 4: CTO approves (should succeed)
console.log('Step 4: CTO signing CRITICAL...');
const approveButtonCTO = page.locator('button:has-text("長按批准")').first();
if (await approveButtonCTO.isVisible()) {
const box = await approveButtonCTO.boundingBox();
if (box) {
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
await page.mouse.down();
await page.waitForTimeout(2500);
await page.mouse.up();
}
}
await page.waitForTimeout(1000);
// Screenshot 6: After CTO signature
await page.screenshot({ path: 'test-results/phase4-06-cto-signed.png' });
// Final screenshot with full page showing timeline
await page.screenshot({ path: 'test-results/phase4-07-final.png', fullPage: true });
console.log('Phase 4 demo flow completed!');
});