diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 519a8968f89f3..84b1b911c975d 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -7,6 +7,7 @@ import capitalize from "lodash/capitalize"; import path from "path"; import * as ssh from "ssh2"; import { Duplex } from "stream"; +import * as API from "api/api"; import type { WorkspaceBuildParameter, UpdateTemplateMeta, @@ -565,7 +566,7 @@ const createTemplateVersionTar = async ( ); }; -const randomName = () => { +export const randomName = () => { return randomUUID().slice(0, 8); }; @@ -603,7 +604,7 @@ export const createServer = async ( return e; }; -const findSessionToken = async (page: Page): Promise => { +export const findSessionToken = async (page: Page): Promise => { const cookies = await page.context().cookies(); const sessionCookie = cookies.find((c) => c.name === "coder_session_token"); if (!sessionCookie) { @@ -825,3 +826,9 @@ export async function openTerminalWindow( return terminal; } + +export const setupApiCalls = async (page: Page) => { + const token = await findSessionToken(page); + API.setSessionToken(token); + API.setHost(`http://127.0.0.1:${coderPort}`); +}; diff --git a/site/e2e/tests/users/createUserWithPassword.spec.ts b/site/e2e/tests/users/createUserWithPassword.spec.ts new file mode 100644 index 0000000000000..b8c95d35b32d7 --- /dev/null +++ b/site/e2e/tests/users/createUserWithPassword.spec.ts @@ -0,0 +1,35 @@ +import { test, expect } from "@playwright/test"; +import { randomName } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => await beforeCoderTest(page)); + +test("create user with password", async ({ page, baseURL }) => { + await page.goto(`${baseURL}/users`, { waitUntil: "domcontentloaded" }); + await expect(page).toHaveTitle("Users - Coder"); + + await page.getByRole("button", { name: "Create user" }).click(); + await expect(page).toHaveTitle("Create User - Coder"); + + const name = randomName(); + const userValues = { + username: name, + email: `${name}@coder.com`, + loginType: "password", + password: "s3cure&password!", + }; + + await page.getByLabel("Username").fill(userValues.username); + await page.getByLabel("Email").fill(userValues.email); + await page.getByLabel("Login Type").click(); + await page.getByRole("option", { name: "Password", exact: false }).click(); + // Using input[name=password] due to the select element utilizing 'password' + // as the label for the currently active option. + const passwordField = page.locator("input[name=password]"); + await passwordField.fill(userValues.password); + await page.getByRole("button", { name: "Create user" }).click(); + await expect(page.getByText("Successfully created user.")).toBeVisible(); + + await expect(page).toHaveTitle("Users - Coder"); + await expect(page.locator("tr", { hasText: userValues.email })).toBeVisible(); +}); diff --git a/site/e2e/tests/users/removeUser.spec.ts b/site/e2e/tests/users/removeUser.spec.ts new file mode 100644 index 0000000000000..c6e60c25e604d --- /dev/null +++ b/site/e2e/tests/users/removeUser.spec.ts @@ -0,0 +1,33 @@ +import { test, expect } from "@playwright/test"; +import * as API from "api/api"; +import { randomName, setupApiCalls } from "../../helpers"; +import { beforeCoderTest } from "../../hooks"; + +test.beforeEach(async ({ page }) => await beforeCoderTest(page)); + +test("remove user", async ({ page, baseURL }) => { + await setupApiCalls(page); + const currentUser = await API.getAuthenticatedUser(); + const name = randomName(); + const user = await API.createUser({ + email: `${name}@coder.com`, + username: name, + password: "s3cure&password!", + login_type: "password", + disable_login: false, + organization_id: currentUser.organization_ids[0], + }); + + await page.goto(`${baseURL}/users`, { waitUntil: "domcontentloaded" }); + await expect(page).toHaveTitle("Users - Coder"); + + const userRow = page.locator("tr", { hasText: user.email }); + await userRow.getByRole("button", { name: "More options" }).click(); + await userRow.getByText("Delete", { exact: false }).click(); + + const dialog = page.getByTestId("dialog"); + await dialog.getByLabel("Name of the user to delete").fill(user.username); + await dialog.getByRole("button", { name: "Delete" }).click(); + + await expect(page.getByText("Successfully deleted the user.")).toBeVisible(); +}); diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 7048d9bca90cb..760f860ebe3c1 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -72,6 +72,14 @@ if (token !== null && token.getAttribute("content") !== null) { } } +export const setSessionToken = (token: string) => { + axios.defaults.headers.common["Coder-Session-Token"] = token; +}; + +export const setHost = (host?: string) => { + axios.defaults.baseURL = host; +}; + const CONTENT_TYPE_JSON = { "Content-Type": "application/json", }; diff --git a/site/src/pages/CreateUserPage/CreateUserForm.tsx b/site/src/pages/CreateUserPage/CreateUserForm.tsx index dee0a4b7c2c8a..3f44c718381d8 100644 --- a/site/src/pages/CreateUserPage/CreateUserForm.tsx +++ b/site/src/pages/CreateUserPage/CreateUserForm.tsx @@ -193,7 +193,11 @@ export const CreateUserForm: FC< type="password" /> - + ); diff --git a/site/src/pages/CreateUserPage/CreateUserPage.test.tsx b/site/src/pages/CreateUserPage/CreateUserPage.test.tsx index 2787b26244bc7..83a1c0266b45e 100644 --- a/site/src/pages/CreateUserPage/CreateUserPage.test.tsx +++ b/site/src/pages/CreateUserPage/CreateUserPage.test.tsx @@ -1,6 +1,5 @@ import { fireEvent, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { Language as FooterLanguage } from "components/FormFooter/FormFooter"; import { renderWithAuth, waitForLoaderToBeRemoved, @@ -35,9 +34,9 @@ const fillForm = async ({ await userEvent.type(emailField, email); await userEvent.type(loginTypeField, "password"); await userEvent.type(passwordField as HTMLElement, password); - const submitButton = await screen.findByText( - FooterLanguage.defaultSubmitLabel, - ); + const submitButton = screen.getByRole("button", { + name: "Create user", + }); fireEvent.click(submitButton); };