mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
test(site): e2e: restart workspace with ephemeral parameters (#9304)
This commit is contained in:
@ -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<void> => {
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
45
site/e2e/tests/restartWorkspace.spec.ts
Normal file
45
site/e2e/tests/restartWorkspace.spec.ts
Normal file
@ -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 },
|
||||
])
|
||||
})
|
49
site/e2e/tests/startWorkspace.spec.ts
Normal file
49
site/e2e/tests/startWorkspace.spec.ts
Normal file
@ -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 },
|
||||
])
|
||||
})
|
@ -94,6 +94,7 @@ export const StopButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
|
||||
loadingPosition="start"
|
||||
startIcon={<CropSquareIcon />}
|
||||
onClick={handleAction}
|
||||
data-testid="workspace-stop-button"
|
||||
>
|
||||
Stop
|
||||
</LoadingButton>
|
||||
|
Reference in New Issue
Block a user