* Switch to TestContainers for manging services in Playwright Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Flip fixture dependency order Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove mas dep Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update matrix-authentication-service in Playwright tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix SMTP port Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Comments Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Strip ansi from playwright logs to make them more readable Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Actually do the update Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove access to homeserver.config.baseUrl field in favour of homeserver.baseUrl Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Use sane default_server_config and specify server.invalid in the specific tests which demand it Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix mas run Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * break cycle Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * typo Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * prettier Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Wire up basics of dendriteHomeserver Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Run Playwright tests against Dendrite & Pinecone periodically Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix playwright-image-updates.yaml workflow Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add `X-Run-All-Tests` label for running all tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Ignore failing tests in stale-screenshot-reporter.ts to avoid confusing errors Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Specify Synapse ui_auth.session_timeout only on tests which require it As Dendrite lacks this configuration option Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * React to MatrixEvent sender/target sentinels being updated for rendering state events Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove test code Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * React to sentinel changes in EventListSummary Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Docs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Avoid reusing user1234 Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix stale-screenshot-reporter.ts Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Clean up public rooms between tests on reused homeserver Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Deflake spotlight when homeserver is reused Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Deflake more tests using existing username Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Clean mailhog between tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix more flakes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix missing _request Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix playwright flaky tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Wipe mailhog between test runs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Deflake more tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix flaky tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix flaky tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix mas config Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix another flaky test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix playwright flakes due to floating promises Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix flaky playwright tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update services.ts --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
401 lines
19 KiB
TypeScript
401 lines
19 KiB
TypeScript
/*
|
||
Copyright 2024 New Vector Ltd.
|
||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||
|
||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||
Please see LICENSE files in the repository root for full details.
|
||
*/
|
||
|
||
import type { AccountDataEvents, Visibility } from "matrix-js-sdk/src/matrix";
|
||
import { test as base, expect } from "../../element-web-test";
|
||
import { Filter } from "../../pages/Spotlight";
|
||
import { Bot } from "../../pages/bot";
|
||
import type { Locator, Page } from "@playwright/test";
|
||
import type { ElementAppPage } from "../../pages/ElementAppPage";
|
||
import { isDendrite } from "../../plugins/homeserver/dendrite";
|
||
|
||
function roomHeaderName(page: Page): Locator {
|
||
return page.locator(".mx_RoomHeader_heading");
|
||
}
|
||
|
||
async function startDM(app: ElementAppPage, page: Page, name: string): Promise<void> {
|
||
const spotlight = await app.openSpotlight();
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(name);
|
||
await page.waitForTimeout(1000); // wait for the dialog code to settle
|
||
await expect(spotlight.dialog.locator(".mx_Spinner")).not.toBeAttached();
|
||
const result = spotlight.results;
|
||
await expect(result).toHaveCount(1);
|
||
await expect(result.first()).toContainText(name);
|
||
await result.first().click();
|
||
|
||
// send first message to start DM
|
||
const locator = page.getByRole("textbox", { name: "Send a message…" });
|
||
await expect(locator).toBeFocused();
|
||
await locator.fill("Hey!");
|
||
await locator.press("Enter");
|
||
// The DM room is created at this point, this can take a little bit of time
|
||
await expect(page.locator(".mx_EventTile_body").getByText("Hey!")).toBeAttached({ timeout: 3000 });
|
||
await expect(page.getByRole("group", { name: "People" }).getByText(name)).toBeAttached();
|
||
}
|
||
|
||
type RoomRef = { name: string; roomId: string };
|
||
const test = base.extend<{
|
||
bot1: Bot;
|
||
bot2: Bot;
|
||
room1: RoomRef;
|
||
room2: RoomRef;
|
||
room3: RoomRef;
|
||
}>({
|
||
bot1: async ({ page, homeserver }, use, testInfo) => {
|
||
const bot = new Bot(page, homeserver, { displayName: `BotBob_${testInfo.testId}`, autoAcceptInvites: true });
|
||
await use(bot);
|
||
},
|
||
bot2: async ({ page, homeserver }, use, testInfo) => {
|
||
const bot = new Bot(page, homeserver, { displayName: `ByteBot_${testInfo.testId}`, autoAcceptInvites: true });
|
||
await use(bot);
|
||
},
|
||
room1: async ({ app }, use) => {
|
||
const name = "247";
|
||
const roomId = await app.client.createRoom({ name, visibility: "public" as Visibility });
|
||
await use({ name, roomId });
|
||
},
|
||
room2: async ({ bot2 }, use) => {
|
||
const name = "Lounge";
|
||
const roomId = await bot2.createRoom({ name, visibility: "public" as Visibility });
|
||
await use({ name, roomId });
|
||
},
|
||
room3: async ({ bot2 }, use) => {
|
||
const name = "Public";
|
||
const roomId = await bot2.createRoom({
|
||
name,
|
||
visibility: "public" as Visibility,
|
||
initial_state: [
|
||
{
|
||
type: "m.room.history_visibility",
|
||
state_key: "",
|
||
content: {
|
||
history_visibility: "world_readable",
|
||
},
|
||
},
|
||
],
|
||
});
|
||
await use({ name, roomId });
|
||
},
|
||
context: async ({ context, homeserver }, use) => {
|
||
// Restart the homeserver to wipe its in-memory db so we can reuse the same user ID without cross-signing prompts
|
||
await homeserver.restart();
|
||
await use(context);
|
||
},
|
||
});
|
||
|
||
test.describe("Spotlight", () => {
|
||
test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488");
|
||
test.use({
|
||
displayName: "Jim",
|
||
});
|
||
|
||
test.beforeEach(async ({ page, user, bot1, bot2, room1, room2, room3 }) => {
|
||
await bot1.joinRoom(room1.roomId);
|
||
await bot2.inviteUser(room2.roomId, bot1.credentials.userId);
|
||
await bot2.inviteUser(room3.roomId, bot1.credentials.userId);
|
||
|
||
await page.goto(`/#/room/${room1.roomId}`);
|
||
await expect(page.locator(".mx_RoomSublist_skeletonUI")).not.toBeAttached();
|
||
});
|
||
|
||
test("should be able to add and remove filters via keyboard", async ({ page, app }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(1000); // wait for the dialog to settle, otherwise our keypresses might race with an update
|
||
|
||
// initially, public spaces should be highlighted (because there are no other suggestions)
|
||
await expect(spotlight.dialog.locator("#mx_SpotlightDialog_button_explorePublicSpaces")).toHaveAttribute(
|
||
"aria-selected",
|
||
"true",
|
||
);
|
||
|
||
// hitting enter should enable the public rooms filter
|
||
await spotlight.searchBox.press("Enter");
|
||
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).toHaveText("Public spaces");
|
||
await spotlight.searchBox.press("Backspace");
|
||
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).not.toBeAttached();
|
||
await page.waitForTimeout(200); // Again, wait to settle so keypresses arrive correctly
|
||
|
||
await spotlight.searchBox.press("ArrowDown");
|
||
await expect(spotlight.dialog.locator("#mx_SpotlightDialog_button_explorePublicRooms")).toHaveAttribute(
|
||
"aria-selected",
|
||
"true",
|
||
);
|
||
await spotlight.searchBox.press("Enter");
|
||
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).toHaveText("Public rooms");
|
||
await spotlight.searchBox.press("Backspace");
|
||
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_filter")).not.toBeAttached();
|
||
});
|
||
|
||
test("should find joined rooms", async ({ page, app, room1 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.search(room1.name);
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(room1.name);
|
||
await resultLocator.first().click();
|
||
await expect(page).toHaveURL(new RegExp(`#/room/${room1.roomId}`));
|
||
await expect(roomHeaderName(page)).toContainText(room1.name);
|
||
});
|
||
|
||
test("should find known public rooms", async ({ page, app, room1 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.PublicRooms);
|
||
await spotlight.search(room1.name);
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(room1.name);
|
||
await expect(resultLocator.first()).toContainText("View");
|
||
await resultLocator.first().click();
|
||
await expect(page).toHaveURL(new RegExp(`#/room/${room1.roomId}`));
|
||
await expect(roomHeaderName(page)).toContainText(room1.name);
|
||
});
|
||
|
||
test("should find unknown public rooms", async ({ page, app, room2 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.PublicRooms);
|
||
await spotlight.search(room2.name);
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(room2.name);
|
||
await expect(resultLocator.first()).toContainText("Join");
|
||
await resultLocator.first().click();
|
||
await expect(page).toHaveURL(new RegExp(`#/room/${room2.roomId}`));
|
||
await expect(page.locator(".mx_RoomView_MessageList")).toHaveCount(1);
|
||
await expect(roomHeaderName(page)).toContainText(room2.name);
|
||
});
|
||
|
||
test("should find unknown public world readable rooms", async ({ page, app, room3 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.PublicRooms);
|
||
await spotlight.search(room3.name);
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(room3.name);
|
||
await expect(resultLocator.first()).toContainText("View");
|
||
await resultLocator.first().click();
|
||
await expect(page).toHaveURL(new RegExp(`#/room/${room3.roomId}`));
|
||
await page.getByRole("button", { name: "Join the discussion" }).click();
|
||
await expect(roomHeaderName(page)).toHaveText(room3.name);
|
||
});
|
||
|
||
// TODO: We currently can’t test finding rooms on other homeservers/other protocols
|
||
// We obviously don’t have federation or bridges in local e2e tests
|
||
test.skip("should find unknown public rooms on other homeservers", async ({ page, app, room3 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.PublicRooms);
|
||
await spotlight.search(room3.name);
|
||
await page.locator("[aria-haspopup=true][role=button]").click();
|
||
|
||
await page
|
||
.locator(".mx_GenericDropdownMenu_Option--header")
|
||
.filter({ hasText: "matrix.org" })
|
||
.locator("..")
|
||
.locator("[role=menuitemradio]")
|
||
.click();
|
||
await page.waitForTimeout(3_600_000);
|
||
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(room3.name);
|
||
await expect(resultLocator.first()).toContainText(room3.roomId);
|
||
});
|
||
|
||
test("should find known people", async ({ page, app, bot1 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot1.credentials.displayName);
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(bot1.credentials.displayName);
|
||
await resultLocator.first().click();
|
||
await expect(roomHeaderName(page)).toHaveText(bot1.credentials.displayName);
|
||
});
|
||
|
||
/**
|
||
* Search sends the correct query to Synapse.
|
||
* Synapse doesn't return the user in the result list.
|
||
* Waiting for the profile to be available via APIs before the tests didn't help.
|
||
*
|
||
* https://github.com/matrix-org/synapse/issues/16472
|
||
*/
|
||
test("should find unknown people", async ({ page, app, bot2 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot2.credentials.displayName);
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(bot2.credentials.displayName);
|
||
await resultLocator.first().click();
|
||
await expect(roomHeaderName(page)).toHaveText(bot2.credentials.displayName);
|
||
});
|
||
|
||
test("should find group DMs by usernames or user ids", async ({ page, app, bot1, bot2, room1 }) => {
|
||
// First we want to share a room with both bots to ensure we’ve got their usernames cached
|
||
await app.client.inviteUser(room1.roomId, bot2.credentials.userId);
|
||
|
||
// Starting a DM with ByteBot (will be turned into a group dm later)
|
||
let spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot2.credentials.displayName);
|
||
let resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(bot2.credentials.displayName);
|
||
await resultLocator.first().click();
|
||
|
||
// Send first message to actually start DM
|
||
await expect(roomHeaderName(page)).toHaveText(bot2.credentials.displayName);
|
||
const locator = page.getByRole("textbox", { name: "Send a message…" });
|
||
await locator.fill("Hey!");
|
||
await locator.press("Enter");
|
||
|
||
// Assert DM exists by checking for the first message and the room being in the room list
|
||
await expect(page.locator(".mx_EventTile_body").filter({ hasText: "Hey!" })).toBeAttached({ timeout: 3000 });
|
||
await expect(page.getByRole("group", { name: "People" })).toContainText(bot2.credentials.displayName);
|
||
|
||
// Invite BotBob into existing DM with ByteBot
|
||
const dmRooms = await app.client.evaluate((client, userId) => {
|
||
const map = client
|
||
.getAccountData("m.direct" as keyof AccountDataEvents)
|
||
?.getContent<Record<string, string[]>>();
|
||
return map[userId] ?? [];
|
||
}, bot2.credentials.userId);
|
||
expect(dmRooms).toHaveLength(1);
|
||
const groupDmName = await app.client.evaluate((client, id) => client.getRoom(id).name, dmRooms[0]);
|
||
await app.client.inviteUser(dmRooms[0], bot1.credentials.userId);
|
||
await expect(roomHeaderName(page).first()).toContainText(groupDmName);
|
||
await expect(page.getByRole("group", { name: "People" }).first()).toContainText(groupDmName);
|
||
|
||
// Search for BotBob by id, should return group DM and user
|
||
spotlight = await app.openSpotlight();
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot1.credentials.userId);
|
||
await page.waitForTimeout(1000); // wait for the dialog to settle
|
||
resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(2);
|
||
await expect(
|
||
spotlight.dialog
|
||
.locator(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option")
|
||
.filter({ hasText: groupDmName }),
|
||
).toBeAttached();
|
||
|
||
// Search for ByteBot by id, should return group DM and user
|
||
spotlight = await app.openSpotlight();
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot2.credentials.userId);
|
||
await page.waitForTimeout(1000); // wait for the dialog to settle
|
||
resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(2);
|
||
await expect(
|
||
spotlight.dialog
|
||
.locator(".mx_SpotlightDialog_section.mx_SpotlightDialog_results .mx_SpotlightDialog_option")
|
||
.filter({ hasText: groupDmName })
|
||
.last(),
|
||
).toBeAttached();
|
||
});
|
||
|
||
// Test against https://github.com/vector-im/element-web/issues/22851
|
||
test("should show each person result only once", async ({ page, app, bot1 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
|
||
// 2 rounds of search to simulate the bug conditions. Specifically, the first search
|
||
// should have 1 result (not 2) and the second search should also have 1 result (instead
|
||
// of the super buggy 3 described by https://github.com/vector-im/element-web/issues/22851)
|
||
//
|
||
// We search for user ID to trigger the profile lookup within the dialog.
|
||
for (let i = 0; i < 2; i++) {
|
||
console.log("Iteration: " + i);
|
||
await spotlight.search(bot1.credentials.userId);
|
||
await page.waitForTimeout(1000); // wait for the dialog to settle
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(bot1.credentials.userId);
|
||
}
|
||
});
|
||
|
||
test("should allow opening group chat dialog", async ({ page, app, bot2 }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot2.credentials.displayName);
|
||
await page.waitForTimeout(3000); // wait for the dialog to settle
|
||
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
await expect(resultLocator.first()).toContainText(bot2.credentials.displayName);
|
||
|
||
await expect(spotlight.dialog.locator(".mx_SpotlightDialog_startGroupChat")).toContainText(
|
||
"Start a group chat",
|
||
);
|
||
await spotlight.dialog.locator(".mx_SpotlightDialog_startGroupChat").click();
|
||
await expect(page.getByRole("dialog")).toContainText("Direct Messages");
|
||
});
|
||
|
||
test("should close spotlight after starting a DM", async ({ page, app, bot1 }) => {
|
||
await startDM(app, page, bot1.credentials.displayName);
|
||
await expect(page.locator(".mx_SpotlightDialog")).toHaveCount(0);
|
||
});
|
||
|
||
test("should show the same user only once", async ({ page, app, bot1 }) => {
|
||
await startDM(app, page, bot1.credentials.displayName);
|
||
await page.goto("/#/home");
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search(bot1.credentials.displayName);
|
||
await page.waitForTimeout(3000); // wait for the dialog to settle
|
||
await expect(spotlight.dialog.locator(".mx_Spinner")).not.toBeAttached();
|
||
const resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(1);
|
||
});
|
||
|
||
test("should be able to navigate results via keyboard", async ({ page, app }) => {
|
||
const spotlight = await app.openSpotlight();
|
||
await page.waitForTimeout(500); // wait for the dialog to settle
|
||
await spotlight.filter(Filter.People);
|
||
await spotlight.search("b");
|
||
|
||
let resultLocator = spotlight.results;
|
||
await expect(resultLocator).toHaveCount(2);
|
||
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "true");
|
||
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "false");
|
||
|
||
await spotlight.searchBox.press("ArrowDown");
|
||
resultLocator = spotlight.results;
|
||
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "false");
|
||
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "true");
|
||
|
||
await spotlight.searchBox.press("ArrowDown");
|
||
resultLocator = spotlight.results;
|
||
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "false");
|
||
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "false");
|
||
|
||
await spotlight.searchBox.press("ArrowUp");
|
||
resultLocator = spotlight.results;
|
||
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "false");
|
||
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "true");
|
||
|
||
await spotlight.searchBox.press("ArrowUp");
|
||
resultLocator = spotlight.results;
|
||
await expect(resultLocator.first()).toHaveAttribute("aria-selected", "true");
|
||
await expect(resultLocator.last()).toHaveAttribute("aria-selected", "false");
|
||
});
|
||
});
|