Skip to content

Commit

Permalink
fix: make the icons and indicators in the select accessible (#1462)
Browse files Browse the repository at this point in the history
  • Loading branch information
haideralsh authored Oct 16, 2024
1 parent c8ee1a4 commit 3b6d900
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 135 deletions.
24 changes: 12 additions & 12 deletions cypress/e2e/components/AsyncSelect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,41 @@ describe("AsyncSelect", () => {
it("can select multiple values", () => {
getMultiselect().click();

cy.focused().type("cana");
assertDropDownIsOpen().contains("Canada");
cy.focused().type("on");
assertDropDownIsOpen().contains("Ontario");
cy.focused().type("{enter}");

cy.focused().type("mex");
assertDropDownIsOpen().contains("Mexico");
cy.focused().type("qu");
assertDropDownIsOpen().contains("Quebec");
cy.focused().type("{enter}");

getMultiselect().contains("Canada");
getMultiselect().contains("Mexico");
getMultiselect().contains("Ontario");
getMultiselect().contains("Quebec");
});

describe("clears selected values", () => {
it("clears all multiselect values", () => {
getMultiselect().click();

cy.focused().type("cana");
assertDropDownIsOpen().contains("Canada");
cy.focused().type("on");
assertDropDownIsOpen().contains("Ontario");
cy.focused().type("{enter}");

getClearButton().click();

getMultiselect().contains("Select countries");
getMultiselect().contains("Enter a province");
});

it("clears single-select values", () => {
getSelectComponent().click();

cy.focused().type("cana");
assertDropDownIsOpen().contains("Canada");
cy.focused().type("on");
assertDropDownIsOpen().contains("Ontario");
cy.focused().type("{enter}");

getClearButton().click();

getMultiselect().contains("Select countries");
getMultiselect().contains("Enter a province");
});
});

Expand Down
91 changes: 37 additions & 54 deletions src/AsyncSelect/AsyncSelect.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,13 @@ import React, { useRef } from "react";
import { action } from "@storybook/addon-actions";
import { useState } from "react";
import { AsyncSelect, Button } from "../index";
import simulatedAPIRequest from "../utils/story/simulatedAPIRequest";

const northAmericanCountries = [
{
value: "Canada",
label: "Canada",
},
{
value: "United States",
label: "United States",
},
{
value: "Mexico",
label: "Mexico",
},
];

const loadMatchingCountries = async (inputValue: string) => {
const data = await simulatedAPIRequest(inputValue, northAmericanCountries);
const results = await data.json();

return results.map(({ name }) => ({
label: name,
value: name,
}));
import { filterOptions } from "../utils/story/simulatedAPIRequests";
import { provinces } from "./fixtures";
import { Flex } from "../Flex";

const loadMatchingProvinces = async (inputValue: string) => {
const data = await filterOptions(inputValue, provinces);
return await data.json();
};

export default {
Expand All @@ -35,14 +17,14 @@ export default {

export const Default = () => (
<AsyncSelect
placeholder="Please select a country"
placeholder="Enter a province"
onChange={action("selection changed")}
onBlur={action("blurred")}
className="Select"
classNamePrefix="SelectTest"
labelText="Country"
labelText="Province"
onInputChange={action("typed input value changed")}
loadOptions={loadMatchingCountries}
loadOptions={loadMatchingProvinces}
/>
);

Expand All @@ -52,25 +34,25 @@ Default.story = {

export const WithDefaultOptions = () => (
<AsyncSelect
placeholder="Filter Countries"
placeholder="Enter a province"
onChange={action("selection changed")}
onBlur={action("blurred")}
className="Select"
classNamePrefix="SelectTest"
labelText="Country"
labelText="Province"
onInputChange={action("typed input value changed")}
isClearable
defaultOptions={[
{
value: "Canada",
label: "Canada",
value: "ON",
label: "Ontario",
},
{
value: "United States",
label: "United States",
value: "QC",
label: "Quebec",
},
]}
loadOptions={loadMatchingCountries}
loadOptions={loadMatchingProvinces}
/>
);

Expand All @@ -80,15 +62,15 @@ WithDefaultOptions.story = {

export const WithADefaultValue = () => (
<AsyncSelect
placeholder="Please select a country"
placeholder="Enter a province"
onChange={action("selection changed")}
onBlur={action("blurred")}
className="Select"
classNamePrefix="SelectTest"
labelText="Country"
defaultValue="Can"
labelText="Province"
defaultValue="Ontario"
onInputChange={action("typed input value changed")}
loadOptions={loadMatchingCountries}
loadOptions={loadMatchingProvinces}
/>
);

Expand All @@ -98,29 +80,29 @@ WithADefaultValue.story = {

export const Multiselect = () => (
<AsyncSelect
placeholder="Select countries"
placeholder="Enter a province"
onChange={action("selection changed")}
onBlur={action("blurred")}
className="Select"
classNamePrefix="SelectTest"
labelText="Countries"
labelText="Provinces"
multiselect
onInputChange={action("typed input value changed")}
loadOptions={loadMatchingCountries}
loadOptions={loadMatchingProvinces}
/>
);

export const WithAClearButton = () => (
<AsyncSelect
placeholder="Select countries"
placeholder="Enter a province"
onChange={action("selection changed")}
onBlur={action("blurred")}
className="Select"
classNamePrefix="SelectTest"
labelText="Countries"
labelText="Provinces"
isClearable
onInputChange={action("typed input value changed")}
loadOptions={loadMatchingCountries}
loadOptions={loadMatchingProvinces}
/>
);

Expand All @@ -131,21 +113,21 @@ export const UsingRefToControlFocus = () => {
};

return (
<>
<Flex gap="x2" flexDirection="column">
<AsyncSelect
ref={ref}
placeholder="Please select a country"
placeholder="Enter a province"
onChange={action("selection changed")}
onBlur={action("blurred")}
className="Select"
classNamePrefix="SelectTest"
labelText="Country"
defaultValue="Can"
labelText="Province"
defaultValue="Ontario"
onInputChange={action("typed input value changed")}
loadOptions={loadMatchingCountries}
loadOptions={loadMatchingProvinces}
/>
<Button onClick={handleClick}>Focus the Input</Button>
</>
</Flex>
);
};

Expand All @@ -164,12 +146,13 @@ export const Controlled = () => {
};

return (
<>
<AsyncSelect onChange={handleChange} value={value} labelText="Country" loadOptions={loadMatchingCountries} />
<Flex gap="x2" flexDirection="column">
<AsyncSelect onChange={handleChange} value={value} labelText="Province" loadOptions={loadMatchingProvinces} />
<Button onClick={handleClear}>Clear</Button>
</>
</Flex>
);
};

Controlled.story = {
name: "controlled",
};
54 changes: 54 additions & 0 deletions src/AsyncSelect/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export const provinces = [
{
label: "Alberta",
value: "AB",
},
{
label: "British Columbia",
value: "BC",
},
{
label: "Manitoba",
value: "MB",
},
{
label: "New Brunswick",
value: "NB",
},
{
label: "Newfoundland and Labrador",
value: "NL",
},
{
label: "Northwest Territories",
value: "NT",
},
{
label: "Nova Scotia",
value: "NS",
},
{
label: "Nunavut",
value: "NU",
},
{
label: "Ontario",
value: "ON",
},
{
label: "Prince Edward Island",
value: "PE",
},
{
label: "Quebec",
value: "QC",
},
{
label: "Saskatchewan",
value: "SK",
},
{
label: "Yukon Territory",
value: "YT",
},
];
12 changes: 6 additions & 6 deletions src/Select/Select.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ WithCloseMenuOnSelectTurnedOff.story = {
};

export const TestMultiselectOverflow = () => (
<>
<Flex gap="x2" flexDirection="column">
<Select
defaultValue={["accepted", "assigned"]}
noOptionsMessage={() => "No options"}
Expand Down Expand Up @@ -517,7 +517,7 @@ export const TestMultiselectOverflow = () => (
onInputChange={action("typed input value changed")}
/>
</Box>
</>
</Flex>
);

TestMultiselectOverflow.story = {
Expand Down Expand Up @@ -551,10 +551,10 @@ WithFixedPositioning.story = {
};

export const WithFetchedOptions = () => (
<Box style={{ width: "300px" }}>
<Flex flexDirection="column" gap="x2" width="300px">
<SelectWithManyOptions labelText="Select from many options:" />
<SelectWithManyOptions multiselect labelText="Multiselect many options:" />
</Box>
</Flex>
);

export const WithCustomOptionComponent = () => {
Expand Down Expand Up @@ -609,7 +609,7 @@ export const UsingRefToControlFocus = () => {
};

return (
<>
<Flex flexDirection="column" gap="x2">
<Select
defaultValue={["accepted"]}
noOptionsMessage={() => "No options"}
Expand All @@ -621,7 +621,7 @@ export const UsingRefToControlFocus = () => {
menuPosition="fixed"
/>
<Button onClick={handleClick}>Focus the Input</Button>
</>
</Flex>
);
};

Expand Down
33 changes: 17 additions & 16 deletions src/Select/customReactSelectStyles.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ import { getControlBorderRadius, getMenuBorderRadius, showIndicatorSeparator } f

describe("custom react-select styles", () => {
describe("showIndicatorSeparator", () => {
test.each`
isMulti | hasValue | hasDefaultOptions | expected
${true} | ${true} | ${true} | ${true}
${true} | ${false} | ${false} | ${false}
${false} | ${true} | ${false} | ${false}
${false} | ${false} | ${true} | ${false}
${true} | ${true} | ${false} | ${false}
${false} | ${true} | ${true} | ${false}
${true} | ${false} | ${true} | ${false}
${false} | ${false} | ${false} | ${false}
`(
"returns $expected when isMulti is $isMulti, hasValue is $hasValue, and hasDefaultOptions is $hasDefaultOptions",
({ isMulti, hasValue, hasDefaultOptions, expected }) => {
expect(showIndicatorSeparator({ isMulti, hasValue, hasDefaultOptions })).toBe(expected);
}
);
it("should not show the indicator separator when the select has no value", () => {
const result = showIndicatorSeparator({ hasValue: false, isClearable: true, isMulti: true });

expect(result).toEqual(false);
});

it("should show the indicator separator when the select allows multiple selections", () => {
const result = showIndicatorSeparator({ hasValue: true, isClearable: false, isMulti: true });

expect(result).toEqual(true);
});

it("should show the indicator separator when the select is clearable", () => {
const result = showIndicatorSeparator({ hasValue: true, isClearable: false, isMulti: true });

expect(result).toEqual(true);
});
});

describe("getControlBorderRadius", () => {
Expand Down
Loading

0 comments on commit 3b6d900

Please sign in to comment.