diff --git a/jam-ui/test/chat/send-message.spec.ts b/jam-ui/test/chat/send-message.spec.ts new file mode 100644 index 000000000..7a293906a --- /dev/null +++ b/jam-ui/test/chat/send-message.spec.ts @@ -0,0 +1,167 @@ +import { test, expect } from '@playwright/test'; +import { loginToJamUI, createAndJoinSession } from '../utils/test-helpers'; + +test.describe('Send Message', () => { + test.beforeEach(async ({ page }) => { + await loginToJamUI(page); + await createAndJoinSession(page); + + // Open chat window + const chatButton = page.locator('img[alt="Chat"]'); + await chatButton.click(); + }); + + test('sends message when Send button clicked', async ({ page, context }) => { + // Wait for popup + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + // Type message + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + await textarea.fill('Hello from test!'); + + // Click send button + const sendButton = popup.locator('button:has-text("Send")'); + await sendButton.click(); + + // Wait for message to appear in list + await popup.waitForTimeout(500); + const message = popup.locator('text=Hello from test!'); + await expect(message).toBeVisible(); + + // Verify textarea cleared + await expect(textarea).toHaveValue(''); + }); + + test('sends message when Enter key pressed', async ({ page, context }) => { + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + await textarea.fill('Hello via Enter!'); + + // Press Enter (not Shift+Enter) + await textarea.press('Enter'); + + // Message should appear + await popup.waitForTimeout(500); + const message = popup.locator('text=Hello via Enter!'); + await expect(message).toBeVisible(); + + // Textarea cleared + await expect(textarea).toHaveValue(''); + }); + + test('inserts newline when Shift+Enter pressed', async ({ page, context }) => { + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + await textarea.fill('Line 1'); + + // Press Shift+Enter + await textarea.press('Shift+Enter'); + + // Type second line + await textarea.type('Line 2'); + + // Verify multiline content + const value = await textarea.inputValue(); + expect(value).toContain('\n'); + expect(value).toContain('Line 1'); + expect(value).toContain('Line 2'); + + // Message NOT sent yet + const messages = popup.locator('[data-testid="chat-message"]'); + expect(await messages.count()).toBe(0); + }); + + test('disables send button when message empty', async ({ page, context }) => { + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + const sendButton = popup.locator('button:has-text("Send")'); + + // Initially disabled (empty) + await expect(sendButton).toBeDisabled(); + + // Type message - becomes enabled + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + await textarea.fill('Test message'); + await expect(sendButton).toBeEnabled(); + + // Clear - becomes disabled again + await textarea.fill(''); + await expect(sendButton).toBeDisabled(); + }); + + test('disables send button when message over 255 characters', async ({ page, context }) => { + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + const sendButton = popup.locator('button:has-text("Send")'); + + // Type 256 characters + const longMessage = 'a'.repeat(256); + await textarea.fill(longMessage); + + // Send button disabled + await expect(sendButton).toBeDisabled(); + + // Character count shows red and over-limit + const charCount = popup.locator('text=/256\\/255/'); + await expect(charCount).toBeVisible(); + + // Validation message appears + const validationMsg = popup.locator('text=/characters too long/i'); + await expect(validationMsg).toBeVisible(); + }); + + test('shows error when send fails', async ({ page, context }) => { + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + // Simulate send failure by mocking the API to fail + await page.route('**/api/chat/messages', route => { + route.fulfill({ + status: 500, + body: JSON.stringify({ error: 'Internal server error' }) + }); + }); + + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + await textarea.fill('Test failure'); + + const sendButton = popup.locator('button:has-text("Send")'); + await sendButton.click(); + + // Error message should appear + await popup.waitForTimeout(500); + const errorMsg = popup.locator('text=/Failed to send message/i'); + await expect(errorMsg).toBeVisible(); + }); + + test('shows optimistic update immediately', async ({ page, context }) => { + const popupPromise = context.waitForEvent('page'); + const popup = await popupPromise; + await popup.waitForLoadState('domcontentloaded'); + + const textarea = popup.locator('textarea[placeholder*="Type a message"]'); + await textarea.fill('Optimistic test'); + + const sendButton = popup.locator('button:has-text("Send")'); + await sendButton.click(); + + // Message should appear immediately (optimistic) + // Don't wait for server - should show right away + const message = popup.locator('text=Optimistic test'); + await expect(message).toBeVisible({ timeout: 1000 }); + }); +});