Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: allow signing in as non-admin users in e2e tests#15892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
aslilac merged 11 commits intomainfromlilac/dont-share-e2e-auth
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletionssite/e2e/api.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,14 +9,9 @@ import { findSessionToken, randomName } from "./helpers";
let currentOrgId: string;

export const setupApiCalls = async (page: Page) => {
try {
const token = await findSessionToken(page);
API.setSessionToken(token);
} catch {
// If this fails, we have an unauthenticated client.
}

API.setHost(`http://127.0.0.1:${coderPort}`);
const token = await findSessionToken(page);
API.setSessionToken(token);
};

export const getCurrentOrgId = async (): Promise<string> => {
Expand Down
27 changes: 23 additions & 4 deletionssite/e2e/constants.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,11 +15,30 @@ export const coderdPProfPort = 6062;

// The name of the organization that should be used by default when needed.
export const defaultOrganizationName = "coder";
export const defaultPassword = "SomeSecurePassword!";

// Credentials for the first user
export const username = "admin";
export const password = "SomeSecurePassword!";
export const email = "admin@coder.com";
// Credentials for users
export const users = {
admin: {
username: "admin",
password: defaultPassword,
email: "admin@coder.com",
},
auditor: {
username: "auditor",
password: defaultPassword,
email: "auditor@coder.com",
roles: ["Template Admin", "Auditor"],
},
user: {
username: "user",
password: defaultPassword,
email: "user@coder.com",
},
} satisfies Record<
string,
{ username: string; password: string; email: string; roles?: string[] }
>;

export const gitAuth = {
deviceProvider: "device",
Expand Down
95 changes: 81 additions & 14 deletionssite/e2e/helpers.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
import { type ChildProcess, exec, spawn } from "node:child_process";
import { randomUUID } from "node:crypto";
import * as fs from "node:fs";
import net from "node:net";
import path from "node:path";
import { Duplex } from "node:stream";
Expand All@@ -19,10 +18,12 @@ import {
coderMain,
coderPort,
defaultOrganizationName,
defaultPassword,
license,
premiumTestsRequired,
prometheusPort,
requireTerraformTests,
users,
} from "./constants";
import { expectUrl } from "./expectUrl";
import {
Expand DownExpand Up@@ -60,28 +61,75 @@ export function requireTerraformProvisioner() {
test.skip(!requireTerraformTests);
}

type LoginOptions = {
username: string;
email: string;
password: string;
};

export async function login(page: Page, options: LoginOptions = users.admin) {
const ctx = page.context();
// biome-ignore lint/suspicious/noExplicitAny: reset the current user
(ctx as any)[Symbol.for("currentUser")] = undefined;
await ctx.clearCookies();
await page.goto("/login");
await page.getByLabel("Email").fill(options.email);
await page.getByLabel("Password").fill(options.password);
await page.getByRole("button", { name: "Sign In" }).click();
await expectUrl(page).toHavePathName("/workspaces");
// biome-ignore lint/suspicious/noExplicitAny: update once logged in
(ctx as any)[Symbol.for("currentUser")] = options;
}

export function currentUser(page: Page): LoginOptions {
const ctx = page.context();
// biome-ignore lint/suspicious/noExplicitAny: get the current user
const user = (ctx as any)[Symbol.for("currentUser")];

if (!user) {
throw new Error("page context does not have a user. did you call `login`?");
}

return user;
}

type CreateWorkspaceOptions = {
richParameters?: RichParameter[];
buildParameters?: WorkspaceBuildParameter[];
useExternalAuth?: boolean;
};

/**
* createWorkspace creates a workspace for a template. It does not wait for it
* to be running, but it does navigate to the page.
*/
export const createWorkspace = async (
page: Page,
templateName: string,
richParameters: RichParameter[] = [],
buildParameters: WorkspaceBuildParameter[] = [],
useExternalAuthProvider: string | undefined = undefined,
template: string | { organization: string; name: string },
options: CreateWorkspaceOptions = {},
): Promise<string> => {
await page.goto(`/templates/${templateName}/workspace`, {
const {
richParameters = [],
buildParameters = [],
useExternalAuth,
} = options;

const templatePath =
typeof template === "string"
? template
: `${template.organization}/${template.name}`;

await page.goto(`/templates/${templatePath}/workspace`, {
waitUntil: "domcontentloaded",
});
await expectUrl(page).toHavePathName(`/templates/${templateName}/workspace`);
await expectUrl(page).toHavePathName(`/templates/${templatePath}/workspace`);

const name = randomName();
await page.getByLabel("name").fill(name);

await fillParameters(page, richParameters, buildParameters);

if (useExternalAuthProvider !== undefined) {
if (useExternalAuth) {
// Create a new context for the popup which will be created when clicking the button
const popupPromise = page.waitForEvent("popup");

Expand All@@ -101,7 +149,9 @@ export const createWorkspace = async (

await page.getByTestId("form-submit").click();

await expectUrl(page).toHavePathName(`/@admin/${name}`);
const user = currentUser(page);

await expectUrl(page).toHavePathName(`/@${user.username}/${name}`);

await page.waitForSelector("[data-testid='build-status'] >> text=Running", {
state: "visible",
Expand DownExpand Up@@ -214,6 +264,12 @@ export const createTemplate = async (
const orgPicker = page.getByLabel("Belongs to *");
const organizationsEnabled = await orgPicker.isVisible();
if (organizationsEnabled) {
if (orgName !== defaultOrganizationName) {
throw new Error(
`No provisioners registered for ${orgName}, creating this template will fail`,
);
}

await orgPicker.click();
await page.getByText(orgName, { exact: true }).click();
}
Expand DownExpand Up@@ -659,8 +715,9 @@ const createTemplateVersionTar = async (
);
};

export const randomName = () => {
return randomUUID().slice(0, 8);
export const randomName = (annotation?: string) => {
const base = randomUUID().slice(0, 8);
return annotation ? `${annotation}-${base}` : base;
};

/**
Expand DownExpand Up@@ -1002,6 +1059,7 @@ type UserValues = {
username: string;
email: string;
password: string;
roles: string[];
};

export async function createUser(
Expand All@@ -1019,7 +1077,8 @@ export async function createUser(
const username = userValues.username ?? randomName();
const name = userValues.name ?? username;
const email = userValues.email ?? `${username}@coder.com`;
const password = userValues.password || "s3cure&password!";
const password = userValues.password || defaultPassword;
const roles = userValues.roles ?? [];

await page.getByLabel("Username").fill(username);
if (name) {
Expand All@@ -1036,10 +1095,18 @@ export async function createUser(
await expect(page.getByText("Successfully created user.")).toBeVisible();

await expect(page).toHaveTitle("Users - Coder");
await expect(page.locator("tr", { hasText: email })).toBeVisible();
const addedRow = page.locator("tr", { hasText: email });
await expect(addedRow).toBeVisible();

// 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.mouse.click(10, 10); // close the popover by clicking outside of it

await page.goto(returnTo, { waitUntil: "domcontentloaded" });
return { name, username, email, password };
return { name, username, email, password, roles };
}

export async function createOrganization(page: Page): Promise<{
Expand Down
2 changes: 1 addition & 1 deletionsite/e2e/hooks.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@ import http from "node:http";
import type { BrowserContext, Page } from "@playwright/test";
import { coderPort, gitAuth } from "./constants";

export const beforeCoderTest =async(page: Page) => {
export const beforeCoderTest = (page: Page) => {
page.on("console", (msg) => console.info(`[onConsole] ${msg.text()}`));

page.on("request", (request) => {
Expand Down
8 changes: 2 additions & 6 deletionssite/e2e/playwright.config.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,9 +13,6 @@ import {

export const wsEndpoint = process.env.CODER_E2E_WS_ENDPOINT;

// This is where auth cookies are stored!
export const storageState = path.join(__dirname, ".auth.json");

// If running terraform tests, verify the requirements exist in the
// environment.
//
Expand DownExpand Up@@ -58,13 +55,12 @@ export default defineConfig({
projects: [
{
name: "testsSetup",
testMatch: /global.setup\.ts/,
testMatch: /setup\/.*\.spec\.ts/,
},
{
name: "tests",
testMatch: /.*\.spec\.ts/,
testMatch: /tests\/.*\.spec\.ts/,
dependencies: ["testsSetup"],
use: { storageState },
timeout: 30_000,
},
],
Expand Down
36 changes: 21 additions & 15 deletionssite/e2e/global.setup.ts → site/e2e/setup/createUsers.spec.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
import { expect, test } from "@playwright/test";
import { API } from "api/api";
import { Language } from "pages/CreateUserPage/CreateUserForm";
import { setupApiCalls } from "./api";
import * as constants from "./constants";
import { expectUrl } from "./expectUrl";
import { storageState } from "./playwright.config";
import { coderPort, license, premiumTestsRequired, users } from "../constants";
import { expectUrl } from "../expectUrl";
import { createUser } from "../helpers";

test("setup deployment", async ({ page }) => {
await page.goto("/", { waitUntil: "domcontentloaded" });
await setupApiCalls(page);
API.setHost(`http://127.0.0.1:${coderPort}`);
const exists = await API.hasFirstUser();
// First user already exists, abort early. All tests execute this as a dependency,
// if you run multiple tests in the UI, this will fail unless we check this.
Expand All@@ -17,28 +16,35 @@ test("setup deployment", async ({ page }) => {
}

// Setup first user
await page.getByLabel(Language.usernameLabel).fill(constants.username);
await page.getByLabel(Language.emailLabel).fill(constants.email);
await page.getByLabel(Language.passwordLabel).fill(constants.password);
await page.getByLabel(Language.usernameLabel).fill(users.admin.username);
await page.getByLabel(Language.emailLabel).fill(users.admin.email);
await page.getByLabel(Language.passwordLabel).fill(users.admin.password);
await page.getByTestId("create").click();

await expectUrl(page).toHavePathName("/workspaces");
await page.context().storageState({ path: storageState });

await page.getByTestId("button-select-template").isVisible();

for (const user of Object.values(users)) {
// Already created as first user
if (user.username === "admin") {
continue;
}

await createUser(page, user);
}

// Setup license
if (constants.premiumTestsRequired ||constants.license) {
if (premiumTestsRequired || license) {
// Make sure that we have something that looks like a real license
expect(constants.license).toBeTruthy();
expect(constants.license.length).toBeGreaterThan(92); // the signature alone should be this long
expect(constants.license.split(".").length).toBe(3); // otherwise it's invalid
expect(license).toBeTruthy();
expect(license.length).toBeGreaterThan(92); // the signature alone should be this long
expect(license.split(".").length).toBe(3); // otherwise it's invalid

await page.goto("/deployment/licenses", { waitUntil: "domcontentloaded" });
await expect(page).toHaveTitle("License Settings - Coder");

await page.getByText("Add a license").click();
await page.getByRole("textbox").fill(constants.license);
await page.getByRole("textbox").fill(license);
await page.getByText("Upload License").click();

await expect(
Expand Down
6 changes: 5 additions & 1 deletionsite/e2e/tests/app.spec.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,13 +4,17 @@ import { test } from "@playwright/test";
import {
createTemplate,
createWorkspace,
login,
startAgent,
stopAgent,
stopWorkspace,
} from "../helpers";
import { beforeCoderTest } from "../hooks";

test.beforeEach(({ page }) => beforeCoderTest(page));
test.beforeEach(async ({ page }) => {
beforeCoderTest(page);
await login(page);
});

test("app", async ({ context, page }) => {
test.setTimeout(75_000);
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp