diff --git a/site/e2e/api.ts b/site/e2e/api.ts index 201a899df5a26..96a2e37260767 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 9418735e22fa1..488ccfec58fb5 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 0a93e049da33f..38a00134800f4 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 bf9681ed43d5d..2b8c4d2287cb2 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 ea55bf398e7df..457d1eed745ca 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 f39a2d475804e..f6817e0fd423d 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 9682fcb5751dc..384c96afcfaac 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 b99cea3ec2818..cd12f7507c1ac 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(); +}); + +test("inspecting and filtering audit logs", async ({ page }) => { + requiresLicense(); - const startedWorkspaceMessage = `${userName} started workspace ${workspaceName}`; - const loginMessage = `${userName} logged in`; + // 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 7d6bffd77fc2a..c2b129c632cb3 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 e4aa5fa1fe832..260a094bcfc93 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("experiments", async ({ page }) => { +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); await setupApiCalls(page); +}); +test("experiments", async ({ 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 6db2955edba97..5743fd83f49e9 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 c0082ed99a7ae..734fedea91058 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 c2c6f0f1c9cf3..d4898ea3e8c13 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("enabled network settings", async ({ page }) => { +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); await setupApiCalls(page); +}); + +test("enabled network settings", async ({ 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 f252fd3784bac..b15f192a241d7 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("enabled observability settings", async ({ page }) => { +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); await setupApiCalls(page); +}); + +test("enabled observability settings", async ({ 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 b9c202a648232..2d8bb0032691b 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("enabled security settings", async ({ page }) => { +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); await setupApiCalls(page); +}); + +test("enabled security settings", async ({ 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 11d8fc5bcc76a..1f97ce90dfac4 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("login with OIDC", async ({ page }) => { +test.beforeEach(async ({ page }) => { + beforeCoderTest(page); + await login(page); await setupApiCalls(page); +}); + +test("login with OIDC", async ({ 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 0e6edd544cc60..f12cd23565978 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 bb882dfcdd2db..be86c0757286b 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 5ef18992f38a8..5b70e8910dc55 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 5524589a1bea8..049049265d5ae 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 3d770a5f1cf08..fbfb775c5b950 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 ef88280a1836a..06d13fd0dfccf 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 0b0f5fa048363..3b5727cc42dba 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 0a049191b97df..c4ef61a3eddeb 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 a761f7c723132..de20ebd9778e7 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 8d26020618643..c7ea60e64eb14 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 99f8801de8141..a9e49c0921740 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 422074d92e341..e5eefd5eb9712 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 3470367c63546..8b80c4f158e7c 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 ec69d1adfc104..6defbe10f40dd 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 ee8301557ed24..3c4d7e2341611 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 55cbfae6f5460..87fc7e5a104cf 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 20396a6ac17eb..ec6006a81dac5 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 f414d26b74bc8..c44d64b39c13c 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 fc6baec7daa67..a4923d7684e31 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 4bb052b4e8bbb..4bf9b26bb205e 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 372e9573fe9be..ce1898a31049a 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 36fbb6bc9a6c8..b65fa95208239 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 684525130fa85..d22c8f4f3457e 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 8018856495c40..1db623164699c 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,