Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

refactor: filter options in the select dropdown #2963

Merged
merged 20 commits into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
20 changes: 10 additions & 10 deletions src/app/__snapshots__/App.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ exports[`App should close splash screen if not demo 1`] = `
class="Toastify"
/>
<div
class="sc-fznLxA kCDRyF"
class="sc-fznyYp ePFTkY"
data-testid="RouterView__wrapper"
>
<div
Expand Down Expand Up @@ -137,7 +137,7 @@ exports[`App should render mock 1`] = `
class="Toastify"
/>
<div
class="sc-fznLxA kCDRyF"
class="sc-fznyYp ePFTkY"
data-testid="RouterView__wrapper"
>
<div
Expand Down Expand Up @@ -257,7 +257,7 @@ exports[`App should render mock 1`] = `
data-testid="profile-card__user--name"
>
<span
class="sc-fzoydu eoIiNI"
class="sc-fzqMAW dOgzZx"
>
John Doe
</span>
Expand Down Expand Up @@ -349,7 +349,7 @@ exports[`App should render mock 1`] = `
data-testid="profile-card__user--name"
>
<span
class="sc-fzoydu eoIiNI"
class="sc-fzqMAW dOgzZx"
>
Jane Doe
</span>
Expand Down Expand Up @@ -451,7 +451,7 @@ exports[`App should render splash screen 1`] = `
class="Toastify"
/>
<div
class="sc-fznLxA kCDRyF"
class="sc-fznyYp ePFTkY"
data-testid="RouterView__wrapper"
>
<div
Expand Down Expand Up @@ -571,7 +571,7 @@ exports[`App should render splash screen 1`] = `
data-testid="profile-card__user--name"
>
<span
class="sc-fzoydu eoIiNI"
class="sc-fzqMAW dOgzZx"
>
John Doe
</span>
Expand Down Expand Up @@ -663,7 +663,7 @@ exports[`App should render splash screen 1`] = `
data-testid="profile-card__user--name"
>
<span
class="sc-fzoydu eoIiNI"
class="sc-fzqMAW dOgzZx"
>
Jane Doe
</span>
Expand Down Expand Up @@ -842,7 +842,7 @@ exports[`App should render welcome screen after splash screen 1`] = `
class="Toastify"
/>
<div
class="sc-fznLxA kCDRyF"
class="sc-fznyYp ePFTkY"
data-testid="RouterView__wrapper"
>
<div
Expand Down Expand Up @@ -962,7 +962,7 @@ exports[`App should render welcome screen after splash screen 1`] = `
data-testid="profile-card__user--name"
>
<span
class="sc-fzoydu eoIiNI"
class="sc-fzqMAW dOgzZx"
>
John Doe
</span>
Expand Down Expand Up @@ -1054,7 +1054,7 @@ exports[`App should render welcome screen after splash screen 1`] = `
data-testid="profile-card__user--name"
>
<span
class="sc-fzoydu eoIiNI"
class="sc-fzqMAW dOgzZx"
>
Jane Doe
</span>
Expand Down
10 changes: 6 additions & 4 deletions src/app/components/SelectDropdown/SelectDropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ export const Dropdown = () => {
value: "3",
},
];

return (
<div className="max-w-xs space-y-4">
<Select placeholder="Select option" options={options} />
<Select placeholder="Invalid" isInvalid options={options} />
<Select placeholder="Disabled" disabled options={options} />
<Select options={options} placeholder="Select option" />
<Select options={options} placeholder="Invalid" isInvalid />
<Select options={options} placeholder="Disabled" disabled />

<div className="mt-4">With default value</div>
<Select placeholder="Disabled" options={options} defaultValue="3" />

<div className="mt-4">With default value (disabled)</div>
<Select placeholder="Disabled" disabled options={options} defaultValue="3" />
<Select options={options} defaultValue="3" placeholder="Disabled" disabled />
</div>
);
};
212 changes: 191 additions & 21 deletions src/app/components/SelectDropdown/SelectDropdown.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { act } from "@testing-library/react-hooks";
import React from "react";
import { fireEvent, render } from "testing-library";
import { fireEvent, render, waitFor } from "testing-library";

import { Select } from "./SelectDropdown";

Expand Down Expand Up @@ -57,12 +57,12 @@ describe("SelectDropdown", () => {

it("should toggle select list options", () => {
const options = [{ label: "Option 1", value: "1" }];
const { getByTestId } = render(<Select options={options} defaultValue="3" />);
const { getByTestId } = render(<Select options={options} />);

const toggle = getByTestId("select-list__toggle-button");
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.click(toggle);
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

const firstOption = getByTestId("select-list__toggle-option-0");
Expand All @@ -75,12 +75,12 @@ describe("SelectDropdown", () => {

it("should select option", () => {
const options = [{ label: "Option 1", value: "1" }];
const { getByTestId } = render(<Select options={options} defaultValue="3" />);
const { getByTestId } = render(<Select options={options} />);

const toggle = getByTestId("select-list__toggle-button");
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.click(toggle);
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

const firstOption = getByTestId("select-list__toggle-option-0");
Expand All @@ -95,36 +95,40 @@ describe("SelectDropdown", () => {

it("should highlight option", () => {
const options = [{ label: "Option 1", value: "1" }];
const { getByTestId } = render(<Select options={options} defaultValue="3" />);
const { getByTestId } = render(<Select options={options} />);

const toggle = getByTestId("select-list__toggle-button");
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.click(toggle);
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

const firstOption = getByTestId("select-list__toggle-option-0");
expect(firstOption).toBeTruthy();

act(() => {
fireEvent.mouseOver(firstOption);
fireEvent.keyDown(selectDropdown, { key: "Tab", code: 9 });
});

act(() => {
fireEvent.keyDown(toggle, { key: "ArrowDown", code: 40 });
});
const firstOption = getByTestId("select-list__toggle-option-0");
expect(firstOption).toBeTruthy();

expect(firstOption).toHaveClass("is-highlighted");
});

it("should select options with arrow keys", () => {
const options = [{ label: "Option 1", value: "1" }];
const { getByTestId } = render(<Select options={options} defaultValue="3" />);
const { getByTestId } = render(<Select options={options} />);

const toggle = getByTestId("select-list__toggle-button");
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.click(toggle);
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Tab", code: 9 });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Backspace", code: 8 });
});

const firstOption = getByTestId("select-list__toggle-option-0");
Expand All @@ -135,7 +139,7 @@ describe("SelectDropdown", () => {
});

act(() => {
fireEvent.keyDown(toggle, { key: "ArrowDown", code: 40 });
fireEvent.keyDown(selectDropdown, { key: "ArrowDown", code: 40 });
});

expect(firstOption).toHaveClass("is-highlighted");
Expand All @@ -146,4 +150,170 @@ describe("SelectDropdown", () => {

expect(getByTestId("select-list__input")).toHaveValue("1");
});

it("should show typeahead when typing has found at least one match", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

expect(getByTestId("SelectDropdownInput__typeahead")).toHaveTextContent("Option 1");
});

it("should select first matching option with enter", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Enter", code: 13 });
});

expect(getByTestId("select-list__input")).toHaveValue("1");
});

it("should select first matching option with tab", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Tab", code: 9 });
});

expect(getByTestId("select-list__input")).toHaveValue("1");
});

it("should not select non-matching option after key input and tab", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Optt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Tab", code: 9 });
});

expect(getByTestId("select-list__input")).toHaveValue("");
});

it("should not select first matched option after random key enter", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "A", code: 65 });
});

expect(getByTestId("select-list__input")).toHaveValue("");
});

it("should clear selection when changing input", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Enter", code: 13 });
});

expect(getByTestId("select-list__input")).toHaveValue("1");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "test" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "A", code: 65 });
});
act(() => {
fireEvent.keyDown(selectDropdown, { key: "B", code: 65 });
});

expect(getByTestId("select-list__input")).toHaveValue("");
});

it("should select match on blur if available", async () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.blur(selectDropdown);
});

await waitFor(() => expect(selectDropdown).toHaveValue("Option 1"));
});

it("should clear input on blur if there is no match", async () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Foobar" } });
});

act(() => {
fireEvent.blur(selectDropdown);
});

await waitFor(() => expect(selectDropdown).toHaveValue(""));
});

it("should not clear input on blur if selected", () => {
const { getByTestId } = render(<Select options={options} />);
const selectDropdown = getByTestId("SelectDropdownInput__input");

act(() => {
fireEvent.change(selectDropdown, { target: { value: "Opt" } });
});

act(() => {
fireEvent.keyDown(selectDropdown, { key: "Enter", code: 13 });
});

expect(selectDropdown).toHaveValue("Option 1");

act(() => {
fireEvent.blur(selectDropdown);
});

expect(selectDropdown).toHaveValue("Option 1");
});

it("should select an option by clicking on it", async () => {
const { getByTestId } = render(<Select options={options} />);

act(() => {
fireEvent.focus(getByTestId("SelectDropdownInput__input"));
});

await waitFor(() => expect(getByTestId("select-list__toggle-option-0")).toBeTruthy());

act(() => {
fireEvent.mouseDown(getByTestId("select-list__toggle-option-0"));
});

expect(getByTestId("select-list__input")).toHaveValue("1");
});
});
Loading