Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2870 Map dropdown options. Tests #2963

Merged
merged 4 commits into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 147 additions & 35 deletions src/components/formBuilder/FormBuilder.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ async function selectUiType(uiType: string) {
}

describe("Dropdown field", () => {
async function addOption() {
// Add a text option
screen.getByText("Add Item").click();
const firstOption = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.enum.0"]`
);
fireTextInput(firstOption, "Test option");
await waitForEffect();
}

async function setVarValue() {
// Switch to @var and insert "@data"
await selectSchemaFieldType(
`form.schema.properties.${defaultFieldName}.enum`,
"var"
);
fireTextInput(screen.getByLabelText("Options"), "@data");
await waitForEffect();
}

let rendered: RenderResult;
beforeEach(async () => {
rendered = renderFormBuilder();
Expand All @@ -85,13 +105,7 @@ describe("Dropdown field", () => {
});

test("can add an option", async () => {
// Add a text option
screen.getByText("Add Item").click();
const firstOption = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.enum.0"]`
);
fireTextInput(firstOption, "Test option");
await waitForEffect();
await addOption();

// Expect the dropdown option rendered in the preview
expect(
Expand All @@ -100,35 +114,70 @@ describe("Dropdown field", () => {
});

test("can use @var", async () => {
// Switch to @var and inset "@data"
await selectSchemaFieldType(
`form.schema.properties.${defaultFieldName}.enum`,
"var"
);
fireTextInput(screen.getByLabelText("Options"), "@data");
await waitForEffect();
await setVarValue();

// Expect the dropdown option rendered in the preview
expect(screen.queryByRole("option", { name: "@data" })).not.toBeNull();
});
});

describe("Dropdown with labels field", () => {
let rendered: RenderResult;
beforeEach(async () => {
rendered = renderFormBuilder();
describe("can be switched to Dropdown with labels", () => {
test("with items", async () => {
await addOption();

// Switch to Dropdown widget
await selectUiType("Dropdown with labels");
});
test("doesn't fail when field type changed to Dropdown with labels", async () => {
// Expect the dropdown rendered in the preview
expect(
rendered.container.querySelector(`select#root_${defaultFieldName}`)
).not.toBeNull();
// Switch to Dropdown widget
await selectUiType("Dropdown with labels");

// Expect the ui type has changed
expect(
screen.queryByLabelText("Input Type")?.parentElement?.parentElement
).toHaveTextContent("Dropdown with labels");

// Expect the dropdown option added in the Editor
const firstOptionValueInput = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.oneOf.0.const"]`
);
// Option value mapped from Dropdown
expect(firstOptionValueInput).toHaveValue("Test option");

const firstOptionTitleInput = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.oneOf.0.title"]`
);
// Option title is empty
expect(firstOptionTitleInput).toHaveValue("");

// Expect the dropdown option rendered in the preview
expect(
screen.queryByRole("option", { name: "Test option" })
).not.toBeNull();
});

test("with @var", async () => {
await setVarValue();

// Switch to Dropdown widget
await selectUiType("Dropdown with labels");

// Expect the ui type has changed
expect(
screen.queryByLabelText("Input Type")?.parentElement?.parentElement
).toHaveTextContent("Dropdown with labels");

// Expect the dropdown options is empty
const firstOptionValueInput = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.oneOf.0.const"]`
);
expect(firstOptionValueInput).toBeNull();

const firstOptionTitleInput = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.oneOf.0.title"]`
);
expect(firstOptionTitleInput).toBeNull();
});
});
});

test("can add an option", async () => {
describe("Dropdown with labels field", () => {
async function addOption() {
// Add a text option
screen.getByText("Add Item").click();

Expand All @@ -145,23 +194,86 @@ describe("Dropdown with labels field", () => {
);
fireTextInput(firstOptionLabelInput, "Test option");
await waitForEffect();
}

// Validate the rendered option
const optionElement = screen.queryByRole("option", { name: "Test option" });
expect(optionElement).not.toBeNull();
expect(optionElement).toHaveValue("1");
});

test("can use @var in Dropdown", async () => {
async function setVarValue() {
// Switch to @var and inset "@data"
await selectSchemaFieldType(
`form.schema.properties.${defaultFieldName}.oneOf`,
"var"
);
fireTextInput(screen.getByLabelText("Options"), "@data");
await waitForEffect();
}

let rendered: RenderResult;
beforeEach(async () => {
rendered = renderFormBuilder();

// Switch to Dropdown widget
await selectUiType("Dropdown with labels");
});
test("doesn't fail when field type changed to Dropdown with labels", async () => {
// Expect the dropdown rendered in the preview
expect(
rendered.container.querySelector(`select#root_${defaultFieldName}`)
).not.toBeNull();
});

test("can add an option", async () => {
await addOption();

// Validate the rendered option
const optionElement = screen.queryByRole("option", { name: "Test option" });
expect(optionElement).not.toBeNull();
expect(optionElement).toHaveValue("1");
});

test("can use @var in Dropdown", async () => {
await setVarValue();

// Expect the dropdown option rendered in the preview
expect(screen.queryByRole("option", { name: "@data" })).not.toBeNull();
});

describe("can be switched to regular Dropdown", () => {
test("with items", async () => {
await addOption();

// Switch to Dropdown widget
await selectUiType("Dropdown");

// Expect the ui type has changed
expect(
screen.queryByLabelText("Input Type")?.parentElement?.parentElement
).toHaveTextContent("Dropdown");

// Expect the dropdown option added in the Editor
const firstOptionInput = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.enum.0"]`
);
expect(firstOptionInput).toHaveValue("1");

// Expect the dropdown option rendered in the preview
expect(screen.queryByRole("option", { name: "1" })).not.toBeNull();
});

test("with @var", async () => {
await setVarValue();

// Switch to Dropdown widget
await selectUiType("Dropdown");

// Expect the ui type has changed
expect(
screen.queryByLabelText("Input Type")?.parentElement?.parentElement
).toHaveTextContent("Dropdown");

// Expect the dropdown options is empty
const firstOptionInput = rendered.container.querySelector(
`[name="form.schema.properties.${defaultFieldName}.enum.0"]`
);
expect(firstOptionInput).toBeNull();
});
});
});
104 changes: 103 additions & 1 deletion src/components/formBuilder/formBuilderHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import {
MINIMAL_UI_SCHEMA,
normalizeUiOrder,
produceSchemaOnPropertyNameChange,
produceSchemaOnUiTypeChange,
replaceStringInArray,
stringifyUiType,
updateRjsfSchemaWithDefaultsIfNeeded,
validateNextPropertyName,
} from "./formBuilderHelpers";
import { RJSFSchema } from "./formBuilderTypes";
import { initRenamingCases } from "./formEditor.testCases";
import { UI_ORDER } from "./schemaFieldNames";
import { UI_ORDER, UI_WIDGET } from "./schemaFieldNames";

describe("replaceStringInArray", () => {
let array: string[];
Expand Down Expand Up @@ -215,3 +217,103 @@ describe("normalizeUiOrder", () => {
expect(actual).toEqual(["propA", "propC", "*"]);
});
});

describe("produceSchemaOnUiTypeChange", () => {
test("converts Dropdown to Dropdown with labels", () => {
const schema: RJSFSchema = {
schema: {
...MINIMAL_SCHEMA,
properties: {
field1: {
title: "Field 1",
type: "string",
enum: ["foo", "bar", "baz"],
},
},
},
uiSchema: {
...MINIMAL_UI_SCHEMA,
field1: {
[UI_WIDGET]: "select",
},
},
};

const nextSchema = produceSchemaOnUiTypeChange(
schema,
"field1",
stringifyUiType({
propertyType: "string",
uiWidget: "select",
extra: "selectWithLabels",
})
);

expect(
(nextSchema.schema.properties.field1 as Schema).enum
).toBeUndefined();
expect((nextSchema.schema.properties.field1 as Schema).oneOf).toEqual([
{
const: "foo",
},
{
const: "bar",
},
{
const: "baz",
},
]);
});

test("converts Dropdown with labels to Dropdown", () => {
const schema: RJSFSchema = {
schema: {
...MINIMAL_SCHEMA,
properties: {
field1: {
title: "Field 1",
type: "string",
oneOf: [
{
const: "foo",
title: "Foo",
},
{
const: "bar",
title: "Bar",
},
{
const: "baz",
title: "Baz",
},
],
},
},
},
uiSchema: {
...MINIMAL_UI_SCHEMA,
field1: {
[UI_WIDGET]: "select",
},
},
};

const nextSchema = produceSchemaOnUiTypeChange(
schema,
"field1",
stringifyUiType({
propertyType: "string",
uiWidget: "select",
})
);

expect(
(nextSchema.schema.properties.field1 as Schema).oneOf
).toBeUndefined();
expect((nextSchema.schema.properties.field1 as Schema).enum).toEqual([
"foo",
"bar",
"baz",
]);
});
});
13 changes: 11 additions & 2 deletions src/components/formBuilder/formBuilderHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
KEYS_OF_UI_SCHEMA,
SafeString,
Schema,
SchemaDefinition,
SchemaPropertyType,
UiSchema,
} from "@/core";
Expand Down Expand Up @@ -297,11 +298,19 @@ export const produceSchemaOnUiTypeChange = (

if (uiWidget === "select") {
if (extra === "selectWithLabels") {
draftPropertySchema.oneOf = [];
// If switching from Dropdown, convert the enum to options with labels
draftPropertySchema.oneOf = Array.isArray(draftPropertySchema.enum)
? draftPropertySchema.enum.map(
(item) => ({ const: item } as SchemaDefinition)
)
: [];
draftPropertySchema.default = "";
delete draftPropertySchema.enum;
} else {
draftPropertySchema.enum = [];
// If switching from Dropdown with labels, convert the values to enum
draftPropertySchema.enum = Array.isArray(draftPropertySchema.oneOf)
? draftPropertySchema.oneOf.map((item: Schema) => item.const)
: [];
delete draftPropertySchema.oneOf;
}
} else {
Expand Down
Loading