test(09-02): add integration tests for receive message flow
- Test WebSocket message display with sender info - Test message deduplication (sent message not duplicated on WebSocket receive) - Test auto-scroll to bottom on new message - Test unread badge increment when window closed - 4 comprehensive tests for real-time receive scenarios
This commit is contained in:
parent
9eb58bd02b
commit
984c60c656
|
|
@ -0,0 +1,153 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { loginToJamUI, createAndJoinSession } from '../utils/test-helpers';
|
||||
|
||||
test.describe('Receive 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('displays message received via WebSocket', async ({ page, context }) => {
|
||||
const popupPromise = context.waitForEvent('page');
|
||||
const popup = await popupPromise;
|
||||
await popup.waitForLoadState('domcontentloaded');
|
||||
|
||||
// Simulate receiving message via WebSocket (dispatch Redux action)
|
||||
await page.evaluate(() => {
|
||||
const store = (window as any).__REDUX_STORE__;
|
||||
|
||||
// Simulate WebSocket message
|
||||
store.dispatch({
|
||||
type: 'sessionChat/addMessageFromWebSocket',
|
||||
payload: {
|
||||
id: 'test-msg-123',
|
||||
senderId: 'other-user-id',
|
||||
senderName: 'Test User',
|
||||
message: 'Hello from WebSocket!',
|
||||
createdAt: new Date().toISOString(),
|
||||
channel: 'test-session-id'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for message to appear in popup
|
||||
await popup.waitForTimeout(500);
|
||||
const message = popup.locator('text=Hello from WebSocket!');
|
||||
await expect(message).toBeVisible();
|
||||
|
||||
// Verify sender name displayed
|
||||
const sender = popup.locator('text=Test User');
|
||||
await expect(sender).toBeVisible();
|
||||
});
|
||||
|
||||
test('does not duplicate sent message when received via WebSocket', async ({ page, context }) => {
|
||||
const popupPromise = context.waitForEvent('page');
|
||||
const popup = await popupPromise;
|
||||
await popup.waitForLoadState('domcontentloaded');
|
||||
|
||||
// Send message
|
||||
const textarea = popup.locator('textarea[placeholder*="Type a message"]');
|
||||
await textarea.fill('No duplicate test');
|
||||
|
||||
const sendButton = popup.locator('button:has-text("Send")');
|
||||
await sendButton.click();
|
||||
|
||||
// Wait for optimistic update
|
||||
await popup.waitForTimeout(300);
|
||||
|
||||
// Simulate receiving same message via WebSocket (with same msg_id)
|
||||
await page.evaluate(() => {
|
||||
const store = (window as any).__REDUX_STORE__;
|
||||
const state = store.getState();
|
||||
|
||||
// Get the message that was just sent (will have msg_id from server)
|
||||
const messages = state.sessionChat.messagesByChannel['test-session-id'] || [];
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
|
||||
// Try to add again via WebSocket (should be deduplicated)
|
||||
if (lastMessage) {
|
||||
store.dispatch({
|
||||
type: 'sessionChat/addMessageFromWebSocket',
|
||||
payload: lastMessage
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await popup.waitForTimeout(300);
|
||||
|
||||
// Should only have ONE instance of the message
|
||||
const messages = popup.locator('text=No duplicate test');
|
||||
expect(await messages.count()).toBe(1);
|
||||
});
|
||||
|
||||
test('auto-scrolls to bottom when new message received', async ({ page, context }) => {
|
||||
const popupPromise = context.waitForEvent('page');
|
||||
const popup = await popupPromise;
|
||||
await popup.waitForLoadState('domcontentloaded');
|
||||
|
||||
// Add multiple messages to enable scrolling
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
await page.evaluate((num) => {
|
||||
const store = (window as any).__REDUX_STORE__;
|
||||
store.dispatch({
|
||||
type: 'sessionChat/addMessageFromWebSocket',
|
||||
payload: {
|
||||
id: `msg-${num}`,
|
||||
senderId: 'user-id',
|
||||
senderName: 'Test User',
|
||||
message: `Message ${num}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
channel: 'test-session-id'
|
||||
}
|
||||
});
|
||||
}, i);
|
||||
|
||||
await popup.waitForTimeout(100);
|
||||
}
|
||||
|
||||
// Last message should be visible (auto-scrolled)
|
||||
const lastMessage = popup.locator('text=Message 10');
|
||||
await expect(lastMessage).toBeVisible();
|
||||
});
|
||||
|
||||
test('increments unread badge when message received and window closed', async ({ page, context }) => {
|
||||
// Open then close chat window
|
||||
const chatButton = page.locator('img[alt="Chat"]');
|
||||
await chatButton.click();
|
||||
|
||||
const popupPromise = context.waitForEvent('page');
|
||||
const popup = await popupPromise;
|
||||
await popup.waitForLoadState('domcontentloaded');
|
||||
|
||||
// Close window
|
||||
const closeButton = popup.locator('button[aria-label="Close chat"]');
|
||||
await closeButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Simulate receiving message while window closed
|
||||
await page.evaluate(() => {
|
||||
const store = (window as any).__REDUX_STORE__;
|
||||
store.dispatch({
|
||||
type: 'sessionChat/addMessageFromWebSocket',
|
||||
payload: {
|
||||
id: 'msg-closed-window',
|
||||
senderId: 'other-user',
|
||||
senderName: 'Test User',
|
||||
message: 'Message while closed',
|
||||
createdAt: new Date().toISOString(),
|
||||
channel: 'test-session-id'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// Unread badge should show "1"
|
||||
const badge = page.locator('div:has-text("1")').filter({ hasText: /^1$/ });
|
||||
await expect(badge).toBeVisible();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue