Files
awoooi/apps/web/tests/e2e/phase4-timeline.spec.ts
OG T 196d269b92 feat: add all application source code
- apps/api: FastAPI backend with Dockerfile
- apps/web: Next.js frontend with Dockerfile
- apps/sensor: Signal collection agent
- packages: shared packages

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-22 18:57:44 +08:00

108 lines
3.7 KiB
TypeScript

import { test, expect } from '@playwright/test';
/**
* Phase 4: Action Timeline 完整流程驗證
* =====================================
* 模擬: AI 提案 ➡️ DevOps 被拒絕 ➡️ CTO 成功批准
*/
test('Phase 4: Full Action Timeline Demo Flow', async ({ page }) => {
// Set larger viewport
await page.setViewportSize({ width: 1920, height: 1200 });
// Navigate to demo page
await page.goto('http://localhost:3333/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!');
});