- purchase.spec.ts: add to cart, checkout, success - chat.spec.ts: load UI, send message (when WebSocket available) - README: document critical flows and prerequisites
137 lines
5.9 KiB
TypeScript
137 lines
5.9 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { TEST_CONFIG, loginAsUser, setupErrorCapture } from '../utils/test-helpers';
|
|
|
|
/**
|
|
* Chat E2E Test Suite (Audit 2.10)
|
|
*
|
|
* Couvre le flow critique du chat :
|
|
* - Load chat page et UI (sidebar, channels, input)
|
|
* - État déconnecté quand WebSocket indisponible
|
|
* - Envoi de message quand WebSocket connecté (skip si non connecté)
|
|
*/
|
|
|
|
test.describe('Chat Flow', () => {
|
|
let consoleErrors: string[] = [];
|
|
let networkErrors: Array<{ url: string; status: number; method: string }> = [];
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
const errorCapture = setupErrorCapture(page);
|
|
consoleErrors = errorCapture.consoleErrors;
|
|
networkErrors = errorCapture.networkErrors;
|
|
});
|
|
|
|
test('should load chat page and show UI', async ({ page }) => {
|
|
console.log('🧪 [CHAT] Running: Load chat page and show UI');
|
|
|
|
await loginAsUser(page);
|
|
await page.waitForTimeout(1000);
|
|
|
|
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/chat`);
|
|
await page.waitForLoadState('domcontentloaded');
|
|
|
|
await page.waitForTimeout(3000);
|
|
|
|
const channelsHeader = page.locator('h3:has-text("Channels")');
|
|
const loadingState = page.locator('text=/ESTABLISHING UPLINK|Establishing/i');
|
|
const errorState = page.locator('text=/Connection Terminated|Access Restricted/i');
|
|
const messageInput = page.locator('input[placeholder*="Broadcast"], input[aria-label*="message" i]');
|
|
|
|
const hasChannels = await channelsHeader.isVisible({ timeout: 5000 }).catch(() => false);
|
|
const hasLoading = await loadingState.isVisible({ timeout: 2000 }).catch(() => false);
|
|
const hasError = await errorState.isVisible({ timeout: 2000 }).catch(() => false);
|
|
const hasInput = await messageInput.isVisible({ timeout: 5000 }).catch(() => false);
|
|
|
|
expect(hasChannels || hasLoading || hasError).toBeTruthy();
|
|
|
|
if (hasChannels) {
|
|
expect(hasInput).toBeTruthy();
|
|
console.log('✅ [CHAT] Chat UI loaded with Channels and input');
|
|
} else if (hasLoading) {
|
|
console.log('✅ [CHAT] Chat page showing loading state');
|
|
} else if (hasError) {
|
|
console.log('✅ [CHAT] Chat page showing error state (expected when chat server unavailable)');
|
|
}
|
|
});
|
|
|
|
test('should show disconnected state when WebSocket unavailable', async ({ page }) => {
|
|
console.log('🧪 [CHAT] Running: Disconnected state indicator');
|
|
|
|
await loginAsUser(page);
|
|
await page.waitForTimeout(1000);
|
|
|
|
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/chat`);
|
|
await page.waitForLoadState('domcontentloaded');
|
|
|
|
await page.waitForTimeout(5000);
|
|
|
|
const channelsHeader = page.locator('h3:has-text("Channels")');
|
|
const statusDot = page.locator('.rounded-full.w-2.h-2, div.w-2.h-2.rounded-full');
|
|
|
|
const hasChannels = await channelsHeader.isVisible({ timeout: 10000 }).catch(() => false);
|
|
test.skip(!hasChannels, 'Chat UI not loaded - may be loading or error state');
|
|
|
|
const hasStatusDot = await statusDot.first().isVisible({ timeout: 3000 }).catch(() => false);
|
|
expect(hasStatusDot).toBeTruthy();
|
|
|
|
const dotClasses = await statusDot.first().getAttribute('class').catch(() => '');
|
|
const isDisconnected = dotClasses?.includes('bg-destructive') ?? false;
|
|
const isConnected = dotClasses?.includes('bg-success') ?? false;
|
|
|
|
expect(isDisconnected || isConnected).toBeTruthy();
|
|
console.log(`✅ [CHAT] Status indicator visible (connected: ${isConnected}, disconnected: ${isDisconnected})`);
|
|
});
|
|
|
|
test('should send and display message when WebSocket connected', async ({ page }) => {
|
|
console.log('🧪 [CHAT] Running: Send message (when WebSocket connected)');
|
|
|
|
await loginAsUser(page);
|
|
await page.waitForTimeout(1000);
|
|
|
|
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/chat`);
|
|
await page.waitForLoadState('domcontentloaded');
|
|
|
|
await page.waitForTimeout(5000);
|
|
|
|
const channelsHeader = page.locator('h3:has-text("Channels")');
|
|
const statusDot = page.locator('div.w-2.h-2.rounded-full, .rounded-full.w-2.h-2').first();
|
|
const conversationItem = page.locator('[data-testid="conversation-item"], button, [role="button"]').filter({ hasText: /general|default|lobby|channel/i }).first();
|
|
const messageInput = page.locator('input[placeholder*="Broadcast"], input[aria-label*="message" i]');
|
|
const sendButton = page.locator('button[type="submit"]').filter({ has: page.locator('svg') });
|
|
|
|
const hasChannels = await channelsHeader.isVisible({ timeout: 10000 }).catch(() => false);
|
|
test.skip(!hasChannels, 'Chat UI not loaded');
|
|
|
|
const dotClasses = await statusDot.getAttribute('class').catch(() => '');
|
|
const isConnected = dotClasses?.includes('bg-success') ?? false;
|
|
test.skip(!isConnected, 'WebSocket not connected - chat server may be unavailable');
|
|
|
|
const hasConversation = await conversationItem.isVisible({ timeout: 3000 }).catch(() => false);
|
|
test.skip(!hasConversation, 'No conversation/channel available to send message');
|
|
|
|
await conversationItem.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
const testMessage = `E2E test ${Date.now()}`;
|
|
await messageInput.fill(testMessage);
|
|
await page.waitForTimeout(300);
|
|
|
|
await sendButton.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
const messageVisible = await page.locator(`text="${testMessage}"`).isVisible({ timeout: 5000 }).catch(() => false);
|
|
expect(messageVisible).toBeTruthy();
|
|
console.log('✅ [CHAT] Message sent and displayed');
|
|
});
|
|
|
|
test.afterEach(async ({}, testInfo) => {
|
|
console.log('\n📊 [CHAT] === Final Verifications ===');
|
|
if (consoleErrors.length > 0) {
|
|
console.log(`🔴 [CHAT] Console errors (${consoleErrors.length}):`);
|
|
consoleErrors.forEach((e) => console.log(` - ${e}`));
|
|
}
|
|
if (networkErrors.length > 0) {
|
|
console.log(`🔴 [CHAT] Network errors (${networkErrors.length}):`);
|
|
networkErrors.forEach((e) => console.log(` - ${e.method} ${e.url}: ${e.status}`));
|
|
}
|
|
});
|
|
});
|