- 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>
108 lines
3.7 KiB
TypeScript
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!');
|
|
});
|