Files
Toju/e2e/tests/chat/dm-flow.spec.ts
2026-04-27 01:02:39 +02:00

118 lines
4.7 KiB
TypeScript

import { type Page } from '@playwright/test';
import {
test,
expect,
type Client
} from '../../fixtures/multi-client';
import { RegisterPage } from '../../pages/register.page';
import { ServerSearchPage } from '../../pages/server-search.page';
import { ChatMessagesPage } from '../../pages/chat-messages.page';
test.describe('Direct message flow', () => {
test.describe.configure({ timeout: 180_000 });
test('opens a DM from a user card and queues messages while offline', async ({ createClient }) => {
const scenario = await createDmScenario(createClient);
const offlineMessage = `Offline DM ${uniqueName('msg')}`;
await test.step('Alice opens Bob from the room user list', async () => {
const bobUserCard = scenario.alice.page.locator('[data-testid^="room-user-card-"]', { hasText: 'Bob' }).first();
await expect(bobUserCard).toBeVisible({ timeout: 20_000 });
await bobUserCard.getByRole('button', { name: 'Message Bob' }).click();
await expect(scenario.alice.page).toHaveURL(/\/dm\//, { timeout: 15_000 });
await expect(scenario.alice.page.getByRole('heading', { name: 'Bob' })).toBeVisible({ timeout: 10_000 });
});
await test.step('Offline send persists locally as queued', async () => {
await scenario.alice.page.evaluate(() => window.simulateOffline?.());
await scenario.alice.page.getByTestId('dm-input').fill(offlineMessage);
await scenario.alice.page.getByTestId('dm-input').press('Enter');
await expect(scenario.alice.page.locator('app-dm-chat').getByText(offlineMessage)).toBeVisible({ timeout: 10_000 });
await expect(scenario.alice.page.getByTestId('message-status').last()).toContainText('QUEUED');
});
});
test('shows friend and message actions on the search people list', async ({ createClient }) => {
const scenario = await createDmScenario(createClient);
await scenario.alice.page.goto('/search', { waitUntil: 'domcontentloaded' });
await expect(scenario.alice.page).toHaveURL(/\/search/, { timeout: 20_000 });
await expect(scenario.alice.page.locator('app-server-search')).toBeVisible({ timeout: 20_000 });
await expect(scenario.alice.page.locator('app-user-search-list')).toBeVisible({ timeout: 20_000 });
const bobPeopleCard = scenario.alice.page.locator(`app-user-search-list [data-testid="user-card-${scenario.bobUserId}"]`);
await expect(bobPeopleCard).toBeVisible({ timeout: 15_000 });
const friendButton = bobPeopleCard.locator(`[data-testid="friend-button-${scenario.bobUserId}"]`);
const messageButton = bobPeopleCard.locator(`[data-testid="message-user-${scenario.bobUserId}"]`);
await expect(friendButton).toBeVisible({ timeout: 15_000 });
await expect(messageButton).toBeVisible({ timeout: 15_000 });
});
});
interface DmScenario {
alice: Client;
bob: Client;
bobUserId: string;
aliceSearch: ServerSearchPage;
}
async function createDmScenario(createClient: () => Promise<Client>): Promise<DmScenario> {
const suffix = uniqueName('dm');
const serverName = `DM Server ${suffix}`;
const alice = await createClient();
const bob = await createClient();
await registerUser(alice.page, `alice_${suffix}`, 'Alice');
await registerUser(bob.page, `bob_${suffix}`, 'Bob');
const aliceSearch = new ServerSearchPage(alice.page);
await aliceSearch.createServer(serverName, { description: 'E2E direct message discovery server' });
await expect(alice.page).toHaveURL(/\/room\//, { timeout: 15_000 });
await new ChatMessagesPage(alice.page).waitForReady();
const bobSearch = new ServerSearchPage(bob.page);
await bobSearch.searchInput.fill(serverName);
await bob.page.locator('button', { hasText: serverName })
.first()
.click();
await expect(bob.page).toHaveURL(/\/room\//, { timeout: 15_000 });
await new ChatMessagesPage(bob.page).waitForReady();
const bobRoomCard = alice.page.locator('[data-testid^="room-user-card-"]', { hasText: 'Bob' }).first();
await expect(bobRoomCard).toBeVisible({ timeout: 20_000 });
const bobUserCardTestId = await bobRoomCard.getAttribute('data-testid');
const bobUserId = bobUserCardTestId?.replace('room-user-card-', '');
if (!bobUserId) {
throw new Error('Expected Bob room user card to expose a stable test id.');
}
return {
alice,
bob,
bobUserId,
aliceSearch
};
}
async function registerUser(page: Page, username: string, displayName: string): Promise<void> {
const registerPage = new RegisterPage(page);
await registerPage.goto();
await registerPage.register(username, displayName, 'TestPass123!');
await expect(page).toHaveURL(/\/search/, { timeout: 15_000 });
}
function uniqueName(prefix: string): string {
return `${prefix}-${Date.now()}-${Math.random().toString(36)
.slice(2, 8)}`;
}