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

Lines changed: 29 additions & 3 deletions
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 28 additions & 1 deletion
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

Lines changed: 12 additions & 3 deletions
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

Lines changed: 9 additions & 11 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy