From d7a788d89d520968875cb49f907f6483f89b1a0f Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 25 Aug 2023 14:50:38 +0200 Subject: [PATCH] test(site): e2e: restart workspace with ephemeral parameters (#9304) --- site/e2e/helpers.ts | 140 ++++++++++++------ site/e2e/parameters.ts | 36 +++-- site/e2e/tests/restartWorkspace.spec.ts | 45 ++++++ site/e2e/tests/startWorkspace.spec.ts | 49 ++++++ .../components/WorkspaceActions/Buttons.tsx | 1 + 5 files changed, 219 insertions(+), 52 deletions(-) create mode 100644 site/e2e/tests/restartWorkspace.spec.ts create mode 100644 site/e2e/tests/startWorkspace.spec.ts diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index aa0e2e32eb..8743b13730 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -34,52 +34,16 @@ export const createWorkspace = async ( const name = randomName() await page.getByLabel("name").fill(name) - for (const buildParameter of buildParameters) { - const richParameter = richParameters.find( - (richParam) => richParam.name === buildParameter.name, - ) - if (!richParameter) { - throw new Error( - "build parameter is expected to be present in rich parameter schema", - ) - } - - const parameterLabel = await page.waitForSelector( - "[data-testid='parameter-field-" + richParameter.name + "']", - { state: "visible" }, - ) - - if (richParameter.type === "bool") { - const parameterField = await parameterLabel.waitForSelector( - "[data-testid='parameter-field-bool'] .MuiRadio-root input[value='" + - buildParameter.value + - "']", - ) - await parameterField.check() - } else if (richParameter.options.length > 0) { - const parameterField = await parameterLabel.waitForSelector( - "[data-testid='parameter-field-options'] .MuiRadio-root input[value='" + - buildParameter.value + - "']", - ) - await parameterField.check() - } else if (richParameter.type === "list(string)") { - throw new Error("not implemented yet") // FIXME - } else { - // text or number - const parameterField = await parameterLabel.waitForSelector( - "[data-testid='parameter-field-text'] input", - ) - await parameterField.fill(buildParameter.value) - } - } - + await fillParameters(page, richParameters, buildParameters) await page.getByTestId("form-submit").click() await expect(page).toHaveURL("/@admin/" + name) - await page.waitForSelector("[data-testid='build-status']", { - state: "visible", - }) + await page.waitForSelector( + "span[data-testid='build-status'] >> text=Running", + { + state: "visible", + }, + ) return name } @@ -213,6 +177,50 @@ export const sshIntoWorkspace = async ( }) } +export const stopWorkspace = async (page: Page, workspaceName: string) => { + await page.goto("/@admin/" + workspaceName, { + waitUntil: "domcontentloaded", + }) + await expect(page).toHaveURL("/@admin/" + workspaceName) + + await page.getByTestId("workspace-stop-button").click() + + await page.waitForSelector( + "span[data-testid='build-status'] >> text=Stopped", + { + state: "visible", + }, + ) +} + +export const buildWorkspaceWithParameters = async ( + page: Page, + workspaceName: string, + richParameters: RichParameter[] = [], + buildParameters: WorkspaceBuildParameter[] = [], + confirm: boolean = false, +) => { + await page.goto("/@admin/" + workspaceName, { + waitUntil: "domcontentloaded", + }) + await expect(page).toHaveURL("/@admin/" + workspaceName) + + await page.getByTestId("build-parameters-button").click() + + await fillParameters(page, richParameters, buildParameters) + await page.getByTestId("build-parameters-submit").click() + if (confirm) { + await page.getByTestId("confirm-button").click() + } + + await page.waitForSelector( + "span[data-testid='build-status'] >> text=Running", + { + state: "visible", + }, + ) +} + // startAgent runs the coder agent with the provided token. // It awaits the agent to be ready before returning. export const startAgent = async (page: Page, token: string): Promise => { @@ -561,3 +569,49 @@ export const echoResponsesWithParameters = ( ], } } + +export const fillParameters = async ( + page: Page, + richParameters: RichParameter[] = [], + buildParameters: WorkspaceBuildParameter[] = [], +) => { + for (const buildParameter of buildParameters) { + const richParameter = richParameters.find( + (richParam) => richParam.name === buildParameter.name, + ) + if (!richParameter) { + throw new Error( + "build parameter is expected to be present in rich parameter schema", + ) + } + + const parameterLabel = await page.waitForSelector( + "[data-testid='parameter-field-" + richParameter.name + "']", + { state: "visible" }, + ) + + if (richParameter.type === "bool") { + const parameterField = await parameterLabel.waitForSelector( + "[data-testid='parameter-field-bool'] .MuiRadio-root input[value='" + + buildParameter.value + + "']", + ) + await parameterField.check() + } else if (richParameter.options.length > 0) { + const parameterField = await parameterLabel.waitForSelector( + "[data-testid='parameter-field-options'] .MuiRadio-root input[value='" + + buildParameter.value + + "']", + ) + await parameterField.check() + } else if (richParameter.type === "list(string)") { + throw new Error("not implemented yet") // FIXME + } else { + // text or number + const parameterField = await parameterLabel.waitForSelector( + "[data-testid='parameter-field-text'] input", + ) + await parameterField.fill(buildParameter.value) + } + } +} diff --git a/site/e2e/parameters.ts b/site/e2e/parameters.ts index c575fdcf83..240eeb0f85 100644 --- a/site/e2e/parameters.ts +++ b/site/e2e/parameters.ts @@ -28,7 +28,6 @@ export const firstParameter: RichParameter = { name: "first_parameter", displayName: "First parameter", type: "number", - options: [], description: "This is first parameter.", icon: "/emojis/1f310.png", defaultValue: "123", @@ -43,10 +42,8 @@ export const secondParameter: RichParameter = { name: "second_parameter", displayName: "Second parameter", type: "string", - options: [], description: "This is second parameter.", defaultValue: "abc", - icon: "", order: 2, } @@ -56,7 +53,6 @@ export const thirdParameter: RichParameter = { name: "third_parameter", type: "string", - options: [], description: "This is third parameter.", defaultValue: "", mutable: true, @@ -69,10 +65,8 @@ export const fourthParameter: RichParameter = { name: "fourth_parameter", type: "bool", - options: [], description: "This is fourth parameter.", defaultValue: "true", - icon: "", order: 3, } @@ -105,7 +99,6 @@ export const fifthParameter: RichParameter = { ], description: "This is fifth parameter.", defaultValue: "def", - icon: "", order: 3, } @@ -116,7 +109,6 @@ export const sixthParameter: RichParameter = { name: "sixth_parameter", displayName: "Sixth parameter", type: "number", - options: [], description: "This is sixth parameter.", icon: "/emojis/1f310.png", required: true, @@ -131,8 +123,34 @@ export const seventhParameter: RichParameter = { name: "seventh_parameter", displayName: "Seventh parameter", type: "string", - options: [], description: "This is seventh parameter.", required: true, order: 1, } + +// Build options + +export const firstBuildOption: RichParameter = { + ...emptyParameter, + + name: "first_build_option", + displayName: "First build option", + type: "string", + description: "This is first build option.", + icon: "/emojis/1f310.png", + defaultValue: "ABCDEF", + mutable: true, + ephemeral: true, +} + +export const secondBuildOption: RichParameter = { + ...emptyParameter, + + name: "second_build_option", + displayName: "Second build option", + type: "bool", + description: "This is second build option.", + defaultValue: "false", + mutable: true, + ephemeral: true, +} diff --git a/site/e2e/tests/restartWorkspace.spec.ts b/site/e2e/tests/restartWorkspace.spec.ts new file mode 100644 index 0000000000..eb5d0c99c0 --- /dev/null +++ b/site/e2e/tests/restartWorkspace.spec.ts @@ -0,0 +1,45 @@ +import { test } from "@playwright/test" +import { + buildWorkspaceWithParameters, + createTemplate, + createWorkspace, + echoResponsesWithParameters, + verifyParameters, +} from "../helpers" + +import { firstBuildOption, secondBuildOption } from "../parameters" +import { RichParameter } from "../provisionerGenerated" + +test("restart workspace with ephemeral parameters", async ({ page }) => { + const richParameters: RichParameter[] = [firstBuildOption, secondBuildOption] + const template = await createTemplate( + page, + echoResponsesWithParameters(richParameters), + ) + const workspaceName = await createWorkspace(page, template) + + // Verify that build options are default (not selected). + await verifyParameters(page, workspaceName, richParameters, [ + { name: firstBuildOption.name, value: firstBuildOption.defaultValue }, + { name: secondBuildOption.name, value: secondBuildOption.defaultValue }, + ]) + + // Now, restart the workspace with ephemeral parameters selected. + const buildParameters = [ + { name: firstBuildOption.name, value: "AAAAA" }, + { name: secondBuildOption.name, value: "true" }, + ] + await buildWorkspaceWithParameters( + page, + workspaceName, + richParameters, + buildParameters, + true, + ) + + // Verify that build options are default (not selected). + await verifyParameters(page, workspaceName, richParameters, [ + { name: firstBuildOption.name, value: firstBuildOption.defaultValue }, + { name: secondBuildOption.name, value: secondBuildOption.defaultValue }, + ]) +}) diff --git a/site/e2e/tests/startWorkspace.spec.ts b/site/e2e/tests/startWorkspace.spec.ts new file mode 100644 index 0000000000..232ac27299 --- /dev/null +++ b/site/e2e/tests/startWorkspace.spec.ts @@ -0,0 +1,49 @@ +import { test } from "@playwright/test" +import { + buildWorkspaceWithParameters, + createTemplate, + createWorkspace, + echoResponsesWithParameters, + stopWorkspace, + verifyParameters, +} from "../helpers" + +import { firstBuildOption, secondBuildOption } from "../parameters" +import { RichParameter } from "../provisionerGenerated" + +test("start workspace with ephemeral parameters", async ({ page }) => { + const richParameters: RichParameter[] = [firstBuildOption, secondBuildOption] + const template = await createTemplate( + page, + echoResponsesWithParameters(richParameters), + ) + const workspaceName = await createWorkspace(page, template) + + // Verify that build options are default (not selected). + await verifyParameters(page, workspaceName, richParameters, [ + { name: firstBuildOption.name, value: firstBuildOption.defaultValue }, + { name: secondBuildOption.name, value: secondBuildOption.defaultValue }, + ]) + + // Stop the workspace + await stopWorkspace(page, workspaceName) + + // Now, start the workspace with ephemeral parameters selected. + const buildParameters = [ + { name: firstBuildOption.name, value: "AAAAA" }, + { name: secondBuildOption.name, value: "true" }, + ] + + await buildWorkspaceWithParameters( + page, + workspaceName, + richParameters, + buildParameters, + ) + + // Verify that build options are default (not selected). + await verifyParameters(page, workspaceName, richParameters, [ + { name: firstBuildOption.name, value: firstBuildOption.defaultValue }, + { name: secondBuildOption.name, value: secondBuildOption.defaultValue }, + ]) +}) diff --git a/site/src/components/WorkspaceActions/Buttons.tsx b/site/src/components/WorkspaceActions/Buttons.tsx index 4d62e0bb9c..e2a005929a 100644 --- a/site/src/components/WorkspaceActions/Buttons.tsx +++ b/site/src/components/WorkspaceActions/Buttons.tsx @@ -94,6 +94,7 @@ export const StopButton: FC = ({ handleAction, loading }) => { loadingPosition="start" startIcon={} onClick={handleAction} + data-testid="workspace-stop-button" > Stop