* Size Autocomplete relative to the RoomView height rather than the viewport height * Add screenshot for the autocomplete in a regression changes the height * Add cjk fonts to support rendering text emoticons displayed in slash command picker * Maybe when actually running the tests? * Try after system dependencies and clear font cache * Add cjk fonts to support rendering text emoticons displayed in slash command picker Try after system dependencies and clear font cache Maybe when actually running the tests? Revert "Add cjk fonts to support rendering text emoticons displayed in slash command picker" This reverts commit 46fa014308b6010626174f8cd0d3a978488963ee. * Render emoji autocoplete instead * Remove font install that didn't work
187 lines
8.3 KiB
TypeScript
187 lines
8.3 KiB
TypeScript
/*
|
|
Copyright 2024 New Vector Ltd.
|
|
Copyright 2022, 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 { test, expect } from "../../element-web-test";
|
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
|
|
|
const CtrlOrMeta = process.platform === "darwin" ? "Meta" : "Control";
|
|
|
|
test.describe("Composer", () => {
|
|
test.use({
|
|
displayName: "Janet",
|
|
botCreateOpts: {
|
|
displayName: "Bob",
|
|
},
|
|
});
|
|
|
|
test.use({
|
|
room: async ({ app, user }, use) => {
|
|
const roomId = await app.client.createRoom({ name: "Composing Room" });
|
|
await app.viewRoomByName("Composing Room");
|
|
await use({ roomId });
|
|
},
|
|
});
|
|
|
|
test.beforeEach(async ({ room }) => {}); // trigger room fixture
|
|
|
|
test.describe("CIDER", () => {
|
|
test("sends a message when you click send or press Enter", async ({ page }) => {
|
|
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
|
|
|
// Type a message
|
|
await composer.pressSequentially("my message 0");
|
|
// It has not been sent yet
|
|
await expect(page.locator(".mx_EventTile_body", { hasText: "my message 0" })).not.toBeVisible();
|
|
|
|
// Click send
|
|
await page.getByRole("button", { name: "Send message" }).click();
|
|
// It has been sent
|
|
await expect(
|
|
page.locator(".mx_EventTile_last .mx_EventTile_body", { hasText: "my message 0" }),
|
|
).toBeVisible();
|
|
|
|
// Type another and press Enter afterward
|
|
await composer.pressSequentially("my message 1");
|
|
await composer.press("Enter");
|
|
// It was sent
|
|
await expect(
|
|
page.locator(".mx_EventTile_last .mx_EventTile_body", { hasText: "my message 1" }),
|
|
).toBeVisible();
|
|
});
|
|
|
|
test("can write formatted text", async ({ page }) => {
|
|
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
|
|
|
await composer.pressSequentially("my bold");
|
|
await composer.press(`${CtrlOrMeta}+KeyB`);
|
|
await composer.pressSequentially(" message");
|
|
await page.getByRole("button", { name: "Send message" }).click();
|
|
// Note: both "bold" and "message" are bold, which is probably surprising
|
|
await expect(page.locator(".mx_EventTile_body strong", { hasText: "bold message" })).toBeVisible();
|
|
});
|
|
|
|
test("should allow user to input emoji via graphical picker", async ({ page, app }) => {
|
|
await app.getComposer(false).getByRole("button", { name: "Emoji" }).click();
|
|
|
|
await page.getByTestId("mx_EmojiPicker").locator(".mx_EmojiPicker_item", { hasText: "😇" }).click();
|
|
|
|
await page.locator(".mx_ContextualMenu_background").click(); // Close emoji picker
|
|
await page.getByRole("textbox", { name: "Send an unencrypted message…" }).press("Enter"); // Send message
|
|
|
|
await expect(page.locator(".mx_EventTile_body", { hasText: "😇" })).toBeVisible();
|
|
});
|
|
|
|
test.describe("render emoji picker with larger viewport height", async () => {
|
|
test.use({ viewport: { width: 1280, height: 720 } });
|
|
test("render emoji picker", { tag: "@screenshot" }, async ({ page, app }) => {
|
|
await app.getComposer(false).getByRole("button", { name: "Emoji" }).click();
|
|
await expect(page.getByTestId("mx_EmojiPicker")).toMatchScreenshot("emoji-picker.png");
|
|
});
|
|
});
|
|
|
|
test.describe("render emoji picker with small viewport height", async () => {
|
|
test.use({ viewport: { width: 1280, height: 360 } });
|
|
test("render emoji picker", { tag: "@screenshot" }, async ({ page, app }) => {
|
|
await app.getComposer(false).getByRole("button", { name: "Emoji" }).click();
|
|
await expect(page.getByTestId("mx_EmojiPicker")).toMatchScreenshot("emoji-picker-small.png");
|
|
});
|
|
});
|
|
|
|
test("should have focus lock in emoji picker", async ({ page, app }) => {
|
|
const emojiButton = app.getComposer(false).getByRole("button", { name: "Emoji" });
|
|
|
|
// Open emoji picker by clicking the button
|
|
await emojiButton.click();
|
|
|
|
// Wait for emoji picker to be visible
|
|
const emojiPicker = page.getByTestId("mx_EmojiPicker");
|
|
await expect(emojiPicker).toBeVisible();
|
|
|
|
// Get initial focused element (should be search input)
|
|
const searchInput = emojiPicker.getByRole("textbox", { name: "Search" });
|
|
await expect(searchInput).toBeFocused();
|
|
|
|
// Try to tab multiple times - focus should stay within emoji picker
|
|
await page.keyboard.press("Tab");
|
|
await page.keyboard.press("Tab");
|
|
await page.keyboard.press("Tab");
|
|
await page.keyboard.press("Tab");
|
|
await page.keyboard.press("Tab");
|
|
|
|
// Verify we're still within the emoji picker (not back to composer)
|
|
const focusedElement = await page.evaluate(() => document.activeElement?.closest(".mx_EmojiPicker"));
|
|
expect(focusedElement).not.toBeNull();
|
|
|
|
// Close with Escape key
|
|
await page.keyboard.press("Escape");
|
|
|
|
// Verify emoji picker is closed
|
|
await expect(emojiPicker).not.toBeVisible();
|
|
|
|
// Verify focus returns to emoji button
|
|
await expect(emojiButton).toBeFocused();
|
|
});
|
|
|
|
test.describe("when Control+Enter is required to send", () => {
|
|
test.beforeEach(async ({ app }) => {
|
|
await app.settings.setValue("MessageComposerInput.ctrlEnterToSend", null, SettingLevel.ACCOUNT, true);
|
|
});
|
|
|
|
test("only sends when you press Control+Enter", async ({ page }) => {
|
|
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
|
// Type a message and press Enter
|
|
await composer.pressSequentially("my message 3");
|
|
await composer.press("Enter");
|
|
// It has not been sent yet
|
|
await expect(page.locator(".mx_EventTile_body", { hasText: "my message 3" })).not.toBeVisible();
|
|
|
|
// Press Control+Enter
|
|
await composer.press(`${CtrlOrMeta}+Enter`);
|
|
// It was sent
|
|
await expect(
|
|
page.locator(".mx_EventTile_last .mx_EventTile_body", { hasText: "my message 3" }),
|
|
).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test("can send mention", { tag: "@screenshot" }, async ({ page, bot, app }) => {
|
|
// Set up a private room so we have another user to mention
|
|
await app.client.createRoom({
|
|
is_direct: true,
|
|
invite: [bot.credentials.userId],
|
|
});
|
|
await app.viewRoomByName("Bob");
|
|
|
|
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
|
await composer.pressSequentially("@bob");
|
|
|
|
// Note that we include the user ID here as the room tile is also an 'option' role
|
|
// with text 'Bob'
|
|
await page.getByRole("option", { name: `Bob ${bot.credentials.userId}` }).click();
|
|
await expect(composer.getByText("Bob")).toBeVisible();
|
|
await expect(composer).toMatchScreenshot("mention.png");
|
|
await composer.press("Enter");
|
|
await expect(page.locator(".mx_EventTile_body", { hasText: "Bob" })).toBeVisible();
|
|
});
|
|
|
|
test("renders emoji autocomplete", { tag: "@screenshot" }, async ({ page }) => {
|
|
const composer = page.getByRole("textbox", { name: "Send an unencrypted message…" });
|
|
|
|
// Type ":+1" to trigger emoji autocomplete
|
|
await composer.pressSequentially(":+1");
|
|
|
|
// Wait for autocomplete to appear
|
|
const autocomplete = page.locator("#mx_Autocomplete");
|
|
await expect(autocomplete).toBeVisible();
|
|
|
|
// Take a screenshot of the autocomplete
|
|
await expect(autocomplete).toMatchScreenshot("emoji-autocomplete.png");
|
|
});
|
|
});
|
|
});
|