Shove Box
+ {/*
The box is at: {box.position}
+
+
+ {box}
+
*/}
{}
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/ChangeColor.tsx b/src/form-components/ChangeColor.tsx
new file mode 100644
index 0000000000..ad0fcba051
--- /dev/null
+++ b/src/form-components/ChangeColor.tsx
@@ -0,0 +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
+
+ {colors.map((color, index) => (
+
+ ))}
+
+
+ {selectedColor || "Select a 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
new file mode 100644
index 0000000000..b4e886a6ed
--- /dev/null
+++ b/src/form-components/CheckAnswer.tsx
@@ -0,0 +1,26 @@
+import React, { useState } from "react";
+
+export function CheckAnswer({
+ expectedAnswer
+}: {
+ expectedAnswer: string;
+}): JSX.Element {
+ const [userAnswer, setUserAnswer] = useState("");
+ const handleInputChange = (event: {
+ target: { value: React.SetStateAction };
+ }) => {
+ setUserAnswer(event.target.value);
+ };
+
+ return (
+
+
+
+ {userAnswer === expectedAnswer ? ✔️ : ❌}
+
+ );
+}
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/EditMode.tsx b/src/form-components/EditMode.tsx
new file mode 100644
index 0000000000..391208db07
--- /dev/null
+++ b/src/form-components/EditMode.tsx
@@ -0,0 +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
+
+
+
+
+ {editMode ? (
+
+
+
+
+
+ ) : (
+
+
+ {userName} is{" "}
+ {isStudent ? "a student" : "not a student"}
+
+
+ )}
+
+ );
+}
diff --git a/src/form-components/GiveAttempts.test.tsx b/src/form-components/GiveAttempts.test.tsx
new file mode 100644
index 0000000000..eb1c3e4a45
--- /dev/null
+++ b/src/form-components/GiveAttempts.test.tsx
@@ -0,0 +1,46 @@
+import React from "react";
+import { fireEvent, 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");
+ fireEvent.change(amountToGive, { target: { value: "" } });
+ gain.click();
+ expect(screen.getByText(/3/i)).toBeInTheDocument();
+ });
+});
diff --git a/src/form-components/GiveAttempts.tsx b/src/form-components/GiveAttempts.tsx
new file mode 100644
index 0000000000..9952d7e5d9
--- /dev/null
+++ b/src/form-components/GiveAttempts.tsx
@@ -0,0 +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
+
Attempts Left: {attemptsLeft}
+
+
+ setRequestedAttempts(e.target.value)}
+ />
+
+
+
+
+ );
+}
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
new file mode 100644
index 0000000000..176189ae3c
--- /dev/null
+++ b/src/form-components/MultipleChoiceQuestion.tsx
@@ -0,0 +1,35 @@
+import React, { useState } from "react";
+
+export function MultipleChoiceQuestion({
+ options,
+ expectedAnswer
+}: {
+ 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
+
+
+ {selectedChoice === expectedAnswer ? (
+ ✔️
+ ) : (
+ ❌
+ )}
+
+ );
+}