Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
986b28a
First stab at questions
acbart Feb 2, 2022
2c852d6
Move Question interface to separate file
acbart Feb 6, 2022
dc3662a
Create answer interface
acbart Feb 8, 2022
51221ee
First stab at nested tasks
acbart Feb 8, 2022
3a793cc
Document Question interface
acbart Feb 9, 2022
5c39a97
Expand questions test data
acbart Feb 9, 2022
6ae0b6f
Add a little hint for a tough one
acbart Feb 9, 2022
b1bbbc8
Nested tests (phew)
acbart Feb 9, 2022
ab9bfb5
Basic starter files for components
acbart Feb 9, 2022
9765863
Another extra paren error
acbart Feb 9, 2022
d6c10cd
Merge branch 'main' of https://github.com/UD-CISC275-S22/react-typesc…
acbart Feb 13, 2022
c0bbc39
Updated, complete tests for all state components
acbart Feb 13, 2022
eb40f3e
Forgot task record for state
acbart Feb 19, 2022
7a20734
Include json test command here
acbart Aug 24, 2024
3660252
First stab at questions
acbart Feb 2, 2022
09d3d4f
Move Question interface to separate file
acbart Feb 6, 2022
9a24024
Create answer interface
acbart Feb 8, 2022
879fe17
First stab at nested tasks
acbart Feb 8, 2022
4d29d21
Document Question interface
acbart Feb 9, 2022
d71d9fc
Expand questions test data
acbart Feb 9, 2022
c955718
Add a little hint for a tough one
acbart Feb 9, 2022
c574699
Nested tests (phew)
acbart Feb 9, 2022
a368ad0
Forgot the task record!
acbart Feb 19, 2022
304184e
Fix typo in editOption test, and missing return type for editOption
acbart Mar 1, 2022
1b76b80
Fix formatting
acbart Aug 24, 2024
23314f3
update point values for tests
acbart Aug 24, 2024
82faacc
Fix react return value
acbart Aug 24, 2024
cc7d4db
Update react tests to use async
acbart Aug 24, 2024
c419dc9
Fix linting
acbart Aug 24, 2024
8f02b0a
Merge remote-tracking branch 'upstream/task-nested'
ariudel Mar 3, 2026
ffc6a37
Working on nested task
ariudel Mar 3, 2026
392e5c2
fixed the rest of nested
ariudel Mar 3, 2026
14024e0
Fix objects.ts
ariudel Mar 3, 2026
3cf1e36
Merge task-state
ariudel Mar 5, 2026
0493838
Restore nested/objects solutions from solved-nested
ariudel Mar 5, 2026
cfa3960
Completed State task
ariudel Mar 6, 2026
ff27aa8
Fixed lint error
ariudel Mar 6, 2026
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
50 changes: 50 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"settings": {
"react": {
"version": "detect"
}
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint", "prettier"],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
],
"no-extra-parens": [
"warn",
"all",
{
"nestedBinaryExpressions": false,
"returnAssign": false,
"enforceForArrowConditionals": false,
"ignoreJSX": "all"
}
],
"brace-style": ["error", "1tbs"],
"indent": ["error", 4],
"quotes": ["error", "double"],
"semi": ["error", "always"]
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"build": "react-scripts build",
"test": "react-scripts test",
"test:cov": "react-scripts test --coverage --watchAll",
"test:json": "react-scripts test --json --watchAll=false --outputFile jest-output.json --coverage",
"eject": "react-scripts eject",
"lint": "eslint ./src --ext .tsx --ext .ts --max-warnings 0",
"eslint-output": "eslint-output ./src --ext .tsx --ext .ts --max-warnings 0",
Expand Down
5 changes: 5 additions & 0 deletions public/tasks/task-nested.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Task - Nested

Version: 0.0.1

Implement functions that work with nested arrays and objects immutably.
5 changes: 5 additions & 0 deletions public/tasks/task-objects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Task - Objects

Version: 0.0.1

Implement functions that work with objects immutably.
5 changes: 5 additions & 0 deletions public/tasks/task-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Task - State

Version: 0.0.1

Create some new components that have React State.
22 changes: 18 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import React from "react";
import "./App.css";
import { ChangeType } from "./components/ChangeType";
import { RevealAnswer } from "./components/RevealAnswer";
import { StartAttempt } from "./components/StartAttempt";
import { TwoDice } from "./components/TwoDice";
import { CycleHoliday } from "./components/CycleHoliday";
import { Counter } from "./components/Counter";

function App(): React.JSX.Element {
return (
<div className="App">
<header className="App-header">
UD CISC275 with React Hooks and TypeScript
</header>
<p>
Edit <code>src/App.tsx</code> and save. This page will
automatically reload.
</p>
<hr></hr>
<Counter></Counter>
<hr />
<RevealAnswer></RevealAnswer>
<hr />
<StartAttempt></StartAttempt>
<hr />
<TwoDice></TwoDice>
<hr />
<ChangeType></ChangeType>
<hr />
<CycleHoliday></CycleHoliday>
</div>
);
}
Expand Down
59 changes: 59 additions & 0 deletions src/components/ChangeType.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { act } from "react";
import { render, screen } from "@testing-library/react";
import { ChangeType } from "./ChangeType";

describe("ChangeType Component tests", () => {
beforeEach(() => {
render(<ChangeType />);
});
test("(1 pts) The initial type is Short Answer", () => {
// We use `getByText` because the text MUST be there
const typeText = screen.getByText(/Short Answer/i);
expect(typeText).toBeInTheDocument();
});
test("(1 pts) The initial type is not Multiple Choice", () => {
// We use `queryByText` because the text might not be there
const typeText = screen.queryByText(/Multiple Choice/i);
expect(typeText).toBeNull();
});

test("(1 pts) There is a button labeled Change Type", () => {
const changeTypeButton = screen.getByRole("button", {
name: /Change Type/i
});
expect(changeTypeButton).toBeInTheDocument();
});

test("(1 pts) Clicking the button changes the type.", async () => {
const changeTypeButton = screen.getByRole("button", {
name: /Change Type/i
});
await act(async () => {
changeTypeButton.click();
});
// Should be Multiple Choice
const typeTextMC = screen.getByText(/Multiple Choice/i);
expect(typeTextMC).toBeInTheDocument();
// Should NOT be Short Answer
const typeTextSA = screen.queryByText(/Short Answer/i);
expect(typeTextSA).toBeNull();
});

test("(1 pts) Clicking the button twice keeps the type the same.", async () => {
const changeTypeButton = screen.getByRole("button", {
name: /Change Type/i
});
await act(async () => {
changeTypeButton.click();
});
await act(async () => {
changeTypeButton.click();
});
// Should be Short Answer
const typeTextSA = screen.getByText(/Short Answer/i);
expect(typeTextSA).toBeInTheDocument();
// Should NOT be Multiple Choice
const typeTextMC = screen.queryByText(/Multiple Choice/i);
expect(typeTextMC).toBeNull();
});
});
24 changes: 24 additions & 0 deletions src/components/ChangeType.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from "react";
import { Button } from "react-bootstrap";
import { QuestionType } from "../interfaces/question";

export function ChangeType(): React.JSX.Element {
const [type, setType] = useState<QuestionType>("short_answer_question");

function changeType(): void {
if (type === "short_answer_question") {
setType("multiple_choice_question");
} else {
setType("short_answer_question");
}
}

return (
<div>
<Button onClick={changeType}>Change Type</Button>

{type === "short_answer_question" && <div>Short Answer</div>}
{type === "multiple_choice_question" && <div>Multiple Choice</div>}
</div>
);
}
45 changes: 45 additions & 0 deletions src/components/Counter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { act } from "react";
import { render, screen } from "@testing-library/react";
import { Counter } from "./Counter";

describe("Counter Component tests", () => {
beforeEach(() => {
render(<Counter />);
});
test("(1 pts) The initial value is 0", () => {
// We use `getByText` because the text MUST be there
const valueText = screen.getByText(/0/i);
expect(valueText).toBeInTheDocument();
});
test("(1 pts) The initial value is not 1", () => {
// We use `queryByText` because the text might not be there
const valueText = screen.queryByText(/1/i);
expect(valueText).toBeNull();
});

test("(1 pts) There is a button named Add One", () => {
const addOneButton = screen.getByRole("button", { name: /Add One/i });
expect(addOneButton).toBeInTheDocument();
});

test("(1 pts) Clicking the button once adds one", async () => {
const addOneButton = screen.getByRole("button", { name: /Add One/i });
await act(async () => {
addOneButton.click();
});
const valueText = screen.getByText(/1/i);
expect(valueText).toBeInTheDocument();
});

test("(1 pts) Clicking the button twice adds two", async () => {
const addOneButton = screen.getByRole("button", { name: /Add One/i });
await act(async () => {
addOneButton.click();
});
await act(async () => {
addOneButton.click();
});
const valueText = screen.getByText(/2/i);
expect(valueText).toBeInTheDocument();
});
});
18 changes: 18 additions & 0 deletions src/components/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useState } from "react";
import { Button } from "react-bootstrap";

export function Counter(): React.JSX.Element {
const [value, setValue] = useState<number>(0);
return (
<span>
<Button
onClick={() => {
setValue(1 + value);
}}
>
Add One
</Button>
to {value}.
</span>
);
}
59 changes: 59 additions & 0 deletions src/components/CycleHoliday.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { act } from "react";
import { render, screen } from "@testing-library/react";
import { CycleHoliday } from "./CycleHoliday";

describe("CycleHoliday Component tests", () => {
beforeEach(() => {
render(<CycleHoliday />);
});

test("(1 pts) An initial holiday is displayed", () => {
const initialHoliday = screen.getByText(/Holiday: (.*)/i);
expect(initialHoliday).toBeInTheDocument();
});

test("(1 pts) There are two buttons", () => {
const alphabetButton = screen.getByRole("button", {
name: /Alphabet/i
});
const yearButton = screen.getByRole("button", {
name: /Year/i
});
expect(alphabetButton).toBeInTheDocument();
expect(yearButton).toBeInTheDocument();
});

test("(1 pts) Can cycle through 5 distinct holidays alphabetically", async () => {
const alphabetButton = screen.getByRole("button", {
name: /Alphabet/i
});
const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i);
const states: string[] = [];
for (let i = 0; i < 6; i++) {
states.push(initialHoliday.textContent || "");
await act(async () => {
alphabetButton.click();
});
}
const uniqueStates = states.filter((x, y) => states.indexOf(x) == y);
expect(uniqueStates).toHaveLength(5);
expect(states[0]).toEqual(states[5]);
});

test("(1 pts) Can cycle through 5 distinct holidays by year", async () => {
const yearButton = screen.getByRole("button", {
name: /Year/i
});
const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i);
const states: string[] = [];
for (let i = 0; i < 6; i++) {
states.push(initialHoliday.textContent || "");
await act(async () => {
yearButton.click();
});
}
const uniqueStates = states.filter((x, y) => states.indexOf(x) == y);
expect(uniqueStates).toHaveLength(5);
expect(states[0]).toEqual(states[5]);
});
});
32 changes: 32 additions & 0 deletions src/components/CycleHoliday.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useState } from "react";
import { Button } from "react-bootstrap";

type Holiday = { name: string; year: number };

export function CycleHoliday(): React.JSX.Element {
const holidays: Holiday[] = [
{ name: "April Fools", year: 2020 },
{ name: "Boxing Day", year: 2021 },
{ name: "Christmas", year: 2022 },
{ name: "Diwali", year: 2023 },
{ name: "Easter", year: 2024 },
];

const [index, setIndex] = useState<number>(0);

function cycleAlphabet(): void {
setIndex((index + 1) % holidays.length);
}

function cycleYear(): void {
setIndex((index + 1) % holidays.length);
}

return (
<div>
<div>Holiday: {holidays[index].name}</div>
<Button onClick={cycleAlphabet}>Alphabet</Button>
<Button onClick={cycleYear}>Year</Button>
</div>
);
}
42 changes: 42 additions & 0 deletions src/components/RevealAnswer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { act } from "react";
import { render, screen } from "@testing-library/react";
import { RevealAnswer } from "./RevealAnswer";

describe("RevealAnswer Component tests", () => {
beforeEach(() => {
render(<RevealAnswer />);
});
test("(1 pts) The answer '42' is not visible initially", () => {
const answerText = screen.queryByText(/42/);
expect(answerText).toBeNull();
});
test("(1 pts) There is a Reveal Answer button", () => {
const revealButton = screen.getByRole("button", {
name: /Reveal Answer/i
});
expect(revealButton).toBeInTheDocument();
});
test("(1 pts) Clicking Reveal Answer button reveals the '42'", async () => {
const revealButton = screen.getByRole("button", {
name: /Reveal Answer/i
});
await act(async () => {
revealButton.click();
});
const answerText = screen.getByText(/42/);
expect(answerText).toBeInTheDocument();
});
test("(1 pts) Clicking Reveal Answer button twice hides the '42'", async () => {
const revealButton = screen.getByRole("button", {
name: /Reveal Answer/i
});
await act(async () => {
revealButton.click();
});
await act(async () => {
revealButton.click();
});
const answerText = screen.queryByText(/42/);
expect(answerText).toBeNull();
});
});
Loading