Files
coder/site/e2e/tests/deployment/idpOrgSync.spec.ts
T
Jaayden Halko 7f44189ed2 feat: orgs IDP sync - add combobox to select claim field value when sync field is set (#16335)
contributes to coder/internal#330

For organizations IdP sync:

1. when the sync field is set, call the claim field values API to see if
the sync field is a valid claim field and return an array of claim field
values
2. If there are 1 or more claim field values, replace the input
component for entering the IdP organization name with a combobox
populated with the claim field values
3. The user can now select a value from the dropdown or enter a custom
value

Tests will be added in a separate PR

The same functionality for Group and Role sync will be handled in a
separate PR.


<img width="832" alt="Screenshot 2025-02-04 at 17 45 42"
src="https://github.com/user-attachments/assets/d9123260-f6c6-4914-869b-f11b14773ea1"
/>

<img width="786" alt="Screenshot 2025-02-04 at 17 45 58"
src="https://github.com/user-attachments/assets/06138320-d50c-43bd-b2b9-676ffee42e1a"
/>

<img width="810" alt="Screenshot 2025-02-04 at 17 46 14"
src="https://github.com/user-attachments/assets/50b74909-4629-435d-9774-67d281bbc442"
/>

<img width="825" alt="Screenshot 2025-02-04 at 17 52 08"
src="https://github.com/user-attachments/assets/7470281e-e88f-497b-a613-52bf8007dae8"
/>
2025-02-05 08:40:07 -05:00

198 lines
5.4 KiB
TypeScript

import { expect, test } from "@playwright/test";
import {
createOrganizationSyncSettings,
createOrganizationWithName,
deleteOrganization,
setupApiCalls,
} from "../../api";
import { randomName, requiresLicense } from "../../helpers";
import { login } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => {
beforeCoderTest(page);
await login(page);
await setupApiCalls(page);
});
test.describe("IdpOrgSyncPage", () => {
test.describe.configure({ retries: 1 });
test("show empty table when no org mappings are present", async ({
page,
}) => {
requiresLicense();
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
await expect(
page.getByRole("row", { name: "idp-org-1" }),
).not.toBeVisible();
await expect(
page.getByRole("heading", { name: "No organization mappings" }),
).toBeVisible();
});
test("add new IdP organization mapping with API", async ({ page }) => {
requiresLicense();
await createOrganizationSyncSettings();
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
await expect(
page.getByRole("switch", { name: "Assign Default Organization" }),
).toBeChecked();
await expect(page.getByRole("row", { name: "idp-org-1" })).toBeVisible();
await expect(
page.getByRole("row", { name: "fbd2116a-8961-4954-87ae-e4575bd29ce0" }),
).toBeVisible();
await expect(page.getByRole("row", { name: "idp-org-2" })).toBeVisible();
await expect(
page.getByRole("row", { name: "6b39f0f1-6ad8-4981-b2fc-d52aef53ff1b" }),
).toBeVisible();
});
test("delete a IdP org to coder org mapping row", async ({ page }) => {
requiresLicense();
await createOrganizationSyncSettings();
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
const row = page.getByTestId("idp-org-idp-org-1");
await expect(row.getByRole("cell", { name: "idp-org-1" })).toBeVisible();
await row.getByRole("button", { name: /delete/i }).click();
await expect(
row.getByRole("cell", { name: "idp-org-1" }),
).not.toBeVisible();
await expect(
page.getByText("Organization sync settings updated."),
).toBeVisible();
});
test("update sync field", async ({ page }) => {
requiresLicense();
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
const syncField = page.getByRole("textbox", {
name: "Organization sync field",
});
const saveButton = page.getByRole("button", { name: /save/i });
await expect(saveButton).toBeDisabled();
await syncField.fill("test-field");
await expect(saveButton).toBeEnabled();
await page.getByRole("button", { name: /save/i }).click();
await expect(
page.getByText("Organization sync settings updated."),
).toBeVisible();
});
test("toggle off default organization assignment", async ({ page }) => {
requiresLicense();
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
const toggle = page.getByRole("switch", {
name: "Assign Default Organization",
});
await toggle.click();
const dialog = page.getByRole("dialog");
await expect(dialog).toBeVisible();
await dialog.getByRole("button", { name: "Confirm" }).click();
await expect(dialog).not.toBeVisible();
await expect(
page.getByText("Organization sync settings updated."),
).toBeVisible();
await expect(toggle).not.toBeChecked();
});
test("export policy button is enabled when sync settings are present", async ({
page,
}) => {
requiresLicense();
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
const exportButton = page.getByRole("button", { name: /Export Policy/i });
await createOrganizationSyncSettings();
await expect(exportButton).toBeEnabled();
await exportButton.click();
});
test("add new IdP organization mapping with UI", async ({ page }) => {
requiresLicense();
const orgName = randomName();
await createOrganizationWithName(orgName);
await page.goto("/deployment/idp-org-sync", {
waitUntil: "domcontentloaded",
});
const syncField = page.getByRole("textbox", {
name: "Organization sync field",
});
await syncField.fill("");
const idpOrgInput = page.getByLabel("IdP organization name");
const addButton = page.getByRole("button", {
name: /Add IdP organization/i,
});
await expect(addButton).toBeDisabled();
const idpOrgName = randomName();
await idpOrgInput.fill(idpOrgName);
// Select Coder organization from combobox
const orgSelector = page.getByPlaceholder("Select organization");
await expect(orgSelector).toBeAttached();
await expect(orgSelector).toBeVisible();
await orgSelector.click();
await page.waitForTimeout(1000);
const option = await page.getByRole("option", { name: orgName });
await expect(option).toBeAttached({ timeout: 30000 });
await expect(option).toBeVisible();
await option.click();
// Add button should now be enabled
await expect(addButton).toBeEnabled();
await addButton.click();
// Verify new mapping appears in table
const newRow = page.getByTestId(`idp-org-${idpOrgName}`);
await expect(newRow).toBeVisible();
await expect(newRow.getByRole("cell", { name: idpOrgName })).toBeVisible();
await expect(newRow.getByRole("cell", { name: orgName })).toBeVisible();
await expect(
page.getByText("Organization sync settings updated."),
).toBeVisible();
await deleteOrganization(orgName);
});
});