From 40a26e9420d38ee6133059ad9a6429588128f4dd Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Mon, 24 Feb 2025 21:11:27 +0000 Subject: [PATCH 1/4] chore: use tighter permissions in e2e workspace tests --- site/e2e/constants.ts | 12 ++++-- site/e2e/helpers.ts | 34 ++++++++--------- .../workspaces/autoCreateWorkspace.spec.ts | 8 ++-- .../tests/workspaces/createWorkspace.spec.ts | 37 +++++++++++-------- .../tests/workspaces/restartWorkspace.spec.ts | 5 ++- .../tests/workspaces/startWorkspace.spec.ts | 5 ++- .../tests/workspaces/updateWorkspace.spec.ts | 12 +++++- 7 files changed, 70 insertions(+), 43 deletions(-) diff --git a/site/e2e/constants.ts b/site/e2e/constants.ts index 4ec0048e691cb..4fcada0e6d15b 100644 --- a/site/e2e/constants.ts +++ b/site/e2e/constants.ts @@ -24,16 +24,22 @@ export const users = { password: defaultPassword, email: "admin@coder.com", }, + templateAdmin: { + username: "template-admin", + password: defaultPassword, + email: "templateadmin@coder.com", + roles: ["Template Admin"], + }, auditor: { username: "auditor", password: defaultPassword, email: "auditor@coder.com", roles: ["Template Admin", "Auditor"], }, - user: { - username: "user", + member: { + username: "member", password: defaultPassword, - email: "user@coder.com", + email: "member@coder.com", }, } satisfies Record< string, diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index a2f55ad2c86ff..5692909355fca 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -150,7 +150,6 @@ export const createWorkspace = async ( await page.getByRole("button", { name: /create workspace/i }).click(); const user = currentUser(page); - await expectUrl(page).toHavePathName(`/@${user.username}/${name}`); await page.waitForSelector("[data-testid='build-status'] >> text=Running", { @@ -165,12 +164,10 @@ export const verifyParameters = async ( richParameters: RichParameter[], expectedBuildParameters: WorkspaceBuildParameter[], ) => { - await page.goto(`/@admin/${workspaceName}/settings/parameters`, { + const user = currentUser(page); + await page.goto(`/@${user.username}/${workspaceName}/settings/parameters`, { waitUntil: "domcontentloaded", }); - await expectUrl(page).toHavePathName( - `/@admin/${workspaceName}/settings/parameters`, - ); for (const buildParameter of expectedBuildParameters) { const richParameter = richParameters.find( @@ -356,10 +353,10 @@ export const sshIntoWorkspace = async ( }; export const stopWorkspace = async (page: Page, workspaceName: string) => { - await page.goto(`/@admin/${workspaceName}`, { + const user = currentUser(page); + await page.goto(`/@${user.username}/${workspaceName}`, { waitUntil: "domcontentloaded", }); - await expectUrl(page).toHavePathName(`/@admin/${workspaceName}`); await page.getByTestId("workspace-stop-button").click(); @@ -375,10 +372,10 @@ export const buildWorkspaceWithParameters = async ( buildParameters: WorkspaceBuildParameter[] = [], confirm = false, ) => { - await page.goto(`/@admin/${workspaceName}`, { + const user = currentUser(page); + await page.goto(`/@${user.username}/${workspaceName}`, { waitUntil: "domcontentloaded", }); - await expectUrl(page).toHavePathName(`/@admin/${workspaceName}`); await page.getByTestId("build-parameters-button").click(); @@ -993,10 +990,10 @@ export const updateWorkspace = async ( richParameters: RichParameter[] = [], buildParameters: WorkspaceBuildParameter[] = [], ) => { - await page.goto(`/@admin/${workspaceName}`, { + const user = currentUser(page); + await page.goto(`/@${user.username}/${workspaceName}`, { waitUntil: "domcontentloaded", }); - await expectUrl(page).toHavePathName(`/@admin/${workspaceName}`); await page.getByTestId("workspace-update-button").click(); await page.getByTestId("confirm-button").click(); @@ -1015,12 +1012,10 @@ export const updateWorkspaceParameters = async ( richParameters: RichParameter[] = [], buildParameters: WorkspaceBuildParameter[] = [], ) => { - await page.goto(`/@admin/${workspaceName}/settings/parameters`, { + const user = currentUser(page); + await page.goto(`/@${user.username}/${workspaceName}/settings/parameters`, { waitUntil: "domcontentloaded", }); - await expectUrl(page).toHavePathName( - `/@admin/${workspaceName}/settings/parameters`, - ); await fillParameters(page, richParameters, buildParameters); await page.getByRole("button", { name: /submit and restart/i }).click(); @@ -1044,11 +1039,14 @@ export async function openTerminalWindow( // Specify that the shell should be `bash`, to prevent inheriting a shell that // isn't POSIX compatible, such as Fish. + const user = currentUser(page); const commandQuery = `?command=${encodeURIComponent("/usr/bin/env bash")}`; await expectUrl(terminal).toHavePathName( - `/@admin/${workspaceName}.${agentName}/terminal`, + `/@${user.username}/${workspaceName}.${agentName}/terminal`, + ); + await terminal.goto( + `/@${user.username}/${workspaceName}.${agentName}/terminal${commandQuery}`, ); - await terminal.goto(`/@admin/${workspaceName}.dev/terminal${commandQuery}`); return terminal; } @@ -1100,7 +1098,7 @@ export async function createUser( // 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.getByRole("group").getByText(role, { exact: true }).click(); } await page.mouse.click(10, 10); // close the popover by clicking outside of it diff --git a/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts b/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts index 4bf9b26bb205e..a6ec00958ad78 100644 --- a/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/autoCreateWorkspace.spec.ts @@ -16,7 +16,7 @@ let template!: string; test.beforeAll(async ({ browser }) => { const page = await (await browser.newContext()).newPage(); - await login(page); + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [ { ...emptyParameter, name: "repo", type: "string" }, @@ -29,7 +29,7 @@ test.beforeAll(async ({ browser }) => { test.beforeEach(async ({ page }) => { beforeCoderTest(page); - await login(page, users.user); + await login(page, users.member); }); test("create workspace in auto mode", async ({ page }) => { @@ -40,7 +40,7 @@ test("create workspace in auto mode", async ({ page }) => { waitUntil: "domcontentloaded", }, ); - await expect(page).toHaveTitle(`${users.user.username}/${name} - Coder`); + await expect(page).toHaveTitle(`${users.member.username}/${name} - Coder`); }); test("use an existing workspace that matches the `match` parameter instead of creating a new one", async ({ @@ -54,7 +54,7 @@ test("use an existing workspace that matches the `match` parameter instead of cr }, ); await expect(page).toHaveTitle( - `${users.user.username}/${prevWorkspace} - Coder`, + `${users.member.username}/${prevWorkspace} - Coder`, ); }); diff --git a/site/e2e/tests/workspaces/createWorkspace.spec.ts b/site/e2e/tests/workspaces/createWorkspace.spec.ts index ce1898a31049a..6ed7c3dd7cf65 100644 --- a/site/e2e/tests/workspaces/createWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/createWorkspace.spec.ts @@ -21,32 +21,26 @@ import { thirdParameter, } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; +import { users } from "../../constants"; test.describe.configure({ mode: "parallel" }); test.beforeEach(async ({ page }) => { beforeCoderTest(page); - await login(page); }); test("create workspace", async ({ page }) => { + await login(page, users.templateAdmin); const template = await createTemplate(page, { - apply: [ - { - apply: { - resources: [ - { - name: "example", - }, - ], - }, - }, - ], + apply: [{ apply: { resources: [{ name: "example" }] } }], }); + + await login(page, users.member); await createWorkspace(page, template); }); test("create workspace with default immutable parameters", async ({ page }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [ secondParameter, fourthParameter, @@ -56,6 +50,8 @@ test("create workspace with default immutable parameters", async ({ page }) => { page, echoResponsesWithParameters(richParameters), ); + + await login(page, users.member); const workspaceName = await createWorkspace(page, template); await verifyParameters(page, workspaceName, richParameters, [ { name: secondParameter.name, value: secondParameter.defaultValue }, @@ -65,11 +61,14 @@ test("create workspace with default immutable parameters", async ({ page }) => { }); test("create workspace with default mutable parameters", async ({ page }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [firstParameter, thirdParameter]; const template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); + + await login(page, users.member); const workspaceName = await createWorkspace(page, template); await verifyParameters(page, workspaceName, richParameters, [ { name: firstParameter.name, value: firstParameter.defaultValue }, @@ -80,6 +79,7 @@ test("create workspace with default mutable parameters", async ({ page }) => { test("create workspace with default and required parameters", async ({ page, }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [ secondParameter, fourthParameter, @@ -94,6 +94,8 @@ test("create workspace with default and required parameters", async ({ page, echoResponsesWithParameters(richParameters), ); + + await login(page, users.member); const workspaceName = await createWorkspace(page, template, { richParameters, buildParameters, @@ -108,6 +110,7 @@ test("create workspace with default and required parameters", async ({ }); test("create workspace and overwrite default parameters", async ({ page }) => { + await login(page, users.templateAdmin); // We use randParamName to prevent the new values from corrupting user_history // and thus affecting other tests. const richParameters: RichParameter[] = [ @@ -124,6 +127,7 @@ test("create workspace and overwrite default parameters", async ({ page }) => { echoResponsesWithParameters(richParameters), ); + await login(page, users.member); const workspaceName = await createWorkspace(page, template, { richParameters, buildParameters, @@ -132,6 +136,7 @@ test("create workspace and overwrite default parameters", async ({ page }) => { }); test("create workspace with disable_param search params", async ({ page }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [ firstParameter, // mutable secondParameter, //immutable @@ -142,6 +147,7 @@ test("create workspace with disable_param search params", async ({ page }) => { echoResponsesWithParameters(richParameters), ); + await login(page, users.member); await page.goto( `/templates/${templateName}/workspace?disable_params=first_parameter,second_parameter`, { @@ -157,8 +163,11 @@ test("create workspace with disable_param search params", async ({ page }) => { // the tests are over. test.skip("create docker workspace", async ({ context, page }) => { requireTerraformProvisioner(); + + await login(page, users.templateAdmin); const template = await createTemplate(page, StarterTemplates.STARTER_DOCKER); + await login(page, users.member); const workspaceName = await createWorkspace(page, template); // The workspace agents must be ready before we try to interact with the workspace. @@ -184,8 +193,6 @@ test.skip("create docker workspace", async ({ context, page }) => { ); await terminal.waitForSelector( `//textarea[contains(@class,"xterm-helper-textarea")]`, - { - state: "visible", - }, + { state: "visible" }, ); }); diff --git a/site/e2e/tests/workspaces/restartWorkspace.spec.ts b/site/e2e/tests/workspaces/restartWorkspace.spec.ts index b65fa95208239..f03becee1cb2d 100644 --- a/site/e2e/tests/workspaces/restartWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/restartWorkspace.spec.ts @@ -10,18 +10,21 @@ import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { firstBuildOption, secondBuildOption } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; +import { users } from "../../constants"; test.beforeEach(async ({ page }) => { beforeCoderTest(page); - await login(page); }); test("restart workspace with ephemeral parameters", async ({ page }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [firstBuildOption, secondBuildOption]; const template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); + + await login(page, users.member); const workspaceName = await createWorkspace(page, template); // Verify that build options are default (not selected). diff --git a/site/e2e/tests/workspaces/startWorkspace.spec.ts b/site/e2e/tests/workspaces/startWorkspace.spec.ts index d22c8f4f3457e..e3c973c7dd87d 100644 --- a/site/e2e/tests/workspaces/startWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/startWorkspace.spec.ts @@ -11,18 +11,21 @@ import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { firstBuildOption, secondBuildOption } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; +import { users } from "../../constants"; test.beforeEach(async ({ page }) => { beforeCoderTest(page); - await login(page); }); test("start workspace with ephemeral parameters", async ({ page }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [firstBuildOption, secondBuildOption]; const template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); + + await login(page, users.member); const workspaceName = await createWorkspace(page, template); // Verify that build options are default (not selected). diff --git a/site/e2e/tests/workspaces/updateWorkspace.spec.ts b/site/e2e/tests/workspaces/updateWorkspace.spec.ts index 1db623164699c..c3fd117eb47c3 100644 --- a/site/e2e/tests/workspaces/updateWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/updateWorkspace.spec.ts @@ -18,21 +18,23 @@ import { sixthParameter, } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; +import { users } from "../../constants"; test.beforeEach(async ({ page }) => { beforeCoderTest(page); - await login(page); }); test("update workspace, new optional, immutable parameter added", async ({ page, }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [firstParameter, secondParameter]; const template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); + await login(page, users.member); const workspaceName = await createWorkspace(page, template); // Verify that parameter values are default. @@ -42,6 +44,7 @@ test("update workspace, new optional, immutable parameter added", async ({ ]); // Push updated template. + await login(page, users.templateAdmin); const updatedRichParameters = [...richParameters, fifthParameter]; await updateTemplate( page, @@ -51,6 +54,7 @@ test("update workspace, new optional, immutable parameter added", async ({ ); // Now, update the workspace, and select the value for immutable parameter. + await login(page, users.member); await updateWorkspace(page, workspaceName, updatedRichParameters, [ { name: fifthParameter.name, value: fifthParameter.options[0].value }, ]); @@ -66,12 +70,14 @@ test("update workspace, new optional, immutable parameter added", async ({ test("update workspace, new required, mutable parameter added", async ({ page, }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [firstParameter, secondParameter]; const template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); + await login(page, users.member); const workspaceName = await createWorkspace(page, template); // Verify that parameter values are default. @@ -81,6 +87,7 @@ test("update workspace, new required, mutable parameter added", async ({ ]); // Push updated template. + await login(page, users.templateAdmin); const updatedRichParameters = [...richParameters, sixthParameter]; await updateTemplate( page, @@ -90,6 +97,7 @@ test("update workspace, new required, mutable parameter added", async ({ ); // Now, update the workspace, and provide the parameter value. + await login(page, users.member); const buildParameters = [{ name: sixthParameter.name, value: "99" }]; await updateWorkspace( page, @@ -107,12 +115,14 @@ test("update workspace, new required, mutable parameter added", async ({ }); test("update workspace with ephemeral parameter enabled", async ({ page }) => { + await login(page, users.templateAdmin); const richParameters: RichParameter[] = [firstParameter, secondBuildOption]; const template = await createTemplate( page, echoResponsesWithParameters(richParameters), ); + await login(page, users.member); const workspaceName = await createWorkspace(page, template); // Verify that parameter values are default. From 94206c67369ef2368fc61d76ab8b3958427d3f1a Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Mon, 24 Feb 2025 21:25:58 +0000 Subject: [PATCH 2/4] :^) --- site/e2e/tests/workspaces/createWorkspace.spec.ts | 2 +- site/e2e/tests/workspaces/restartWorkspace.spec.ts | 2 +- site/e2e/tests/workspaces/startWorkspace.spec.ts | 2 +- site/e2e/tests/workspaces/updateWorkspace.spec.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/site/e2e/tests/workspaces/createWorkspace.spec.ts b/site/e2e/tests/workspaces/createWorkspace.spec.ts index 6ed7c3dd7cf65..49b832d285e0b 100644 --- a/site/e2e/tests/workspaces/createWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/createWorkspace.spec.ts @@ -1,4 +1,5 @@ import { expect, test } from "@playwright/test"; +import { users } from "../../constants"; import { StarterTemplates, createTemplate, @@ -21,7 +22,6 @@ import { thirdParameter, } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -import { users } from "../../constants"; test.describe.configure({ mode: "parallel" }); diff --git a/site/e2e/tests/workspaces/restartWorkspace.spec.ts b/site/e2e/tests/workspaces/restartWorkspace.spec.ts index f03becee1cb2d..444ff891f0fdc 100644 --- a/site/e2e/tests/workspaces/restartWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/restartWorkspace.spec.ts @@ -1,4 +1,5 @@ import { test } from "@playwright/test"; +import { users } from "../../constants"; import { buildWorkspaceWithParameters, createTemplate, @@ -10,7 +11,6 @@ import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { firstBuildOption, secondBuildOption } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -import { users } from "../../constants"; test.beforeEach(async ({ page }) => { beforeCoderTest(page); diff --git a/site/e2e/tests/workspaces/startWorkspace.spec.ts b/site/e2e/tests/workspaces/startWorkspace.spec.ts index e3c973c7dd87d..90fac440046ea 100644 --- a/site/e2e/tests/workspaces/startWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/startWorkspace.spec.ts @@ -1,4 +1,5 @@ import { test } from "@playwright/test"; +import { users } from "../../constants"; import { buildWorkspaceWithParameters, createTemplate, @@ -11,7 +12,6 @@ import { login } from "../../helpers"; import { beforeCoderTest } from "../../hooks"; import { firstBuildOption, secondBuildOption } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -import { users } from "../../constants"; test.beforeEach(async ({ page }) => { beforeCoderTest(page); diff --git a/site/e2e/tests/workspaces/updateWorkspace.spec.ts b/site/e2e/tests/workspaces/updateWorkspace.spec.ts index c3fd117eb47c3..48c341eb63956 100644 --- a/site/e2e/tests/workspaces/updateWorkspace.spec.ts +++ b/site/e2e/tests/workspaces/updateWorkspace.spec.ts @@ -1,4 +1,5 @@ import { test } from "@playwright/test"; +import { users } from "../../constants"; import { createTemplate, createWorkspace, @@ -18,7 +19,6 @@ import { sixthParameter, } from "../../parameters"; import type { RichParameter } from "../../provisionerGenerated"; -import { users } from "../../constants"; test.beforeEach(async ({ page }) => { beforeCoderTest(page); From c5e3af1105805c3773f11d33d685cd269e79f56b Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Mon, 24 Feb 2025 23:39:45 +0000 Subject: [PATCH 3/4] chore: use org-scoped roles for organization groups and members e2e tests --- site/e2e/api.ts | 32 ++++++++++++++++++++-- site/e2e/constants.ts | 7 +++++ site/e2e/helpers.ts | 29 +++++++++++++++++++- site/e2e/tests/organizationGroups.spec.ts | 15 ++++++++-- site/e2e/tests/organizationMembers.spec.ts | 20 ++++++-------- 5 files changed, 85 insertions(+), 18 deletions(-) diff --git a/site/e2e/api.ts b/site/e2e/api.ts index 902485b7b15b6..72aababc4b910 100644 --- a/site/e2e/api.ts +++ b/site/e2e/api.ts @@ -3,8 +3,8 @@ import { expect } from "@playwright/test"; import { API, type DeploymentConfig } from "api/api"; import type { SerpentOption } from "api/typesGenerated"; import { formatDuration, intervalToDuration } from "date-fns"; -import { coderPort } from "./constants"; -import { findSessionToken, randomName } from "./helpers"; +import { coderPort, defaultPassword } from "./constants"; +import { findSessionToken, type LoginOptions, randomName } from "./helpers"; let currentOrgId: string; @@ -29,14 +29,40 @@ export const createUser = async (...orgIds: string[]) => { email: `${name}@coder.com`, username: name, name: name, - password: "s3cure&password!", + password: defaultPassword, login_type: "password", organization_ids: orgIds, user_status: null, }); + return user; }; +export const createOrganizationMember = async ( + orgRoles: Record, +): Promise => { + const name = randomName(); + const user = await API.createUser({ + email: `${name}@coder.com`, + username: name, + name: name, + password: defaultPassword, + login_type: "password", + organization_ids: Object.keys(orgRoles), + user_status: null, + }); + + for (const [org, roles] of Object.entries(orgRoles)) { + API.updateOrganizationMemberRoles(org, user.id, roles); + } + + return { + username: user.username, + email: user.email, + password: defaultPassword, + }; +}; + export const createGroup = async (orgId: string) => { const name = randomName(); const group = await API.createGroup(orgId, { diff --git a/site/e2e/constants.ts b/site/e2e/constants.ts index 4fcada0e6d15b..4d2d9099692d5 100644 --- a/site/e2e/constants.ts +++ b/site/e2e/constants.ts @@ -15,6 +15,7 @@ export const coderdPProfPort = 6062; // The name of the organization that should be used by default when needed. export const defaultOrganizationName = "coder"; +export const defaultOrganizationId = "00000000-0000-0000-0000-000000000000"; export const defaultPassword = "SomeSecurePassword!"; // Credentials for users @@ -30,6 +31,12 @@ export const users = { email: "templateadmin@coder.com", roles: ["Template Admin"], }, + userAdmin: { + username: "user-admin", + password: defaultPassword, + email: "useradmin@coder.com", + roles: ["User Admin"], + }, auditor: { username: "auditor", password: defaultPassword, diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 5692909355fca..24b46d47a151b 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -61,7 +61,7 @@ export function requireTerraformProvisioner() { test.skip(!requireTerraformTests); } -type LoginOptions = { +export type LoginOptions = { username: string; email: string; password: string; @@ -1127,3 +1127,30 @@ export async function createOrganization(page: Page): Promise<{ return { name, displayName, description }; } + +/** + * @param organization organization name + * @param user user email or username + */ +export async function addUserToOrganization( + page: Page, + organization: string, + user: string, + roles: string[] = [], +): Promise { + await page.goto(`/organizations/${organization}`, { + waitUntil: "domcontentloaded", + }); + + await page.getByPlaceholder("User email or username").fill(user); + await page.getByRole("option", { name: user }).click(); + await page.getByRole("button", { name: "Add user" }).click(); + const addedRow = page.locator("tr", { hasText: user }); + await expect(addedRow).toBeVisible(); + + await addedRow.getByLabel("Edit user roles").click(); + for (const role of roles) { + await page.getByText(role).click(); + } + await page.mouse.click(10, 10); // close the popover by clicking outside of it +} diff --git a/site/e2e/tests/organizationGroups.spec.ts b/site/e2e/tests/organizationGroups.spec.ts index dff12ab91c453..6e8aa74a4bf8b 100644 --- a/site/e2e/tests/organizationGroups.spec.ts +++ b/site/e2e/tests/organizationGroups.spec.ts @@ -2,10 +2,11 @@ import { expect, test } from "@playwright/test"; import { createGroup, createOrganization, + createOrganizationMember, createUser, setupApiCalls, } from "../api"; -import { defaultOrganizationName } from "../constants"; +import { defaultOrganizationId, defaultOrganizationName } from "../constants"; import { expectUrl } from "../expectUrl"; import { login, randomName, requiresLicense } from "../helpers"; import { beforeCoderTest } from "../hooks"; @@ -32,6 +33,11 @@ test("create group", async ({ page }) => { // Create a new organization const org = await createOrganization(); + const orgUserAdmin = await createOrganizationMember({ + [org.id]: ["organization-user-admin"], + }); + + await login(page, orgUserAdmin); await page.goto(`/organizations/${org.name}`); // Navigate to groups page @@ -64,8 +70,7 @@ test("create group", async ({ page }) => { await expect(addedRow).toBeVisible(); // Ensure we can't add a user who isn't in the org - const otherOrg = await createOrganization(); - const personToReject = await createUser(otherOrg.id); + const personToReject = await createUser(defaultOrganizationId); await page .getByPlaceholder("User email or username") .fill(personToReject.email); @@ -93,8 +98,12 @@ test("change quota settings", async ({ page }) => { // Create a new organization and group const org = await createOrganization(); const group = await createGroup(org.id); + const orgUserAdmin = await createOrganizationMember({ + [org.id]: ["organization-user-admin"], + }); // Go to settings + await login(page, orgUserAdmin); await page.goto(`/organizations/${org.name}/groups/${group.name}`); await page.getByRole("button", { name: "Settings", exact: true }).click(); expectUrl(page).toHavePathName( diff --git a/site/e2e/tests/organizationMembers.spec.ts b/site/e2e/tests/organizationMembers.spec.ts index 9edb2eb922ab8..51c3491ae3d62 100644 --- a/site/e2e/tests/organizationMembers.spec.ts +++ b/site/e2e/tests/organizationMembers.spec.ts @@ -1,6 +1,7 @@ import { expect, test } from "@playwright/test"; import { setupApiCalls } from "../api"; import { + addUserToOrganization, createOrganization, createUser, login, @@ -18,7 +19,7 @@ test("add and remove organization member", async ({ page }) => { requiresLicense(); // Create a new organization - const { displayName } = await createOrganization(page); + const { name: orgName, displayName } = await createOrganization(page); // Navigate to members page await page.getByRole("link", { name: "Members" }).click(); @@ -26,17 +27,14 @@ test("add and remove organization member", async ({ page }) => { // Add a user to the org const personToAdd = await createUser(page); - await page.getByPlaceholder("User email or username").fill(personToAdd.email); - await page.getByRole("option", { name: personToAdd.email }).click(); - await page.getByRole("button", { name: "Add user" }).click(); - const addedRow = page.locator("tr", { hasText: personToAdd.email }); - await expect(addedRow).toBeVisible(); + // This must be done as an admin, because you can't assign a role that has more + // permissions than you, even if you have the ability to assign roles. + await addUserToOrganization(page, orgName, personToAdd.email, [ + "Organization User Admin", + "Organization Template Admin", + ]); - // Give them a role - await addedRow.getByLabel("Edit user roles").click(); - await page.getByText("Organization User Admin").click(); - await page.getByText("Organization Template Admin").click(); - await page.mouse.click(10, 10); // close the popover by clicking outside of it + const addedRow = page.locator("tr", { hasText: personToAdd.email }); await expect(addedRow.getByText("Organization User Admin")).toBeVisible(); await expect(addedRow.getByText("+1 more")).toBeVisible(); From a9b68f28b79025df762b51f74934e166ef6919fa Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Mon, 24 Feb 2025 23:40:36 +0000 Subject: [PATCH 4/4] mhm --- site/e2e/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/e2e/api.ts b/site/e2e/api.ts index 72aababc4b910..0dc9e46831708 100644 --- a/site/e2e/api.ts +++ b/site/e2e/api.ts @@ -4,7 +4,7 @@ import { API, type DeploymentConfig } from "api/api"; import type { SerpentOption } from "api/typesGenerated"; import { formatDuration, intervalToDuration } from "date-fns"; import { coderPort, defaultPassword } from "./constants"; -import { findSessionToken, type LoginOptions, randomName } from "./helpers"; +import { type LoginOptions, findSessionToken, randomName } from "./helpers"; let currentOrgId: string;