Updated GroupEdit to testing-library. Added tests

This commit is contained in:
Nathan Barber
2021-12-01 00:03:56 -05:00
parent c048ad4aac
commit db7cdc4aa7
3 changed files with 229 additions and 94 deletions

View File

@@ -42,7 +42,7 @@ const GroupEdit = (props) => {
if (!group_data) return <div></div>; if (!group_data) return <div></div>;
return ( return (
<div className="container"> <div className="container" data-testid="container">
{errorAlert != null ? ( {errorAlert != null ? (
<div className="row"> <div className="row">
<div className="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> <div className="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
@@ -84,6 +84,7 @@ const GroupEdit = (props) => {
<span> </span> <span> </span>
<button <button
id="submit" id="submit"
data-testid="submit"
className="btn btn-primary" className="btn btn-primary"
onClick={() => { onClick={() => {
// check for changes // check for changes
@@ -108,31 +109,35 @@ const GroupEdit = (props) => {
); );
Promise.all(promiseQueue) Promise.all(promiseQueue)
// TODO add error if res not ok .then((data) => {
.then(() => { data.status < 300
updateGroups(0, limit) ? updateGroups(0, limit)
.then((data) => dispatchPageUpdate(data, 0)) .then((data) => dispatchPageUpdate(data, 0))
.then(() => history.push("/groups")); .then(() => history.push("/groups"))
: setErrorAlert(`Failed to edit group.`);
}) })
.catch((err) => setErrorAlert(`Could not edit group.`)); .catch((err) => setErrorAlert(`Failed to edit group.`));
}} }}
> >
Apply Apply
</button> </button>
<button <button
id="delete-group" id="delete-group"
data-testid="delete-group"
className="btn btn-danger" className="btn btn-danger"
style={{ float: "right" }} style={{ float: "right" }}
onClick={() => { onClick={() => {
var groupName = group_data.name; var groupName = group_data.name;
deleteGroup(groupName) deleteGroup(groupName)
// TODO add error if res not ok // TODO add error if res not ok
.then(() => { .then((data) => {
updateGroups(0, limit) data.status < 300
? updateGroups(0, limit)
.then((data) => dispatchPageUpdate(data, 0)) .then((data) => dispatchPageUpdate(data, 0))
.then(() => history.push("/groups")); .then(() => history.push("/groups"))
: setErrorAlert(`Failed to delete group.`);
}) })
.catch((err) => setErrorAlert(`Could not delete group.`)); .catch((err) => setErrorAlert(`Failed to delete group.`));
}} }}
> >
Delete Group Delete Group

View File

@@ -1,22 +1,26 @@
import React from "react"; import React from "react";
import Enzyme, { mount } from "enzyme"; import "@testing-library/jest-dom";
import GroupEdit from "./GroupEdit"; import { act } from "react-dom/test-utils";
import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; import { render, screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Provider, useSelector } from "react-redux"; import { Provider, useSelector } from "react-redux";
import { createStore } from "redux"; import { createStore } from "redux";
import { HashRouter } from "react-router-dom"; import { HashRouter } from "react-router-dom";
import { act } from "react-dom/test-utils"; // eslint-disable-next-line
import regeneratorRuntime from "regenerator-runtime"; // eslint-disable-line import regeneratorRuntime from "regenerator-runtime";
Enzyme.configure({ adapter: new Adapter() }); import GroupEdit from "./GroupEdit";
jest.mock("react-redux", () => ({ jest.mock("react-redux", () => ({
...jest.requireActual("react-redux"), ...jest.requireActual("react-redux"),
useSelector: jest.fn(), useSelector: jest.fn(),
})); }));
describe("GroupEdit Component: ", () => { var mockAsync = (data) =>
var mockAsync = () => jest.fn().mockImplementation(() => Promise.resolve()); jest.fn().mockImplementation(() => Promise.resolve(data));
var mockAsyncRejection = () =>
jest.fn().mockImplementation(() => Promise.reject());
var okPacket = new Promise((resolve) => resolve(true)); var okPacket = new Promise((resolve) => resolve(true));
@@ -55,46 +59,170 @@ describe("GroupEdit Component: ", () => {
useSelector.mockClear(); useSelector.mockClear();
}); });
it("Adds user from input to user selectables on button click", async () => { test("Renders", async () => {
let callbackSpy = mockAsync(), let callbackSpy = mockAsync();
component = mount(groupEditJsx(callbackSpy)),
input = component.find("#username-input"), await act(async () => {
validateUser = component.find("#validate-user"), render(groupEditJsx(callbackSpy));
submit = component.find("#submit"); });
expect(screen.getByTestId("container")).toBeVisible();
});
test("Adds user from input to user selectables on button click", async () => {
let callbackSpy = mockAsync();
await act(async () => {
render(groupEditJsx(callbackSpy));
});
let input = screen.getByTestId("username-input");
let validateUser = screen.getByTestId("validate-user");
let submit = screen.getByTestId("submit");
userEvent.type(input, "bar");
fireEvent.click(validateUser);
await act(async () => okPacket);
await act(async () => {
fireEvent.click(submit);
});
input.simulate("change", { target: { value: "bar" } });
validateUser.simulate("click");
await act(() => okPacket);
submit.simulate("click");
expect(callbackSpy).toHaveBeenNthCalledWith(1, ["bar"], "group"); expect(callbackSpy).toHaveBeenNthCalledWith(1, ["bar"], "group");
}); });
it("Removes a user recently added from input from the selectables list", () => { test("Removes a user recently added from input from the selectables list", async () => {
let callbackSpy = mockAsync(), let callbackSpy = mockAsync();
component = mount(groupEditJsx(callbackSpy)),
unsubmittedUser = component.find(".item.selected").last(); await act(async () => {
unsubmittedUser.simulate("click"); render(groupEditJsx(callbackSpy));
expect(component.find(".item").length).toBe(1);
}); });
it("Grays out a user, already in the group, when unselected and calls deleteUser on submit", () => { let selectedUser = screen.getByText("foo");
let callbackSpy = mockAsync(), fireEvent.click(selectedUser);
component = mount(groupEditJsx(callbackSpy)),
groupUser = component.find(".item.selected").first(); let unselectedUser = screen.getByText("foo");
groupUser.simulate("click");
expect(component.find(".item.unselected").length).toBe(1); expect(unselectedUser.className).toBe("item unselected");
expect(component.find(".item").length).toBe(1); });
test("Grays out a user, already in the group, when unselected and calls deleteUser on submit", async () => {
let callbackSpy = mockAsync();
await act(async () => {
render(groupEditJsx(callbackSpy));
});
let submit = screen.getByTestId("submit");
let groupUser = screen.getByText("foo");
fireEvent.click(groupUser);
let unselectedUser = screen.getByText("foo");
expect(unselectedUser.className).toBe("item unselected");
// test deleteUser call // test deleteUser call
let submit = component.find("#submit"); await act(async () => {
submit.simulate("click"); fireEvent.click(submit);
});
expect(callbackSpy).toHaveBeenNthCalledWith(1, ["foo"], "group"); expect(callbackSpy).toHaveBeenNthCalledWith(1, ["foo"], "group");
}); });
it("Calls deleteGroup on button click", () => { test("Calls deleteGroup on button click", async () => {
let callbackSpy = mockAsync(), let callbackSpy = mockAsync();
component = mount(groupEditJsx(callbackSpy)),
deleteGroup = component.find("#delete-group").first(); await act(async () => {
deleteGroup.simulate("click"); render(groupEditJsx(callbackSpy));
});
let deleteGroup = screen.getByTestId("delete-group");
await act(async () => {
fireEvent.click(deleteGroup);
});
expect(callbackSpy).toHaveBeenNthCalledWith(1, "group"); expect(callbackSpy).toHaveBeenNthCalledWith(1, "group");
}); });
test("Shows a UI error dialogue when group edit fails", async () => {
let callbackSpy = mockAsyncRejection();
await act(async () => {
render(groupEditJsx(callbackSpy));
});
let groupUser = screen.getByText("foo");
fireEvent.click(groupUser);
let submit = screen.getByTestId("submit");
await act(async () => {
fireEvent.click(submit);
});
let errorDialog = screen.getByText("Failed to edit group.");
expect(errorDialog).toBeVisible();
expect(callbackSpy).toHaveBeenCalled();
});
test("Shows a UI error dialogue when group edit returns an improper status code", async () => {
let callbackSpy = mockAsync({ status: 403 });
await act(async () => {
render(groupEditJsx(callbackSpy));
});
let groupUser = screen.getByText("foo");
fireEvent.click(groupUser);
let submit = screen.getByTestId("submit");
await act(async () => {
fireEvent.click(submit);
});
let errorDialog = screen.getByText("Failed to edit group.");
expect(errorDialog).toBeVisible();
expect(callbackSpy).toHaveBeenCalled();
});
test("Shows a UI error dialogue when group delete fails", async () => {
let callbackSpy = mockAsyncRejection();
await act(async () => {
render(groupEditJsx(callbackSpy));
});
let deleteGroup = screen.getByTestId("delete-group");
await act(async () => {
fireEvent.click(deleteGroup);
});
let errorDialog = screen.getByText("Failed to delete group.");
expect(errorDialog).toBeVisible();
expect(callbackSpy).toHaveBeenCalled();
});
test("Shows a UI error dialogue when group delete returns an improper status code", async () => {
let callbackSpy = mockAsync({ status: 403 });
await act(async () => {
render(groupEditJsx(callbackSpy));
});
let deleteGroup = screen.getByTestId("delete-group");
await act(async () => {
fireEvent.click(deleteGroup);
});
let errorDialog = screen.getByText("Failed to delete group.");
expect(errorDialog).toBeVisible();
expect(callbackSpy).toHaveBeenCalled();
}); });

View File

@@ -24,6 +24,7 @@ const GroupSelect = (props) => {
<div className="input-group"> <div className="input-group">
<input <input
id="username-input" id="username-input"
data-testid="username-input"
type="text" type="text"
className="form-control" className="form-control"
placeholder="Add by username" placeholder="Add by username"
@@ -35,6 +36,7 @@ const GroupSelect = (props) => {
<span className="input-group-btn"> <span className="input-group-btn">
<button <button
id="validate-user" id="validate-user"
data-testid="validate-user"
className="btn btn-default" className="btn btn-default"
type="button" type="button"
onClick={() => { onClick={() => {