chore: turn e2e enterprise tests into e2e premium tests (#14979)

This commit is contained in:
Kayla Washburn-Love
2024-10-16 16:54:30 -06:00
committed by GitHub
parent 02f6203dc7
commit 40fb57aa23
21 changed files with 201 additions and 137 deletions
+12 -15
View File
@@ -549,8 +549,8 @@ jobs:
working-directory: site
test-e2e:
runs-on: ${{ github.repository_owner == 'coder' && (matrix.variant.enterprise && 'depot-ubuntu-22.04' || 'depot-ubuntu-22.04-4') || 'ubuntu-latest' }}
# test-e2e fails on 2-core 8GB runners, so we use the 4-core 16GB runner
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-4' || 'ubuntu-latest' }}
needs: changes
if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ts == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main'
timeout-minutes: 20
@@ -558,10 +558,10 @@ jobs:
fail-fast: false
matrix:
variant:
- enterprise: false
- premium: false
name: test-e2e
- enterprise: true
name: test-e2e-enterprise
- premium: true
name: test-e2e-premium
name: ${{ matrix.variant.name }}
steps:
- name: Harden Runner
@@ -590,30 +590,27 @@ jobs:
- run: pnpm playwright:install
working-directory: site
# Run tests that don't require an enterprise license without an enterprise license
# Run tests that don't require a premium license without a premium license
- run: pnpm playwright:test --forbid-only --workers 1
if: ${{ !matrix.variant.enterprise }}
if: ${{ !matrix.variant.premium }}
env:
DEBUG: pw:api
working-directory: site
# Run all of the tests with an enterprise license
# Run all of the tests with a premium license
- run: pnpm playwright:test --forbid-only --workers 1
if: ${{ matrix.variant.enterprise }}
if: ${{ matrix.variant.premium }}
env:
DEBUG: pw:api
CODER_E2E_ENTERPRISE_LICENSE: ${{ secrets.CODER_E2E_ENTERPRISE_LICENSE }}
CODER_E2E_REQUIRE_ENTERPRISE_TESTS: "1"
CODER_E2E_LICENSE: ${{ secrets.CODER_E2E_LICENSE }}
CODER_E2E_REQUIRE_PREMIUM_TESTS: "1"
working-directory: site
# Temporarily allow these to fail so that I can gather data about which
# tests are failing.
continue-on-error: true
- name: Upload Playwright Failed Tests
if: always() && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && !github.event.pull_request.head.repo.fork
uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
with:
name: failed-test-videos${{ matrix.variant.enterprise && '-enterprise' || '-agpl' }}
name: failed-test-videos${{ matrix.variant.premium && '-premium' || '' }}
path: ./site/test-results/**/*.webm
retention-days: 7
@@ -621,7 +618,7 @@ jobs:
if: always() && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && !github.event.pull_request.head.repo.fork
uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
with:
name: debug-pprof-dumps${{ matrix.variant.enterprise && '-enterprise' || '-agpl' }}
name: debug-pprof-dumps${{ matrix.variant.premium && '-premium' || '' }}
path: ./site/test-results/**/debug-pprof-*.txt
retention-days: 7
+18 -3
View File
@@ -13,6 +13,9 @@ export const workspaceProxyPort = 3112;
export const agentPProfPort = 6061;
export const coderdPProfPort = 6062;
// The name of the organization that should be used by default when needed.
export const defaultOrganizationName = "coder";
// Credentials for the first user
export const username = "admin";
export const password = "SomeSecurePassword!";
@@ -34,10 +37,22 @@ export const gitAuth = {
installationsPath: "/installations",
};
export const requireEnterpriseTests = Boolean(
process.env.CODER_E2E_REQUIRE_ENTERPRISE_TESTS,
/**
* Will make the tests fail if set to `true` and a license was not provided.
*/
export const premiumTestsRequired = Boolean(
process.env.CODER_E2E_REQUIRE_PREMIUM_TESTS,
);
export const enterpriseLicense = process.env.CODER_E2E_ENTERPRISE_LICENSE ?? "";
export const license = process.env.CODER_E2E_LICENSE ?? "";
/**
* Certain parts of the UI change when organizations are enabled. Organizations
* are enabled by a license entitlement, and license configuration is guaranteed
* to run before any other tests, so having this as a bit of "global state" is
* fine.
*/
export const organizationsEnabled = Boolean(license);
// Disabling terraform tests is optional for environments without Docker + Terraform.
// By default, we opt into these tests.
+41 -1
View File
@@ -4,7 +4,8 @@ type PollingOptions = { timeout?: number; intervals?: number[] };
export const expectUrl = expect.extend({
/**
* toHavePathName is an alternative to `toHaveURL` that won't fail if the URL contains query parameters.
* toHavePathName is an alternative to `toHaveURL` that won't fail if the URL
* contains query parameters.
*/
async toHavePathName(page: Page, expected: string, options?: PollingOptions) {
let actual: string = new URL(page.url()).pathname;
@@ -34,4 +35,43 @@ export const expectUrl = expect.extend({
)}\nActual: ${this.utils.printReceived(actual)}`,
};
},
/**
* toHavePathNameEndingWith allows checking the end of the URL (ie. to make
* sure we redirected to a specific page) without caring about the entire URL,
* which might depend on things like whether or not organizations or other
* features are enabled.
*/
async toHavePathNameEndingWith(
page: Page,
expected: string,
options?: PollingOptions,
) {
let actual: string = new URL(page.url()).pathname;
let pass: boolean;
try {
await expect
.poll(() => {
actual = new URL(page.url()).pathname;
return actual.endsWith(expected);
}, options)
.toBe(true);
pass = true;
} catch {
pass = false;
}
return {
name: "toHavePathNameEndingWith",
pass,
actual,
expected,
message: () =>
`The page does not have the expected URL pathname.\nExpected a url ${
this.isNot ? "not " : ""
}ending with: ${this.utils.printExpected(
expected,
)}\nActual: ${this.utils.printReceived(actual)}`,
};
},
});
+5 -5
View File
@@ -28,16 +28,16 @@ test("setup deployment", async ({ page }) => {
await page.getByTestId("button-select-template").isVisible();
// Setup license
if (constants.requireEnterpriseTests || constants.enterpriseLicense) {
if (constants.premiumTestsRequired || constants.license) {
// Make sure that we have something that looks like a real license
expect(constants.enterpriseLicense).toBeTruthy();
expect(constants.enterpriseLicense.length).toBeGreaterThan(92); // the signature alone should be this long
expect(constants.enterpriseLicense.split(".").length).toBe(3); // otherwise it's invalid
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
await page.goto("/deployment/licenses", { waitUntil: "domcontentloaded" });
await page.getByText("Add a license").click();
await page.getByRole("textbox").fill(constants.enterpriseLicense);
await page.getByRole("textbox").fill(constants.license);
await page.getByText("Upload License").click();
await expect(
+68 -33
View File
@@ -16,9 +16,10 @@ import {
agentPProfPort,
coderMain,
coderPort,
enterpriseLicense,
defaultOrganizationName,
license,
premiumTestsRequired,
prometheusPort,
requireEnterpriseTests,
requireTerraformTests,
} from "./constants";
import { expectUrl } from "./expectUrl";
@@ -35,22 +36,28 @@ import {
type RichParameter,
} from "./provisionerGenerated";
// requiresEnterpriseLicense will skip the test if we're not running with an enterprise license
export function requiresEnterpriseLicense() {
if (requireEnterpriseTests) {
/**
* requiresLicense will skip the test if we're not running with a license added
*/
export function requiresLicense() {
if (premiumTestsRequired) {
return;
}
test.skip(!enterpriseLicense);
test.skip(!license);
}
// requireTerraformProvisioner by default is enabled.
/**
* requireTerraformProvisioner by default is enabled.
*/
export function requireTerraformProvisioner() {
test.skip(!requireTerraformTests);
}
// createWorkspace creates a workspace for a template.
// It does not wait for it to be running, but it does navigate to the page.
/**
* 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,
@@ -90,7 +97,7 @@ export const createWorkspace = async (
await expectUrl(page).toHavePathName(`/@admin/${name}`);
await page.waitForSelector("*[data-testid='build-status'] >> text=Running", {
await page.waitForSelector("[data-testid='build-status'] >> text=Running", {
state: "visible",
});
return name;
@@ -151,8 +158,10 @@ export const verifyParameters = async (
}
};
// StarterTemplates are ids of starter templates that can be used in place of
// the responses payload. These starter templates will require real provisioners.
/**
* StarterTemplates are ids of starter templates that can be used in place of
* the responses payload. These starter templates will require real provisioners.
*/
export enum StarterTemplates {
STARTER_DOCKER = "docker",
}
@@ -166,11 +175,14 @@ function isStarterTemplate(
return typeof input === "string";
}
// createTemplate navigates to the /templates/new page and uploads a template
// with the resources provided in the responses argument.
/**
* createTemplate navigates to the /templates/new page and uploads a template
* with the resources provided in the responses argument.
*/
export const createTemplate = async (
page: Page,
responses?: EchoProvisionerResponses | StarterTemplates,
orgName = defaultOrganizationName,
): Promise<string> => {
let path = "/templates/new";
if (isStarterTemplate(responses)) {
@@ -191,17 +203,33 @@ export const createTemplate = async (
});
}
// If the organization picker is present on the page, select the default
// organization.
const orgPicker = page.getByLabel("Belongs to *");
const organizationsEnabled = await orgPicker.isVisible();
if (organizationsEnabled) {
await orgPicker.click();
await page.getByText(orgName, { exact: true }).click();
}
const name = randomName();
await page.getByLabel("Name *").fill(name);
await page.getByTestId("form-submit").click();
await expectUrl(page).toHavePathName(`/templates/${name}/files`, {
timeout: 30000,
});
await expectUrl(page).toHavePathName(
organizationsEnabled
? `/templates/${orgName}/${name}/files`
: `/templates/${name}/files`,
{
timeout: 30000,
},
);
return name;
};
// createGroup navigates to the /groups/create page and creates a group with a
// random name.
/**
* createGroup navigates to the /groups/create page and creates a group with a
* random name.
*/
export const createGroup = async (page: Page): Promise<string> => {
await page.goto("/groups/create", { waitUntil: "domcontentloaded" });
await expectUrl(page).toHavePathName("/groups/create");
@@ -209,13 +237,13 @@ export const createGroup = async (page: Page): Promise<string> => {
const name = randomName();
await page.getByLabel("Name", { exact: true }).fill(name);
await page.getByTestId("form-submit").click();
await expect(page).toHaveURL(
/\/groups\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
);
await expectUrl(page).toHavePathName(`/groups/${name}`);
return name;
};
// sshIntoWorkspace spawns a Coder SSH process and a client connected to it.
/**
* sshIntoWorkspace spawns a Coder SSH process and a client connected to it.
*/
export const sshIntoWorkspace = async (
page: Page,
workspace: string,
@@ -298,8 +326,10 @@ export const buildWorkspaceWithParameters = async (
});
};
// startAgent runs the coder agent with the provided token.
// It awaits the agent to be ready before returning.
/**
* startAgent runs the coder agent with the provided token. It waits for the
* agent to be ready before returning.
*/
export const startAgent = async (
page: Page,
token: string,
@@ -307,8 +337,10 @@ export const startAgent = async (
return startAgentWithCommand(page, token, "go", "run", coderMain);
};
// downloadCoderVersion downloads the version provided into a temporary dir and
// caches it so subsequent calls are fast.
/**
* downloadCoderVersion downloads the version provided into a temporary dir and
* caches it so subsequent calls are fast.
*/
export const downloadCoderVersion = async (
version: string,
): Promise<string> => {
@@ -448,8 +480,10 @@ interface EchoProvisionerResponses {
apply?: RecursivePartial<Response>[];
}
// createTemplateVersionTar consumes a series of echo provisioner protobufs and
// converts it into an uploadable tar file.
/**
* createTemplateVersionTar consumes a series of echo provisioner protobufs and
* converts it into an uploadable tar file.
*/
const createTemplateVersionTar = async (
responses?: EchoProvisionerResponses,
): Promise<Buffer> => {
@@ -619,8 +653,10 @@ export const randomName = () => {
return randomUUID().slice(0, 8);
};
// Awaiter is a helper that allows you to wait for a callback to be called.
// It is useful for waiting for events to occur.
/**
* Awaiter is a helper that allows you to wait for a callback to be called. It
* is useful for waiting for events to occur.
*/
export class Awaiter {
private promise: Promise<void>;
private callback?: () => void;
@@ -825,7 +861,6 @@ export const updateTemplateSettings = async (
await page.goto(`/templates/${templateName}/settings`, {
waitUntil: "domcontentloaded",
});
await expectUrl(page).toHavePathName(`/templates/${templateName}/settings`);
for (const [key, value] of Object.entries(templateSettingValues)) {
// Skip max_port_share_level for now since the frontend is not yet able to handle it
@@ -839,7 +874,7 @@ export const updateTemplateSettings = async (
await page.getByTestId("form-submit").click();
const name = templateSettingValues.name ?? templateName;
await expectUrl(page).toHavePathName(`/templates/${name}`);
await expectUrl(page).toHavePathNameEndingWith(`/${name}`);
};
export const updateWorkspace = async (
+5
View File
@@ -70,6 +70,11 @@ export default defineConfig({
],
reporter: [["./reporter.ts"]],
use: {
// It'd be very nice to add this, but there are some tests that need
// tweaking to make it work consistently (notably, ones that wait for agent
// stats on the workspace page. The default is like 50 seconds, which is
// way too long and makes it painful to wait for test runs in CI.
// actionTimeout: 5000, // 5 seconds
baseURL: `http://localhost:${coderPort}`,
video: "retain-on-failure",
...(wsEndpoint
+3 -3
View File
@@ -10,7 +10,7 @@ import type {
TestResult,
} from "@playwright/test/reporter";
import { API } from "api/api";
import { coderdPProfPort, enterpriseLicense } from "./constants";
import { coderdPProfPort, license } from "./constants";
class CoderReporter implements Reporter {
config: FullConfig | null = null;
@@ -108,9 +108,9 @@ class CoderReporter implements Reporter {
onEnd(result: FullResult) {
console.info(`==> Tests ${result.status}`);
if (!enterpriseLicense) {
if (!license) {
console.info(
"==> Enterprise tests were skipped, because no license was provided",
"==> Tests that require a license were skipped, because no license was provided",
);
}
console.info(`${this.passedCount} passed`);
+9 -9
View File
@@ -1,15 +1,11 @@
import { expect, test } from "@playwright/test";
import {
createTemplate,
createWorkspace,
requiresEnterpriseLicense,
} from "../helpers";
import { createTemplate, createWorkspace, requiresLicense } from "../helpers";
import { beforeCoderTest } from "../hooks";
test.beforeEach(({ page }) => beforeCoderTest(page));
test("inspecting and filtering audit logs", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
const userName = "admin";
// Do some stuff that should show up in the audit logs
@@ -48,20 +44,24 @@ test("inspecting and filtering audit logs", async ({ page }) => {
// Filter by resource type
await page.getByText("All resource types").click();
await page.getByRole("menu").getByText("Workspace Build").click();
const workspaceBuildsOption = page.getByText("Workspace Build");
await workspaceBuildsOption.scrollIntoViewIfNeeded({ timeout: 5000 });
await workspaceBuildsOption.click();
// Our workspace build should be visible
await expect(page.getByText(startedWorkspaceMessage)).toBeVisible();
// Logins should no longer be visible
await expect(page.getByText(loginMessage)).not.toBeVisible();
// Clear filters, everything should be visible again
await page.getByLabel("Clear filter").click();
await page.getByLabel("Clear search").click();
await expect(page.getByText(startedWorkspaceMessage)).toBeVisible();
await expect(page.getByText(loginMessage)).toBeVisible();
// Filter by action type
await page.getByText("All actions").click();
await page.getByRole("menu").getByText("Login").click();
const loginOption = page.getByText("Login");
await loginOption.scrollIntoViewIfNeeded({ timeout: 5000 });
await loginOption.click();
// Logins should be visible
await expect(page.getByText(loginMessage)).toBeVisible();
// Our workspace build should no longer be visible
+7 -7
View File
@@ -1,9 +1,9 @@
import { chromium, expect, test } from "@playwright/test";
import { expectUrl } from "../../expectUrl";
import { randomName, requiresEnterpriseLicense } from "../../helpers";
import { randomName, requiresLicense } from "../../helpers";
test("set application name", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
await page.goto("/deployment/appearance", { waitUntil: "domcontentloaded" });
@@ -33,7 +33,7 @@ test("set application name", async ({ page }) => {
});
test("set application logo", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
await page.goto("/deployment/appearance", { waitUntil: "domcontentloaded" });
@@ -61,17 +61,17 @@ test("set application logo", async ({ page }) => {
});
test("set service banner", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
await page.goto("/deployment/appearance", { waitUntil: "domcontentloaded" });
const message = "Mary has a little lamb.";
// Fill out the form
const form = page.locator("form", { hasText: "Service Banner" });
await form.getByLabel("Enabled", { exact: true }).check();
await page.getByRole("button", { name: "New" }).click();
const form = page.getByRole("presentation");
await form.getByLabel("Message", { exact: true }).fill(message);
await form.getByRole("button", { name: "Submit" }).click();
await form.getByRole("button", { name: "Update" }).click();
// Verify service banner
await page.goto("/workspaces", { waitUntil: "domcontentloaded" });
+3 -7
View File
@@ -1,8 +1,8 @@
import { expect, test } from "@playwright/test";
import { requiresEnterpriseLicense } from "../../helpers";
import { requiresLicense } from "../../helpers";
test("license was added successfully", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
await page.goto("/deployment/licenses", { waitUntil: "domcontentloaded" });
const firstLicense = page.locator(".licenses > .license-card", {
@@ -12,11 +12,7 @@ test("license was added successfully", async ({ page }) => {
// Trial vs. Enterprise?
const accountType = firstLicense.locator(".account-type");
await expect(accountType).toHaveText("Enterprise");
// User limit 1/1
const userLimit = firstLicense.locator(".user-limit");
await expect(userLimit).toHaveText("1 / 1");
await expect(accountType).toHaveText("Premium");
// License should not be expired yet
const licenseExpires = firstLicense.locator(".license-expires");
@@ -2,11 +2,11 @@ import { type Page, expect, test } from "@playwright/test";
import { API } from "api/api";
import { setupApiCalls } from "../../api";
import { coderPort, workspaceProxyPort } from "../../constants";
import { randomName, requiresEnterpriseLicense } from "../../helpers";
import { randomName, requiresLicense } from "../../helpers";
import { startWorkspaceProxy, stopWorkspaceProxy } from "../../proxy";
test("default proxy is online", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
await setupApiCalls(page);
await page.goto("/deployment/workspace-proxies", {
@@ -28,7 +28,7 @@ test("default proxy is online", async ({ page }) => {
});
test("custom proxy is online", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
await setupApiCalls(page);
const proxyName = randomName();
+2 -2
View File
@@ -5,13 +5,13 @@ import {
getCurrentOrgId,
setupApiCalls,
} from "../../api";
import { requiresEnterpriseLicense } from "../../helpers";
import { requiresLicense } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
test("add members", async ({ page, baseURL }) => {
requiresEnterpriseLicense();
requiresLicense();
await setupApiCalls(page);
const orgId = await getCurrentOrgId();
const group = await createGroup(orgId);
@@ -1,6 +1,6 @@
import { expect, test } from "@playwright/test";
import { createUser, getCurrentOrgId, setupApiCalls } from "../../api";
import { requiresEnterpriseLicense } from "../../helpers";
import { requiresLicense } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
@@ -11,7 +11,7 @@ test(`Every user should be automatically added to the default '${DEFAULT_GROUP_N
page,
baseURL,
}) => {
requiresEnterpriseLicense();
requiresLicense();
await setupApiCalls(page);
const orgId = await getCurrentOrgId();
const numberOfMembers = 3;
+2 -2
View File
@@ -1,11 +1,11 @@
import { expect, test } from "@playwright/test";
import { randomName, requiresEnterpriseLicense } from "../../helpers";
import { randomName, requiresLicense } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
test("create group", async ({ page, baseURL }) => {
requiresEnterpriseLicense();
requiresLicense();
await page.goto(`${baseURL}/groups`, { waitUntil: "domcontentloaded" });
await expect(page).toHaveTitle("Groups - Coder");
@@ -1,23 +0,0 @@
import { expect, test } from "@playwright/test";
import { createGroup, getCurrentOrgId, setupApiCalls } from "../../api";
import { requiresEnterpriseLicense } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
test("navigate to group page", async ({ page, baseURL }) => {
requiresEnterpriseLicense();
await setupApiCalls(page);
const orgId = await getCurrentOrgId();
const group = await createGroup(orgId);
await page.goto(`${baseURL}/users`, { waitUntil: "domcontentloaded" });
await expect(page).toHaveTitle("Users - Coder");
await page.getByRole("link", { name: "Groups" }).click();
await expect(page).toHaveTitle("Groups - Coder");
const groupRow = page.getByRole("row", { name: group.display_name });
await groupRow.click();
await expect(page).toHaveTitle(`${group.display_name} - Coder`);
});
+2 -2
View File
@@ -1,12 +1,12 @@
import { expect, test } from "@playwright/test";
import { createGroup, getCurrentOrgId, setupApiCalls } from "../../api";
import { requiresEnterpriseLicense } from "../../helpers";
import { requiresLicense } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
test("remove group", async ({ page, baseURL }) => {
requiresEnterpriseLicense();
requiresLicense();
await setupApiCalls(page);
const orgId = await getCurrentOrgId();
const group = await createGroup(orgId);
+2 -2
View File
@@ -6,13 +6,13 @@ import {
getCurrentOrgId,
setupApiCalls,
} from "../../api";
import { requiresEnterpriseLicense } from "../../helpers";
import { requiresLicense } from "../../helpers";
import { beforeCoderTest } from "../../hooks";
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
test("remove member", async ({ page, baseURL }) => {
requiresEnterpriseLicense();
requiresLicense();
await setupApiCalls(page);
const orgId = await getCurrentOrgId();
const [group, member] = await Promise.all([
+5 -5
View File
@@ -1,7 +1,7 @@
import { expect, test } from "@playwright/test";
import { setupApiCalls } from "../api";
import { expectUrl } from "../expectUrl";
import { requiresEnterpriseLicense } from "../helpers";
import { requiresLicense } from "../helpers";
import { beforeCoderTest } from "../hooks";
test.beforeEach(async ({ page }) => {
@@ -9,15 +9,15 @@ test.beforeEach(async ({ page }) => {
await setupApiCalls(page);
});
test("create and delete organization", async ({ page, baseURL }) => {
requiresEnterpriseLicense();
test("create and delete organization", async ({ page }) => {
requiresLicense();
// Create an organization
await page.goto(`${baseURL}/organizations/new`, {
await page.goto("/organizations/new", {
waitUntil: "domcontentloaded",
});
await page.getByLabel("Name", { exact: true }).fill("floop");
await page.getByLabel("Slug", { exact: true }).fill("floop");
await page.getByLabel("Display name").fill("Floop");
await page.getByLabel("Description").fill("Org description floop");
await page.getByLabel("Icon", { exact: true }).fill("/emojis/1f957.png");
+9 -10
View File
@@ -1,9 +1,10 @@
import { expect, test } from "@playwright/test";
import { defaultOrganizationName } from "../constants";
import { expectUrl } from "../expectUrl";
import {
createGroup,
createTemplate,
requiresEnterpriseLicense,
requiresLicense,
updateTemplateSettings,
} from "../helpers";
import { beforeCoderTest } from "../hooks";
@@ -14,23 +15,21 @@ test("template update with new name redirects on successful submit", async ({
page,
}) => {
const templateName = await createTemplate(page);
await updateTemplateSettings(page, templateName, {
name: "new-name",
});
});
test("add and remove a group", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
const templateName = await createTemplate(page);
const orgName = defaultOrganizationName;
const templateName = await createTemplate(page, undefined, orgName);
const groupName = await createGroup(page);
await page.goto(`/templates/${templateName}/settings/permissions`, {
waitUntil: "domcontentloaded",
});
await expectUrl(page).toHavePathName(
`/templates/${templateName}/settings/permissions`,
await page.goto(
`/templates/${orgName}/${templateName}/settings/permissions`,
{ waitUntil: "domcontentloaded" },
);
// Type the first half of the group name
@@ -52,7 +51,7 @@ test("add and remove a group", async ({ page }) => {
});
test("require latest version", async ({ page }) => {
requiresEnterpriseLicense();
requiresLicense();
const templateName = await createTemplate(page);
@@ -40,6 +40,6 @@ export const ClearValue: Story = {
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole("button", { name: "Clear field" }));
await userEvent.click(canvas.getByRole("button", { name: "Clear search" }));
},
};
@@ -40,7 +40,7 @@ export const SearchField: FC<SearchFieldProps> = ({
),
endAdornment: value !== "" && (
<InputAdornment position="end">
<Tooltip title="Clear field">
<Tooltip title="Clear search">
<IconButton
size="small"
onClick={() => {
@@ -48,7 +48,7 @@ export const SearchField: FC<SearchFieldProps> = ({
}}
>
<CloseIcon css={{ fontSize: 14 }} />
<span css={{ ...visuallyHidden }}>Clear field</span>
<span css={{ ...visuallyHidden }}>Clear search</span>
</IconButton>
</Tooltip>
</InputAdornment>