Files
cinny/e2e/localHs.ts
T

115 lines
3.6 KiB
TypeScript
Raw Normal View History

import { Page, expect } from '@playwright/test';
/**
* Tier 3 (Gitea #220): regression tests against a throwaway Synapse the job
* starts itself (`scripts/dev-homeserver.sh start`). No prod secrets. Set
* E2E_LOCAL_HS (default http://localhost:8008) — the spec skips when the
* server isn't reachable.
*/
export const HS = process.env.E2E_LOCAL_HS || 'http://localhost:8008';
export const PASSWORD = 'password123';
export const enc = encodeURIComponent;
export async function hsReachable(): Promise<boolean> {
try {
const res = await fetch(`${HS}/_matrix/client/versions`);
return res.ok;
} catch {
return false;
}
}
export async function api<T = Record<string, unknown>>(
method: string,
path: string,
token?: string,
body?: unknown,
): Promise<T> {
const res = await fetch(`${HS}${path}`, {
method,
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: body === undefined ? undefined : JSON.stringify(body),
});
return (await res.json()) as T;
}
export type TestUser = { localpart: string; userId: string; token: string };
/** Registers (open registration) or logs in a test user. */
export async function ensureUser(localpart: string): Promise<TestUser> {
const reg = await api<{ user_id?: string; access_token?: string }>(
'POST',
'/_matrix/client/v3/register',
undefined,
{ username: localpart, password: PASSWORD, auth: { type: 'm.login.dummy' } },
);
if (reg.access_token && reg.user_id) {
return { localpart, userId: reg.user_id, token: reg.access_token };
}
const login = await api<{ user_id: string; access_token: string }>(
'POST',
'/_matrix/client/v3/login',
undefined,
{
type: 'm.login.password',
identifier: { type: 'm.id.user', user: localpart },
password: PASSWORD,
},
);
return { localpart, userId: login.user_id, token: login.access_token };
}
export async function createRoom(
owner: TestUser,
name: string,
opts: { invite?: string[]; preset?: string } = {},
): Promise<string> {
const res = await api<{ room_id: string }>('POST', '/_matrix/client/v3/createRoom', owner.token, {
name,
preset: opts.preset ?? 'public_chat',
invite: opts.invite,
});
return res.room_id;
}
export async function joinRoom(user: TestUser, roomId: string): Promise<void> {
await api('POST', `/_matrix/client/v3/rooms/${enc(roomId)}/join`, user.token, {});
}
let txn = 0;
export async function sendText(
user: TestUser,
roomId: string,
body: string,
extra: Record<string, unknown> = {},
): Promise<string> {
txn += 1;
const res = await api<{ event_id: string }>(
'PUT',
`/_matrix/client/v3/rooms/${enc(roomId)}/send/m.room.message/e2e${Date.now()}_${txn}`,
user.token,
{ msgtype: 'm.text', body, ...extra },
);
return res.event_id;
}
/** Password login through the UI against the local homeserver. */
export async function loginUI(page: Page, user: TestUser): Promise<void> {
await page.goto(`/login/${enc(HS)}/`);
await page.getByLabel('Username or email').fill(user.localpart);
await page.getByLabel('Password', { exact: true }).fill(PASSWORD);
await page.getByRole('button', { name: 'Login' }).click();
await page.waitForURL(/\/home/, { timeout: 60_000 });
}
export async function openRoom(page: Page, roomId: string): Promise<void> {
await page.goto(`/home/${enc(roomId)}`);
await expect(page.locator('[data-slate-editor]').first()).toBeVisible({ timeout: 30_000 });
}
export const uniq = (prefix: string): string =>
`${prefix}${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;