chore: add more e2e template settings tests (#12717)

This commit is contained in:
Kayla Washburn-Love 2024-03-28 16:00:27 -06:00 committed by GitHub
parent 8cf1e84bb5
commit f3cfe10c26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 87 additions and 41 deletions

View File

@ -472,11 +472,19 @@ jobs:
- run: pnpm playwright:install
working-directory: site
- run: pnpm playwright:test --workers 1
# Run tests that don't require an enterprise license without an enterprise license
- run: pnpm playwright:test --forbid-only --workers 1
env:
DEBUG: pw:api
working-directory: site
# Run all of the tests with an enterprise license
- run: pnpm playwright:test --forbid-only --workers 1
env:
DEBUG: pw:api
CODER_E2E_ENTERPRISE_LICENSE: ${{ secrets.CODER_E2E_ENTERPRISE_LICENSE }}
working-directory: site
- 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@v4

View File

@ -3,7 +3,7 @@ set -euo pipefail
workspace=${1:-}
coder_repo=${2:-.}
port=${3:-3000}
port=${3:-3111}
if [[ -z "${workspace}" ]]; then
echo "Usage: $0 <workspace> [workspace coder/coder dir] [e2e port]"

View File

@ -1,3 +1,7 @@
import * as path from "path";
export const coderMain = path.join(__dirname, "../../enterprise/cmd/coder");
// Default port from the server
export const coderPort = process.env.CODER_E2E_PORT
? Number(process.env.CODER_E2E_PORT)
@ -28,3 +32,5 @@ export const gitAuth = {
validatePath: "/validate",
installationsPath: "/installations",
};
export const enterpriseLicense = process.env.CODER_E2E_ENTERPRISE_LICENSE ?? "";

View File

@ -6,6 +6,7 @@ import { storageState } from "./playwright.config";
test("setup first user", async ({ page }) => {
await page.goto("/", { waitUntil: "domcontentloaded" });
// 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);
@ -15,4 +16,15 @@ test("setup first user", async ({ page }) => {
await page.context().storageState({ path: storageState });
await page.getByTestId("button-select-template").isVisible();
// Setup license
if (constants.enterpriseLicense) {
await page.goto("/deployment/licenses", { waitUntil: "domcontentloaded" });
await page.getByText("Add a license").click();
await page.getByRole("textbox").fill(constants.enterpriseLicense);
await page.getByText("Upload License").click();
await page.getByText("You have successfully added a license").isVisible();
}
});

View File

@ -1,4 +1,4 @@
import { type BrowserContext, expect, type Page } from "@playwright/test";
import { type BrowserContext, expect, type Page, test } from "@playwright/test";
import axios from "axios";
import { type ChildProcess, exec, spawn } from "child_process";
import { randomUUID } from "crypto";
@ -12,7 +12,13 @@ import type {
UpdateTemplateMeta,
} from "api/typesGenerated";
import { TarWriter } from "utils/tar";
import { agentPProfPort, coderPort, prometheusPort } from "./constants";
import {
agentPProfPort,
coderMain,
coderPort,
enterpriseLicense,
prometheusPort,
} from "./constants";
import {
Agent,
type App,
@ -25,6 +31,11 @@ import {
type RichParameter,
} from "./provisionerGenerated";
// requiresEnterpriseLicense will skip the test if we're not running with an enterprise license
export function requiresEnterpriseLicense() {
test.skip(!enterpriseLicense);
}
// 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 (
@ -147,7 +158,7 @@ export const sshIntoWorkspace = async (
binaryArgs: string[] = [],
): Promise<ssh.Client> => {
if (binaryPath === "go") {
binaryArgs = ["run", coderMainPath()];
binaryArgs = ["run", coderMain];
}
const sessionToken = await findSessionToken(page);
return new Promise<ssh.Client>((resolve, reject) => {
@ -229,7 +240,7 @@ export const startAgent = async (
page: Page,
token: string,
): Promise<ChildProcess> => {
return startAgentWithCommand(page, token, "go", "run", coderMainPath());
return startAgentWithCommand(page, token, "go", "run", coderMain);
};
// downloadCoderVersion downloads the version provided into a temporary dir and
@ -358,18 +369,6 @@ const waitUntilUrlIsNotResponding = async (url: string) => {
);
};
const coderMainPath = (): string => {
return path.join(
__dirname,
"..",
"..",
"enterprise",
"cmd",
"coder",
"main.go",
);
};
// Allows users to more easily define properties they want for agents and resources!
type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends (infer U)[]
@ -686,7 +685,7 @@ export const updateTemplate = async (
"go",
[
"run",
coderMainPath(),
coderMain,
"templates",
"push",
"--test.provisioner",

View File

@ -1,11 +1,9 @@
import { defineConfig } from "@playwright/test";
import path from "path";
import { coderPort, coderdPProfPort, gitAuth } from "./constants";
import * as path from "path";
import { coderMain, coderPort, coderdPProfPort, gitAuth } from "./constants";
export const wsEndpoint = process.env.CODER_E2E_WS_ENDPOINT;
const coderMain = path.join(__dirname, "../../enterprise/cmd/coder");
// This is where auth cookies are stored!
export const storageState = path.join(__dirname, ".auth.json");
@ -16,16 +14,14 @@ const localURL = (port: number, path: string): string => {
export default defineConfig({
projects: [
{
name: "setup",
name: "testsSetup",
testMatch: /global.setup\.ts/,
},
{
name: "tests",
testMatch: /.*\.spec\.ts/,
dependencies: ["setup"],
use: {
storageState: storageState,
},
dependencies: ["testsSetup"],
use: { storageState },
timeout: 60_000,
},
],

View File

@ -1,5 +1,9 @@
import { test } from "@playwright/test";
import { createTemplate, updateTemplateSettings } from "../helpers";
import { expect, test } from "@playwright/test";
import {
createTemplate,
requiresEnterpriseLicense,
updateTemplateSettings,
} from "../helpers";
test("template update with new name redirects on successful submit", async ({
page,
@ -10,3 +14,24 @@ test("template update with new name redirects on successful submit", async ({
name: "new-name",
});
});
test("require latest version", async ({ page }) => {
requiresEnterpriseLicense();
const templateName = await createTemplate(page);
await page.goto(`/templates/${templateName}/settings`, {
waitUntil: "domcontentloaded",
});
await expect(page).toHaveURL(`/templates/${templateName}/settings`);
let checkbox = await page.waitForSelector("#require_active_version");
await checkbox.click();
await page.getByTestId("form-submit").click();
await page.goto(`/templates/${templateName}/settings`, {
waitUntil: "domcontentloaded",
});
checkbox = await page.waitForSelector("#require_active_version");
await checkbox.scrollIntoViewIfNeeded();
expect(await checkbox.isChecked()).toBe(true);
});

View File

@ -95,7 +95,7 @@
},
"devDependencies": {
"@octokit/types": "12.3.0",
"@playwright/test": "1.39.0",
"@playwright/test": "1.42.1",
"@storybook/addon-actions": "7.6.11",
"@storybook/addon-essentials": "7.6.11",
"@storybook/addon-interactions": "7.6.11",

View File

@ -204,8 +204,8 @@ devDependencies:
specifier: 12.3.0
version: 12.3.0
'@playwright/test':
specifier: 1.39.0
version: 1.39.0
specifier: 1.42.1
version: 1.42.1
'@storybook/addon-actions':
specifier: 7.6.11
version: 7.6.11
@ -3064,12 +3064,12 @@ packages:
dev: true
optional: true
/@playwright/test@1.39.0:
resolution: {integrity: sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==}
/@playwright/test@1.42.1:
resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==}
engines: {node: '>=16'}
hasBin: true
dependencies:
playwright: 1.39.0
playwright: 1.42.1
dev: true
/@popperjs/core@2.11.8:
@ -11478,18 +11478,18 @@ packages:
find-up: 5.0.0
dev: true
/playwright-core@1.39.0:
resolution: {integrity: sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==}
/playwright-core@1.42.1:
resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==}
engines: {node: '>=16'}
hasBin: true
dev: true
/playwright@1.39.0:
resolution: {integrity: sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==}
/playwright@1.42.1:
resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==}
engines: {node: '>=16'}
hasBin: true
dependencies:
playwright-core: 1.39.0
playwright-core: 1.42.1
optionalDependencies:
fsevents: 2.3.2
dev: true