Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert front-end tests from enzyme to react testing library #7379

Merged
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 Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Cache playwright's chromium installation on GitHub Actions (#7372)
- Fix broken link to the Vagrant installation guide in `README.md` (#7349)
- Fix `extra_hosts` configuration in `compose.yaml` (#7375)
- Convert front-end tests from enzyme to react testing library; add `@testing-library/user-event` (#7379)

## [v2.6.1]

Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/Grader/marking.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
// designate $next_criteria as the currently selected criteria
function activeCriterion($next_criteria) {
if (!$next_criteria.hasClass("active-criterion")) {
$criteria_list = $(".marks-list > li");
const $criteria_list = $(".marks-list > li");
// remove all previous active-criterion (there should only be one)
$criteria_list.removeClass("active-criterion");
// scroll the $next_criteria to the top of the criterion bar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class GraderDistributionModal extends React.Component {
</label>
<input
className={`input-${grader.user_name}`}
id={`input-${grader.user_name}`}
type="number"
step="0.01"
min="0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class SubmissionFileUploadModal extends React.Component {
);
} else if (this.props.requiredFiles.length >= 1) {
fileRenameInput = [
<datalist id="fileInput_datalist">
<datalist id="fileInput_datalist" key={`datalist-${filesToShow}`}>
{filesToShow.map(filename => {
return <option key={filename} value={filename}></option>;
})}
Expand All @@ -103,6 +103,7 @@ class SubmissionFileUploadModal extends React.Component {
disabled={this.state.newFiles.length !== 1}
title={I18n.t("submissions.student.one_file_allowed")}
id={"rename-box"}
key={"datalist-textbox"}
/>,
];
} else {
Expand Down Expand Up @@ -155,6 +156,7 @@ class SubmissionFileUploadModal extends React.Component {
name={"new_files"}
multiple={true}
onChange={this.handleFileUpload}
title={I18n.t("modals.file_upload.file_input_label")}
/>
</div>
<label htmlFor={"rename-box"}>
Expand Down
1 change: 1 addition & 0 deletions app/javascript/Components/Result/marks_panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export class FlexibleCriterionInput extends React.Component {
a.id
)
}
href="#"
className={"red-text"}
>
{"-" + a.deduction}
Expand Down
16 changes: 2 additions & 14 deletions app/javascript/Components/Result/submission_selector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,19 +178,6 @@ export class SubmissionSelector extends React.Component {
return "";
}

const url = Routes.next_grouping_course_result_path(this.props.course_id, this.props.result_id);

const progressBarWidth =
this.props.num_collected > 0 ? this.props.num_marked / this.props.num_collected : 1;
let progressBarColour;
if (progressBarWidth > 0.75) {
progressBarColour = "green";
} else if (progressBarWidth > 0.35) {
progressBarColour = "#FBC02D";
} else {
progressBarColour = "#FE2A2A";
}

let meterLow = 0;
let meterHigh = 1;
if (this.props.num_collected !== null && this.props.num_collected !== undefined) {
Expand All @@ -199,7 +186,7 @@ export class SubmissionSelector extends React.Component {
}

return (
<div className="submission-selector-container">
<div className="submission-selector-container" data-testid="submission-selector-container">
<div className="submission-selector">
<button
className="button previous"
Expand All @@ -226,6 +213,7 @@ export class SubmissionSelector extends React.Component {
low={meterLow}
high={meterHigh}
optimum={this.props.num_collected}
data-testid="progress-bar"
>
{this.props.num_marked}/{this.props.num_collected}
</meter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

import {AssignmentSummaryTable} from "../assignment_summary_table";
import {render, screen, fireEvent, cleanup, waitFor} from "@testing-library/react";
import {render, screen, fireEvent} from "@testing-library/react";

describe("For the AssignmentSummaryTable's display of inactive groups", () => {
let groups_sample;
Expand Down
3 changes: 1 addition & 2 deletions app/javascript/Components/__tests__/binary_viewer.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import {render, screen, cleanup, waitFor, fireEvent} from "@testing-library/react";
import {render, screen, waitFor, fireEvent} from "@testing-library/react";
import {BinaryViewer} from "../Result/binary_viewer";
import fetchMock from "jest-fetch-mock";

Expand All @@ -19,7 +19,6 @@ describe("BinaryViewer", () => {
afterEach(() => {
jest.clearAllMocks();
fetchMock.resetMocks();
cleanup();
});

it("should fetch content when a URL is passed but not show it until requested by the user", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import {render, screen, fireEvent, waitFor, cleanup} from "@testing-library/react";
import {render, screen, fireEvent, waitFor} from "@testing-library/react";
import CreateTagModal from "../Modals/create_tag_modal";
import Modal from "react-modal";
import fetchMock from "jest-fetch-mock";
Expand Down Expand Up @@ -37,7 +37,6 @@ describe("CreateTagModal", () => {

afterEach(() => {
fetchMock.resetMocks();
cleanup();
});

it("should be called with correct params on successful submit", async () => {
Expand Down
3 changes: 1 addition & 2 deletions app/javascript/Components/__tests__/edit_tag_modal.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import {render, screen, fireEvent, waitFor, cleanup} from "@testing-library/react";
import {render, screen, fireEvent, waitFor} from "@testing-library/react";
import EditTagModal from "../Modals/edit_tag_modal";
import Modal from "react-modal";
import fetchMock from "jest-fetch-mock";
Expand Down Expand Up @@ -34,7 +34,6 @@ describe("EditTagModal", () => {

afterEach(() => {
fetchMock.resetMocks();
cleanup();
});

it("should be called with correct params on successful submit", async () => {
Expand Down
3 changes: 1 addition & 2 deletions app/javascript/Components/__tests__/file_viewer.test.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from "react";
import {render, screen, cleanup} from "@testing-library/react";
import {render, screen} from "@testing-library/react";
import {FileViewer} from "../Result/file_viewer";
import fetchMock from "jest-fetch-mock";

describe("FileViewer", () => {
afterEach(() => {
fetchMock.resetMocks();
cleanup();
});

it("should not render oversized files", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {shallow} from "enzyme";
import {render, screen} from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import {GraderDistributionModal} from "../Modals/graders_distribution_modal";

Expand All @@ -10,12 +11,7 @@ const createExampleForm = () => {
};

describe("GraderDistributionModal", () => {
let wrapper, props;
const getWrapper = props => {
return shallow(<GraderDistributionModal {...props} />);
};
const fakeEvent = {preventDefault: jest.fn()};
let mockRef;
let props;
const form1 = createExampleForm();
beforeEach(() => {
props = {
Expand All @@ -31,24 +27,32 @@ describe("GraderDistributionModal", () => {
});

it("should display as many rows as there are graders", () => {
wrapper = getWrapper(props);

expect(wrapper.find(".modal-inline-label").length).toBe(2);
render(<GraderDistributionModal {...props} />);
for (let grader of props.graders) {
expect(screen.getByRole("spinbutton", {name: grader.user_name, hidden: true})).toBeTruthy();
}
});

it("should close on submit", () => {
wrapper = getWrapper(props);

wrapper.find("form").simulate("submit", fakeEvent);
it("should close on submit", async () => {
render(<GraderDistributionModal {...props} />);
let submit = screen.getByRole("button", {
name: I18n.t("graders.actions.randomly_assign_graders"),
hidden: true,
});
await userEvent.click(submit);

expect(props.onSubmit).toHaveBeenCalled();
expect(props.isOpen).toBeFalsy();
});

it("should call setWeighting with value of 1 on build", () => {
wrapper = getWrapper(props);
it("should call setWeighting with value of 1 on build", async () => {
render(<GraderDistributionModal {...props} />);
let submit = screen.getByRole("button", {
name: I18n.t("graders.actions.randomly_assign_graders"),
hidden: true,
});
await userEvent.click(submit);

wrapper.find("form").simulate("submit", fakeEvent);
expect(props.onSubmit).toHaveBeenCalledWith({
1: "1",
2: "1",
Expand Down
34 changes: 20 additions & 14 deletions app/javascript/Components/__tests__/instructor_table.test.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {mount} from "enzyme";
import {render, screen} from "@testing-library/react";

import {InstructorTable} from "../instructor_table";

Expand All @@ -14,18 +14,24 @@ global.fetch = jest.fn(() =>
);

describe("For the InstructorTable's display of instructors", () => {
let wrapper, instructors_sample;
let instructors_sample;

describe("when some instructors are fetched", () => {
const instructors_in_one_row = (wrapper, instructor) => {
// Find the row
const row = wrapper.find({children: instructor.user_name}).parent();
// Expect the row to contain these information
expect(row.children({children: instructor.first_name})).toBeTruthy();
expect(row.children({children: instructor.last_name})).toBeTruthy();
if (instructor.email) {
expect(row.children({children: instructor.email})).toBeTruthy();
const instructors_in_one_row = instructor => {
const rows = screen.getAllByRole("row");
for (let row of rows) {
const cells = Array.from(row.childNodes).map(c => c.textContent);
if (cells[0] === instructor.user_name) {
expect(cells[1]).toEqual(instructor.first_name);
expect(cells[2]).toEqual(instructor.last_name);
if (instructor.email) {
expect(cells[3]).toEqual(instructor.email);
}
return;
}
}
// If the loop ends without finding the instructor, raise an error
throw `Could not find row for ${instructor.user_name}`;
};

beforeAll(() => {
Expand Down Expand Up @@ -56,11 +62,11 @@ describe("For the InstructorTable's display of instructors", () => {
counts: {all: 2, active: 1, inactive: 1},
}),
});
wrapper = mount(<InstructorTable course_id={1} />);
render(<InstructorTable course_id={1} />);
});

it("each instructor is displayed as a row of the table", () => {
instructors_sample.forEach(instructor => instructors_in_one_row(wrapper, instructor));
instructors_sample.forEach(instructor => instructors_in_one_row(instructor));
});
});

Expand All @@ -76,11 +82,11 @@ describe("For the InstructorTable's display of instructors", () => {
counts: {all: 0, active: 0, inactive: 0},
}),
});
wrapper = mount(<InstructorTable course_id={1} />);
render(<InstructorTable course_id={1} />);
});

it("No rows found is shown", () => {
expect(wrapper.find({children: "No rows found"})).toBeTruthy();
expect(screen.queryByText("No rows found")).toBeTruthy();
});
});
});
53 changes: 19 additions & 34 deletions app/javascript/Components/__tests__/markdown_editor.test.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {shallow} from "enzyme";
import {render, screen} from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import MarkdownEditor from "../markdown_editor";

const basicProps = {
Expand All @@ -12,54 +14,37 @@ const basicProps = {
};

describe("MarkdownEditor", () => {
let props, wrapper;
const getWrapper = () => {
return shallow(<MarkdownEditor {...props} />);
};
let props;
beforeEach(() => {
props = {...basicProps};
});

it("should properly handle the text input change", () => {
wrapper = getWrapper(props);

const inputBox = wrapper.find("#new_annotation_content");

expect(inputBox.exists()).toBeTruthy();

const event = {
target: {
value: "Hello world",
},
};
it("should properly handle the text input change", async () => {
render(<MarkdownEditor {...props} />);

inputBox.simulate("change", event);
const inputBox = screen.getByRole("textbox");
await userEvent.type(inputBox, "Hello world");

expect(props.handleChange).toHaveBeenCalledWith(event);
expect(props.handleChange).toHaveBeenCalled();
});

it("should show autocomplete if desired", () => {
it("should show autocomplete if desired", async () => {
props.show_autocomplete = true;
props.annotation_text_id = "id";
wrapper = getWrapper(props);
render(<MarkdownEditor {...props} />);

const annotationList = wrapper.find("#annotation_text_list");

expect(annotationList.exists()).toBeTruthy();
const autocompleteList = screen.queryByTestId("markdown-editor-autocomplete-root");
expect(autocompleteList).toBeTruthy();
});

it("should properly display and pass down props to the preview tab", () => {
it("should properly display and pass down props to the preview tab", async () => {
props.content = "arma virumque cano";
wrapper = getWrapper(props);

//At 1 because it is the 2nd tab
wrapper.find("Tab").at(1).simulate("click");

const preview = wrapper.find("#markdown-preview");
render(<MarkdownEditor {...props} />);

expect(preview.exists()).toBeTruthy();
await userEvent.click(screen.getByRole("tab", {name: "Preview"}));

expect(preview.props().content).toBe(props.content);
expect(preview.props().updateAnnotationCompletion).toBe(props.updateAnnotationCompletion);
const preview = document.querySelector("#annotation-preview");
expect(preview).toBeTruthy();
expect(preview.textContent.trim()).toEqual(props.content);
});
});
Loading