mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat(site): support match option for auto create workspace flow (#13836)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { username } from "../../constants";
|
||||
import {
|
||||
createTemplate,
|
||||
createWorkspace,
|
||||
echoResponsesWithParameters,
|
||||
} from "../../helpers";
|
||||
import { emptyParameter } from "../../parameters";
|
||||
import type { RichParameter } from "../../provisionerGenerated";
|
||||
|
||||
test("create workspace in auto mode", async ({ page }) => {
|
||||
const richParameters: RichParameter[] = [
|
||||
{ ...emptyParameter, name: "repo", type: "string" },
|
||||
];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
const name = "test-workspace";
|
||||
await page.goto(
|
||||
`/templates/${template}/workspace?mode=auto¶m.repo=example&name=${name}`,
|
||||
{
|
||||
waitUntil: "domcontentloaded",
|
||||
},
|
||||
);
|
||||
await expect(page).toHaveTitle(`${username}/${name} - Coder`);
|
||||
});
|
||||
|
||||
test("use an existing workspace that matches the `match` parameter instead of creating a new one", async ({
|
||||
page,
|
||||
}) => {
|
||||
const richParameters: RichParameter[] = [
|
||||
{ ...emptyParameter, name: "repo", type: "string" },
|
||||
];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
const prevWorkspace = await createWorkspace(page, template);
|
||||
await page.goto(
|
||||
`/templates/${template}/workspace?mode=auto¶m.repo=example&name=new-name&match=name:${prevWorkspace}`,
|
||||
{
|
||||
waitUntil: "domcontentloaded",
|
||||
},
|
||||
);
|
||||
await expect(page).toHaveTitle(`${username}/${prevWorkspace} - Coder`);
|
||||
});
|
||||
|
||||
test("show error if `match` parameter is invalid", async ({ page }) => {
|
||||
const richParameters: RichParameter[] = [
|
||||
{ ...emptyParameter, name: "repo", type: "string" },
|
||||
];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
const prevWorkspace = await createWorkspace(page, template);
|
||||
await page.goto(
|
||||
`/templates/${template}/workspace?mode=auto¶m.repo=example&name=new-name&match=not-valid-query:${prevWorkspace}`,
|
||||
{
|
||||
waitUntil: "domcontentloaded",
|
||||
},
|
||||
);
|
||||
await expect(page.getByText("Invalid match value")).toBeVisible();
|
||||
});
|
||||
@@ -0,0 +1,191 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import {
|
||||
StarterTemplates,
|
||||
createTemplate,
|
||||
createWorkspace,
|
||||
echoResponsesWithParameters,
|
||||
openTerminalWindow,
|
||||
requireTerraformProvisioner,
|
||||
verifyParameters,
|
||||
} from "../../helpers";
|
||||
import { beforeCoderTest } from "../../hooks";
|
||||
import {
|
||||
secondParameter,
|
||||
fourthParameter,
|
||||
fifthParameter,
|
||||
firstParameter,
|
||||
thirdParameter,
|
||||
seventhParameter,
|
||||
sixthParameter,
|
||||
randParamName,
|
||||
} from "../../parameters";
|
||||
import type { RichParameter } from "../../provisionerGenerated";
|
||||
|
||||
test.beforeEach(({ page }) => beforeCoderTest(page));
|
||||
|
||||
test("create workspace", async ({ page }) => {
|
||||
const template = await createTemplate(page, {
|
||||
apply: [
|
||||
{
|
||||
apply: {
|
||||
resources: [
|
||||
{
|
||||
name: "example",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
await createWorkspace(page, template);
|
||||
});
|
||||
|
||||
test("create workspace with default immutable parameters", async ({ page }) => {
|
||||
const richParameters: RichParameter[] = [
|
||||
secondParameter,
|
||||
fourthParameter,
|
||||
fifthParameter,
|
||||
];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
const workspaceName = await createWorkspace(page, template);
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: secondParameter.name, value: secondParameter.defaultValue },
|
||||
{ name: fourthParameter.name, value: fourthParameter.defaultValue },
|
||||
{ name: fifthParameter.name, value: fifthParameter.defaultValue },
|
||||
]);
|
||||
});
|
||||
|
||||
test("create workspace with default mutable parameters", async ({ page }) => {
|
||||
const richParameters: RichParameter[] = [firstParameter, thirdParameter];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
const workspaceName = await createWorkspace(page, template);
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: thirdParameter.name, value: thirdParameter.defaultValue },
|
||||
]);
|
||||
});
|
||||
|
||||
test("create workspace with default and required parameters", async ({
|
||||
page,
|
||||
}) => {
|
||||
const richParameters: RichParameter[] = [
|
||||
secondParameter,
|
||||
fourthParameter,
|
||||
sixthParameter,
|
||||
seventhParameter,
|
||||
];
|
||||
const buildParameters = [
|
||||
{ name: sixthParameter.name, value: "12345" },
|
||||
{ name: seventhParameter.name, value: "abcdef" },
|
||||
];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
const workspaceName = await createWorkspace(
|
||||
page,
|
||||
template,
|
||||
richParameters,
|
||||
buildParameters,
|
||||
);
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
// user values:
|
||||
...buildParameters,
|
||||
// default values:
|
||||
{ name: secondParameter.name, value: secondParameter.defaultValue },
|
||||
{ name: fourthParameter.name, value: fourthParameter.defaultValue },
|
||||
]);
|
||||
});
|
||||
|
||||
test("create workspace and overwrite default parameters", async ({ page }) => {
|
||||
// We use randParamName to prevent the new values from corrupting user_history
|
||||
// and thus affecting other tests.
|
||||
const richParameters: RichParameter[] = [
|
||||
randParamName(secondParameter),
|
||||
randParamName(fourthParameter),
|
||||
];
|
||||
|
||||
const buildParameters = [
|
||||
{ name: richParameters[0].name, value: "AAAAA" },
|
||||
{ name: richParameters[1].name, value: "false" },
|
||||
];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
|
||||
const workspaceName = await createWorkspace(
|
||||
page,
|
||||
template,
|
||||
richParameters,
|
||||
buildParameters,
|
||||
);
|
||||
await verifyParameters(page, workspaceName, richParameters, buildParameters);
|
||||
});
|
||||
|
||||
test("create workspace with disable_param search params", async ({ page }) => {
|
||||
const richParameters: RichParameter[] = [
|
||||
firstParameter, // mutable
|
||||
secondParameter, //immutable
|
||||
];
|
||||
|
||||
const templateName = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
|
||||
await page.goto(
|
||||
`/templates/${templateName}/workspace?disable_params=first_parameter,second_parameter`,
|
||||
{
|
||||
waitUntil: "domcontentloaded",
|
||||
},
|
||||
);
|
||||
|
||||
await expect(page.getByLabel(/First parameter/i)).toBeDisabled();
|
||||
await expect(page.getByLabel(/Second parameter/i)).toBeDisabled();
|
||||
});
|
||||
|
||||
test("create docker workspace", async ({ context, page }) => {
|
||||
test.skip(
|
||||
true,
|
||||
"creating docker containers is currently leaky. They are not cleaned up when the tests are over.",
|
||||
);
|
||||
requireTerraformProvisioner();
|
||||
const template = await createTemplate(page, StarterTemplates.STARTER_DOCKER);
|
||||
|
||||
const workspaceName = await createWorkspace(page, template);
|
||||
|
||||
// The workspace agents must be ready before we try to interact with the workspace.
|
||||
await page.waitForSelector(
|
||||
`//div[@role="status"][@data-testid="agent-status-ready"]`,
|
||||
{
|
||||
state: "visible",
|
||||
},
|
||||
);
|
||||
|
||||
// Wait for the terminal button to be visible, and click it.
|
||||
const terminalButton =
|
||||
"//a[@data-testid='terminal'][normalize-space()='Terminal']";
|
||||
await page.waitForSelector(terminalButton, {
|
||||
state: "visible",
|
||||
});
|
||||
|
||||
const terminal = await openTerminalWindow(
|
||||
page,
|
||||
context,
|
||||
workspaceName,
|
||||
"main",
|
||||
);
|
||||
await terminal.waitForSelector(
|
||||
`//textarea[contains(@class,"xterm-helper-textarea")]`,
|
||||
{
|
||||
state: "visible",
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { test } from "@playwright/test";
|
||||
import {
|
||||
buildWorkspaceWithParameters,
|
||||
createTemplate,
|
||||
createWorkspace,
|
||||
echoResponsesWithParameters,
|
||||
verifyParameters,
|
||||
} from "../../helpers";
|
||||
import { beforeCoderTest } from "../../hooks";
|
||||
import { firstBuildOption, secondBuildOption } from "../../parameters";
|
||||
import type { RichParameter } from "../../provisionerGenerated";
|
||||
|
||||
test.beforeEach(({ page }) => beforeCoderTest(page));
|
||||
|
||||
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: richParameters[0].name, value: firstBuildOption.defaultValue },
|
||||
{ name: richParameters[1].name, value: secondBuildOption.defaultValue },
|
||||
]);
|
||||
|
||||
// Now, restart the workspace with ephemeral parameters selected.
|
||||
const buildParameters = [
|
||||
{ name: richParameters[0].name, value: "AAAAA" },
|
||||
{ name: richParameters[1].name, value: "true" },
|
||||
];
|
||||
await buildWorkspaceWithParameters(
|
||||
page,
|
||||
workspaceName,
|
||||
richParameters,
|
||||
buildParameters,
|
||||
true,
|
||||
);
|
||||
|
||||
// Verify that build options are default (not selected).
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: richParameters[0].name, value: firstBuildOption.defaultValue },
|
||||
{ name: richParameters[1].name, value: secondBuildOption.defaultValue },
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { test } from "@playwright/test";
|
||||
import {
|
||||
buildWorkspaceWithParameters,
|
||||
createTemplate,
|
||||
createWorkspace,
|
||||
echoResponsesWithParameters,
|
||||
stopWorkspace,
|
||||
verifyParameters,
|
||||
} from "../../helpers";
|
||||
import { beforeCoderTest } from "../../hooks";
|
||||
import { firstBuildOption, secondBuildOption } from "../../parameters";
|
||||
import type { RichParameter } from "../../provisionerGenerated";
|
||||
|
||||
test.beforeEach(({ page }) => beforeCoderTest(page));
|
||||
|
||||
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: richParameters[0].name, value: firstBuildOption.defaultValue },
|
||||
{ name: richParameters[1].name, value: secondBuildOption.defaultValue },
|
||||
]);
|
||||
|
||||
// Stop the workspace
|
||||
await stopWorkspace(page, workspaceName);
|
||||
|
||||
// Now, start the workspace with ephemeral parameters selected.
|
||||
const buildParameters = [
|
||||
{ name: richParameters[0].name, value: "AAAAA" },
|
||||
{ name: richParameters[1].name, value: "true" },
|
||||
];
|
||||
|
||||
await buildWorkspaceWithParameters(
|
||||
page,
|
||||
workspaceName,
|
||||
richParameters,
|
||||
buildParameters,
|
||||
);
|
||||
|
||||
// Verify that build options are default (not selected).
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: richParameters[0].name, value: firstBuildOption.defaultValue },
|
||||
{ name: richParameters[1].name, value: secondBuildOption.defaultValue },
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
import { test } from "@playwright/test";
|
||||
import {
|
||||
createTemplate,
|
||||
createWorkspace,
|
||||
echoResponsesWithParameters,
|
||||
updateTemplate,
|
||||
updateWorkspace,
|
||||
updateWorkspaceParameters,
|
||||
verifyParameters,
|
||||
} from "../../helpers";
|
||||
import { beforeCoderTest } from "../../hooks";
|
||||
import {
|
||||
fifthParameter,
|
||||
firstParameter,
|
||||
secondParameter,
|
||||
sixthParameter,
|
||||
secondBuildOption,
|
||||
} from "../../parameters";
|
||||
import type { RichParameter } from "../../provisionerGenerated";
|
||||
|
||||
test.beforeEach(({ page }) => beforeCoderTest(page));
|
||||
|
||||
test("update workspace, new optional, immutable parameter added", async ({
|
||||
page,
|
||||
}) => {
|
||||
const richParameters: RichParameter[] = [firstParameter, secondParameter];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
|
||||
const workspaceName = await createWorkspace(page, template);
|
||||
|
||||
// Verify that parameter values are default.
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: secondParameter.name, value: secondParameter.defaultValue },
|
||||
]);
|
||||
|
||||
// Push updated template.
|
||||
const updatedRichParameters = [...richParameters, fifthParameter];
|
||||
await updateTemplate(
|
||||
page,
|
||||
template,
|
||||
echoResponsesWithParameters(updatedRichParameters),
|
||||
);
|
||||
|
||||
// Now, update the workspace, and select the value for immutable parameter.
|
||||
await updateWorkspace(page, workspaceName, updatedRichParameters, [
|
||||
{ name: fifthParameter.name, value: fifthParameter.options[0].value },
|
||||
]);
|
||||
|
||||
// Verify parameter values.
|
||||
await verifyParameters(page, workspaceName, updatedRichParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: secondParameter.name, value: secondParameter.defaultValue },
|
||||
{ name: fifthParameter.name, value: fifthParameter.options[0].value },
|
||||
]);
|
||||
});
|
||||
|
||||
test("update workspace, new required, mutable parameter added", async ({
|
||||
page,
|
||||
}) => {
|
||||
const richParameters: RichParameter[] = [firstParameter, secondParameter];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
|
||||
const workspaceName = await createWorkspace(page, template);
|
||||
|
||||
// Verify that parameter values are default.
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: secondParameter.name, value: secondParameter.defaultValue },
|
||||
]);
|
||||
|
||||
// Push updated template.
|
||||
const updatedRichParameters = [...richParameters, sixthParameter];
|
||||
await updateTemplate(
|
||||
page,
|
||||
template,
|
||||
echoResponsesWithParameters(updatedRichParameters),
|
||||
);
|
||||
|
||||
// Now, update the workspace, and provide the parameter value.
|
||||
const buildParameters = [{ name: sixthParameter.name, value: "99" }];
|
||||
await updateWorkspace(
|
||||
page,
|
||||
workspaceName,
|
||||
updatedRichParameters,
|
||||
buildParameters,
|
||||
);
|
||||
|
||||
// Verify parameter values.
|
||||
await verifyParameters(page, workspaceName, updatedRichParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: secondParameter.name, value: secondParameter.defaultValue },
|
||||
...buildParameters,
|
||||
]);
|
||||
});
|
||||
|
||||
test("update workspace with ephemeral parameter enabled", async ({ page }) => {
|
||||
const richParameters: RichParameter[] = [firstParameter, secondBuildOption];
|
||||
const template = await createTemplate(
|
||||
page,
|
||||
echoResponsesWithParameters(richParameters),
|
||||
);
|
||||
|
||||
const workspaceName = await createWorkspace(page, template);
|
||||
|
||||
// Verify that parameter values are default.
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: secondBuildOption.name, value: secondBuildOption.defaultValue },
|
||||
]);
|
||||
|
||||
// Now, update the workspace, and select the value for ephemeral parameter.
|
||||
const buildParameters = [{ name: secondBuildOption.name, value: "true" }];
|
||||
await updateWorkspaceParameters(
|
||||
page,
|
||||
workspaceName,
|
||||
richParameters,
|
||||
buildParameters,
|
||||
);
|
||||
|
||||
// Verify that parameter values are default.
|
||||
await verifyParameters(page, workspaceName, richParameters, [
|
||||
{ name: firstParameter.name, value: firstParameter.defaultValue },
|
||||
{ name: secondBuildOption.name, value: secondBuildOption.defaultValue },
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user