From 962608cde0b7ceb8b3e6145eb102c5d56aa9fcd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=B1=E3=82=A4=E3=83=A9?= Date: Thu, 19 Dec 2024 15:16:34 -0800 Subject: [PATCH] chore: allow signing in as non-admin users in e2e tests (#15892) Closes coder/internal#168 Gets rid of the "global state" authentication, and adds a `login` helper which should be called at the beginning of each test. This means that not every test needs to authenticated as admin, and we can even have tests that encompass multiple permission levels. We also now create more than just the single admin user during setup, so that we can have a set of users to pick from as appropriate. --- site/e2e/api.ts | 9 +- site/e2e/constants.ts | 27 +++++- site/e2e/helpers.ts | 95 ++++++++++++++++--- site/e2e/hooks.ts | 2 +- site/e2e/playwright.config.ts | 8 +- .../createUsers.spec.ts} | 36 ++++--- site/e2e/tests/app.spec.ts | 6 +- site/e2e/tests/auditLogs.spec.ts | 88 +++++++++++++---- site/e2e/tests/deployment/appearance.spec.ts | 8 +- site/e2e/tests/deployment/general.spec.ts | 10 +- site/e2e/tests/deployment/idpOrgSync.spec.ts | 13 +-- site/e2e/tests/deployment/licenses.spec.ts | 8 +- site/e2e/tests/deployment/network.spec.ts | 9 +- .../tests/deployment/observability.spec.ts | 9 +- site/e2e/tests/deployment/security.spec.ts | 9 +- site/e2e/tests/deployment/userAuth.spec.ts | 9 +- .../tests/deployment/workspaceProxies.spec.ts | 7 ++ site/e2e/tests/externalAuth.spec.ts | 11 ++- site/e2e/tests/groups/addMembers.spec.ts | 9 +- .../groups/addUsersToDefaultGroup.spec.ts | 6 +- site/e2e/tests/groups/createGroup.spec.ts | 7 +- site/e2e/tests/groups/removeGroup.spec.ts | 9 +- site/e2e/tests/groups/removeMember.spec.ts | 9 +- site/e2e/tests/organizationGroups.spec.ts | 5 +- site/e2e/tests/organizationMembers.spec.ts | 10 +- site/e2e/tests/organizations.spec.ts | 5 +- .../customRoles/customRoles.spec.ts | 13 +-- site/e2e/tests/outdatedAgent.spec.ts | 6 +- site/e2e/tests/outdatedCLI.spec.ts | 6 +- .../e2e/tests/templates/listTemplates.spec.ts | 6 +- .../templates/updateTemplateSchedule.spec.ts | 8 +- site/e2e/tests/updateTemplate.spec.ts | 10 +- .../users/createUserWithPassword.spec.ts | 6 +- site/e2e/tests/users/removeUser.spec.ts | 8 +- site/e2e/tests/webTerminal.spec.ts | 10 +- .../workspaces/autoCreateWorkspace.spec.ts | 43 +++++---- .../tests/workspaces/createWorkspace.spec.ts | 28 +++--- .../tests/workspaces/restartWorkspace.spec.ts | 6 +- .../tests/workspaces/startWorkspace.spec.ts | 6 +- .../tests/workspaces/updateWorkspace.spec.ts | 6 +- 40 files changed, 430 insertions(+), 156 deletions(-) rename site/e2e/{global.setup.ts => setup/createUsers.spec.ts} (55%) diff --git a/site/e2e/api.ts b/site/e2e/api.ts index 201a899df5..96a2e37260 100644 --- a/site/e2e/api.ts +++ b/site/e2e/api.ts @@ -9,14 +9,9 @@ import { findSessionToken, randomName } from "./helpers"; let currentOrgId: string; export const setupApiCalls = async (page: Page) => { - try { - const token = await findSessionToken(page); - API.setSessionToken(token); - } catch { - // If this fails, we have an unauthenticated client. - } - API.setHost(`http://127.0.0.1:${coderPort}`); + const token = await findSessionToken(page); + API.setSessionToken(token); }; export const getCurrentOrgId = async (): Promise => { diff --git a/site/e2e/constants.ts b/site/e2e/constants.ts index 9418735e22..488ccfec58 100644 --- a/site/e2e/constants.ts +++ b/site/e2e/constants.ts @@ -15,11 +15,30 @@ export const coderdPProfPort = 6062; // The name of the organization that should be used by default when needed. export const defaultOrganizationName = "coder"; +export const defaultPassword = "SomeSecurePassword!"; -// Credentials for the first user -export const username = "admin"; -export const password = "SomeSecurePassword!"; -export const email = "admin@coder.com"; +// Credentials for users +export const users = { + admin: { + username: "admin", + password: defaultPassword, + email: "admin@coder.com", + }, + auditor: { + username: "auditor", + password: defaultPassword, + email: "auditor@coder.com", + roles: ["Template Admin", "Auditor"], + }, + user: { + username: "user", + password: defaultPassword, + email: "user@coder.com", + }, +} satisfies Record< + string, + { username: string; password: string; email: string; roles?: string[] } +>; export const gitAuth = { deviceProvider: "device", diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 0a93e049da..38a0013480 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -1,6 +1,5 @@ import { type ChildProcess, exec, spawn } from "node:child_process"; import { randomUUID } from "node:crypto"; -import * as fs from "node:fs"; import net from "node:net"; import path from "node:path"; import { Duplex } from "node:stream"; @@ -19,10 +18,12 @@ import { coderMain, coderPort, defaultOrganizationName, + defaultPassword, license, premiumTestsRequired, prometheusPort, requireTerraformTests, + users, } from "./constants"; import { expectUrl } from "./expectUrl"; import { @@ -60,28 +61,75 @@ export function requireTerraformProvisioner() { test.skip(!requireTerraformTests); } +type LoginOptions = { + username: string; + email: string; + password: string; +}; + +export async function login(page: Page, options: LoginOptions = users.admin) { + const ctx = page.context(); + // biome-ignore lint/suspicious/noExplicitAny: reset the current user + (ctx as any)[Symbol.for("currentUser")] = undefined; + await ctx.clearCookies(); + await page.goto("/login"); + await page.getByLabel("Email").fill(options.email); + await page.getByLabel("Password").fill(options.password); + await page.getByRole("button", { name: "Sign In" }).click(); + await expectUrl(page).toHavePathName("/workspaces"); + // biome-ignore lint/suspicious/noExplicitAny: update once logged in + (ctx as any)[Symbol.for("currentUser")] = options; +} + +export function currentUser(page: Page): LoginOptions { + const ctx = page.context(); + // biome-ignore lint/suspicious/noExplicitAny: get the current user + const user = (ctx as any)[Symbol.for("currentUser")]; + + if (!user) { + throw new Error("page context does not have a user. did you call `login`?"); + } + + return user; +} + +type CreateWorkspaceOptions = { + richParameters?: RichParameter[]; + buildParameters?: WorkspaceBuildParameter[]; + useExternalAuth?: boolean; +}; + /** * createWorkspace creates a workspace for a template. It does not wait for it * to be running, but it does navigate to the page. */ export const createWorkspace = async ( page: Page, - templateName: string, - richParameters: RichParameter[] = [], - buildParameters: WorkspaceBuildParameter[] = [], - useExternalAuthProvider: string | undefined = undefined, + template: string | { organization: string; name: string }, + options: CreateWorkspaceOptions = {}, ): Promise => { - await page.goto(`/templates/${templateName}/workspace`, { + const { + richParameters = [], + buildParameters = [], + useExternalAuth, + } = options; + + const templatePath = + typeof template === "string" + ? template + : `${template.organization}/${template.name}`; + + await page.goto(`/templates/${templatePath}/workspace`, { waitUntil: "domcontentloaded", }); - await expectUrl(page).toHavePathName(`/templates/${templateName}/workspace`); + await expectUrl(page).toHavePathName(`/templates/${templatePath}/workspace`); const name = randomName(); await page.getByLabel("name").fill(name); await fillParameters(page, richParameters, buildParameters); - if (useExternalAuthProvider !== undefined) { + if (useExternalAuth) { // Create a new context for the popup which will be created when clicking the button const popupPromise = page.waitForEvent("popup"); @@ -101,7 +149,9 @@ export const createWorkspace = async ( await page.getByTestId("form-submit").click(); - await expectUrl(page).toHavePathName(`/@admin/${name}`); + const user = currentUser(page); + + await expectUrl(page).toHavePathName(`/@${user.username}/${name}`); await page.waitForSelector("[data-testid='build-status'] >> text=Running", { state: "visible", @@ -214,6 +264,12 @@ export const createTemplate = async ( const orgPicker = page.getByLabel("Belongs to *"); const organizationsEnabled = await orgPicker.isVisible(); if (organizationsEnabled) { + if (orgName !== defaultOrganizationName) { + throw new Error( + `No provisioners registered for ${orgName}, creating this template will fail`, + ); + } + await orgPicker.click(); await page.getByText(orgName, { exact: true }).click(); } @@ -659,8 +715,9 @@ const createTemplateVersionTar = async ( ); }; -export const randomName = () => { - return randomUUID().slice(0, 8); +export const randomName = (annotation?: string) => { + const base = randomUUID().slice(0, 8); + return annotation ? `${annotation}-${base}` : base; }; /** @@ -1002,6 +1059,7 @@ type UserValues = { username: string; email: string; password: string; + roles: string[]; }; export async function createUser( @@ -1019,7 +1077,8 @@ export async function createUser( const username = userValues.username ?? randomName(); const name = userValues.name ?? username; const email = userValues.email ?? `${username}@coder.com`; - const password = userValues.password || "s3cure&password!"; + const password = userValues.password || defaultPassword; + const roles = userValues.roles ?? []; await page.getByLabel("Username").fill(username); if (name) { @@ -1036,10 +1095,18 @@ export async function createUser( await expect(page.getByText("Successfully created user.")).toBeVisible(); await expect(page).toHaveTitle("Users - Coder"); - await expect(page.locator("tr", { hasText: email })).toBeVisible(); + const addedRow = page.locator("tr", { hasText: email }); + await expect(addedRow).toBeVisible(); + + // Give them a role + await addedRow.getByLabel("Edit user roles").click(); + for (const role of roles) { + await page.getByText(role, { exact: true }).click(); + } + await page.mouse.click(10, 10); // close the popover by clicking outside of it await page.goto(returnTo, { waitUntil: "domcontentloaded" }); - return { name, username, email, password }; + return { name, username, email, password, roles }; } export async function createOrganization(page: Page): Promise<{ diff --git a/site/e2e/hooks.ts b/site/e2e/hooks.ts index bf9681ed43..2b8c4d2287 100644 --- a/site/e2e/hooks.ts +++ b/site/e2e/hooks.ts @@ -2,7 +2,7 @@ import http from "node:http"; import type { BrowserContext, Page } from "@playwright/test"; import { coderPort, gitAuth } from "./constants"; -export const beforeCoderTest = async (page: Page) => { +export const beforeCoderTest = (page: Page) => { page.on("console", (msg) => console.info(`[onConsole] ${msg.text()}`)); page.on("request", (request) => { diff --git a/site/e2e/playwright.config.ts b/site/e2e/playwright.config.ts index ea55bf398e..457d1eed74 100644 --- a/site/e2e/playwright.config.ts +++ b/site/e2e/playwright.config.ts @@ -13,9 +13,6 @@ import { export const wsEndpoint = process.env.CODER_E2E_WS_ENDPOINT; -// This is where auth cookies are stored! -export const storageState = path.join(__dirname, ".auth.json"); - // If running terraform tests, verify the requirements exist in the // environment. // @@ -58,13 +55,12 @@ export default defineConfig({ projects: [ { name: "testsSetup", - testMatch: /global.setup\.ts/, + testMatch: /setup\/.*\.spec\.ts/, }, { name: "tests", - testMatch: /.*\.spec\.ts/, + testMatch: /tests\/.*\.spec\.ts/, dependencies: ["testsSetup"], - use: { storageState }, timeout: 30_000, }, ], diff --git a/site/e2e/global.setup.ts b/site/e2e/setup/createUsers.spec.ts similarity index 55% rename from site/e2e/global.setup.ts rename to site/e2e/setup/createUsers.spec.ts index f39a2d4758..f6817e0fd4 100644 --- a/site/e2e/global.setup.ts +++ b/site/e2e/setup/createUsers.spec.ts @@ -1,14 +1,13 @@ import { expect, test } from "@playwright/test"; import { API } 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"; +import { coderPort, license, premiumTestsRequired, users } from "../constants"; +import { expectUrl } from "../expectUrl"; +import { createUser } from "../helpers"; test("setup deployment", async ({ page }) => { await page.goto("/", { waitUntil: "domcontentloaded" }); - await setupApiCalls(page); + API.setHost(`http://127.0.0.1:${coderPort}`); const exists = await API.hasFirstUser(); // First user already exists, abort early. All tests execute this as a dependency, // if you run multiple tests in the UI, this will fail unless we check this. @@ -17,28 +16,35 @@ test("setup deployment", async ({ page }) => { } // Setup first user - await page.getByLabel(Language.usernameLabel).fill(constants.username); - await page.getByLabel(Language.emailLabel).fill(constants.email); - await page.getByLabel(Language.passwordLabel).fill(constants.password); + await page.getByLabel(Language.usernameLabel).fill(users.admin.username); + await page.getByLabel(Language.emailLabel).fill(users.admin.email); + await page.getByLabel(Language.passwordLabel).fill(users.admin.password); await page.getByTestId("create").click(); await expectUrl(page).toHavePathName("/workspaces"); - await page.context().storageState({ path: storageState }); - await page.getByTestId("button-select-template").isVisible(); + for (const user of Object.values(users)) { + // Already created as first user + if (user.username === "admin") { + continue; + } + + await createUser(page, user); + } + // Setup license - if (constants.premiumTestsRequired || constants.license) { + if (premiumTestsRequired || license) { // Make sure that we have something that looks like a real license - expect(constants.license).toBeTruthy(); - expect(constants.license.length).toBeGreaterThan(92); // the signature alone should be this long - expect(constants.license.split(".").length).toBe(3); // otherwise it's invalid + expect(license).toBeTruthy(); + expect(license.length).toBeGreaterThan(92); // the signature alone should be this long + expect(license.split(".").length).toBe(3); // otherwise it's invalid await page.goto("/deployment/licenses", { waitUntil: "domcontentloaded" }); await expect(page).toHaveTitle("License Settings - Coder"); await page.getByText("Add a license").click(); - await page.getByRole("textbox").fill(constants.license); + await page.getByRole("textbox").fill(license); await page.getByText("Upload License").click(); await expect( diff --git a/site/e2e/tests/app.spec.ts b/site/e2e/tests/app.spec.ts index 9682fcb575..384c96afcf 100644 --- a/site/e2e/tests/app.spec.ts +++ b/site/e2e/tests/app.spec.ts @@ -4,13 +4,17 @@ import { test } from "@playwright/test"; import { createTemplate, createWorkspace, + login, startAgent, stopAgent, stopWorkspace, } from "../helpers"; import { beforeCoderTest } from "../hooks"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("app", async ({ context, page }) => { test.setTimeout(75_000); diff --git a/site/e2e/tests/auditLogs.spec.ts b/site/e2e/tests/auditLogs.spec.ts index b99cea3ec2..cd12f7507c 100644 --- a/site/e2e/tests/auditLogs.spec.ts +++ b/site/e2e/tests/auditLogs.spec.ts @@ -1,13 +1,50 @@ -import { expect, test } from "@playwright/test"; -import { createTemplate, createWorkspace, requiresLicense } from "../helpers"; +import { type Page, expect, test } from "@playwright/test"; +import { users } from "../constants"; +import { + createTemplate, + createWorkspace, + currentUser, + login, + requiresLicense, +} from "../helpers"; import { beforeCoderTest } from "../hooks"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.describe.configure({ mode: "parallel" }); -test("inspecting and filtering audit logs", async ({ page }) => { +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page, users.auditor); +}); + +async function resetSearch(page: Page) { + const clearButton = page.getByLabel("Clear search"); + if (await clearButton.isVisible()) { + await clearButton.click(); + } + + // Filter by the auditor test user to prevent race conditions + const user = currentUser(page); + await expect(page.getByText("All users")).toBeVisible(); + await page.getByPlaceholder("Search...").fill(`username:${user.username}`); + await expect(page.getByText("All users")).not.toBeVisible(); +} + +test("logins are logged", async ({ page }) => { + requiresLicense(); + + // Go to the audit history + await page.goto("/audit"); + + const user = currentUser(page); + const loginMessage = `${user.username} logged in`; + // Make sure those things we did all actually show up + await resetSearch(page); + await expect(page.getByText(loginMessage).first()).toBeVisible(); +}); + +test("creating templates and workspaces is logged", async ({ page }) => { requiresLicense(); - const userName = "admin"; // Do some stuff that should show up in the audit logs const templateName = await createTemplate(page); const workspaceName = await createWorkspace(page, templateName); @@ -15,21 +52,23 @@ test("inspecting and filtering audit logs", async ({ page }) => { // Go to the audit history await page.goto("/audit"); + const user = currentUser(page); + // Make sure those things we did all actually show up - await expect(page.getByText(`${userName} logged in`)).toBeVisible(); + await resetSearch(page); await expect( - page.getByText(`${userName} created template ${templateName}`), + page.getByText(`${user.username} created template ${templateName}`), ).toBeVisible(); await expect( - page.getByText(`${userName} created workspace ${workspaceName}`), + page.getByText(`${user.username} created workspace ${workspaceName}`), ).toBeVisible(); await expect( - page.getByText(`${userName} started workspace ${workspaceName}`), + page.getByText(`${user.username} started workspace ${workspaceName}`), ).toBeVisible(); // Make sure we can inspect the details of the log item const createdWorkspace = page.locator(".MuiTableRow-root", { - hasText: `${userName} created workspace ${workspaceName}`, + hasText: `${user.username} created workspace ${workspaceName}`, }); await createdWorkspace.getByLabel("open-dropdown").click(); await expect( @@ -38,11 +77,24 @@ test("inspecting and filtering audit logs", async ({ page }) => { await expect( createdWorkspace.getByText(`name: "${workspaceName}"`), ).toBeVisible(); +}); - const startedWorkspaceMessage = `${userName} started workspace ${workspaceName}`; - const loginMessage = `${userName} logged in`; +test("inspecting and filtering audit logs", async ({ page }) => { + requiresLicense(); + + // Do some stuff that should show up in the audit logs + const templateName = await createTemplate(page); + const workspaceName = await createWorkspace(page, templateName); + + // Go to the audit history + await page.goto("/audit"); + + const user = currentUser(page); + const loginMessage = `${user.username} logged in`; + const startedWorkspaceMessage = `${user.username} started workspace ${workspaceName}`; // Filter by resource type + await resetSearch(page); await page.getByText("All resource types").click(); const workspaceBuildsOption = page.getByText("Workspace Build"); await workspaceBuildsOption.scrollIntoViewIfNeeded({ timeout: 5000 }); @@ -51,19 +103,15 @@ test("inspecting and filtering audit logs", async ({ page }) => { await expect(page.getByText(startedWorkspaceMessage)).toBeVisible(); // Logins should no longer be visible await expect(page.getByText(loginMessage)).not.toBeVisible(); - - // Clear filters, everything should be visible again await page.getByLabel("Clear search").click(); - await expect(page.getByText(startedWorkspaceMessage)).toBeVisible(); - await expect(page.getByText(loginMessage)).toBeVisible(); + await expect(page.getByText("All resource types")).toBeVisible(); // Filter by action type + await resetSearch(page); await page.getByText("All actions").click(); - const loginOption = page.getByText("Login"); - await loginOption.scrollIntoViewIfNeeded({ timeout: 5000 }); - await loginOption.click(); + await page.getByText("Login", { exact: true }).click(); // Logins should be visible - await expect(page.getByText(loginMessage)).toBeVisible(); + await expect(page.getByText(loginMessage).first()).toBeVisible(); // Our workspace build should no longer be visible await expect(page.getByText(startedWorkspaceMessage)).not.toBeVisible(); }); diff --git a/site/e2e/tests/deployment/appearance.spec.ts b/site/e2e/tests/deployment/appearance.spec.ts index 7d6bffd77f..c2b129c632 100644 --- a/site/e2e/tests/deployment/appearance.spec.ts +++ b/site/e2e/tests/deployment/appearance.spec.ts @@ -1,6 +1,12 @@ import { chromium, expect, test } from "@playwright/test"; import { expectUrl } from "../../expectUrl"; -import { randomName, requiresLicense } from "../../helpers"; +import { login, randomName, requiresLicense } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("set application name", async ({ page }) => { requiresLicense(); diff --git a/site/e2e/tests/deployment/general.spec.ts b/site/e2e/tests/deployment/general.spec.ts index e4aa5fa1fe..260a094bcf 100644 --- a/site/e2e/tests/deployment/general.spec.ts +++ b/site/e2e/tests/deployment/general.spec.ts @@ -2,10 +2,16 @@ import { expect, test } from "@playwright/test"; import { API } from "api/api"; import { setupApiCalls } from "../../api"; import { e2eFakeExperiment1, e2eFakeExperiment2 } from "../../constants"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("experiments", async ({ page }) => { - await setupApiCalls(page); - // Load experiments from backend API const availableExperiments = await API.getAvailableExperiments(); diff --git a/site/e2e/tests/deployment/idpOrgSync.spec.ts b/site/e2e/tests/deployment/idpOrgSync.spec.ts index 6db2955edb..5743fd83f4 100644 --- a/site/e2e/tests/deployment/idpOrgSync.spec.ts +++ b/site/e2e/tests/deployment/idpOrgSync.spec.ts @@ -6,14 +6,18 @@ import { setupApiCalls, } from "../../api"; import { randomName, requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.describe("IdpOrgSyncPage", () => { - test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); +test.describe("IdpOrgSyncPage", () => { test("add new IdP organization mapping with API", async ({ page }) => { requiresLicense(); - await setupApiCalls(page); await createOrganizationSyncSettings(); @@ -38,7 +42,6 @@ test.describe("IdpOrgSyncPage", () => { test("delete a IdP org to coder org mapping row", async ({ page }) => { requiresLicense(); - await setupApiCalls(page); await createOrganizationSyncSettings(); await page.goto("/deployment/idp-org-sync", { waitUntil: "domcontentloaded", @@ -106,7 +109,6 @@ test.describe("IdpOrgSyncPage", () => { page, }) => { requiresLicense(); - await setupApiCalls(page); await page.goto("/deployment/idp-org-sync", { waitUntil: "domcontentloaded", @@ -121,7 +123,6 @@ test.describe("IdpOrgSyncPage", () => { test("add new IdP organization mapping with UI", async ({ page }) => { requiresLicense(); - await setupApiCalls(page); const orgName = randomName(); diff --git a/site/e2e/tests/deployment/licenses.spec.ts b/site/e2e/tests/deployment/licenses.spec.ts index c0082ed99a..734fedea91 100644 --- a/site/e2e/tests/deployment/licenses.spec.ts +++ b/site/e2e/tests/deployment/licenses.spec.ts @@ -1,5 +1,11 @@ import { expect, test } from "@playwright/test"; -import { requiresLicense } from "../../helpers"; +import { login, requiresLicense } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("license was added successfully", async ({ page }) => { requiresLicense(); diff --git a/site/e2e/tests/deployment/network.spec.ts b/site/e2e/tests/deployment/network.spec.ts index c2c6f0f1c9..d4898ea3e8 100644 --- a/site/e2e/tests/deployment/network.spec.ts +++ b/site/e2e/tests/deployment/network.spec.ts @@ -8,9 +8,16 @@ import { verifyConfigFlagNumber, verifyConfigFlagString, } from "../../api"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("enabled network settings", async ({ page }) => { - await setupApiCalls(page); const config = await API.getDeploymentConfig(); await page.goto("/deployment/network", { waitUntil: "domcontentloaded" }); diff --git a/site/e2e/tests/deployment/observability.spec.ts b/site/e2e/tests/deployment/observability.spec.ts index f252fd3784..b15f192a24 100644 --- a/site/e2e/tests/deployment/observability.spec.ts +++ b/site/e2e/tests/deployment/observability.spec.ts @@ -8,9 +8,16 @@ import { verifyConfigFlagEmpty, verifyConfigFlagString, } from "../../api"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("enabled observability settings", async ({ page }) => { - await setupApiCalls(page); const config = await API.getDeploymentConfig(); await page.goto("/deployment/observability", { diff --git a/site/e2e/tests/deployment/security.spec.ts b/site/e2e/tests/deployment/security.spec.ts index b9c202a648..2d8bb00326 100644 --- a/site/e2e/tests/deployment/security.spec.ts +++ b/site/e2e/tests/deployment/security.spec.ts @@ -8,9 +8,16 @@ import { verifyConfigFlagNumber, verifyConfigFlagString, } from "../../api"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("enabled security settings", async ({ page }) => { - await setupApiCalls(page); const config = await API.getDeploymentConfig(); await page.goto("/deployment/security", { waitUntil: "domcontentloaded" }); diff --git a/site/e2e/tests/deployment/userAuth.spec.ts b/site/e2e/tests/deployment/userAuth.spec.ts index 11d8fc5bcc..1f97ce90df 100644 --- a/site/e2e/tests/deployment/userAuth.spec.ts +++ b/site/e2e/tests/deployment/userAuth.spec.ts @@ -7,9 +7,16 @@ import { verifyConfigFlagEntries, verifyConfigFlagString, } from "../../api"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("login with OIDC", async ({ page }) => { - await setupApiCalls(page); const config = await API.getDeploymentConfig(); await page.goto("/deployment/userauth", { waitUntil: "domcontentloaded" }); diff --git a/site/e2e/tests/deployment/workspaceProxies.spec.ts b/site/e2e/tests/deployment/workspaceProxies.spec.ts index 0e6edd544c..f12cd23565 100644 --- a/site/e2e/tests/deployment/workspaceProxies.spec.ts +++ b/site/e2e/tests/deployment/workspaceProxies.spec.ts @@ -3,8 +3,15 @@ import { API } from "api/api"; import { setupApiCalls } from "../../api"; import { coderPort, workspaceProxyPort } from "../../constants"; import { randomName, requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; import { startWorkspaceProxy, stopWorkspaceProxy } from "../../proxy"; +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); + test("default proxy is online", async ({ page }) => { requiresLicense(); await setupApiCalls(page); diff --git a/site/e2e/tests/externalAuth.spec.ts b/site/e2e/tests/externalAuth.spec.ts index bb882dfcdd..be86c07572 100644 --- a/site/e2e/tests/externalAuth.spec.ts +++ b/site/e2e/tests/externalAuth.spec.ts @@ -8,6 +8,7 @@ import { createTemplate, createWorkspace, echoResponsesWithExternalAuth, + login, } from "../helpers"; import { beforeCoderTest, resetExternalAuthKey } from "../hooks"; @@ -31,9 +32,11 @@ test.beforeAll(async ({ baseURL }) => { }); }); -test.beforeEach(async ({ context }) => resetExternalAuthKey(context)); - -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ context, page }) => { + beforeCoderTest(page); + await login(page); + await resetExternalAuthKey(context); +}); // Ensures that a Git auth provider with the device flow functions and completes! test("external auth device", async ({ page }) => { @@ -101,7 +104,7 @@ test("successful external auth from workspace", async ({ page }) => { ]), ); - await createWorkspace(page, templateName, [], [], gitAuth.webProvider); + await createWorkspace(page, templateName, { useExternalAuth: true }); }); const ghUser: Endpoints["GET /user"]["response"]["data"] = { diff --git a/site/e2e/tests/groups/addMembers.spec.ts b/site/e2e/tests/groups/addMembers.spec.ts index 5ef18992f3..5b70e8910d 100644 --- a/site/e2e/tests/groups/addMembers.spec.ts +++ b/site/e2e/tests/groups/addMembers.spec.ts @@ -6,13 +6,18 @@ import { setupApiCalls, } from "../../api"; import { requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("add members", async ({ page, baseURL }) => { requiresLicense(); - await setupApiCalls(page); + const orgId = await getCurrentOrgId(); const group = await createGroup(orgId); const numberOfMembers = 3; diff --git a/site/e2e/tests/groups/addUsersToDefaultGroup.spec.ts b/site/e2e/tests/groups/addUsersToDefaultGroup.spec.ts index 5524589a1b..049049265d 100644 --- a/site/e2e/tests/groups/addUsersToDefaultGroup.spec.ts +++ b/site/e2e/tests/groups/addUsersToDefaultGroup.spec.ts @@ -1,9 +1,13 @@ import { expect, test } from "@playwright/test"; import { createUser, getCurrentOrgId, setupApiCalls } from "../../api"; import { requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); const DEFAULT_GROUP_NAME = "Everyone"; diff --git a/site/e2e/tests/groups/createGroup.spec.ts b/site/e2e/tests/groups/createGroup.spec.ts index 3d770a5f1c..fbfb775c5b 100644 --- a/site/e2e/tests/groups/createGroup.spec.ts +++ b/site/e2e/tests/groups/createGroup.spec.ts @@ -1,11 +1,16 @@ import { expect, test } from "@playwright/test"; import { randomName, requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("create group", async ({ page, baseURL }) => { requiresLicense(); + await page.goto(`${baseURL}/groups`, { waitUntil: "domcontentloaded" }); await expect(page).toHaveTitle("Groups - Coder"); diff --git a/site/e2e/tests/groups/removeGroup.spec.ts b/site/e2e/tests/groups/removeGroup.spec.ts index ef88280a18..06d13fd0df 100644 --- a/site/e2e/tests/groups/removeGroup.spec.ts +++ b/site/e2e/tests/groups/removeGroup.spec.ts @@ -1,13 +1,18 @@ import { expect, test } from "@playwright/test"; import { createGroup, getCurrentOrgId, setupApiCalls } from "../../api"; import { requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("remove group", async ({ page, baseURL }) => { requiresLicense(); - await setupApiCalls(page); + const orgId = await getCurrentOrgId(); const group = await createGroup(orgId); diff --git a/site/e2e/tests/groups/removeMember.spec.ts b/site/e2e/tests/groups/removeMember.spec.ts index 0b0f5fa048..3b5727cc42 100644 --- a/site/e2e/tests/groups/removeMember.spec.ts +++ b/site/e2e/tests/groups/removeMember.spec.ts @@ -7,13 +7,18 @@ import { setupApiCalls, } from "../../api"; import { requiresLicense } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("remove member", async ({ page, baseURL }) => { requiresLicense(); - await setupApiCalls(page); + const orgId = await getCurrentOrgId(); const [group, member] = await Promise.all([ createGroup(orgId), diff --git a/site/e2e/tests/organizationGroups.spec.ts b/site/e2e/tests/organizationGroups.spec.ts index 0a049191b9..c4ef61a3ed 100644 --- a/site/e2e/tests/organizationGroups.spec.ts +++ b/site/e2e/tests/organizationGroups.spec.ts @@ -6,11 +6,12 @@ import { setupApiCalls, } from "../api"; import { expectUrl } from "../expectUrl"; -import { randomName, requiresLicense } from "../helpers"; +import { login, randomName, requiresLicense } from "../helpers"; import { beforeCoderTest } from "../hooks"; test.beforeEach(async ({ page }) => { - await beforeCoderTest(page); + beforeCoderTest(page); + await login(page); await setupApiCalls(page); }); diff --git a/site/e2e/tests/organizationMembers.spec.ts b/site/e2e/tests/organizationMembers.spec.ts index a761f7c723..de20ebd977 100644 --- a/site/e2e/tests/organizationMembers.spec.ts +++ b/site/e2e/tests/organizationMembers.spec.ts @@ -1,10 +1,16 @@ import { expect, test } from "@playwright/test"; import { setupApiCalls } from "../api"; -import { createOrganization, createUser, requiresLicense } from "../helpers"; +import { + createOrganization, + createUser, + login, + requiresLicense, +} from "../helpers"; import { beforeCoderTest } from "../hooks"; test.beforeEach(async ({ page }) => { - await beforeCoderTest(page); + beforeCoderTest(page); + await login(page); await setupApiCalls(page); }); diff --git a/site/e2e/tests/organizations.spec.ts b/site/e2e/tests/organizations.spec.ts index 8d26020618..c7ea60e64e 100644 --- a/site/e2e/tests/organizations.spec.ts +++ b/site/e2e/tests/organizations.spec.ts @@ -1,11 +1,12 @@ import { expect, test } from "@playwright/test"; import { setupApiCalls } from "../api"; import { expectUrl } from "../expectUrl"; -import { randomName, requiresLicense } from "../helpers"; +import { login, randomName, requiresLicense } from "../helpers"; import { beforeCoderTest } from "../hooks"; test.beforeEach(async ({ page }) => { - await beforeCoderTest(page); + beforeCoderTest(page); + await login(page); await setupApiCalls(page); }); diff --git a/site/e2e/tests/organizations/customRoles/customRoles.spec.ts b/site/e2e/tests/organizations/customRoles/customRoles.spec.ts index 99f8801de8..a9e49c0921 100644 --- a/site/e2e/tests/organizations/customRoles/customRoles.spec.ts +++ b/site/e2e/tests/organizations/customRoles/customRoles.spec.ts @@ -6,17 +6,22 @@ import { setupApiCalls, } from "../../../api"; import { + login, randomName, requiresLicense, requiresUnlicensed, } from "../../../helpers"; import { beforeCoderTest } from "../../../hooks"; +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); + test.describe("CustomRolesPage", () => { - test.beforeEach(async ({ page }) => await beforeCoderTest(page)); + requiresLicense(); test("create custom role and cancel edit changes", async ({ page }) => { - requiresLicense(); await setupApiCalls(page); const org = await createOrganizationWithName(randomName()); @@ -50,7 +55,6 @@ test.describe("CustomRolesPage", () => { }); test("create custom role, edit role and save changes", async ({ page }) => { - requiresLicense(); await setupApiCalls(page); const org = await createOrganizationWithName(randomName()); @@ -101,7 +105,6 @@ test.describe("CustomRolesPage", () => { test("displays built-in role without edit/delete options", async ({ page, }) => { - requiresLicense(); await setupApiCalls(page); const org = await createOrganizationWithName(randomName()); @@ -122,7 +125,6 @@ test.describe("CustomRolesPage", () => { }); test("create custom role with UI", async ({ page }) => { - requiresLicense(); await setupApiCalls(page); const org = await createOrganizationWithName(randomName()); @@ -162,7 +164,6 @@ test.describe("CustomRolesPage", () => { }); test("delete custom role", async ({ page }) => { - requiresLicense(); await setupApiCalls(page); const org = await createOrganizationWithName(randomName()); diff --git a/site/e2e/tests/outdatedAgent.spec.ts b/site/e2e/tests/outdatedAgent.spec.ts index 422074d92e..e5eefd5eb9 100644 --- a/site/e2e/tests/outdatedAgent.spec.ts +++ b/site/e2e/tests/outdatedAgent.spec.ts @@ -4,6 +4,7 @@ import { createTemplate, createWorkspace, downloadCoderVersion, + login, sshIntoWorkspace, startAgentWithCommand, stopAgent, @@ -14,7 +15,10 @@ import { beforeCoderTest } from "../hooks"; // we no longer support versions w/o DRPC const agentVersion = "v2.12.1"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test(`ssh with agent ${agentVersion}`, async ({ page }) => { test.setTimeout(60_000); diff --git a/site/e2e/tests/outdatedCLI.spec.ts b/site/e2e/tests/outdatedCLI.spec.ts index 3470367c63..8b80c4f158 100644 --- a/site/e2e/tests/outdatedCLI.spec.ts +++ b/site/e2e/tests/outdatedCLI.spec.ts @@ -4,6 +4,7 @@ import { createTemplate, createWorkspace, downloadCoderVersion, + login, sshIntoWorkspace, startAgent, stopAgent, @@ -14,7 +15,10 @@ import { beforeCoderTest } from "../hooks"; // we no longer support versions prior to Tailnet v2 API support: https://github.com/coder/coder/commit/059e533544a0268acbc8831006b2858ead2f0d8e const clientVersion = "v2.8.0"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test(`ssh with client ${clientVersion}`, async ({ page }) => { test.setTimeout(60_000); diff --git a/site/e2e/tests/templates/listTemplates.spec.ts b/site/e2e/tests/templates/listTemplates.spec.ts index ec69d1adfc..6defbe10f4 100644 --- a/site/e2e/tests/templates/listTemplates.spec.ts +++ b/site/e2e/tests/templates/listTemplates.spec.ts @@ -1,7 +1,11 @@ import { expect, test } from "@playwright/test"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("list templates", async ({ page, baseURL }) => { await page.goto(`${baseURL}/templates`, { waitUntil: "domcontentloaded" }); diff --git a/site/e2e/tests/templates/updateTemplateSchedule.spec.ts b/site/e2e/tests/templates/updateTemplateSchedule.spec.ts index ee8301557e..3c4d7e2341 100644 --- a/site/e2e/tests/templates/updateTemplateSchedule.spec.ts +++ b/site/e2e/tests/templates/updateTemplateSchedule.spec.ts @@ -1,15 +1,19 @@ import { expect, test } from "@playwright/test"; import { API } from "api/api"; import { getCurrentOrgId, setupApiCalls } from "../../api"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("update template schedule settings without override other settings", async ({ page, baseURL, }) => { - await setupApiCalls(page); const orgId = await getCurrentOrgId(); const templateVersion = await API.createTemplateVersion(orgId, { storage_method: "file" as const, diff --git a/site/e2e/tests/updateTemplate.spec.ts b/site/e2e/tests/updateTemplate.spec.ts index 55cbfae6f5..87fc7e5a10 100644 --- a/site/e2e/tests/updateTemplate.spec.ts +++ b/site/e2e/tests/updateTemplate.spec.ts @@ -7,9 +7,15 @@ import { requiresLicense, updateTemplateSettings, } from "../helpers"; +import { login } from "../helpers"; import { beforeCoderTest } from "../hooks"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.describe.configure({ mode: "parallel" }); + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("template update with new name redirects on successful submit", async ({ page, @@ -24,7 +30,7 @@ test("add and remove a group", async ({ page }) => { requiresLicense(); const orgName = defaultOrganizationName; - const templateName = await createTemplate(page, undefined, orgName); + const templateName = await createTemplate(page); const groupName = await createGroup(page); await page.goto( diff --git a/site/e2e/tests/users/createUserWithPassword.spec.ts b/site/e2e/tests/users/createUserWithPassword.spec.ts index 20396a6ac1..ec6006a81d 100644 --- a/site/e2e/tests/users/createUserWithPassword.spec.ts +++ b/site/e2e/tests/users/createUserWithPassword.spec.ts @@ -1,8 +1,12 @@ import { test } from "@playwright/test"; import { createUser } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("create user with password", async ({ page }) => { await createUser(page); diff --git a/site/e2e/tests/users/removeUser.spec.ts b/site/e2e/tests/users/removeUser.spec.ts index f414d26b74..c44d64b39c 100644 --- a/site/e2e/tests/users/removeUser.spec.ts +++ b/site/e2e/tests/users/removeUser.spec.ts @@ -1,11 +1,15 @@ import { expect, test } from "@playwright/test"; import { createUser, getCurrentOrgId, setupApiCalls } from "../../api"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; -test.beforeEach(async ({ page }) => await beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); + await setupApiCalls(page); +}); test("remove user", async ({ page, baseURL }) => { - await setupApiCalls(page); const orgId = await getCurrentOrgId(); const user = await createUser(orgId); diff --git a/site/e2e/tests/webTerminal.spec.ts b/site/e2e/tests/webTerminal.spec.ts index fc6baec7da..a4923d7684 100644 --- a/site/e2e/tests/webTerminal.spec.ts +++ b/site/e2e/tests/webTerminal.spec.ts @@ -7,9 +7,13 @@ import { startAgent, stopAgent, } from "../helpers"; +import { login } from "../helpers"; import { beforeCoderTest } from "../hooks"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("web terminal", async ({ context, page }) => { test.setTimeout(75_000); @@ -24,9 +28,7 @@ test("web terminal", async ({ context, page }) => { agents: [ { token, - displayApps: { - webTerminal: true, - }, + displayApps: { webTerminal: true }, order: 0, }, ], diff --git a/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts b/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts index 4bb052b4e8..4bf9b26bb2 100644 --- a/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts @@ -1,21 +1,38 @@ import { expect, test } from "@playwright/test"; -import { username } from "../../constants"; +import { users } from "../../constants"; import { createTemplate, createWorkspace, echoResponsesWithParameters, } from "../../helpers"; +import { login } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; import { emptyParameter } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -test("create workspace in auto mode", async ({ page }) => { +test.describe.configure({ mode: "parallel" }); + +let template!: string; + +test.beforeAll(async ({ browser }) => { + const page = await (await browser.newContext()).newPage(); + await login(page); + const richParameters: RichParameter[] = [ { ...emptyParameter, name: "repo", type: "string" }, ]; - const template = await createTemplate( + template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); +}); + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page, users.user); +}); + +test("create workspace in auto mode", async ({ page }) => { const name = "test-workspace"; await page.goto( `/templates/${template}/workspace?mode=auto¶m.repo=example&name=${name}`, @@ -23,19 +40,12 @@ test("create workspace in auto mode", async ({ page }) => { waitUntil: "domcontentloaded", }, ); - await expect(page).toHaveTitle(`${username}/${name} - Coder`); + await expect(page).toHaveTitle(`${users.user.username}/${name} - Coder`); }); test("use an existing workspace that matches the `match` parameter instead of creating a new one", async ({ page, }) => { - const richParameters: RichParameter[] = [ - { ...emptyParameter, name: "repo", type: "string" }, - ]; - const template = await createTemplate( - page, - echoResponsesWithParameters(richParameters), - ); const prevWorkspace = await createWorkspace(page, template); await page.goto( `/templates/${template}/workspace?mode=auto¶m.repo=example&name=new-name&match=name:${prevWorkspace}`, @@ -43,17 +53,12 @@ test("use an existing workspace that matches the `match` parameter instead of cr waitUntil: "domcontentloaded", }, ); - await expect(page).toHaveTitle(`${username}/${prevWorkspace} - Coder`); + await expect(page).toHaveTitle( + `${users.user.username}/${prevWorkspace} - Coder`, + ); }); test("show error if `match` parameter is invalid", async ({ page }) => { - const richParameters: RichParameter[] = [ - { ...emptyParameter, name: "repo", type: "string" }, - ]; - const template = await createTemplate( - page, - echoResponsesWithParameters(richParameters), - ); const prevWorkspace = await createWorkspace(page, template); await page.goto( `/templates/${template}/workspace?mode=auto¶m.repo=example&name=new-name&match=not-valid-query:${prevWorkspace}`, diff --git a/site/e2e/tests/workspaces/createWorkspace.spec.ts b/site/e2e/tests/workspaces/createWorkspace.spec.ts index 372e9573fe..ce1898a310 100644 --- a/site/e2e/tests/workspaces/createWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/createWorkspace.spec.ts @@ -8,6 +8,7 @@ import { requireTerraformProvisioner, verifyParameters, } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { fifthParameter, @@ -21,7 +22,12 @@ import { } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.describe.configure({ mode: "parallel" }); + +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("create workspace", async ({ page }) => { const template = await createTemplate(page, { @@ -88,12 +94,10 @@ test("create workspace with default and required parameters", async ({ page, echoResponsesWithParameters(richParameters), ); - const workspaceName = await createWorkspace( - page, - template, + const workspaceName = await createWorkspace(page, template, { richParameters, buildParameters, - ); + }); await verifyParameters(page, workspaceName, richParameters, [ // user values: ...buildParameters, @@ -120,12 +124,10 @@ test("create workspace and overwrite default parameters", async ({ page }) => { echoResponsesWithParameters(richParameters), ); - const workspaceName = await createWorkspace( - page, - template, + const workspaceName = await createWorkspace(page, template, { richParameters, buildParameters, - ); + }); await verifyParameters(page, workspaceName, richParameters, buildParameters); }); @@ -151,11 +153,9 @@ test("create workspace with disable_param search params", async ({ page }) => { await expect(page.getByLabel(/Second parameter/i)).toBeDisabled(); }); -test("create docker workspace", async ({ context, page }) => { - test.skip( - true, - "creating docker containers is currently leaky. They are not cleaned up when the tests are over.", - ); +// Creating docker containers is currently leaky. They are not cleaned up when +// the tests are over. +test.skip("create docker workspace", async ({ context, page }) => { requireTerraformProvisioner(); const template = await createTemplate(page, StarterTemplates.STARTER_DOCKER); diff --git a/site/e2e/tests/workspaces/restartWorkspace.spec.ts b/site/e2e/tests/workspaces/restartWorkspace.spec.ts index 36fbb6bc9a..b65fa95208 100644 --- a/site/e2e/tests/workspaces/restartWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/restartWorkspace.spec.ts @@ -6,11 +6,15 @@ import { echoResponsesWithParameters, verifyParameters, } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { firstBuildOption, secondBuildOption } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("restart workspace with ephemeral parameters", async ({ page }) => { const richParameters: RichParameter[] = [firstBuildOption, secondBuildOption]; diff --git a/site/e2e/tests/workspaces/startWorkspace.spec.ts b/site/e2e/tests/workspaces/startWorkspace.spec.ts index 684525130f..d22c8f4f34 100644 --- a/site/e2e/tests/workspaces/startWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/startWorkspace.spec.ts @@ -7,11 +7,15 @@ import { stopWorkspace, verifyParameters, } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { firstBuildOption, secondBuildOption } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("start workspace with ephemeral parameters", async ({ page }) => { const richParameters: RichParameter[] = [firstBuildOption, secondBuildOption]; diff --git a/site/e2e/tests/workspaces/updateWorkspace.spec.ts b/site/e2e/tests/workspaces/updateWorkspace.spec.ts index 8018856495..1db6231646 100644 --- a/site/e2e/tests/workspaces/updateWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/updateWorkspace.spec.ts @@ -8,6 +8,7 @@ import { updateWorkspaceParameters, verifyParameters, } from "../../helpers"; +import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { fifthParameter, @@ -18,7 +19,10 @@ import { } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -test.beforeEach(({ page }) => beforeCoderTest(page)); +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); +}); test("update workspace, new optional, immutable parameter added", async ({ page,