From 41387d36384e8b2a3551fd8772d9f7928ed1275d Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Fri, 25 Feb 2022 17:07:48 -0500 Subject: [PATCH 1/4] First stab at form task components --- src/App.tsx | 15 +++++++++++++++ src/form-components/AddQuestion.tsx | 9 +++++++++ src/form-components/CheckAnswer.tsx | 9 +++++++++ src/form-components/EditMode.tsx | 9 +++++++++ src/form-components/GiveAttempts.tsx | 9 +++++++++ src/form-components/MultipleChoiceQuestion.tsx | 9 +++++++++ 6 files changed, 60 insertions(+) create mode 100644 src/form-components/AddQuestion.tsx create mode 100644 src/form-components/CheckAnswer.tsx create mode 100644 src/form-components/EditMode.tsx create mode 100644 src/form-components/GiveAttempts.tsx create mode 100644 src/form-components/MultipleChoiceQuestion.tsx diff --git a/src/App.tsx b/src/App.tsx index e09c26ec76..84c54a446a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,11 @@ import { DoubleHalf } from "./bad-components/DoubleHalf"; import { ColoredBox } from "./bad-components/ColoredBox"; import { ShoveBox } from "./bad-components/ShoveBox"; import { ChooseTeam } from "./bad-components/ChooseTeam"; +import { CheckAnswer } from "./form-components/CheckAnswer"; +import { GiveAttempts } from "./form-components/GiveAttempts"; +import { EditMode } from "./form-components/EditMode"; +import { MultipleChoiceQuestion } from "./form-components/MultipleChoiceQuestion"; +import { AddQuestion } from "./form-components/AddQuestion"; function App(): JSX.Element { return ( @@ -18,6 +23,16 @@ function App(): JSX.Element { UD CISC275 with React Hooks and TypeScript
+ +
+ +
+ +
+ +
+ +
{/* */}
diff --git a/src/form-components/AddQuestion.tsx b/src/form-components/AddQuestion.tsx new file mode 100644 index 0000000000..24210d9a1b --- /dev/null +++ b/src/form-components/AddQuestion.tsx @@ -0,0 +1,9 @@ +import React, { useState } from "react"; + +export function AddQuestion(): JSX.Element { + return ( +
+

Add Question

+
+ ); +} diff --git a/src/form-components/CheckAnswer.tsx b/src/form-components/CheckAnswer.tsx new file mode 100644 index 0000000000..7127833cad --- /dev/null +++ b/src/form-components/CheckAnswer.tsx @@ -0,0 +1,9 @@ +import React, { useState } from "react"; + +export function CheckAnswer(): JSX.Element { + return ( +
+

Check Answer

+
+ ); +} diff --git a/src/form-components/EditMode.tsx b/src/form-components/EditMode.tsx new file mode 100644 index 0000000000..fac8734531 --- /dev/null +++ b/src/form-components/EditMode.tsx @@ -0,0 +1,9 @@ +import React, { useState } from "react"; + +export function EditMode(): JSX.Element { + return ( +
+

Edit Mode

+
+ ); +} diff --git a/src/form-components/GiveAttempts.tsx b/src/form-components/GiveAttempts.tsx new file mode 100644 index 0000000000..2ca61863fc --- /dev/null +++ b/src/form-components/GiveAttempts.tsx @@ -0,0 +1,9 @@ +import React, { useState } from "react"; + +export function GiveAttempts(): JSX.Element { + return ( +
+

Give Attempts

+
+ ); +} diff --git a/src/form-components/MultipleChoiceQuestion.tsx b/src/form-components/MultipleChoiceQuestion.tsx new file mode 100644 index 0000000000..80a482d063 --- /dev/null +++ b/src/form-components/MultipleChoiceQuestion.tsx @@ -0,0 +1,9 @@ +import React, { useState } from "react"; + +export function MultipleChoiceQuestion(): JSX.Element { + return ( +
+

Multiple Choice Question

+
+ ); +} From 1b03faf6c20bb63ee4a6a282772fb0529ac1b0fa Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 27 Feb 2022 14:26:41 -0500 Subject: [PATCH 2/4] Provide tests, change addQuestion to changeColor --- src/App.tsx | 11 ++- src/form-components/ChangeColor.test.tsx | 35 ++++++++ .../{AddQuestion.tsx => ChangeColor.tsx} | 4 +- src/form-components/CheckAnswer.test.tsx | 45 +++++++++++ src/form-components/CheckAnswer.tsx | 6 +- src/form-components/EditMode.test.tsx | 48 +++++++++++ src/form-components/GiveAttempts.test.tsx | 46 +++++++++++ .../MultipleChoiceQuestion.test.tsx | 79 +++++++++++++++++++ .../MultipleChoiceQuestion.tsx | 8 +- 9 files changed, 274 insertions(+), 8 deletions(-) create mode 100644 src/form-components/ChangeColor.test.tsx rename src/form-components/{AddQuestion.tsx => ChangeColor.tsx} (54%) create mode 100644 src/form-components/CheckAnswer.test.tsx create mode 100644 src/form-components/EditMode.test.tsx create mode 100644 src/form-components/GiveAttempts.test.tsx create mode 100644 src/form-components/MultipleChoiceQuestion.test.tsx diff --git a/src/App.tsx b/src/App.tsx index 84c54a446a..097f7e9ed2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,7 +14,7 @@ import { CheckAnswer } from "./form-components/CheckAnswer"; import { GiveAttempts } from "./form-components/GiveAttempts"; import { EditMode } from "./form-components/EditMode"; import { MultipleChoiceQuestion } from "./form-components/MultipleChoiceQuestion"; -import { AddQuestion } from "./form-components/AddQuestion"; +import { ChangeColor } from "./form-components/ChangeColor"; function App(): JSX.Element { return ( @@ -23,15 +23,18 @@ function App(): JSX.Element { UD CISC275 with React Hooks and TypeScript
- +


- +
- +
{/* */}
diff --git a/src/form-components/ChangeColor.test.tsx b/src/form-components/ChangeColor.test.tsx new file mode 100644 index 0000000000..d74ba37243 --- /dev/null +++ b/src/form-components/ChangeColor.test.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { ChangeColor } from "./ChangeColor"; + +describe("ChangeColor Component tests", () => { + beforeEach(() => render()); + test("There are at least 8 radio buttons and the colored box", () => { + const radios = screen.getAllByRole("radio"); + expect(radios.length).toBeGreaterThanOrEqual(8); + expect(screen.getByTestId("colored-box")).toBeInTheDocument(); + }); + test("Switching the color switches the displayed color.", () => { + const radios: HTMLInputElement[] = screen.getAllByRole("radio"); + // Switch to first + radios[0].click(); + let coloredBox = screen.getByTestId("colored-box"); + expect(coloredBox).toHaveTextContent(radios[0].value); + expect(coloredBox).toHaveStyle({ backgroundColor: radios[0].value }); + // Switch to third + radios[2].click(); + coloredBox = screen.getByTestId("colored-box"); + expect(coloredBox).toHaveTextContent(radios[2].value); + expect(coloredBox).toHaveStyle({ backgroundColor: radios[2].value }); + // Switch to 8th + radios[7].click(); + coloredBox = screen.getByTestId("colored-box"); + expect(coloredBox).toHaveTextContent(radios[7].value); + expect(coloredBox).toHaveStyle({ backgroundColor: radios[7].value }); + // Switch back to first + radios[0].click(); + coloredBox = screen.getByTestId("colored-box"); + expect(coloredBox).toHaveTextContent(radios[0].value); + expect(coloredBox).toHaveStyle({ backgroundColor: radios[0].value }); + }); +}); diff --git a/src/form-components/AddQuestion.tsx b/src/form-components/ChangeColor.tsx similarity index 54% rename from src/form-components/AddQuestion.tsx rename to src/form-components/ChangeColor.tsx index 24210d9a1b..bcb584fcf9 100644 --- a/src/form-components/AddQuestion.tsx +++ b/src/form-components/ChangeColor.tsx @@ -1,9 +1,9 @@ import React, { useState } from "react"; -export function AddQuestion(): JSX.Element { +export function ChangeColor(): JSX.Element { return (
-

Add Question

+

Change Color

); } diff --git a/src/form-components/CheckAnswer.test.tsx b/src/form-components/CheckAnswer.test.tsx new file mode 100644 index 0000000000..076ab209a7 --- /dev/null +++ b/src/form-components/CheckAnswer.test.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { CheckAnswer } from "./CheckAnswer"; +import userEvent from "@testing-library/user-event"; + +describe("CheckAnswer Component tests", () => { + test("There is an input box", () => { + render(); + const inputBox = screen.getByRole("textbox"); + expect(inputBox).toBeInTheDocument(); + }); + test("The answer is originally incorrect.", () => { + render(); + expect(screen.getByText(/❌/i)).toBeInTheDocument(); + expect(screen.queryByText(/✔️/i)).not.toBeInTheDocument(); + }); + test("Entering the right answer makes it correct.", () => { + render(); + const inputBox = screen.getByRole("textbox"); + userEvent.type(inputBox, "42"); + expect(screen.getByText(/✔️/i)).toBeInTheDocument(); + expect(screen.queryByText(/❌/i)).not.toBeInTheDocument(); + }); + test("Entering the wrong answer makes it incorrect.", () => { + render(); + const inputBox = screen.getByRole("textbox"); + userEvent.type(inputBox, "43"); + expect(screen.getByText(/❌/i)).toBeInTheDocument(); + expect(screen.queryByText(/✔️/i)).not.toBeInTheDocument(); + }); + test("Entering a different right answer makes it correct.", () => { + render(); + const inputBox = screen.getByRole("textbox"); + userEvent.type(inputBox, "Hello"); + expect(screen.getByText(/✔️/i)).toBeInTheDocument(); + expect(screen.queryByText(/❌/i)).not.toBeInTheDocument(); + }); + test("Entering a different wrong answer still makes it incorrect.", () => { + render(); + const inputBox = screen.getByRole("textbox"); + userEvent.type(inputBox, "42"); + expect(screen.getByText(/❌/i)).toBeInTheDocument(); + expect(screen.queryByText(/✔️/i)).not.toBeInTheDocument(); + }); +}); diff --git a/src/form-components/CheckAnswer.tsx b/src/form-components/CheckAnswer.tsx index 7127833cad..afb3dbf8a4 100644 --- a/src/form-components/CheckAnswer.tsx +++ b/src/form-components/CheckAnswer.tsx @@ -1,6 +1,10 @@ import React, { useState } from "react"; -export function CheckAnswer(): JSX.Element { +export function CheckAnswer({ + expectedAnswer +}: { + expectedAnswer: string; +}): JSX.Element { return (

Check Answer

diff --git a/src/form-components/EditMode.test.tsx b/src/form-components/EditMode.test.tsx new file mode 100644 index 0000000000..b2f2a43a36 --- /dev/null +++ b/src/form-components/EditMode.test.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { EditMode } from "./EditMode"; +import userEvent from "@testing-library/user-event"; + +describe("EditMode Component tests", () => { + beforeEach(() => render()); + test("There is one checkbox and no textboxes", () => { + const switchButton = screen.getByRole("checkbox"); + expect(switchButton).toBeInTheDocument(); + expect(switchButton.parentElement).toHaveClass("form-switch"); + expect(screen.queryByRole("textbox")).not.toBeInTheDocument(); + }); + test("Initial text should be 'Your Name is a student'.", () => { + expect(screen.getByText(/Your Name is a student/i)).toBeInTheDocument(); + }); + test("Can switch into Edit Mode", () => { + const switchButton = screen.getByRole("checkbox"); + switchButton.click(); + expect(screen.getByRole("textbox")).toBeInTheDocument(); + expect(screen.getAllByRole("checkbox")).toHaveLength(2); + }); + test("Editing the name and student status changes the text", () => { + const switchButton = screen.getByRole("checkbox"); + switchButton.click(); + const nameBox = screen.getByRole("textbox"); + userEvent.type(nameBox, "Ada Lovelace"); + const studentBox = screen.getByRole("checkbox", { name: /student/i }); + studentBox.click(); + switchButton.click(); + expect( + screen.getByText(/Ada Lovelace is not a student/i) + ).toBeInTheDocument(); + }); + test("Different name, click student box twice changes the text", () => { + const switchButton = screen.getByRole("checkbox"); + switchButton.click(); + const nameBox = screen.getByRole("textbox"); + userEvent.type(nameBox, "Alan Turing"); + const studentBox = screen.getByRole("checkbox", { name: /student/i }); + studentBox.click(); + studentBox.click(); + switchButton.click(); + expect( + screen.getByText(/Alan Turing is a student/i) + ).toBeInTheDocument(); + }); +}); diff --git a/src/form-components/GiveAttempts.test.tsx b/src/form-components/GiveAttempts.test.tsx new file mode 100644 index 0000000000..df6f218a20 --- /dev/null +++ b/src/form-components/GiveAttempts.test.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { GiveAttempts } from "./GiveAttempts"; +import userEvent from "@testing-library/user-event"; + +describe("GiveAttempts Component tests", () => { + beforeEach(() => { + render(); + }); + + test("There is a number entry box and two buttons", () => { + expect(screen.getByRole("spinbutton")).toBeInTheDocument(); + expect(screen.getAllByRole("button")).toHaveLength(2); + }); + + test("There is are initially 3 attempts", () => { + expect(screen.getByText(/3/i)).toBeInTheDocument(); + }); + + test("You can use attempts", () => { + const use = screen.getByRole("button", { name: /use/i }); + use.click(); + expect(screen.getByText(/2/i)).toBeInTheDocument(); + use.click(); + use.click(); + expect(screen.getByText(/0/i)).toBeInTheDocument(); + expect(use).toBeDisabled(); + }); + test("You can gain arbitrary attempts", () => { + const gain = screen.getByRole("button", { name: /gain/i }); + const amountToGive = screen.getByRole("spinbutton"); + userEvent.type(amountToGive, "10"); + gain.click(); + expect(screen.getByText(/13/i)).toBeInTheDocument(); + userEvent.type(amountToGive, "100"); + gain.click(); + expect(screen.getByText(/113/i)).toBeInTheDocument(); + }); + test("Cannot gain blank amounts", () => { + const gain = screen.getByRole("button", { name: /gain/i }); + const amountToGive = screen.getByRole("spinbutton"); + userEvent.type(amountToGive, ""); + gain.click(); + expect(screen.getByText(/3/i)).toBeInTheDocument(); + }); +}); diff --git a/src/form-components/MultipleChoiceQuestion.test.tsx b/src/form-components/MultipleChoiceQuestion.test.tsx new file mode 100644 index 0000000000..03a520a818 --- /dev/null +++ b/src/form-components/MultipleChoiceQuestion.test.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { MultipleChoiceQuestion } from "./MultipleChoiceQuestion"; +import userEvent from "@testing-library/user-event"; + +describe("MultipleChoiceQuestion Component tests", () => { + test("There is a select box", () => { + render( + + ); + expect(screen.getByRole("combobox")).toBeInTheDocument(); + }); + test("The answer is initially incorrect", () => { + render( + + ); + expect(screen.getByText(/❌/i)).toBeInTheDocument(); + expect(screen.queryByText(/✔️/i)).not.toBeInTheDocument(); + }); + test("Can choose the correct answer", () => { + render( + + ); + const select = screen.getByRole("combobox"); + userEvent.selectOptions(select, "2"); + expect(screen.getByText(/✔️/i)).toBeInTheDocument(); + expect(screen.queryByText(/❌/i)).not.toBeInTheDocument(); + }); + test("Can choose the correct answer and then incorrect", () => { + render( + + ); + const select = screen.getByRole("combobox"); + userEvent.selectOptions(select, "2"); + expect(screen.getByText(/✔️/i)).toBeInTheDocument(); + expect(screen.queryByText(/❌/i)).not.toBeInTheDocument(); + userEvent.selectOptions(select, "3"); + expect(screen.getByText(/❌/i)).toBeInTheDocument(); + expect(screen.queryByText(/✔️/i)).not.toBeInTheDocument(); + }); + test("Can start off initially correct", () => { + render( + + ); + const select = screen.getByRole("combobox"); + userEvent.selectOptions(select, "Alpha"); + expect(screen.getByText(/✔️/i)).toBeInTheDocument(); + expect(screen.queryByText(/❌/i)).not.toBeInTheDocument(); + }); + test("One more test of choosing the right answer", () => { + render( + + ); + expect(screen.getByText(/❌/i)).toBeInTheDocument(); + expect(screen.queryByText(/✔️/i)).not.toBeInTheDocument(); + const select = screen.getByRole("combobox"); + userEvent.selectOptions(select, "World"); + expect(screen.getByText(/✔️/i)).toBeInTheDocument(); + expect(screen.queryByText(/❌/i)).not.toBeInTheDocument(); + }); +}); diff --git a/src/form-components/MultipleChoiceQuestion.tsx b/src/form-components/MultipleChoiceQuestion.tsx index 80a482d063..a84759862f 100644 --- a/src/form-components/MultipleChoiceQuestion.tsx +++ b/src/form-components/MultipleChoiceQuestion.tsx @@ -1,6 +1,12 @@ import React, { useState } from "react"; -export function MultipleChoiceQuestion(): JSX.Element { +export function MultipleChoiceQuestion({ + options, + expectedAnswer +}: { + options: string[]; + expectedAnswer: string; +}): JSX.Element { return (

Multiple Choice Question

From 43b41ec5873213a8fd0ec104cce219ebc29d2aa5 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Mar 2022 20:21:59 -0500 Subject: [PATCH 3/4] Fix entering blank text for GiveAttempts --- src/form-components/GiveAttempts.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/form-components/GiveAttempts.test.tsx b/src/form-components/GiveAttempts.test.tsx index df6f218a20..eb1c3e4a45 100644 --- a/src/form-components/GiveAttempts.test.tsx +++ b/src/form-components/GiveAttempts.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { fireEvent, render, screen } from "@testing-library/react"; import { GiveAttempts } from "./GiveAttempts"; import userEvent from "@testing-library/user-event"; @@ -39,7 +39,7 @@ describe("GiveAttempts Component tests", () => { test("Cannot gain blank amounts", () => { const gain = screen.getByRole("button", { name: /gain/i }); const amountToGive = screen.getByRole("spinbutton"); - userEvent.type(amountToGive, ""); + fireEvent.change(amountToGive, { target: { value: "" } }); gain.click(); expect(screen.getByText(/3/i)).toBeInTheDocument(); }); From b6aad3546c864662a07a1783d78efe7dbc0a0a46 Mon Sep 17 00:00:00 2001 From: Lizzy Kalfas Date: Mon, 9 Oct 2023 20:14:27 -0400 Subject: [PATCH 4/4] updating all functions --- src/form-components/ChangeColor.tsx | 44 ++++++++++++++- src/form-components/CheckAnswer.tsx | 15 +++++- src/form-components/EditMode.tsx | 54 ++++++++++++++++++- src/form-components/GiveAttempts.tsx | 36 ++++++++++++- .../MultipleChoiceQuestion.tsx | 22 +++++++- 5 files changed, 166 insertions(+), 5 deletions(-) diff --git a/src/form-components/ChangeColor.tsx b/src/form-components/ChangeColor.tsx index bcb584fcf9..ad0fcba051 100644 --- a/src/form-components/ChangeColor.tsx +++ b/src/form-components/ChangeColor.tsx @@ -1,9 +1,51 @@ import React, { useState } from "react"; export function ChangeColor(): JSX.Element { + const [selectedColor, setSelectedColor] = useState(""); + const colors = [ + "red", + "blue", + "green", + "yellow", + "purple", + "orange", + "pink", + "brown" + ]; + const handleColorChange = (event: { + target: { value: React.SetStateAction }; + }) => { + setSelectedColor(event.target.value); + }; + return (
-

Change Color

+

Change Color

+
+ {colors.map((color, index) => ( + + ))} +
+
+ {selectedColor || "Select a color"} +
); } diff --git a/src/form-components/CheckAnswer.tsx b/src/form-components/CheckAnswer.tsx index afb3dbf8a4..b4e886a6ed 100644 --- a/src/form-components/CheckAnswer.tsx +++ b/src/form-components/CheckAnswer.tsx @@ -5,9 +5,22 @@ export function CheckAnswer({ }: { expectedAnswer: string; }): JSX.Element { + const [userAnswer, setUserAnswer] = useState(""); + const handleInputChange = (event: { + target: { value: React.SetStateAction }; + }) => { + setUserAnswer(event.target.value); + }; + return (
-

Check Answer

+ + + {userAnswer === expectedAnswer ? ✔️ : }
); } diff --git a/src/form-components/EditMode.tsx b/src/form-components/EditMode.tsx index fac8734531..391208db07 100644 --- a/src/form-components/EditMode.tsx +++ b/src/form-components/EditMode.tsx @@ -1,9 +1,61 @@ import React, { useState } from "react"; export function EditMode(): JSX.Element { + const [editMode, setEditMode] = useState(false); + const [userName, setUserName] = useState("Your Name"); + const [isStudent, setIsStudent] = useState(true); + + const handleEditModeToggle = () => { + setEditMode(!editMode); + }; + const handleUserNameChange = (event: { + target: { value: React.SetStateAction }; + }) => { + setUserName(event.target.value); + }; + + const handleStudentCheckboxChange = () => { + setIsStudent(!isStudent); + }; return (
-

Edit Mode

+

Edit Mode

+
+ + +
+ {editMode ? ( +
+ + + +
+ ) : ( +
+

+ {userName} is{" "} + {isStudent ? "a student" : "not a student"} +

+
+ )}
); } diff --git a/src/form-components/GiveAttempts.tsx b/src/form-components/GiveAttempts.tsx index 2ca61863fc..9952d7e5d9 100644 --- a/src/form-components/GiveAttempts.tsx +++ b/src/form-components/GiveAttempts.tsx @@ -1,9 +1,43 @@ import React, { useState } from "react"; +import { Button } from "react-bootstrap"; export function GiveAttempts(): JSX.Element { + const [attemptsLeft, setAttemptsLeft] = useState(3); + const [requestedAttempts, setRequestedAttempts] = useState(""); + + const handleUseAttempt = () => { + if (attemptsLeft > 0) { + setAttemptsLeft(attemptsLeft - 1); + } + }; + + const handleGainAttempts = () => { + const parsedAttempts = parseInt(requestedAttempts, 10); + + if (!isNaN(parsedAttempts) && parsedAttempts >= 0) { + setAttemptsLeft(attemptsLeft + parsedAttempts); + setRequestedAttempts(""); + } + }; return (
-

Give Attempts

+

Give Attempts

+

Attempts Left: {attemptsLeft}

+
+ + setRequestedAttempts(e.target.value)} + /> + + +
); } diff --git a/src/form-components/MultipleChoiceQuestion.tsx b/src/form-components/MultipleChoiceQuestion.tsx index a84759862f..176189ae3c 100644 --- a/src/form-components/MultipleChoiceQuestion.tsx +++ b/src/form-components/MultipleChoiceQuestion.tsx @@ -7,9 +7,29 @@ export function MultipleChoiceQuestion({ options: string[]; expectedAnswer: string; }): JSX.Element { + const [selectedChoice, setSelectedChoice] = useState(options[0]); + + const handleChoiceSelect = (event: { + target: { value: React.SetStateAction }; + }) => { + setSelectedChoice(event.target.value); + }; return (
-

Multiple Choice Question

+

Multiple Choice Question

+ + + {selectedChoice === expectedAnswer ? ( + ✔️ + ) : ( + + )}
); }