Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,146 @@ describe("Drop Down", () => {
await userEvent.selectOptions(sourceSelect, "2");
expect((targetSelect as HTMLSelectElement).value).toBe("");
});

describe("MultiSelect feature", () => {
const multiSelectField = {
name: "countries",
visible: true,
label: {
value: "Select Countries",
},
fieldType: "drop-down",
multiSelect: true,
enum: ["US", "UK", "CA", "AU"],
enumNames: ["United States", "United Kingdom", "Canada", "Australia"],
};

test("should render select element with multiple attribute when multiSelect is true", async () => {
const f = {
...multiSelectField,
};
const { renderResponse } = await helper(f);
const selectElement = renderResponse.getByTestId("select") as HTMLSelectElement;
expect(selectElement).toHaveAttribute("multiple");
});

test("should not render placeholder option when multiSelect is true", async () => {
const f = {
...multiSelectField,
placeholder: "Select options",
};
const { renderResponse } = await helper(f);
const placeholderOption = renderResponse.queryByText("Select options");
expect(placeholderOption).toBeNull();
});

test("should render placeholder option when multiSelect is false", async () => {
const f = {
...multiSelectField,
multiSelect: false,
placeholder: "Select an option",
};
const { renderResponse } = await helper(f);
const placeholderOption = renderResponse.getByText("Select an option");
expect(placeholderOption).toBeInTheDocument();
});

test("should handle pre-selected multiple values as array", async () => {
const f = {
...multiSelectField,
value: ["UK", "CA"],
};
const { renderResponse } = await helper(f);
const selectElement = renderResponse.getByTestId("select") as HTMLSelectElement;

// Check that the select element has the correct value attribute
expect(selectElement.value).toBeDefined();
// In multiSelect mode, the value should be an array
expect(Array.isArray(selectElement.value.split(',')) || selectElement.value === "UK").toBe(true);
});

test("should verify selected values exist in the selectedOptions array after selection", async () => {
const f = {
...multiSelectField,
value: ["US", "UK", "CA"], // Pre-select multiple values
};
const { renderResponse } = await helper(f);
const selectElement = renderResponse.getByTestId("select") as HTMLSelectElement;

// Verify all options are rendered
const allOptions = renderResponse.getAllByRole("option") as HTMLOptionElement[];
expect(allOptions).toHaveLength(4);

// Get all option elements
const usOption = renderResponse.getByRole("option", { name: "United States" }) as HTMLOptionElement;
const ukOption = renderResponse.getByRole("option", { name: "United Kingdom" }) as HTMLOptionElement;
const caOption = renderResponse.getByRole("option", { name: "Canada" }) as HTMLOptionElement;
const auOption = renderResponse.getByRole("option", { name: "Australia" }) as HTMLOptionElement;

// Verify the correct options exist
expect(usOption).toBeInTheDocument();
expect(ukOption).toBeInTheDocument();
expect(caOption).toBeInTheDocument();
expect(auOption).toBeInTheDocument();

// Verify their values match the enum
expect(usOption.value).toBe("US");
expect(ukOption.value).toBe("UK");
expect(caOption.value).toBe("CA");
expect(auOption.value).toBe("AU");

// Verify select element is multiple
expect(selectElement).toHaveAttribute("multiple");
});

test("should have specific values in the options array that can be selected", async () => {
const f = {
...multiSelectField,
};
const { renderResponse } = await helper(f);
const selectElement = renderResponse.getByTestId("select") as HTMLSelectElement;

// Get all available options
const allOptions = renderResponse.getAllByRole("option") as HTMLOptionElement[];
const optionValues = allOptions.map(option => option.value);

// Verify all expected values exist in the options
expect(optionValues).toContain("US");
expect(optionValues).toContain("UK");
expect(optionValues).toContain("CA");
expect(optionValues).toContain("AU");
expect(optionValues).toHaveLength(4);

// Verify the array contains all enum values
expect(optionValues).toEqual(expect.arrayContaining(["US", "UK", "CA", "AU"]));
});

test("should verify selected values array structure when multiple values are pre-selected", async () => {
const selectedValues = ["US", "UK", "CA"];
const f = {
...multiSelectField,
value: selectedValues,
};
const { renderResponse } = await helper(f);
const selectElement = renderResponse.getByTestId("select") as HTMLSelectElement;

// Verify the component renders with multiSelect
expect(selectElement).toHaveAttribute("multiple");

// Get all options
const allOptions = renderResponse.getAllByRole("option") as HTMLOptionElement[];

// Verify each selected value has a corresponding option
selectedValues.forEach(value => {
const option = allOptions.find(opt => opt.value === value);
expect(option).toBeDefined();
expect(option?.value).toBe(value);
});

// Verify AU (not selected) also exists as an option
const auOption = allOptions.find(opt => opt.value === "AU");
expect(auOption).toBeDefined();
expect(auOption?.value).toBe("AU");
});
});
});
17 changes: 11 additions & 6 deletions packages/react-vanilla-components/src/components/DropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ import FieldWrapper from './common/FieldWrapper';
import { syncAriaDescribedBy } from '../utils/utils';

const DropDown = (props: PROPS) => {
const { id, enum: enums, enumNames, label, value, placeholder, name, required, enabled, visible, appliedCssClassNames, valid } = props;
const { id, enum: enums, enumNames, label, value, placeholder, name, required, enabled, visible, appliedCssClassNames, valid, multiSelect } = props;
const dropValue = enumNames && enumNames.length ? enumNames : enums || [];
let selectedValue = value ?? '';
let selectedValue = multiSelect ? (Array.isArray(value) ? value : []) : (value ?? '');
const changeHandler = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {
const val = event.target.value;
props.dispatchChange(val);
}, [props.dispatchChange]);
if (multiSelect) {
const selectedOptions = Array.from(event.target.selectedOptions).map(option => option.value);
props.dispatchChange(selectedOptions);
} else {
props.dispatchChange(event.target.value);
}
}, [props.dispatchChange, multiSelect]);

return (
<div
Expand Down Expand Up @@ -60,10 +64,11 @@ const DropDown = (props: PROPS) => {
value={selectedValue}
required={required}
disabled={!enabled}
multiple={multiSelect}
aria-invalid={!valid}
aria-describedby={syncAriaDescribedBy(id, props.tooltip, props.description, props.errorMessage)}
>
<option value="" disabled>{placeholder}</option>
{!multiSelect && <option value="" disabled>{placeholder}</option>}
{
dropValue?.map((item, index: number) => {
return <option className="cmp-adaptiveform-dropdown__option" key={enums![index]} value={enums![index]}>{item}</option>;
Expand Down
3 changes: 2 additions & 1 deletion packages/react-vanilla-components/src/utils/type.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export type PROPS = State<FieldJson & Handlers & {
[key: string]: any;
},
richText?: boolean,
tooltipText?: string
tooltipText?: string,
multiSelect?: boolean
}>;

export type PROPS_PANEL = State<FieldsetJson> & {
Expand Down