import { test, expect } from '@playwright/test'; import { api, createRoom, enc, ensureUser, hsReachable, loginUI, openRoom, sendText, uniq, } from './localHs'; // Offline outbox (#112): messages sent while offline are queued, then // delivered once each, in order, when the connection returns. Checked on the // server, so duplicates or reordering would show. test.describe('offline outbox', () => { test.beforeAll(async () => { test.skip(!(await hsReachable()), 'local homeserver not running'); }); test('queued while offline, delivered once each and in order when back', async ({ page, context, }) => { test.setTimeout(120_000); const me = await ensureUser(uniq('outbox')); const room = await createRoom(me, 'Outbox Room'); await sendText(me, room, 'before going offline'); await loginUI(page, me); await openRoom(page, room); await expect(page.getByText('before going offline')).toBeVisible(); await context.setOffline(true); const composer = page.getByRole('textbox', { name: /message/i }).last(); const texts = [uniq('one '), uniq('two '), uniq('three ')]; for (const text of texts) { // eslint-disable-next-line no-await-in-loop await composer.fill(text); // eslint-disable-next-line no-await-in-loop await composer.press('Enter'); } for (const text of texts) { const item = page.locator('[data-message-item]', { hasText: text }); // eslint-disable-next-line no-await-in-loop await expect(item).toHaveCount(1); // eslint-disable-next-line no-await-in-loop await expect(item.getByLabel(/^Queued\. Will send when you're back online/)).toBeVisible({ timeout: 20_000, }); } await context.setOffline(false); const bodiesOnServer = async () => { const res = await api<{ chunk: { type: string; content?: { body?: string } }[] }>( 'GET', `/_matrix/client/v3/rooms/${enc(room)}/messages?dir=f&limit=100`, me.token, ); return res.chunk .filter((e) => e.type === 'm.room.message' && texts.includes(e.content?.body ?? '')) .map((e) => e.content?.body); }; await expect.poll(bodiesOnServer, { timeout: 60_000, intervals: [1000] }).toEqual(texts); for (const text of texts) { // eslint-disable-next-line no-await-in-loop await expect( page.locator('[data-message-item]', { hasText: text }).getByLabel(/^Queued/), ).toHaveCount(0, { timeout: 20_000 }); } }); });