Extract functions for service worker usage, and add initial MSC3916 playwright test (when supported) (#12414)
* Send user credentials to service worker for MSC3916 authentication * appease linter * Add initial test The test fails, seemingly because the service worker isn't being installed or because the network mock can't reach that far. * Remove unsafe access token code * Split out base IDB operations to avoid importing `document` in serviceworkers * Use safe crypto access for service workers * Fix tests/unsafe access * Remove backwards compatibility layer & appease linter * Add docs * Fix tests * Appease the linter * Iterate tests * Factor out pickle key handling for service workers * Enable everything we can about service workers * Appease the linter * Add docs * Rename win32 image to linux in hopes of it just working * Use actual image * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Improve documentation * Document `??` not working * Try to appease the tests * Add some notes --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
parent
374cee9080
commit
d25d529e86
12 changed files with 435 additions and 176 deletions
|
@ -70,6 +70,22 @@ const sendEvent = async (client: Client, roomId: string, html = false): Promise<
|
|||
return client.sendEvent(roomId, null, "m.room.message" as EventType, content);
|
||||
};
|
||||
|
||||
const sendImage = async (
|
||||
client: Client,
|
||||
roomId: string,
|
||||
pngBytes: Buffer,
|
||||
additionalContent?: any,
|
||||
): Promise<ISendEventResponse> => {
|
||||
const upload = await client.uploadContent(pngBytes, { name: "image.png", type: "image/png" });
|
||||
return client.sendEvent(roomId, null, "m.room.message" as EventType, {
|
||||
...(additionalContent ?? {}),
|
||||
|
||||
msgtype: "m.image" as MsgType,
|
||||
body: "image.png",
|
||||
url: upload.content_uri,
|
||||
});
|
||||
};
|
||||
|
||||
test.describe("Timeline", () => {
|
||||
test.use({
|
||||
displayName: OLD_NAME,
|
||||
|
@ -1136,5 +1152,91 @@ test.describe("Timeline", () => {
|
|||
screenshotOptions,
|
||||
);
|
||||
});
|
||||
|
||||
async function testImageRendering(page: Page, app: ElementAppPage, room: { roomId: string }) {
|
||||
await app.viewRoomById(room.roomId);
|
||||
|
||||
// Reinstall the service workers to clear their implicit caches (global-level stuff)
|
||||
await page.evaluate(async () => {
|
||||
const registrations = await window.navigator.serviceWorker.getRegistrations();
|
||||
registrations.forEach((r) => r.update());
|
||||
});
|
||||
|
||||
await sendImage(app.client, room.roomId, NEW_AVATAR);
|
||||
await expect(page.locator(".mx_MImageBody").first()).toBeVisible();
|
||||
|
||||
// Exclude timestamp and read marker from snapshot
|
||||
const screenshotOptions = {
|
||||
mask: [page.locator(".mx_MessageTimestamp")],
|
||||
css: `
|
||||
.mx_TopUnreadMessagesBar, .mx_MessagePanel_myReadMarker {
|
||||
display: none !important;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
await expect(page.locator(".mx_ScrollPanel")).toMatchScreenshot(
|
||||
"image-in-timeline-default-layout.png",
|
||||
screenshotOptions,
|
||||
);
|
||||
}
|
||||
|
||||
test("should render images in the timeline", async ({ page, app, room, context }) => {
|
||||
await testImageRendering(page, app, room);
|
||||
});
|
||||
|
||||
// XXX: This test doesn't actually work because the service worker relies on IndexedDB, which Playwright forces
|
||||
// to be a localstorage implementation, which service workers cannot access.
|
||||
// See https://github.com/microsoft/playwright/issues/11164
|
||||
// See https://github.com/microsoft/playwright/issues/15684#issuecomment-2070862042
|
||||
//
|
||||
// In practice, this means this test will *always* succeed because it ends up relying on fallback behaviour tested
|
||||
// above (unless of course the above tests are also broken).
|
||||
test.describe("MSC3916 - Authenticated Media", () => {
|
||||
test("should render authenticated images in the timeline", async ({ page, app, room, context }) => {
|
||||
// Note: we have to use `context` instead of `page` for routing, otherwise we'll miss Service Worker events.
|
||||
// See https://playwright.dev/docs/service-workers-experimental#network-events-and-routing
|
||||
|
||||
// Install our mocks and preventative measures
|
||||
await context.route("**/_matrix/client/versions", async (route) => {
|
||||
// Force enable MSC3916, which may require the service worker's internal cache to be cleared later.
|
||||
const json = await (await route.fetch()).json();
|
||||
if (!json["unstable_features"]) json["unstable_features"] = {};
|
||||
json["unstable_features"]["org.matrix.msc3916"] = true;
|
||||
await route.fulfill({ json });
|
||||
});
|
||||
await context.route("**/_matrix/media/*/download/**", async (route) => {
|
||||
// should not be called. We don't use `abort` so that it's clearer in the logs what happened.
|
||||
await route.fulfill({
|
||||
status: 500,
|
||||
json: { errcode: "M_UNKNOWN", error: "Unexpected route called." },
|
||||
});
|
||||
});
|
||||
await context.route("**/_matrix/media/*/thumbnail/**", async (route) => {
|
||||
// should not be called. We don't use `abort` so that it's clearer in the logs what happened.
|
||||
await route.fulfill({
|
||||
status: 500,
|
||||
json: { errcode: "M_UNKNOWN", error: "Unexpected route called." },
|
||||
});
|
||||
});
|
||||
await context.route("**/_matrix/client/unstable/org.matrix.msc3916/download/**", async (route) => {
|
||||
expect(route.request().headers()["Authorization"]).toBeDefined();
|
||||
// we can't use route.continue() because no configured homeserver supports MSC3916 yet
|
||||
await route.fulfill({
|
||||
body: NEW_AVATAR,
|
||||
});
|
||||
});
|
||||
await context.route("**/_matrix/client/unstable/org.matrix.msc3916/thumbnail/**", async (route) => {
|
||||
expect(route.request().headers()["Authorization"]).toBeDefined();
|
||||
// we can't use route.continue() because no configured homeserver supports MSC3916 yet
|
||||
await route.fulfill({
|
||||
body: NEW_AVATAR,
|
||||
});
|
||||
});
|
||||
|
||||
// We check the same screenshot because there should be no user-visible impact to using authentication.
|
||||
await testImageRendering(page, app, room);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue