Skip to content

Commit

Permalink
#8206: playwright tests for MS Edge sidebar links (#8216)
Browse files Browse the repository at this point in the history
* #8206: playwright tests for links

* Open the extension console

* Fix jest snapshots

* Add commentary on MS Edge behavior and try to fix

* #8206: add more comments on playwright issues

* Work around msedge bugs

* fix snapshots

* wip

* fix snapshots

* always reopen sidebar

* wip

* fix e2e flakiness with deleting mods cleanup

* lint fix

* skip iframe link test in linux

* fix os check

* fix os check

* fix osname check

---------

Co-authored-by: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Co-authored-by: Graham Langford <30706330+grahamlangford@users.noreply.github.com>
Co-authored-by: Eduardo <eduardo@pixiebrix.com>
  • Loading branch information
4 people authored May 15, 2024
1 parent 5e76596 commit 8a67ea8
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 2 deletions.
190 changes: 190 additions & 0 deletions end-to-end-tests/tests/regressions/sidebarLinks.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { test, expect } from "../../fixtures/extensionBase";
import { ActivateModPage } from "../../pageObjects/extensionConsole/modsPage";
import {
type BrowserContext,
type Locator,
type Page,
// @ts-expect-error -- https://youtrack.jetbrains.com/issue/AQUA-711/Provide-a-run-configuration-for-Playwright-tests-in-specs-with-fixture-imports-only
test as base,
} from "@playwright/test";
import { ensureVisibility, getBrowserOs, getSidebarPage } from "../../utils";
import { getBaseExtensionConsoleUrl } from "../../pageObjects/constants";
import { MV } from "../../env";

async function openSidebar(page: Page, extensionId: string) {
// The mod contains a trigger to open the sidebar on h1. If the sidePanel is already open, it's a NOP
await page.click("h1");

const sideBarPage = await getSidebarPage(page, extensionId);

await expect(
sideBarPage.getByRole("heading", { name: "Sidebar Links" }),
).toBeVisible();

return sideBarPage;
}

async function reopenSidebar(page: Page, extensionId: string) {
await page.bringToFront();
// eslint-disable-next-line playwright/no-wait-for-timeout -- if we try to reopen to quickly, the sidebar does not respond in time since it was just closed
await page.waitForTimeout(500);
return openSidebar(page, extensionId);
}

async function clickLinkInSidebarAndWaitForPage(
context: BrowserContext,
locator: Locator,
chromiumChannel: string,
) {
const pagePromise = context.waitForEvent("page");
if (chromiumChannel === "msedge") {
// On MS Edge, opening a new tab closes the sidebar. The click steps fail because MS Edge closes the sidebar when the new tab is opened
// Error: locator.click: Target page, context or browser has been closed.
// Even though it errors, the link is still opened in a new tab.
// See https://github.com/w3c/webextensions/issues/588.
await expect(async () => locator.click()).not.toPass({
timeout: 3000,
});
} else {
await locator.click();
}

return pagePromise;
}

test("#8206: clicking links from the sidebar doesn't crash browser", async ({
page,
context,
extensionId,
chromiumChannel,
baseURL,
}) => {
test.skip(MV === "2", "MV3 specific test");

const browserOSName = await getBrowserOs(page);
const modId = "@pixies/test/sidebar-links";
const modActivationPage = new ActivateModPage(page, extensionId, modId);
await modActivationPage.goto();
await modActivationPage.clickActivateAndWaitForModsPageRedirect();

await page.goto("/");
// On MS Edge, and in Linux (both chrome and Edge) opening a new tab closes the sidebar,
// so we have to re-open it on the page after clicking each link
// See https://github.com/w3c/webextensions/issues/588.
let sideBarPage = await openSidebar(page, extensionId);

await test.step("Clicking extension console link", async () => {
const extensionConsolePage = await clickLinkInSidebarAndWaitForPage(
context,
sideBarPage.getByRole("link", { name: "Open Extension Console" }),
chromiumChannel,
);

expect(extensionConsolePage.url()).toContain(
getBaseExtensionConsoleUrl(extensionId),
);

// eslint-disable-next-line playwright/no-conditional-in-test -- msedge bug
if (chromiumChannel === "msedge") {
// Another msedge bug causes the browser to fail to open the extension console page from the sidebar until you refresh the page.
// "Error: This script should only be loaded in a browser extension."
await extensionConsolePage.reload();
}

const activeModsHeading = extensionConsolePage.getByRole("heading", {
name: "Active Mods",
});
// `activeModsHeading` may be initially be detached and hidden, so toBeVisible() would immediately fail
await ensureVisibility(activeModsHeading, { timeout: 10_000 });
});

await test.step("Clicking markdown text link", async () => {
// eslint-disable-next-line playwright/no-conditional-in-test -- msedge and linux bug that causes the sidebar to close on clicking a link
if (browserOSName === "Linux" || chromiumChannel === "msedge") {
sideBarPage = await reopenSidebar(page, extensionId);
}

const markdownTextLinkPage = await clickLinkInSidebarAndWaitForPage(
context,
sideBarPage.getByRole("link", { name: "Markdown Text Link" }),
chromiumChannel,
);
expect(markdownTextLinkPage.url()).toBe(`${baseURL}/bootstrap-5/`);
});

await test.step("Clicking react bootstrap link", async () => {
// eslint-disable-next-line playwright/no-conditional-in-test -- msedge/linux bug
if (browserOSName === "Linux" || chromiumChannel === "msedge") {
sideBarPage = await reopenSidebar(page, extensionId);
}

const reactBootstrapLinkPage = await clickLinkInSidebarAndWaitForPage(
context,
sideBarPage.getByRole("button", { name: "Open a Tab Link" }),
chromiumChannel,
);
expect(reactBootstrapLinkPage.url()).toBe(`${baseURL}/bootstrap-5/#gamma`);
});

await test.step("Clicking html renderer link", async () => {
// eslint-disable-next-line playwright/no-conditional-in-test -- msedge/linux bug
if (browserOSName === "Linux" || chromiumChannel === "msedge") {
sideBarPage = await reopenSidebar(page, extensionId);
}

const htmlRendererLinkPage = await clickLinkInSidebarAndWaitForPage(
context,
sideBarPage.getByRole("link", { name: "HTML Renderer Link" }),
chromiumChannel,
);
expect(htmlRendererLinkPage.url()).toBe(`${baseURL}/bootstrap-5/`);
});

await test.step("Clicking embedded form link", async () => {
// eslint-disable-next-line playwright/no-conditional-in-test -- msedge/linux bug
if (browserOSName === "Linux" || chromiumChannel === "msedge") {
sideBarPage = await reopenSidebar(page, extensionId);
}

const embeddedFormLinkPage = await clickLinkInSidebarAndWaitForPage(
context,
sideBarPage.getByRole("link", { name: "Embedded Form Link" }),
chromiumChannel,
);
expect(embeddedFormLinkPage.url()).toBe(`${baseURL}/bootstrap-5/#beta`);
});

// Clicking link in IFrame will crash MS Edge until the issue is fixed
// https://github.com/microsoft/MicrosoftEdge-Extensions/issues/145
// For some reason this also happens in Chrome/Linux in the CI github workflow.
// eslint-disable-next-line playwright/no-conditional-in-test -- see above comment
if (browserOSName !== "Linux" && chromiumChannel !== "msedge") {
await test.step("Clicking link in IFrame", async () => {
// PixieBrix uses 2 layers of frames to get around the host page CSP. Test page has 2 layers
const pixiebrixFrame = sideBarPage.frameLocator("iframe").first();
const mainFrame = pixiebrixFrame.frameLocator("iframe").first();
// eslint-disable-next-line playwright/no-conditional-expect -- see above
await expect(mainFrame.getByText("Alpha")).toBeVisible();

const srcdocFrame = mainFrame.frameLocator("iframe").first();
await srcdocFrame.getByRole("link", { name: "IFrame Link" }).click();
});
}
});
6 changes: 4 additions & 2 deletions end-to-end-tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,13 @@ export async function clickAndWaitForNewPage(
return pagePromise;
}

type OSName = "Windows" | "MacOS" | "Unix" | "Linux" | "Unknown";

// Temporary workaround for determining which modifiers to use for keyboard shortcuts
// A permanent fix has been merged but not released
// See: https://github.com/microsoft/playwright/pull/30572
export async function getBrowserOs(page: Page): Promise<string> {
let OSName = "";
export async function getBrowserOs(page: Page): Promise<OSName> {
let OSName: OSName = "Unknown";

const response = String(await page.evaluate(() => navigator.userAgent));

Expand Down
1 change: 1 addition & 0 deletions src/sidebar/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ const Header: React.FunctionComponent = () => {
size="sm"
variant="link"
className={headerButtonClassName}
title="Open Extension Console"
>
<FontAwesomeIcon icon={faCog} />
</Button>
Expand Down
2 changes: 2 additions & 0 deletions src/sidebar/__snapshots__/Header.test.tsx.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/sidebar/__snapshots__/SidebarBody.test.tsx.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8a67ea8

Please sign in to comment.