Skip to content

Commit b615a35

Browse files
chore: use org-scoped roles for organization user e2e tests (cherry-pick #16691) (#16793)
Cherry-picked chore: use org-scoped roles for organization groups and members e2e tests (#16691) Co-authored-by: ケイラ <mckayla@hey.com>
1 parent bdd7794 commit b615a35

File tree

5 files changed

+85
-18
lines changed

5 files changed

+85
-18
lines changed

site/e2e/api.ts

+29-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { expect } from "@playwright/test";
33
import { API, type DeploymentConfig } from "api/api";
44
import type { SerpentOption } from "api/typesGenerated";
55
import { formatDuration, intervalToDuration } from "date-fns";
6-
import { coderPort } from "./constants";
7-
import { findSessionToken, randomName } from "./helpers";
6+
import { coderPort, defaultPassword } from "./constants";
7+
import { type LoginOptions, findSessionToken, randomName } from "./helpers";
88

99
let currentOrgId: string;
1010

@@ -29,14 +29,40 @@ export const createUser = async (...orgIds: string[]) => {
2929
email: `${name}@coder.com`,
3030
username: name,
3131
name: name,
32-
password: "s3cure&password!",
32+
password: defaultPassword,
3333
login_type: "password",
3434
organization_ids: orgIds,
3535
user_status: null,
3636
});
37+
3738
return user;
3839
};
3940

41+
export const createOrganizationMember = async (
42+
orgRoles: Record<string, string[]>,
43+
): Promise<LoginOptions> => {
44+
const name = randomName();
45+
const user = await API.createUser({
46+
email: `${name}@coder.com`,
47+
username: name,
48+
name: name,
49+
password: defaultPassword,
50+
login_type: "password",
51+
organization_ids: Object.keys(orgRoles),
52+
user_status: null,
53+
});
54+
55+
for (const [org, roles] of Object.entries(orgRoles)) {
56+
API.updateOrganizationMemberRoles(org, user.id, roles);
57+
}
58+
59+
return {
60+
username: user.username,
61+
email: user.email,
62+
password: defaultPassword,
63+
};
64+
};
65+
4066
export const createGroup = async (orgId: string) => {
4167
const name = randomName();
4268
const group = await API.createGroup(orgId, {

site/e2e/constants.ts

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const coderdPProfPort = 6062;
1515

1616
// The name of the organization that should be used by default when needed.
1717
export const defaultOrganizationName = "coder";
18+
export const defaultOrganizationId = "00000000-0000-0000-0000-000000000000";
1819
export const defaultPassword = "SomeSecurePassword!";
1920

2021
// Credentials for users
@@ -30,6 +31,12 @@ export const users = {
3031
email: "templateadmin@coder.com",
3132
roles: ["Template Admin"],
3233
},
34+
userAdmin: {
35+
username: "user-admin",
36+
password: defaultPassword,
37+
email: "useradmin@coder.com",
38+
roles: ["User Admin"],
39+
},
3340
auditor: {
3441
username: "auditor",
3542
password: defaultPassword,

site/e2e/helpers.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function requireTerraformProvisioner() {
6161
test.skip(!requireTerraformTests);
6262
}
6363

64-
type LoginOptions = {
64+
export type LoginOptions = {
6565
username: string;
6666
email: string;
6767
password: string;
@@ -1127,3 +1127,30 @@ export async function createOrganization(page: Page): Promise<{
11271127

11281128
return { name, displayName, description };
11291129
}
1130+
1131+
/**
1132+
* @param organization organization name
1133+
* @param user user email or username
1134+
*/
1135+
export async function addUserToOrganization(
1136+
page: Page,
1137+
organization: string,
1138+
user: string,
1139+
roles: string[] = [],
1140+
): Promise<void> {
1141+
await page.goto(`/organizations/${organization}`, {
1142+
waitUntil: "domcontentloaded",
1143+
});
1144+
1145+
await page.getByPlaceholder("User email or username").fill(user);
1146+
await page.getByRole("option", { name: user }).click();
1147+
await page.getByRole("button", { name: "Add user" }).click();
1148+
const addedRow = page.locator("tr", { hasText: user });
1149+
await expect(addedRow).toBeVisible();
1150+
1151+
await addedRow.getByLabel("Edit user roles").click();
1152+
for (const role of roles) {
1153+
await page.getByText(role).click();
1154+
}
1155+
await page.mouse.click(10, 10); // close the popover by clicking outside of it
1156+
}

site/e2e/tests/organizationGroups.spec.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { expect, test } from "@playwright/test";
22
import {
33
createGroup,
44
createOrganization,
5+
createOrganizationMember,
56
createUser,
67
setupApiCalls,
78
} from "../api";
8-
import { defaultOrganizationName } from "../constants";
9+
import { defaultOrganizationId, defaultOrganizationName } from "../constants";
910
import { expectUrl } from "../expectUrl";
1011
import { login, randomName, requiresLicense } from "../helpers";
1112
import { beforeCoderTest } from "../hooks";
@@ -32,6 +33,11 @@ test("create group", async ({ page }) => {
3233

3334
// Create a new organization
3435
const org = await createOrganization();
36+
const orgUserAdmin = await createOrganizationMember({
37+
[org.id]: ["organization-user-admin"],
38+
});
39+
40+
await login(page, orgUserAdmin);
3541
await page.goto(`/organizations/${org.name}`);
3642

3743
// Navigate to groups page
@@ -64,8 +70,7 @@ test("create group", async ({ page }) => {
6470
await expect(addedRow).toBeVisible();
6571

6672
// Ensure we can't add a user who isn't in the org
67-
const otherOrg = await createOrganization();
68-
const personToReject = await createUser(otherOrg.id);
73+
const personToReject = await createUser(defaultOrganizationId);
6974
await page
7075
.getByPlaceholder("User email or username")
7176
.fill(personToReject.email);
@@ -93,8 +98,12 @@ test("change quota settings", async ({ page }) => {
9398
// Create a new organization and group
9499
const org = await createOrganization();
95100
const group = await createGroup(org.id);
101+
const orgUserAdmin = await createOrganizationMember({
102+
[org.id]: ["organization-user-admin"],
103+
});
96104

97105
// Go to settings
106+
await login(page, orgUserAdmin);
98107
await page.goto(`/organizations/${org.name}/groups/${group.name}`);
99108
await page.getByRole("button", { name: "Settings", exact: true }).click();
100109
expectUrl(page).toHavePathName(

site/e2e/tests/organizationMembers.spec.ts

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { expect, test } from "@playwright/test";
22
import { setupApiCalls } from "../api";
33
import {
4+
addUserToOrganization,
45
createOrganization,
56
createUser,
67
login,
@@ -18,25 +19,22 @@ test("add and remove organization member", async ({ page }) => {
1819
requiresLicense();
1920

2021
// Create a new organization
21-
const { displayName } = await createOrganization(page);
22+
const { name: orgName, displayName } = await createOrganization(page);
2223

2324
// Navigate to members page
2425
await page.getByRole("link", { name: "Members" }).click();
2526
await expect(page).toHaveTitle(`Members - ${displayName} - Coder`);
2627

2728
// Add a user to the org
2829
const personToAdd = await createUser(page);
29-
await page.getByPlaceholder("User email or username").fill(personToAdd.email);
30-
await page.getByRole("option", { name: personToAdd.email }).click();
31-
await page.getByRole("button", { name: "Add user" }).click();
32-
const addedRow = page.locator("tr", { hasText: personToAdd.email });
33-
await expect(addedRow).toBeVisible();
30+
// This must be done as an admin, because you can't assign a role that has more
31+
// permissions than you, even if you have the ability to assign roles.
32+
await addUserToOrganization(page, orgName, personToAdd.email, [
33+
"Organization User Admin",
34+
"Organization Template Admin",
35+
]);
3436

35-
// Give them a role
36-
await addedRow.getByLabel("Edit user roles").click();
37-
await page.getByText("Organization User Admin").click();
38-
await page.getByText("Organization Template Admin").click();
39-
await page.mouse.click(10, 10); // close the popover by clicking outside of it
37+
const addedRow = page.locator("tr", { hasText: personToAdd.email });
4038
await expect(addedRow.getByText("Organization User Admin")).toBeVisible();
4139
await expect(addedRow.getByText("+1 more")).toBeVisible();
4240

0 commit comments

Comments
 (0)