From c5367c201b287918db7a90f827e22405bb5fefa6 Mon Sep 17 00:00:00 2001 From: Kayla Washburn-Love Date: Thu, 11 Apr 2024 15:48:53 -0600 Subject: [PATCH] test: fix url checks in e2e tests (#12881) --- site/e2e/expectUrl.ts | 29 +++++++++++++++ site/e2e/global.setup.ts | 3 +- site/e2e/helpers.ts | 37 ++++++++++--------- site/e2e/tests/updateTemplate.spec.ts | 5 ++- .../pages/CreateTokenPage/CreateTokenForm.tsx | 1 + 5 files changed, 54 insertions(+), 21 deletions(-) create mode 100644 site/e2e/expectUrl.ts diff --git a/site/e2e/expectUrl.ts b/site/e2e/expectUrl.ts new file mode 100644 index 0000000000..eb3777f577 --- /dev/null +++ b/site/e2e/expectUrl.ts @@ -0,0 +1,29 @@ +import { expect, type Page } from "@playwright/test"; + +type PollingOptions = { timeout?: number; intervals?: number[] }; + +export const expectUrl = expect.extend({ + /** + * toHavePathName is an alternative to `toHaveURL` that won't fail if the URL contains query parameters. + */ + async toHavePathName(page: Page, expected: string, options?: PollingOptions) { + let actual: string = new URL(page.url()).pathname; + let pass: boolean; + try { + await expect + .poll(() => (actual = new URL(page.url()).pathname), options) + .toBe(expected); + pass = true; + } catch { + pass = false; + } + + return { + name: "toHavePathName", + pass, + actual, + expected, + message: () => "The page does not have the expected URL pathname.", + }; + }, +}); diff --git a/site/e2e/global.setup.ts b/site/e2e/global.setup.ts index b99c461308..8c8526af9a 100644 --- a/site/e2e/global.setup.ts +++ b/site/e2e/global.setup.ts @@ -3,6 +3,7 @@ import { hasFirstUser } from "api/api"; import { Language } from "pages/CreateUserPage/CreateUserForm"; import { setupApiCalls } from "./api"; import * as constants from "./constants"; +import { expectUrl } from "./expectUrl"; import { storageState } from "./playwright.config"; test("setup deployment", async ({ page }) => { @@ -21,7 +22,7 @@ test("setup deployment", async ({ page }) => { await page.getByLabel(Language.passwordLabel).fill(constants.password); await page.getByTestId("create").click(); - await expect(page).toHaveURL(/\/workspaces.*/); + await expectUrl(page).toHavePathName("/workspaces"); await page.context().storageState({ path: storageState }); await page.getByTestId("button-select-template").isVisible(); diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 040bcb6d55..05ce694a97 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -20,6 +20,7 @@ import { prometheusPort, requireEnterpriseTests, } from "./constants"; +import { expectUrl } from "./expectUrl"; import { Agent, type App, @@ -49,10 +50,10 @@ export const createWorkspace = async ( richParameters: RichParameter[] = [], buildParameters: WorkspaceBuildParameter[] = [], ): Promise => { - await page.goto("/templates/" + templateName + "/workspace", { + await page.goto(`/templates/${templateName}/workspace`, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL("/templates/" + templateName + "/workspace"); + await expectUrl(page).toHavePathName(`/templates/${templateName}/workspace`); const name = randomName(); await page.getByLabel("name").fill(name); @@ -60,9 +61,7 @@ export const createWorkspace = async ( await fillParameters(page, richParameters, buildParameters); await page.getByTestId("form-submit").click(); - // Workaround: OutdatedAgent lands at "http://localhost:3111/@admin/8d6225b7?resources=echo_dev" - // and this is also a correct location. - await page.waitForURL(new RegExp("/@admin/" + name)); + await expectUrl(page).toHavePathName("/@admin/" + name); await page.waitForSelector("*[data-testid='build-status'] >> text=Running", { state: "visible", @@ -79,8 +78,8 @@ export const verifyParameters = async ( await page.goto("/@admin/" + workspaceName + "/settings/parameters", { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL( - "/@admin/" + workspaceName + "/settings/parameters", + await expectUrl(page).toHavePathName( + `/@admin/${workspaceName}/settings/parameters`, ); for (const buildParameter of expectedBuildParameters) { @@ -141,7 +140,7 @@ export const createTemplate = async ( }); await page.goto("/templates/new", { waitUntil: "domcontentloaded" }); - await expect(page).toHaveURL("/templates/new"); + await expectUrl(page).toHavePathName("/templates/new"); await page.getByTestId("file-upload").setInputFiles({ buffer: await createTemplateVersionTar(responses), @@ -151,7 +150,7 @@ export const createTemplate = async ( const name = randomName(); await page.getByLabel("Name *").fill(name); await page.getByTestId("form-submit").click(); - await expect(page).toHaveURL(`/templates/${name}/files`, { + await expectUrl(page).toHavePathName(`/templates/${name}/files`, { timeout: 30000, }); return name; @@ -161,7 +160,7 @@ export const createTemplate = async ( // random name. export const createGroup = async (page: Page): Promise => { await page.goto("/groups/create", { waitUntil: "domcontentloaded" }); - await expect(page).toHaveURL("/groups/create"); + await expectUrl(page).toHavePathName("/groups/create"); const name = randomName(); await page.getByLabel("Name", { exact: true }).fill(name); @@ -222,7 +221,7 @@ export const stopWorkspace = async (page: Page, workspaceName: string) => { await page.goto("/@admin/" + workspaceName, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL("/@admin/" + workspaceName); + await expectUrl(page).toHavePathName(`/@admin/${workspaceName}`); await page.getByTestId("workspace-stop-button").click(); @@ -241,7 +240,7 @@ export const buildWorkspaceWithParameters = async ( await page.goto("/@admin/" + workspaceName, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL("/@admin/" + workspaceName); + await expectUrl(page).toHavePathName(`/@admin/${workspaceName}`); await page.getByTestId("build-parameters-button").click(); @@ -753,7 +752,7 @@ export const updateTemplateSettings = async ( await page.goto(`/templates/${templateName}/settings`, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL(`/templates/${templateName}/settings`); + await expectUrl(page).toHavePathName(`/templates/${templateName}/settings`); for (const [key, value] of Object.entries(templateSettingValues)) { // Skip max_port_share_level for now since the frontend is not yet able to handle it @@ -767,7 +766,7 @@ export const updateTemplateSettings = async ( await page.getByTestId("form-submit").click(); const name = templateSettingValues.name ?? templateName; - await expect(page).toHaveURL(`/templates/${name}`); + await expectUrl(page).toHavePathName(`/templates/${name}`); }; export const updateWorkspace = async ( @@ -779,7 +778,7 @@ export const updateWorkspace = async ( await page.goto("/@admin/" + workspaceName, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL("/@admin/" + workspaceName); + await expectUrl(page).toHavePathName(`/@admin/${workspaceName}`); await page.getByTestId("workspace-update-button").click(); await page.getByTestId("confirm-button").click(); @@ -801,8 +800,8 @@ export const updateWorkspaceParameters = async ( await page.goto("/@admin/" + workspaceName + "/settings/parameters", { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL( - "/@admin/" + workspaceName + "/settings/parameters", + await expectUrl(page).toHavePathName( + `/@admin/${workspaceName}/settings/parameters`, ); await fillParameters(page, richParameters, buildParameters); @@ -827,7 +826,9 @@ export async function openTerminalWindow( // Specify that the shell should be `bash`, to prevent inheriting a shell that // isn't POSIX compatible, such as Fish. const commandQuery = `?command=${encodeURIComponent("/usr/bin/env bash")}`; - await expect(terminal).toHaveURL(`/@admin/${workspaceName}.dev/terminal`); + await expectUrl(terminal).toHavePathName( + `/@admin/${workspaceName}.dev/terminal`, + ); await terminal.goto(`/@admin/${workspaceName}.dev/terminal${commandQuery}`); return terminal; diff --git a/site/e2e/tests/updateTemplate.spec.ts b/site/e2e/tests/updateTemplate.spec.ts index 95182ca19e..4e967b2947 100644 --- a/site/e2e/tests/updateTemplate.spec.ts +++ b/site/e2e/tests/updateTemplate.spec.ts @@ -1,4 +1,5 @@ import { expect, test } from "@playwright/test"; +import { expectUrl } from "../expectUrl"; import { createGroup, createTemplate, @@ -25,7 +26,7 @@ test("add and remove a group", async ({ page }) => { await page.goto(`/templates/${templateName}/settings/permissions`, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL( + await expectUrl(page).toHavePathName( `/templates/${templateName}/settings/permissions`, ); @@ -55,7 +56,7 @@ test("require latest version", async ({ page }) => { await page.goto(`/templates/${templateName}/settings`, { waitUntil: "domcontentloaded", }); - await expect(page).toHaveURL(`/templates/${templateName}/settings`); + await expectUrl(page).toHavePathName(`/templates/${templateName}/settings`); let checkbox = await page.waitForSelector("#require_active_version"); await checkbox.click(); await page.getByTestId("form-submit").click(); diff --git a/site/src/pages/CreateTokenPage/CreateTokenForm.tsx b/site/src/pages/CreateTokenPage/CreateTokenForm.tsx index d679e8f812..15af6174cb 100644 --- a/site/src/pages/CreateTokenPage/CreateTokenForm.tsx +++ b/site/src/pages/CreateTokenPage/CreateTokenForm.tsx @@ -116,6 +116,7 @@ export const CreateTokenForm: FC = ({ {lifetimeDays === "custom" && (