Skip to content
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ An example for React Semantic UI sortable table.
![Build and Deploy](https://github.com/gges5110/React-Semantic-UI-Sortable-Table-Example/workflows/Test%20and%20Deploy/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/gges5110/React-Semantic-UI-Sortable-Table-Example/badge.svg?branch=master&service=github)](https://coveralls.io/github/gges5110/React-Semantic-UI-Sortable-Table-Example?branch=master)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a5f2bc2a9a8944549c95a17de5d863e9)](https://www.codacy.com/app/gges5110/React-Semantic-UI-Sortable-Table-Example?utm_source=github.com&utm_medium=referral&utm_content=gges5110/React-Semantic-UI-Sortable-Table-Example&utm_campaign=Badge_Grade)
[![CodeFactor](https://www.codefactor.io/repository/github/gges5110/react-semantic-ui-sortable-table-example/badge)](https://www.codefactor.io/repository/github/gges5110/react-semantic-ui-sortable-table-example)

## Prerequisite
Node.js runtime environment of 10.16.0.
Expand Down
21 changes: 21 additions & 0 deletions src/VehicleFilter.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { VehicleFilter } from "./VehicleFilter";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

jest.mock("lodash.debounce", () => jest.fn(fn => fn));

describe("VehicleFilter", () => {
it("renders", () => {
const filter = "";
Expand Down Expand Up @@ -57,4 +59,23 @@ describe("VehicleFilter", () => {
expect(onSubmitFilter).toHaveBeenCalled();
expect(onSubmitFilter.mock.calls).toHaveLength(5);
});

it("submits invalid", () => {
const filter = "";
const totalCount = 10;
const onSubmitFilter = jest.fn();

render(
<VehicleFilter
filter={filter}
totalCount={totalCount}
onSubmitFilter={onSubmitFilter}
/>
);

userEvent.type(screen.getByRole("textbox"), "#");

expect(onSubmitFilter).not.toHaveBeenCalled();
waitFor(() => expect(screen.getByText("Invalid")).toBeInTheDocument());
});
});
116 changes: 56 additions & 60 deletions src/VehicleFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,82 +1,78 @@
import React from "react";
import PropTypes from "prop-types";
import React, { useState } from "react";
import { Form, Popup } from "semantic-ui-react";
import { InputOnChangeData } from "semantic-ui-react/dist/commonjs/elements/Input/Input";
import debounce from "lodash.debounce";

const regex = new RegExp("^[a-zA-Z0-9 ]+$");

interface VehicleFilterProps {
filter: string;
totalCount: number;
loading?: boolean;
onSubmitFilter(value: string): void;
}

interface VehicleFilterState {
[index: string]: any;
filter: string;
filterValid: boolean;
}

export class VehicleFilter extends React.Component<
VehicleFilterProps,
VehicleFilterState
> {
static propTypes = {
onSubmitFilter: PropTypes.func.isRequired,
filter: PropTypes.string.isRequired,
totalCount: PropTypes.number.isRequired
};
export const VehicleFilter: React.FC<VehicleFilterProps> = ({
totalCount,
loading,
onSubmitFilter
}) => {
const [state, setState] = useState<VehicleFilterState>({
filter: "",
filterValid: true
});

constructor(props: VehicleFilterProps) {
super(props);
this.state = {
filter: "",
filterValid: true
};
}

handleOnChange = (event: any, { name, value }: any) => {
const f = debounce((value: string) => {
if (value !== "" && !regex.test(value)) {
this.setState({ [name]: value, filterValid: false });
setState({ filter: value, filterValid: false });
} else {
this.setState({ [name]: value, filterValid: true });
this.props.onSubmitFilter(value);
setState({ filter: value, filterValid: true });
onSubmitFilter(value);
}
};
}, 500);

render() {
const { filter } = this.state;
let popupMessage = "";
if (!this.state.filterValid) {
popupMessage = "Invalid character.";
} else if (this.props.totalCount === 0) {
popupMessage = "No results found.";
}
const handleOnChange = (
event: React.ChangeEvent<HTMLInputElement>,
{ value }: InputOnChangeData
) => {
f(value);
};

return (
<Form>
<Form.Group>
<Form.Field>
<Popup
trigger={
<Form.Input
placeholder="Enter the filter."
name="filter"
value={filter}
error={!this.state.filterValid}
label="Filter"
onChange={this.handleOnChange}
icon="search"
loading={this.props.loading}
/>
}
content={popupMessage}
on="click"
open={!this.state.filterValid || this.props.totalCount === 0}
position="right center"
/>
</Form.Field>
</Form.Group>
</Form>
);
let popupMessage = "";
if (!state.filterValid) {
popupMessage = "Invalid character.";
} else if (totalCount === 0) {
popupMessage = "No results found.";
}
}

return (
<Form>
<Form.Group>
<Form.Field>
<Popup
trigger={
<Form.Input
placeholder={"Enter a filter."}
name={"filter"}
error={!state.filterValid}
label={"Filter"}
onChange={handleOnChange}
icon={"search"}
loading={loading}
/>
}
content={popupMessage}
on={"click"}
open={!state.filterValid || totalCount === 0}
position={"right center"}
/>
</Form.Field>
</Form.Group>
</Form>
);
};
22 changes: 21 additions & 1 deletion src/VehicleList.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { VehicleList } from "./VehicleList";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

jest.mock("lodash.debounce", () => jest.fn(fn => fn));

describe("VehicleList", () => {
beforeEach(() => {
fetchMock.mock("*", [
Expand Down Expand Up @@ -46,7 +48,7 @@ describe("VehicleList", () => {
render(<VehicleList />);
});

it("handles sort", async () => {
it("handles changes", async () => {
render(<VehicleList />);
await waitFor(() => expect(screen.getByText("Mazda")).toBeInTheDocument());

Expand Down Expand Up @@ -97,6 +99,24 @@ describe("VehicleList", () => {
}
);
userEvent.click(screen.getByRole("columnheader", { name: "Make" }));

// change filter
await userEvent.type(screen.getByRole("textbox"), "Volvo");

// change limit
userEvent.click(screen.getByRole("listbox"));

const options = await screen.findAllByRole("option");
const option = options.find(ele => ele.textContent === "25");
expect(option).toBeDefined();
if (option) {
userEvent.click(option); // verify your onChange event
}

// change page
expect(screen.getByRole("navigation")).toBeInTheDocument();
expect(screen.getByRole("navigation").childElementCount).toEqual(5);
userEvent.click(screen.getByRole("navigation").children[3]);
});

it("add favorite", async () => {
Expand Down
Loading