From 2b5f14cf6979706d394a7699aa00f2b5e9d02bbb Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:37:54 -0500 Subject: [PATCH 01/81] Require Hello World in the document --- src/text.Test.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/text.Test.tsx diff --git a/src/text.Test.tsx b/src/text.Test.tsx new file mode 100644 index 0000000000..b32c330d3f --- /dev/null +++ b/src/text.Test.tsx @@ -0,0 +1,9 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import App from "./App"; + +test("renders the text 'Hello World' somewhere", () => { + render(); + const text = screen.getByText(/Hello World/); + expect(text).toBeInTheDocument(); +}); From a7dee05e0bee0379110c6189433d12482280146a Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:41:17 -0500 Subject: [PATCH 02/81] Rename text.Test.tsx to text.test.tsx --- src/{text.Test.tsx => text.test.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{text.Test.tsx => text.test.tsx} (100%) diff --git a/src/text.Test.tsx b/src/text.test.tsx similarity index 100% rename from src/text.Test.tsx rename to src/text.test.tsx From 3e381f38b1d44afd102eb053a8ba9a48a069434e Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:56:42 -0500 Subject: [PATCH 03/81] Include the task info --- public/tasks/task-first-branch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 public/tasks/task-first-branch.md diff --git a/public/tasks/task-first-branch.md b/public/tasks/task-first-branch.md new file mode 100644 index 0000000000..94333338a0 --- /dev/null +++ b/public/tasks/task-first-branch.md @@ -0,0 +1,5 @@ +# Task - First Branch + +Version: 0.0.1 + +Pass a short test to have certain text on the page. From e6b1dab1961daf6f03459789cef974bf043501f2 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 3 Feb 2022 14:10:55 -0500 Subject: [PATCH 04/81] Allow one or more instances of the Hello World text --- src/text.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/text.test.tsx b/src/text.test.tsx index b32c330d3f..f99a063e76 100644 --- a/src/text.test.tsx +++ b/src/text.test.tsx @@ -4,6 +4,6 @@ import App from "./App"; test("renders the text 'Hello World' somewhere", () => { render(); - const text = screen.getByText(/Hello World/); - expect(text).toBeInTheDocument(); + const texts = screen.getAllByText(/Hello World/); + expect(texts.length).toBeGreaterThanOrEqual(1); }); From 7a207345d9e404afd04607811b89bb758de02905 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 12:52:12 -0400 Subject: [PATCH 05/81] Include json test command here --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index cf6e1bc772..fc2b66a549 100644 --- a/package.json +++ b/package.json @@ -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", From 7fe9ca316fad2e694586e037fe601b85a2584c56 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:37:54 -0500 Subject: [PATCH 06/81] Require Hello World in the document --- src/text.Test.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/text.Test.tsx diff --git a/src/text.Test.tsx b/src/text.Test.tsx new file mode 100644 index 0000000000..b32c330d3f --- /dev/null +++ b/src/text.Test.tsx @@ -0,0 +1,9 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import App from "./App"; + +test("renders the text 'Hello World' somewhere", () => { + render(); + const text = screen.getByText(/Hello World/); + expect(text).toBeInTheDocument(); +}); From b8b8878c873d4faa2fd5f04d656e23d66c7d6cef Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:56:42 -0500 Subject: [PATCH 07/81] Include the task info --- public/tasks/task-first-branch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 public/tasks/task-first-branch.md diff --git a/public/tasks/task-first-branch.md b/public/tasks/task-first-branch.md new file mode 100644 index 0000000000..94333338a0 --- /dev/null +++ b/public/tasks/task-first-branch.md @@ -0,0 +1,5 @@ +# Task - First Branch + +Version: 0.0.1 + +Pass a short test to have certain text on the page. From fbdebdec2006b01d3976bd9408037baf82eb5e56 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:41:17 -0500 Subject: [PATCH 08/81] Rename text.Test.tsx to text.test.tsx --- src/{text.Test.tsx => text.test.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{text.Test.tsx => text.test.tsx} (100%) diff --git a/src/text.Test.tsx b/src/text.test.tsx similarity index 100% rename from src/text.Test.tsx rename to src/text.test.tsx From 2f0146c22beca5c5ac48603876f0fa8ea2e2e905 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 3 Feb 2022 14:10:55 -0500 Subject: [PATCH 09/81] Allow one or more instances of the Hello World text --- src/text.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/text.test.tsx b/src/text.test.tsx index b32c330d3f..f99a063e76 100644 --- a/src/text.test.tsx +++ b/src/text.test.tsx @@ -4,6 +4,6 @@ import App from "./App"; test("renders the text 'Hello World' somewhere", () => { render(); - const text = screen.getByText(/Hello World/); - expect(text).toBeInTheDocument(); + const texts = screen.getAllByText(/Hello World/); + expect(texts.length).toBeGreaterThanOrEqual(1); }); From ac36b32302a8ea2e66b4b954626c8e396e172075 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 29 Jan 2022 23:59:24 -0500 Subject: [PATCH 10/81] First set of tests --- public/tasks/task-html-css.md | 5 +++++ src/HtmlCss.test.tsx | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 public/tasks/task-html-css.md create mode 100644 src/HtmlCss.test.tsx diff --git a/public/tasks/task-html-css.md b/public/tasks/task-html-css.md new file mode 100644 index 0000000000..ebc0efcba5 --- /dev/null +++ b/public/tasks/task-html-css.md @@ -0,0 +1,5 @@ +# Task - HTML/CSS + +Version: 0.0.1 + +Add in some HTML and CSS, including a fancy looking button. diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx new file mode 100644 index 0000000000..168ce37fde --- /dev/null +++ b/src/HtmlCss.test.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import App from "./App"; + +describe("Some HTML Elements are added.", () => { + test("There is a header", () => { + render(); + const header = screen.getByRole("heading"); + expect(header).toBeInTheDocument(); + }); +}); + +describe("Some basic CSS is added.", () => { + test("There is a floating red box", () => { + render(); + expect(true); + }); +}); + +describe("Some Bootstrap Elements are added", () => { + test("There is a bootstrap button", () => { + render(); + const button = screen.getByRole("button"); + expect(button).toBeInTheDocument(); + expect(button).toHaveClass("btn"); + expect(button).toHaveClass("btn-primary"); + }); +}); From d04739d1d2ec0c934c0ecf1dc05ac1289063627d Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 30 Jan 2022 00:24:38 -0500 Subject: [PATCH 11/81] Some logging tests --- src/HtmlCss.test.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 168ce37fde..bf957616f9 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -1,6 +1,7 @@ import React from "react"; import { render, screen } from "@testing-library/react"; import App from "./App"; +import userEvent from "@testing-library/user-event"; describe("Some HTML Elements are added.", () => { test("There is a header", () => { @@ -18,11 +19,25 @@ describe("Some basic CSS is added.", () => { }); describe("Some Bootstrap Elements are added", () => { - test("There is a bootstrap button", () => { + test("There is one bootstrap button with the text 'Log Hello World'", () => { render(); - const button = screen.getByRole("button"); + const button = screen.getByRole("button", { name: /Log Hello World/i }); expect(button).toBeInTheDocument(); expect(button).toHaveClass("btn"); expect(button).toHaveClass("btn-primary"); }); + + test("Not clicking the bootstrap button does not logs 'Hello World!'", () => { + const consoleSpy = jest.spyOn(console, "log"); + render(); + expect(consoleSpy).not.toHaveBeenCalledWith("Hello World!"); + }); + + test("Clicking the bootstrap button logs 'Hello World!'", () => { + const consoleSpy = jest.spyOn(console, "log"); + render(); + const button = screen.getByRole("button", { name: /Log Hello World/i }); + userEvent.click(button); + expect(consoleSpy).toHaveBeenCalledWith("Hello World!"); + }); }); From b26100f543943eced73fdff33784861243c65386 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 30 Jan 2022 00:47:43 -0500 Subject: [PATCH 12/81] More html tests --- src/HtmlCss.test.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index bf957616f9..676c37f903 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -9,6 +9,20 @@ describe("Some HTML Elements are added.", () => { const header = screen.getByRole("heading"); expect(header).toBeInTheDocument(); }); + + test("There is an image with alt text", () => { + render(); + const image = screen.getByRole("image"); + expect(image).toBeInTheDocument(); + expect(image).toHaveAttribute("alt"); + }); + + test("There is a list with at least three elements", () => { + render(); + const list = screen.getByRole("list"); + expect(list).toBeInTheDocument(); + expect(list.children.length).toBeGreaterThanOrEqual(3); + }); }); describe("Some basic CSS is added.", () => { From 3bf4550a8f042dee28a57c06abec05dfce779519 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 30 Jan 2022 00:55:24 -0500 Subject: [PATCH 13/81] Fix the image test --- src/HtmlCss.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 676c37f903..79b7db2dda 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -12,7 +12,7 @@ describe("Some HTML Elements are added.", () => { test("There is an image with alt text", () => { render(); - const image = screen.getByRole("image"); + const image = screen.getByRole("img"); expect(image).toBeInTheDocument(); expect(image).toHaveAttribute("alt"); }); From 8dff2b64a2efc0b1b49703077965fe5e334eab1a Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:31:58 -0500 Subject: [PATCH 14/81] Updated CSS tests, left a note about additional tests --- src/HtmlCss.test.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 79b7db2dda..379fc8f449 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -30,6 +30,14 @@ describe("Some basic CSS is added.", () => { render(); expect(true); }); + + test("The background color of the header area is different", () => { + render(); + const banner = screen.getByRole("banner"); + expect(banner).not.toHaveStyle({ + "background-color": "rgb(40, 44, 52)" + }); + }); }); describe("Some Bootstrap Elements are added", () => { From b66d4de909f74de4cba160a6fff05b078b9b47cc Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Mon, 31 Jan 2022 16:32:13 -0500 Subject: [PATCH 15/81] See previous commit message --- src/HtmlCss.test.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 379fc8f449..36767ad350 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -26,11 +26,6 @@ describe("Some HTML Elements are added.", () => { }); describe("Some basic CSS is added.", () => { - test("There is a floating red box", () => { - render(); - expect(true); - }); - test("The background color of the header area is different", () => { render(); const banner = screen.getByRole("banner"); @@ -63,3 +58,7 @@ describe("Some Bootstrap Elements are added", () => { expect(consoleSpy).toHaveBeenCalledWith("Hello World!"); }); }); + +/** + * Remember, there are additional tasks described on the page! + */ From 0a24364f67b1ee221ebe175d6c494d5eca6ad7dc Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:10:09 -0400 Subject: [PATCH 16/81] Add in new css test --- src/HtmlCss.test.tsx | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 36767ad350..48b0a6df2d 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -30,7 +30,7 @@ describe("Some basic CSS is added.", () => { render(); const banner = screen.getByRole("banner"); expect(banner).not.toHaveStyle({ - "background-color": "rgb(40, 44, 52)" + "background-color": "rgb(40, 44, 52)", }); }); }); @@ -59,6 +59,25 @@ describe("Some Bootstrap Elements are added", () => { }); }); -/** - * Remember, there are additional tasks described on the page! - */ +describe("Some additional CSS was added", () => { + test("checks if any element has a background color of red", () => { + const { container } = render(); + // Get all elements in the rendered container + const elements = container.querySelectorAll("*"); + + // Check if any element has a background color of red + let foundRedBackground = false; + + elements.forEach((element) => { + const style = getComputedStyle(element); + if ( + style.backgroundColor === "red" || + style.backgroundColor === "rgb(255, 0, 0)" + ) { + foundRedBackground = true; + } + }); + + expect(foundRedBackground).toBe(true); + }); +}); From 4d43d7a5d133522b0a8d92e1cb3d7e4053a81992 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:12:28 -0400 Subject: [PATCH 17/81] Add in points --- src/HtmlCss.test.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 48b0a6df2d..320cb97524 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -4,20 +4,20 @@ import App from "./App"; import userEvent from "@testing-library/user-event"; describe("Some HTML Elements are added.", () => { - test("There is a header", () => { + test("(2 pts) There is a header", () => { render(); const header = screen.getByRole("heading"); expect(header).toBeInTheDocument(); }); - test("There is an image with alt text", () => { + test("(2 pts) There is an image with alt text", () => { render(); const image = screen.getByRole("img"); expect(image).toBeInTheDocument(); expect(image).toHaveAttribute("alt"); }); - test("There is a list with at least three elements", () => { + test("(2 pts) There is a list with at least three elements", () => { render(); const list = screen.getByRole("list"); expect(list).toBeInTheDocument(); @@ -25,7 +25,7 @@ describe("Some HTML Elements are added.", () => { }); }); -describe("Some basic CSS is added.", () => { +describe("(2 pts) Some basic CSS is added.", () => { test("The background color of the header area is different", () => { render(); const banner = screen.getByRole("banner"); @@ -35,7 +35,7 @@ describe("Some basic CSS is added.", () => { }); }); -describe("Some Bootstrap Elements are added", () => { +describe("(2 pts) Some Bootstrap Elements are added", () => { test("There is one bootstrap button with the text 'Log Hello World'", () => { render(); const button = screen.getByRole("button", { name: /Log Hello World/i }); @@ -44,13 +44,13 @@ describe("Some Bootstrap Elements are added", () => { expect(button).toHaveClass("btn-primary"); }); - test("Not clicking the bootstrap button does not logs 'Hello World!'", () => { + test("(2 pts) Not clicking the bootstrap button does not logs 'Hello World!'", () => { const consoleSpy = jest.spyOn(console, "log"); render(); expect(consoleSpy).not.toHaveBeenCalledWith("Hello World!"); }); - test("Clicking the bootstrap button logs 'Hello World!'", () => { + test("(2 pts) Clicking the bootstrap button logs 'Hello World!'", () => { const consoleSpy = jest.spyOn(console, "log"); render(); const button = screen.getByRole("button", { name: /Log Hello World/i }); @@ -60,7 +60,7 @@ describe("Some Bootstrap Elements are added", () => { }); describe("Some additional CSS was added", () => { - test("checks if any element has a background color of red", () => { + test("(2 pts) checks if any element has a background color of red", () => { const { container } = render(); // Get all elements in the rendered container const elements = container.querySelectorAll("*"); From 83c4461f9dbe7d2a66c09eed18959565a302eea2 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 29 Jan 2022 23:23:45 -0500 Subject: [PATCH 18/81] Basic functions tests and stubs --- public/tasks/task-functions.md | 5 +++ src/functions.test.ts | 59 ++++++++++++++++++++++++++++++++++ src/functions.ts | 19 +++++++++++ 3 files changed, 83 insertions(+) create mode 100644 public/tasks/task-functions.md create mode 100644 src/functions.test.ts create mode 100644 src/functions.ts diff --git a/public/tasks/task-functions.md b/public/tasks/task-functions.md new file mode 100644 index 0000000000..36e7926bb7 --- /dev/null +++ b/public/tasks/task-functions.md @@ -0,0 +1,5 @@ +# Task - Functions + +Version: 0.0.1 + +Implement a bunch of functions that work on primitives. diff --git a/src/functions.test.ts b/src/functions.test.ts new file mode 100644 index 0000000000..e0bef414ea --- /dev/null +++ b/src/functions.test.ts @@ -0,0 +1,59 @@ +import { + add3, + fahrenheitToCelius, + shout, + isQuestion, + convertYesNo +} from "./functions"; + +test("Testing the basic functions", () => { + it("Testing the add3 function", () => { + expect(add3(1, 2, 3)).toBe(6); + expect(add3(9, 7, 4)).toBe(20); + expect(add3(6, -3, 9)).toBe(15); + expect(add3(10, 1, -9)).toBe(11); + expect(add3(-9, -100, -4)).toBe(0); + expect(add3(-1, -1, 1)).toBe(1); + }); + + it("Testing the fahrenheitToCelius function", () => { + expect(fahrenheitToCelius(32)).toBe(0); + expect(fahrenheitToCelius(-40)).toBe(40); + expect(fahrenheitToCelius(-22)).toBe(-30); + expect(fahrenheitToCelius(14)).toBe(-10); + expect(fahrenheitToCelius(68)).toBe(20); + expect(fahrenheitToCelius(86)).toBe(30); + expect(fahrenheitToCelius(212)).toBe(100); + }); + + it("Testing the shout function", () => { + expect(shout("Hello")).toBe("HELLO!"); + expect(shout("What?")).toBe("WHAT?!"); + expect(shout("oHo")).toBe("OHO!"); + expect(shout("AHHHH!!!")).toBe("AHHHH!!!!"); + expect(shout("")).toBe("!"); + expect(shout("Please go outside")).toBe("PLEASE GO OUTSIDE!"); + }); + + it("Testing the isQuestion function", () => { + expect(isQuestion("Is this a question?")).toBe(true); + expect(isQuestion("Who are you?")).toBe(true); + expect(isQuestion("WHAT ARE YOU !?")).toBe(true); + expect(isQuestion("WHAT IS THIS?!")).toBe(false); + expect(isQuestion("OH GOD!")).toBe(false); + expect(isQuestion("Oh nevermind, it's fine.")).toBe(false); + expect(isQuestion("")).toBe(false); + }); + + it("Testing the convertYesNo function", () => { + expect(convertYesNo("yes")).toBe(true); + expect(convertYesNo("YES")).toBe(true); + expect(convertYesNo("NO")).toBe(false); + expect(convertYesNo("no")).toBe(false); + expect(convertYesNo("Apple")).toBe(null); + expect(convertYesNo("Bananas")).toBe(null); + expect(convertYesNo("Nope")).toBe(null); + expect(convertYesNo("Yesterday")).toBe(null); + expect(convertYesNo("Maybe")).toBe(null); + }); +}); diff --git a/src/functions.ts b/src/functions.ts new file mode 100644 index 0000000000..03193e4212 --- /dev/null +++ b/src/functions.ts @@ -0,0 +1,19 @@ +export function fahrenheitToCelius(temperature: number): number { + return 0; +} + +export function add3(first: number, second: number, third: number): number { + return 0; +} + +export function shout(message: string): string { + return ""; +} + +export function isQuestion(message: string): boolean { + return true; +} + +export function convertYesNo(word: string): boolean | null { + return true; +} From a48653022ec3c8b7ce99cf49d98b041e20815420 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 29 Jan 2022 23:30:17 -0500 Subject: [PATCH 19/81] Fix test organization --- src/functions.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/functions.test.ts b/src/functions.test.ts index e0bef414ea..98c926bb6f 100644 --- a/src/functions.test.ts +++ b/src/functions.test.ts @@ -6,8 +6,8 @@ import { convertYesNo } from "./functions"; -test("Testing the basic functions", () => { - it("Testing the add3 function", () => { +describe("Testing the basic functions", () => { + test("Testing the add3 function", () => { expect(add3(1, 2, 3)).toBe(6); expect(add3(9, 7, 4)).toBe(20); expect(add3(6, -3, 9)).toBe(15); @@ -16,7 +16,7 @@ test("Testing the basic functions", () => { expect(add3(-1, -1, 1)).toBe(1); }); - it("Testing the fahrenheitToCelius function", () => { + test("Testing the fahrenheitToCelius function", () => { expect(fahrenheitToCelius(32)).toBe(0); expect(fahrenheitToCelius(-40)).toBe(40); expect(fahrenheitToCelius(-22)).toBe(-30); @@ -26,7 +26,7 @@ test("Testing the basic functions", () => { expect(fahrenheitToCelius(212)).toBe(100); }); - it("Testing the shout function", () => { + test("Testing the shout function", () => { expect(shout("Hello")).toBe("HELLO!"); expect(shout("What?")).toBe("WHAT?!"); expect(shout("oHo")).toBe("OHO!"); @@ -35,7 +35,7 @@ test("Testing the basic functions", () => { expect(shout("Please go outside")).toBe("PLEASE GO OUTSIDE!"); }); - it("Testing the isQuestion function", () => { + test("Testing the isQuestion function", () => { expect(isQuestion("Is this a question?")).toBe(true); expect(isQuestion("Who are you?")).toBe(true); expect(isQuestion("WHAT ARE YOU !?")).toBe(true); @@ -45,7 +45,7 @@ test("Testing the basic functions", () => { expect(isQuestion("")).toBe(false); }); - it("Testing the convertYesNo function", () => { + test("Testing the convertYesNo function", () => { expect(convertYesNo("yes")).toBe(true); expect(convertYesNo("YES")).toBe(true); expect(convertYesNo("NO")).toBe(false); From 9722564e99cecda5d50dd95524c94a76c4cda923 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 29 Jan 2022 23:39:22 -0500 Subject: [PATCH 20/81] Fix issue in fahrenheit conversion --- src/functions.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions.test.ts b/src/functions.test.ts index 98c926bb6f..3eb9f4f3aa 100644 --- a/src/functions.test.ts +++ b/src/functions.test.ts @@ -18,7 +18,7 @@ describe("Testing the basic functions", () => { test("Testing the fahrenheitToCelius function", () => { expect(fahrenheitToCelius(32)).toBe(0); - expect(fahrenheitToCelius(-40)).toBe(40); + expect(fahrenheitToCelius(-40)).toBe(-40); expect(fahrenheitToCelius(-22)).toBe(-30); expect(fahrenheitToCelius(14)).toBe(-10); expect(fahrenheitToCelius(68)).toBe(20); From bd06d5d0e3ed264f7bffb4e8e4811d0efc170255 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 3 Feb 2022 14:27:08 -0500 Subject: [PATCH 21/81] Move around some of the functions --- src/functions.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/functions.test.ts b/src/functions.test.ts index 3eb9f4f3aa..c496ac7e99 100644 --- a/src/functions.test.ts +++ b/src/functions.test.ts @@ -7,15 +7,6 @@ import { } from "./functions"; describe("Testing the basic functions", () => { - test("Testing the add3 function", () => { - expect(add3(1, 2, 3)).toBe(6); - expect(add3(9, 7, 4)).toBe(20); - expect(add3(6, -3, 9)).toBe(15); - expect(add3(10, 1, -9)).toBe(11); - expect(add3(-9, -100, -4)).toBe(0); - expect(add3(-1, -1, 1)).toBe(1); - }); - test("Testing the fahrenheitToCelius function", () => { expect(fahrenheitToCelius(32)).toBe(0); expect(fahrenheitToCelius(-40)).toBe(-40); @@ -26,6 +17,15 @@ describe("Testing the basic functions", () => { expect(fahrenheitToCelius(212)).toBe(100); }); + test("Testing the add3 function", () => { + expect(add3(1, 2, 3)).toBe(6); + expect(add3(9, 7, 4)).toBe(20); + expect(add3(6, -3, 9)).toBe(15); + expect(add3(10, 1, -9)).toBe(11); + expect(add3(-9, -100, -4)).toBe(0); + expect(add3(-1, -1, 1)).toBe(1); + }); + test("Testing the shout function", () => { expect(shout("Hello")).toBe("HELLO!"); expect(shout("What?")).toBe("WHAT?!"); From 4cd1900783f690690229b7c17cf9e81995f52b3a Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 3 Feb 2022 14:27:18 -0500 Subject: [PATCH 22/81] Explain what the actual functions require you to do --- src/functions.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/functions.ts b/src/functions.ts index 03193e4212..e614c81c0c 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -1,19 +1,41 @@ +/** + * Consumes a single temperature in Fahrenheit (a number) and converts to Celsius + * using this formula: + * C = (F - 32) * 5/9 + */ export function fahrenheitToCelius(temperature: number): number { return 0; } +/** + * Consumes three numbers and produces their sum. BUT you should only add a number + * if the number is greater than zero. + */ export function add3(first: number, second: number, third: number): number { return 0; } +/** + * Consumes a string and produces the same string in UPPERCASE and with an exclamation + * mark added to the end. + */ export function shout(message: string): string { return ""; } +/** + * Consumes a string (a message) and returns a boolean if the string ends in a question + * mark. Do not use an `if` statement in solving this question. + */ export function isQuestion(message: string): boolean { return true; } +/** + * Consumes a word (a string) and returns either `true`, `false`, or `null`. If the string + * is "yes" (upper or lower case), then return `true`. If the string is "no" (again, either + * upper or lower case), then return `false`. Otherwise, return `null`. + */ export function convertYesNo(word: string): boolean | null { return true; } From cf1d21a31d00c2e8dc8bb7c76f372b3e0adebfbe Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:15:59 -0400 Subject: [PATCH 23/81] Update formatting --- src/functions.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions.test.ts b/src/functions.test.ts index c496ac7e99..a082bfd61a 100644 --- a/src/functions.test.ts +++ b/src/functions.test.ts @@ -3,7 +3,7 @@ import { fahrenheitToCelius, shout, isQuestion, - convertYesNo + convertYesNo, } from "./functions"; describe("Testing the basic functions", () => { From e11693a366f61cdb442c6f6f5822bd49e2dd604f Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:18:24 -0400 Subject: [PATCH 24/81] Add in points --- src/functions.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/functions.test.ts b/src/functions.test.ts index a082bfd61a..3d921f5d64 100644 --- a/src/functions.test.ts +++ b/src/functions.test.ts @@ -7,7 +7,7 @@ import { } from "./functions"; describe("Testing the basic functions", () => { - test("Testing the fahrenheitToCelius function", () => { + test("(3 pts) Testing the fahrenheitToCelius function", () => { expect(fahrenheitToCelius(32)).toBe(0); expect(fahrenheitToCelius(-40)).toBe(-40); expect(fahrenheitToCelius(-22)).toBe(-30); @@ -17,7 +17,7 @@ describe("Testing the basic functions", () => { expect(fahrenheitToCelius(212)).toBe(100); }); - test("Testing the add3 function", () => { + test("(3 pts) Testing the add3 function", () => { expect(add3(1, 2, 3)).toBe(6); expect(add3(9, 7, 4)).toBe(20); expect(add3(6, -3, 9)).toBe(15); @@ -26,7 +26,7 @@ describe("Testing the basic functions", () => { expect(add3(-1, -1, 1)).toBe(1); }); - test("Testing the shout function", () => { + test("(3 pts) Testing the shout function", () => { expect(shout("Hello")).toBe("HELLO!"); expect(shout("What?")).toBe("WHAT?!"); expect(shout("oHo")).toBe("OHO!"); @@ -35,7 +35,7 @@ describe("Testing the basic functions", () => { expect(shout("Please go outside")).toBe("PLEASE GO OUTSIDE!"); }); - test("Testing the isQuestion function", () => { + test("(3 pts) Testing the isQuestion function", () => { expect(isQuestion("Is this a question?")).toBe(true); expect(isQuestion("Who are you?")).toBe(true); expect(isQuestion("WHAT ARE YOU !?")).toBe(true); @@ -45,7 +45,7 @@ describe("Testing the basic functions", () => { expect(isQuestion("")).toBe(false); }); - test("Testing the convertYesNo function", () => { + test("(3 pts) Testing the convertYesNo function", () => { expect(convertYesNo("yes")).toBe(true); expect(convertYesNo("YES")).toBe(true); expect(convertYesNo("NO")).toBe(false); From 7cc4e3f20e61307e9f22eb466fe21871b3eefbd3 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 1 Feb 2022 14:51:32 -0500 Subject: [PATCH 25/81] First stab at array problems --- public/tasks/task-arrays.md | 5 +++ src/arrays.test.ts | 12 ++++++ src/arrays.ts | 84 +++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 public/tasks/task-arrays.md create mode 100644 src/arrays.test.ts create mode 100644 src/arrays.ts diff --git a/public/tasks/task-arrays.md b/public/tasks/task-arrays.md new file mode 100644 index 0000000000..c2fbf80f8d --- /dev/null +++ b/public/tasks/task-arrays.md @@ -0,0 +1,5 @@ +# Task - Arrays + +Version: 0.0.1 + +Implement functions that work with arrays immutably. diff --git a/src/arrays.test.ts b/src/arrays.test.ts new file mode 100644 index 0000000000..b812349d2f --- /dev/null +++ b/src/arrays.test.ts @@ -0,0 +1,12 @@ +import { bookEndList } from "./arrays"; + +describe("Testing the array functions", () => { + const NUMBERS_1 = [1, 2, 3]; + + test("Testing the bookEndList function", () => { + // Ensure that the original array was not changed + expect(bookEndList(NUMBERS_1)).not.toBe(NUMBERS_1); + // And that a correct new array was returned + expect(bookEndList(NUMBERS_1)).toEqual([1, 3]); + }); +}); diff --git a/src/arrays.ts b/src/arrays.ts new file mode 100644 index 0000000000..7604b40cdb --- /dev/null +++ b/src/arrays.ts @@ -0,0 +1,84 @@ +/** + * Consume an array of numbers, and return a new array containing + * JUST the first and last number. If there are no elements, return + * an empty array. If there is one element, the resulting list should + * the number twice. + */ +export function bookEndList(numbers: number[]): number[] { + return numbers; +} + +/** + * Consume an array of numbers, and return a new array where each + * number has been tripled (multiplied by 3). + */ +export function tripleNumbers(numbers: number[]): number[] { + return numbers; +} + +/** + * Consume an array of strings and convert them to integers. If + * the number cannot be parsed as an integer, convert it to "?" instead. + */ +export function stringsToIntegers(numbers: string[]): number[] { + return []; +} + +/** + * Consume an array of strings and return them as numbers. Note that + * the strings MAY have "$" symbols at the beginning, in which case + * those should be removed. If the result cannot be parsed as an integer, + * convert it to "?" instead. + */ +// Remember, you can write functions as lambdas too! They work exactly the same. +export const removeDollars = (amounts: string[]): number[] => { + return []; +}; + +/** + * Consume an array of messages and return a new list of the messages. However, any + * string that ends in "!" should be made uppercase. + */ +export const shoutIfExclaiming = (messages: string[]): string[] => { + return []; +}; + +/** + * Consumes an array of words and returns the number of words that are LESS THAN + * 4 letters long. + */ +export function countShortWords(words: string[]): number { + return 0; +} + +/** + * Consumes an array of colors (e.g., 'red', 'purple') and returns true if ALL + * the colors are either 'red', 'blue', or 'green'. If an empty list is given, + * then return true. + */ +export function allRGB(colors: string[]): boolean { + return false; +} + +/** + * Consumes an array of numbers, and produces a string representation of the + * numbers being added together along with their actual sum. + * + * For instance, the array [1, 2, 3] would become "6=1+2+3". + */ +export function makeMath(addends: number[]): string { + return ""; +} + +/** + * Consumes an array of numbers and produces a new array of the same numbers, + * with one difference. After the FIRST negative number, insert the sum of all + * previous numbers in the list. If there are no negative numbers, then append + * 0 to the list. + * + * For instance, the array [1, 9, -5, 7] would become [1, 9, -5, 10, 7] + * And the array [1, 9, 7] would become [1, 9, 0] + */ +export function injectPositive(values: number[]): number[] { + return []; +} From f25333778032fc42866a278af6a3ce871f735150 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 1 Feb 2022 16:09:10 -0500 Subject: [PATCH 26/81] Add in the rest of the tests --- src/arrays.test.ts | 269 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 265 insertions(+), 4 deletions(-) diff --git a/src/arrays.test.ts b/src/arrays.test.ts index b812349d2f..0881d9fe8a 100644 --- a/src/arrays.test.ts +++ b/src/arrays.test.ts @@ -1,12 +1,273 @@ -import { bookEndList } from "./arrays"; +import { + allRGB, + bookEndList, + countShortWords, + injectPositive, + makeMath, + removeDollars, + shoutIfExclaiming, + stringsToIntegers, + tripleNumbers +} from "./arrays"; describe("Testing the array functions", () => { + ////////////////////////////////// + // bookEndList and tripleNumbers + const NUMBERS_1 = [1, 2, 3]; + const NUMBERS_2 = [100, 300, 200]; + const NUMBERS_3 = [5]; + const NUMBERS_4: number[] = []; + const NUMBERS_5 = [100, 199, 1, -5, 7, 3]; + const NUMBERS_6 = [-100, -200, 100, 200]; + const NUMBERS_7 = [199, 1, 550, 50, 200]; + + // Ensure that none of the arrays were changed mutably + // If you fail these, you aren't using map/filter/reduce/etc. properly! + afterEach(() => { + expect(NUMBERS_1).toEqual([1, 2, 3]); + expect(NUMBERS_2).toEqual([100, 300, 200]); + expect(NUMBERS_3).toEqual([5]); + expect(NUMBERS_4).toEqual([]); + expect(NUMBERS_5).toEqual([100, 199, 1, -5, 7, 3]); + expect(NUMBERS_6).toEqual([-100, -200, 100, 200]); + expect(NUMBERS_7).toEqual([199, 1, 550, 50, 200]); + }); test("Testing the bookEndList function", () => { - // Ensure that the original array was not changed - expect(bookEndList(NUMBERS_1)).not.toBe(NUMBERS_1); - // And that a correct new array was returned expect(bookEndList(NUMBERS_1)).toEqual([1, 3]); + expect(bookEndList(NUMBERS_2)).toEqual([100, 200]); + expect(bookEndList(NUMBERS_3)).toEqual([5, 5]); + expect(bookEndList(NUMBERS_4)).toEqual([]); + expect(bookEndList(NUMBERS_5)).toEqual([100, 3]); + expect(bookEndList(NUMBERS_6)).toEqual([-100, 200]); + }); + + test("Testing the tripleNumbers function", () => { + expect(tripleNumbers(NUMBERS_1)).toEqual([3, 6, 9]); + expect(tripleNumbers(NUMBERS_2)).toEqual([300, 900, 600]); + expect(tripleNumbers(NUMBERS_3)).toEqual([15]); + expect(tripleNumbers(NUMBERS_4)).toEqual([]); + expect(tripleNumbers(NUMBERS_5)).toEqual([300, 597, 3, -15, 21, 9]); + expect(tripleNumbers(NUMBERS_6)).toEqual([-300, -600, 300, 600]); + }); + + ////////////////////////////////// + // stringsToIntegers + + const VALUES_1 = ["1", "2", "3"]; + const VALUES_2 = ["100", "200", "300"]; + const VALUES_3 = ["5"]; + const VALUES_4: string[] = []; + const VALUES_5 = ["100", "?", "27", "$44"]; + const VALUES_6 = ["-1", "0", "1", "*1"]; + const VALUES_7 = ["apple", "banana", "cactus"]; + + // Ensure that none of the arrays were changed mutably + // If you fail these, you aren't using map/filter/reduce/etc. properly! + afterEach(() => { + expect(VALUES_1).toEqual(["1", "2", "3"]); + expect(VALUES_2).toEqual(["100", "200", "300"]); + expect(VALUES_3).toEqual(["5"]); + expect(VALUES_4).toEqual([]); + expect(VALUES_5).toEqual(["100", "?", "27", "$44"]); + expect(VALUES_6).toEqual(["-1", "0", "1", "*1"]); + expect(VALUES_7).toEqual(["apple", "banana", "cactus"]); + }); + + test("Testing the stringsToIntegers function", () => { + expect(stringsToIntegers(VALUES_1)).toEqual([1, 2, 3]); + expect(stringsToIntegers(VALUES_2)).toEqual([100, 200, 300]); + expect(stringsToIntegers(VALUES_3)).toEqual([5]); + expect(stringsToIntegers(VALUES_4)).toEqual([]); + expect(stringsToIntegers(VALUES_5)).toEqual([100, 0, 27, 0]); + expect(stringsToIntegers(VALUES_6)).toEqual([-1, 0, 1, 0]); + expect(stringsToIntegers(VALUES_7)).toEqual([0, 0, 0]); + }); + + ////////////////////////////////// + // removeDollars + + const AMOUNTS_1 = ["$1", "$2", "$3"]; + const AMOUNTS_2 = ["$100", "$200", "$300", "$400"]; + const AMOUNTS_3 = ["$5"]; + const AMOUNTS_4 = ["$"]; + const AMOUNTS_5 = ["100", "200", "$300", "$400"]; + const AMOUNTS_6: string[] = []; + const AMOUNTS_7 = ["100", "???", "7", "$233", "", "$"]; + const AMOUNTS_8 = ["$one", "two", "$three"]; + + // Ensure that none of the arrays were changed mutably + // If you fail these, you aren't using map/filter/reduce/etc. properly! + afterEach(() => { + expect(AMOUNTS_1).toEqual(["$1", "$2", "$3"]); + expect(AMOUNTS_2).toEqual(["$100", "$200", "$300", "$400"]); + expect(AMOUNTS_3).toEqual(["$5"]); + expect(AMOUNTS_4).toEqual(["$"]); + expect(AMOUNTS_5).toEqual(["100", "200", "$300", "$400"]); + expect(AMOUNTS_6).toEqual([]); + expect(AMOUNTS_7).toEqual(["100", "???", "7", "$233", "", "$"]); + expect(AMOUNTS_8).toEqual(["$one", "two", "$three"]); + }); + + test("Testing the removeDollars function", () => { + expect(removeDollars(AMOUNTS_1)).toEqual([1, 2, 3]); + expect(removeDollars(AMOUNTS_2)).toEqual([100, 200, 300, 400]); + expect(removeDollars(AMOUNTS_3)).toEqual([5]); + expect(removeDollars(AMOUNTS_4)).toEqual([0]); + expect(removeDollars(AMOUNTS_5)).toEqual([100, 200, 300, 400]); + expect(removeDollars(AMOUNTS_6)).toEqual([]); + expect(removeDollars(AMOUNTS_7)).toEqual([100, 0, 7, 233, 0, 0]); + expect(removeDollars(AMOUNTS_8)).toEqual([0, 0, 0]); + }); + + ////////////////////////////////// + // shoutIfExclaiming + + const MESSAGE_1 = ["Hello", "you", "are", "great!"]; + const MESSAGE_2 = ["oho!", "Oho!", "oHo!", "oHO!", "OHO!"]; + const MESSAGE_3 = ["Wait?", "What?", "Lo", "How?", "High!"]; + const MESSAGE_4 = ["??????"]; + const MESSAGE_5: string[] = ["This one is very long!"]; + const MESSAGE_6 = ["No", "Caps", "here.", "Right?"]; + + // Ensure that none of the arrays were changed mutably + // If you fail these, you aren't using map/filter/reduce/etc. properly! + afterEach(() => { + expect(MESSAGE_1).toEqual(["Hello", "you", "are", "great!"]); + expect(MESSAGE_2).toEqual(["oho!", "Oho!", "oHo!", "oHO!", "OHO!"]); + expect(MESSAGE_3).toEqual(["Wait?", "What?", "Lo", "How?", "High!"]); + expect(MESSAGE_4).toEqual(["??????"]); + expect(MESSAGE_5).toEqual(["This one is very long!"]); + expect(MESSAGE_6).toEqual(["No", "Caps", "here.", "Right?"]); + }); + + test("Testing the shoutIfExclaiming function", () => { + expect(shoutIfExclaiming(MESSAGE_1)).toEqual([ + "Hello", + "you", + "are", + "GREAT!" + ]); + expect(shoutIfExclaiming(MESSAGE_2)).toEqual([ + "OHO!", + "OHO!", + "OHO!", + "OHO!", + "OHO!" + ]); + expect(shoutIfExclaiming(MESSAGE_3)).toEqual(["Lo", "HIGH!"]); + expect(shoutIfExclaiming(MESSAGE_4)).toEqual([]); + expect(shoutIfExclaiming(MESSAGE_5)).toEqual([ + "THIS ONE IS VERY LONG!" + ]); + expect(shoutIfExclaiming(MESSAGE_6)).toEqual(["No", "Caps", "here."]); + }); + + ////////////////////////////////// + // countShortWords + + const WORDS_1 = ["the", "cat", "in", "the", "hat"]; + const WORDS_2 = ["one", "two", "three", "four", "five", "six", "seven"]; + const WORDS_3 = ["alpha", "beta", "gamma"]; + const WORDS_4 = ["Longest", "Words", "Possible"]; + const WORDS_5: string[] = []; + const WORDS_6 = ["", "", "", ""]; + + // Ensure that none of the arrays were changed mutably + // If you fail these, you aren't using map/filter/reduce/etc. properly! + afterEach(() => { + expect(WORDS_1).toEqual(["the", "cat", "in", "the", "hat"]); + expect(WORDS_2).toEqual([ + "one", + "two", + "three", + "four", + "five", + "six", + "seven" + ]); + expect(WORDS_3).toEqual(["alpha", "beta", "gamma"]); + expect(WORDS_4).toEqual(["Longest", "Words", "Possible"]); + expect(WORDS_5).toEqual([]); + expect(WORDS_6).toEqual(["", "", "", ""]); + }); + + test("Testing the countShortWords function", () => { + expect(countShortWords(WORDS_1)).toEqual(5); + expect(countShortWords(WORDS_2)).toEqual(3); + expect(countShortWords(WORDS_3)).toEqual(0); + expect(countShortWords(WORDS_4)).toEqual(0); + expect(countShortWords(WORDS_5)).toEqual(0); + expect(countShortWords(WORDS_6)).toEqual(4); + }); + + ////////////////////////////////// + // allRGB + + const COLORS_1 = ["red", "green", "blue"]; + const COLORS_2 = ["red", "red", "red"]; + const COLORS_3 = ["red", "red", "blue", "blue", "green", "red"]; + const COLORS_4 = ["purple", "orange", "violet"]; + const COLORS_5 = ["red", "blue", "yellow"]; + const COLORS_6 = ["green"]; + const COLORS_7 = ["red"]; + const COLORS_8 = ["kabluey"]; + const COLORS_9: string[] = []; + + // Ensure that none of the arrays were changed mutably + // If you fail these, you aren't using map/filter/reduce/etc. properly! + afterEach(() => { + expect(COLORS_1).toEqual(["red", "green", "blue"]); + expect(COLORS_2).toEqual(["red", "red", "red"]); + expect(COLORS_3).toEqual([ + "red", + "red", + "blue", + "blue", + "green", + "red" + ]); + expect(COLORS_4).toEqual(["purple", "orange", "violet"]); + expect(COLORS_5).toEqual(["red", "blue", "yellow"]); + expect(COLORS_6).toEqual(["green"]); + expect(COLORS_7).toEqual(["red"]); + expect(COLORS_8).toEqual(["kabluey"]); + expect(COLORS_9).toEqual([]); + }); + + test("Testing the allRGB function", () => { + expect(allRGB(COLORS_1)).toEqual(true); + expect(allRGB(COLORS_2)).toEqual(true); + expect(allRGB(COLORS_3)).toEqual(true); + expect(allRGB(COLORS_4)).toEqual(false); + expect(allRGB(COLORS_5)).toEqual(false); + expect(allRGB(COLORS_6)).toEqual(true); + expect(allRGB(COLORS_7)).toEqual(true); + expect(allRGB(COLORS_8)).toEqual(false); + expect(allRGB(COLORS_9)).toEqual(true); + }); + + ////////////////////////////////// + // makeMath + + test("Testing the makeMath function", () => { + expect(makeMath(NUMBERS_1)).toEqual("6=1+2+3"); + expect(makeMath(NUMBERS_2)).toEqual("600=100+300+200"); + expect(makeMath(NUMBERS_3)).toEqual("5=5"); + expect(makeMath(NUMBERS_4)).toEqual("0=0"); + expect(makeMath(NUMBERS_7)).toEqual("1000=199+1+550+50+200"); + }); + + ////////////////////////////////// + // injectPositive + test("Testing the tripleNumbers function", () => { + expect(injectPositive(NUMBERS_1)).toEqual([1, 2, 3, 6]); + expect(injectPositive(NUMBERS_2)).toEqual([100, 300, 200, 600]); + expect(injectPositive(NUMBERS_3)).toEqual([5, 5]); + expect(injectPositive(NUMBERS_4)).toEqual([0]); + expect(injectPositive(NUMBERS_5)).toEqual([100, 199, 1, -5, 300, 7, 3]); + expect(injectPositive(NUMBERS_6)).toEqual([-100, 0, -200, 100, 200]); + expect(injectPositive(NUMBERS_7)).toEqual([199, 1, 550, 50, 200, 1000]); }); }); From b8777b1873553a2e2780b67fd504486b9d16bd92 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 1 Feb 2022 16:09:25 -0500 Subject: [PATCH 27/81] Fix question text --- src/arrays.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/arrays.ts b/src/arrays.ts index 7604b40cdb..4a2ffe8e5b 100644 --- a/src/arrays.ts +++ b/src/arrays.ts @@ -18,7 +18,7 @@ export function tripleNumbers(numbers: number[]): number[] { /** * Consume an array of strings and convert them to integers. If - * the number cannot be parsed as an integer, convert it to "?" instead. + * the number cannot be parsed as an integer, convert it to 0 instead. */ export function stringsToIntegers(numbers: string[]): number[] { return []; @@ -28,7 +28,7 @@ export function stringsToIntegers(numbers: string[]): number[] { * Consume an array of strings and return them as numbers. Note that * the strings MAY have "$" symbols at the beginning, in which case * those should be removed. If the result cannot be parsed as an integer, - * convert it to "?" instead. + * convert it to 0 instead. */ // Remember, you can write functions as lambdas too! They work exactly the same. export const removeDollars = (amounts: string[]): number[] => { @@ -37,7 +37,8 @@ export const removeDollars = (amounts: string[]): number[] => { /** * Consume an array of messages and return a new list of the messages. However, any - * string that ends in "!" should be made uppercase. + * string that ends in "!" should be made uppercase. Also, remove any strings that end + * in question marks ("?"). */ export const shoutIfExclaiming = (messages: string[]): string[] => { return []; @@ -65,6 +66,7 @@ export function allRGB(colors: string[]): boolean { * numbers being added together along with their actual sum. * * For instance, the array [1, 2, 3] would become "6=1+2+3". + * And the array [] would become "0=0". */ export function makeMath(addends: number[]): string { return ""; @@ -74,10 +76,10 @@ export function makeMath(addends: number[]): string { * Consumes an array of numbers and produces a new array of the same numbers, * with one difference. After the FIRST negative number, insert the sum of all * previous numbers in the list. If there are no negative numbers, then append - * 0 to the list. + * the sum to the list. * * For instance, the array [1, 9, -5, 7] would become [1, 9, -5, 10, 7] - * And the array [1, 9, 7] would become [1, 9, 0] + * And the array [1, 9, 7] would become [1, 9, 7, 17] */ export function injectPositive(values: number[]): number[] { return []; From f87771e7d8058f6c4fc6d8c6d036953f65b3a775 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Fri, 11 Feb 2022 14:24:17 -0500 Subject: [PATCH 28/81] Update arrays.test.ts --- src/arrays.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arrays.test.ts b/src/arrays.test.ts index 0881d9fe8a..3652078efa 100644 --- a/src/arrays.test.ts +++ b/src/arrays.test.ts @@ -261,7 +261,7 @@ describe("Testing the array functions", () => { ////////////////////////////////// // injectPositive - test("Testing the tripleNumbers function", () => { + test("Testing the injectPositive function", () => { expect(injectPositive(NUMBERS_1)).toEqual([1, 2, 3, 6]); expect(injectPositive(NUMBERS_2)).toEqual([100, 300, 200, 600]); expect(injectPositive(NUMBERS_3)).toEqual([5, 5]); From f0d316b36ae394d502e75849b5532b76ffdf7c68 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:21:13 -0400 Subject: [PATCH 29/81] Add in points --- src/arrays.test.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/arrays.test.ts b/src/arrays.test.ts index 3652078efa..c2847517bd 100644 --- a/src/arrays.test.ts +++ b/src/arrays.test.ts @@ -7,7 +7,7 @@ import { removeDollars, shoutIfExclaiming, stringsToIntegers, - tripleNumbers + tripleNumbers, } from "./arrays"; describe("Testing the array functions", () => { @@ -34,7 +34,7 @@ describe("Testing the array functions", () => { expect(NUMBERS_7).toEqual([199, 1, 550, 50, 200]); }); - test("Testing the bookEndList function", () => { + test("(3 pts) Testing the bookEndList function", () => { expect(bookEndList(NUMBERS_1)).toEqual([1, 3]); expect(bookEndList(NUMBERS_2)).toEqual([100, 200]); expect(bookEndList(NUMBERS_3)).toEqual([5, 5]); @@ -43,7 +43,7 @@ describe("Testing the array functions", () => { expect(bookEndList(NUMBERS_6)).toEqual([-100, 200]); }); - test("Testing the tripleNumbers function", () => { + test("(3 pts) Testing the tripleNumbers function", () => { expect(tripleNumbers(NUMBERS_1)).toEqual([3, 6, 9]); expect(tripleNumbers(NUMBERS_2)).toEqual([300, 900, 600]); expect(tripleNumbers(NUMBERS_3)).toEqual([15]); @@ -75,7 +75,7 @@ describe("Testing the array functions", () => { expect(VALUES_7).toEqual(["apple", "banana", "cactus"]); }); - test("Testing the stringsToIntegers function", () => { + test("(3 pts) Testing the stringsToIntegers function", () => { expect(stringsToIntegers(VALUES_1)).toEqual([1, 2, 3]); expect(stringsToIntegers(VALUES_2)).toEqual([100, 200, 300]); expect(stringsToIntegers(VALUES_3)).toEqual([5]); @@ -110,7 +110,7 @@ describe("Testing the array functions", () => { expect(AMOUNTS_8).toEqual(["$one", "two", "$three"]); }); - test("Testing the removeDollars function", () => { + test("(3 pts) Testing the removeDollars function", () => { expect(removeDollars(AMOUNTS_1)).toEqual([1, 2, 3]); expect(removeDollars(AMOUNTS_2)).toEqual([100, 200, 300, 400]); expect(removeDollars(AMOUNTS_3)).toEqual([5]); @@ -142,24 +142,24 @@ describe("Testing the array functions", () => { expect(MESSAGE_6).toEqual(["No", "Caps", "here.", "Right?"]); }); - test("Testing the shoutIfExclaiming function", () => { + test("(3 pts) Testing the shoutIfExclaiming function", () => { expect(shoutIfExclaiming(MESSAGE_1)).toEqual([ "Hello", "you", "are", - "GREAT!" + "GREAT!", ]); expect(shoutIfExclaiming(MESSAGE_2)).toEqual([ "OHO!", "OHO!", "OHO!", "OHO!", - "OHO!" + "OHO!", ]); expect(shoutIfExclaiming(MESSAGE_3)).toEqual(["Lo", "HIGH!"]); expect(shoutIfExclaiming(MESSAGE_4)).toEqual([]); expect(shoutIfExclaiming(MESSAGE_5)).toEqual([ - "THIS ONE IS VERY LONG!" + "THIS ONE IS VERY LONG!", ]); expect(shoutIfExclaiming(MESSAGE_6)).toEqual(["No", "Caps", "here."]); }); @@ -185,7 +185,7 @@ describe("Testing the array functions", () => { "four", "five", "six", - "seven" + "seven", ]); expect(WORDS_3).toEqual(["alpha", "beta", "gamma"]); expect(WORDS_4).toEqual(["Longest", "Words", "Possible"]); @@ -193,7 +193,7 @@ describe("Testing the array functions", () => { expect(WORDS_6).toEqual(["", "", "", ""]); }); - test("Testing the countShortWords function", () => { + test("(3 pts) Testing the countShortWords function", () => { expect(countShortWords(WORDS_1)).toEqual(5); expect(countShortWords(WORDS_2)).toEqual(3); expect(countShortWords(WORDS_3)).toEqual(0); @@ -226,7 +226,7 @@ describe("Testing the array functions", () => { "blue", "blue", "green", - "red" + "red", ]); expect(COLORS_4).toEqual(["purple", "orange", "violet"]); expect(COLORS_5).toEqual(["red", "blue", "yellow"]); @@ -236,7 +236,7 @@ describe("Testing the array functions", () => { expect(COLORS_9).toEqual([]); }); - test("Testing the allRGB function", () => { + test("(3 pts) Testing the allRGB function", () => { expect(allRGB(COLORS_1)).toEqual(true); expect(allRGB(COLORS_2)).toEqual(true); expect(allRGB(COLORS_3)).toEqual(true); @@ -251,7 +251,7 @@ describe("Testing the array functions", () => { ////////////////////////////////// // makeMath - test("Testing the makeMath function", () => { + test("(3 pts) Testing the makeMath function", () => { expect(makeMath(NUMBERS_1)).toEqual("6=1+2+3"); expect(makeMath(NUMBERS_2)).toEqual("600=100+300+200"); expect(makeMath(NUMBERS_3)).toEqual("5=5"); @@ -261,7 +261,7 @@ describe("Testing the array functions", () => { ////////////////////////////////// // injectPositive - test("Testing the injectPositive function", () => { + test("(3 pts) Testing the injectPositive function", () => { expect(injectPositive(NUMBERS_1)).toEqual([1, 2, 3, 6]); expect(injectPositive(NUMBERS_2)).toEqual([100, 300, 200, 600]); expect(injectPositive(NUMBERS_3)).toEqual([5, 5]); From c2e556dece7ea7737c13bdd355ef3ebcee121e70 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 2 Feb 2022 13:12:40 -0500 Subject: [PATCH 30/81] First stab at questions --- public/tasks/task-objects.md | 5 + src/data/questions.json | 79 ++++++++++ src/objects.test.ts | 295 +++++++++++++++++++++++++++++++++++ src/objects.ts | 141 +++++++++++++++++ 4 files changed, 520 insertions(+) create mode 100644 public/tasks/task-objects.md create mode 100644 src/data/questions.json create mode 100644 src/objects.test.ts create mode 100644 src/objects.ts diff --git a/public/tasks/task-objects.md b/public/tasks/task-objects.md new file mode 100644 index 0000000000..480889da0d --- /dev/null +++ b/public/tasks/task-objects.md @@ -0,0 +1,5 @@ +# Task - Objects + +Version: 0.0.1 + +Implement functions that work with objects immutably. diff --git a/src/data/questions.json b/src/data/questions.json new file mode 100644 index 0000000000..3b19537526 --- /dev/null +++ b/src/data/questions.json @@ -0,0 +1,79 @@ +{ + "BLANK_QUESTIONS": [ + { + "id": 1, + "name": "Question 1", + "body": "", + "type": "multiple_choice_question", + "options": [], + "expected": "", + "points": 1, + "published": false + }, + { + "id": 47, + "name": "My New Question", + "body": "", + "type": "multiple_choice_question", + "options": [], + "expected": "", + "points": 1, + "published": false + }, + { + "id": 2, + "name": "Question 2", + "body": "", + "type": "short_answer_question", + "options": [], + "expected": "", + "points": 1, + "published": false + } + ], + "SIMPLE_QUESTIONS": [ + { + "id": 1, + "name": "Addition", + "body": "What is 2+2?", + "type": "short_answer_question", + "options": [], + "expected": "4", + "points": 1, + "published": true + }, + { + "id": 2, + "name": "Letters", + "body": "What is the last letter of the English alphabet?", + "type": "short_answer_question", + "options": [], + "expected": "Z", + "points": 1, + "published": false + }, + { + "id": 5, + "name": "Colors", + "body": "Which of these is a color?", + "type": "multiple_choice_question", + "options": ["red", "apple", "firetruck"], + "expected": "red", + "points": 1, + "published": true + }, + { + "id": 9, + "name": "Shapes", + "body": "What shape can you make with one line?", + "type": "multiple_choice_question", + "options": ["square", "triangle", "circle"], + "expected": "circle", + "points": 2, + "published": false + } + ], + "SIMPLE_QUESTIONS_2": [], + "EMPTY_QUESTIONS": [], + "TRIVIA_QUESTIONS": [] +} diff --git a/src/objects.test.ts b/src/objects.test.ts new file mode 100644 index 0000000000..bcff7ab176 --- /dev/null +++ b/src/objects.test.ts @@ -0,0 +1,295 @@ +import { + makeBlankQuestion, + isCorrect, + Question, + isValid, + toShortForm, + toMarkdown, + duplicateQuestion, + renameQuestion, + publishQuestion, + addOption, + mergeQuestion +} from "./objects"; +import testQuestionData from "./data/questions.json"; +import backupQuestionData from "./data/questions.json"; + +//////////////////////////////////////////// +// Setting up the test data + +const { BLANK_QUESTIONS, SIMPLE_QUESTIONS }: Record = + // Typecast the test data that we imported to be a record matching + // strings to the question list + testQuestionData as Record; + +// We have backup versions of the data to make sure all changes are immutable +const { + BLANK_QUESTIONS: BACKUP_BLANK_QUESTIONS, + SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS +}: Record = backupQuestionData as Record< + string, + Question[] +>; + +// Unpack the list of simple questions into convenient constants +const [ADDITION_QUESTION, LETTER_QUESTION, COLOR_QUESTION, SHAPE_QUESTION] = + SIMPLE_QUESTIONS; +const [ + BACKUP_ADDITION_QUESTION, + BACKUP_LETTER_QUESTION, + BACKUP_COLOR_QUESTION, + BACKUP_SHAPE_QUESTION +] = BACKUP_SIMPLE_QUESTIONS; + +//////////////////////////////////////////// +// Actual tests + +describe("Testing the object functions", () => { + ////////////////////////////////// + // makeBlankQuestion + + test("Testing the makeBlankQuestion function", () => { + expect( + makeBlankQuestion(1, "Question 1", "multiple_choice_question") + ).toEqual(BLANK_QUESTIONS[0]); + expect( + makeBlankQuestion(47, "My New Question", "multiple_choice_question") + ).toEqual(BLANK_QUESTIONS[1]); + expect( + makeBlankQuestion(2, "Question 2", "short_answer_question") + ).toEqual(BLANK_QUESTIONS[2]); + }); + + /////////////////////////////////// + // isCorrect + test("Testing the isCorrect function", () => { + expect(isCorrect(ADDITION_QUESTION, "4")).toEqual(true); + expect(isCorrect(ADDITION_QUESTION, "2")).toEqual(false); + expect(isCorrect(ADDITION_QUESTION, " 4\n")).toEqual(true); + expect(isCorrect(LETTER_QUESTION, "Z")).toEqual(true); + expect(isCorrect(LETTER_QUESTION, "z")).toEqual(true); + expect(isCorrect(LETTER_QUESTION, "4")).toEqual(false); + expect(isCorrect(LETTER_QUESTION, "0")).toEqual(false); + expect(isCorrect(LETTER_QUESTION, "zed")).toEqual(false); + expect(isCorrect(COLOR_QUESTION, "red")).toEqual(true); + expect(isCorrect(COLOR_QUESTION, "apple")).toEqual(false); + expect(isCorrect(COLOR_QUESTION, "firetruck")).toEqual(false); + expect(isCorrect(SHAPE_QUESTION, "square")).toEqual(false); + expect(isCorrect(SHAPE_QUESTION, "triangle")).toEqual(false); + expect(isCorrect(SHAPE_QUESTION, "circle")).toEqual(true); + }); + + /////////////////////////////////// + // isValid + test("Testing the isValid function", () => { + expect(isValid(ADDITION_QUESTION, "4")).toEqual(true); + expect(isValid(ADDITION_QUESTION, "2")).toEqual(true); + expect(isValid(ADDITION_QUESTION, " 4\n")).toEqual(true); + expect(isValid(LETTER_QUESTION, "Z")).toEqual(true); + expect(isValid(LETTER_QUESTION, "z")).toEqual(true); + expect(isValid(LETTER_QUESTION, "4")).toEqual(true); + expect(isValid(LETTER_QUESTION, "0")).toEqual(true); + expect(isValid(LETTER_QUESTION, "zed")).toEqual(true); + expect(isValid(COLOR_QUESTION, "red")).toEqual(true); + expect(isValid(COLOR_QUESTION, "apple")).toEqual(true); + expect(isValid(COLOR_QUESTION, "firetruck")).toEqual(true); + expect(isValid(COLOR_QUESTION, "RED")).toEqual(false); + expect(isValid(COLOR_QUESTION, "orange")).toEqual(false); + expect(isValid(SHAPE_QUESTION, "square")).toEqual(true); + expect(isValid(SHAPE_QUESTION, "triangle")).toEqual(true); + expect(isValid(SHAPE_QUESTION, "circle")).toEqual(true); + expect(isValid(SHAPE_QUESTION, "circle ")).toEqual(false); + expect(isValid(SHAPE_QUESTION, "rhombus")).toEqual(false); + }); + + /////////////////////////////////// + // toShortForm + test("Testing the toShortForm function", () => { + expect(toShortForm(ADDITION_QUESTION)).toEqual("1: Addition"); + expect(toShortForm(LETTER_QUESTION)).toEqual("2: Letters"); + expect(toShortForm(COLOR_QUESTION)).toEqual("5: Colors"); + expect(toShortForm(SHAPE_QUESTION)).toEqual("9: Shapes"); + expect(toShortForm(BLANK_QUESTIONS[1])).toEqual("47: My New Que"); + }); + + /////////////////////////////////// + // toMarkdown + test("Testing the toMarkdown function", () => { + expect(toMarkdown(ADDITION_QUESTION)).toEqual(`# Addition +What is 2+2?`); + expect(toMarkdown(LETTER_QUESTION)).toEqual(`# Letters +What is the last letter of the English alphabet?`); + expect(toMarkdown(COLOR_QUESTION)).toEqual(`# Colors +Which of these is a color? +- red +- apple +- firetruck`); + expect(toMarkdown(SHAPE_QUESTION)).toEqual(`# Shapes +What shape can you make with one line? +- square +- triangle +- circle`); + }); + + afterEach(() => { + expect(ADDITION_QUESTION).toEqual(BACKUP_ADDITION_QUESTION); + expect(LETTER_QUESTION).toEqual(BACKUP_LETTER_QUESTION); + expect(SHAPE_QUESTION).toEqual(BACKUP_SHAPE_QUESTION); + expect(COLOR_QUESTION).toEqual(BACKUP_COLOR_QUESTION); + expect(BLANK_QUESTIONS).toEqual(BACKUP_BLANK_QUESTIONS); + }); + + /////////////////////////////////// + // renameQuestion + test("Testing the renameQuestion function", () => { + expect( + renameQuestion(ADDITION_QUESTION, "My Addition Question") + ).toEqual({ + id: 1, + name: "My Addition Question", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }); + expect( + renameQuestion(SHAPE_QUESTION, "I COMPLETELY CHANGED THIS NAME") + ).toEqual({ + id: 9, + name: "I COMPLETELY CHANGED THIS NAME", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + }); + }); + + /////////////////////////////////// + // publishQuestion + test("Testing the publishQuestion function", () => { + expect(publishQuestion(ADDITION_QUESTION)).toEqual({ + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: false + }); + expect(publishQuestion(LETTER_QUESTION)).toEqual({ + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: true + }); + expect(publishQuestion(publishQuestion(ADDITION_QUESTION))).toEqual({ + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }); + }); + + /////////////////////////////////// + // duplicateQuestion + test("Testing the duplicateQuestion function", () => { + expect(duplicateQuestion(9, ADDITION_QUESTION)).toEqual({ + id: 9, + name: "Copy of Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: false + }); + expect(duplicateQuestion(55, LETTER_QUESTION)).toEqual({ + id: 55, + name: "Copy of Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }); + }); + + /////////////////////////////////// + // addOption + test("Testing the addOption function", () => { + expect(addOption(SHAPE_QUESTION, "heptagon")).toEqual({ + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle", "heptagon"], + expected: "circle", + points: 2, + published: false + }); + expect(addOption(COLOR_QUESTION, "squiggles")).toEqual({ + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck", "squiggles"], + expected: "red", + points: 1, + published: true + }); + }); + + /////////////////////////////////// + // mergeQuestion + test("Testing the mergeQuestion function", () => { + expect( + mergeQuestion( + 192, + "More Points Addition", + ADDITION_QUESTION, + SHAPE_QUESTION + ) + ).toEqual({ + id: 192, + name: "More Points Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 2, + published: false + }); + + expect( + mergeQuestion( + 99, + "Less Points Shape", + SHAPE_QUESTION, + ADDITION_QUESTION + ) + ).toEqual({ + id: 99, + name: "Less Points Shape", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 1, + published: false + }); + }); +}); diff --git a/src/objects.ts b/src/objects.ts new file mode 100644 index 0000000000..d03dd473e3 --- /dev/null +++ b/src/objects.ts @@ -0,0 +1,141 @@ +/** QuestionType influences how a question is asked and what kinds of answers are possible */ +export type QuestionType = "multiple_choice_question" | "short_answer_question"; + +export interface Question { + /** A unique identifier for the question */ + id: number; + /** The human-friendly title of the question */ + name: string; + /** The instructions and content of the Question */ + body: string; + /** The kind of Question; influences how the user answers and what options are displayed */ + type: QuestionType; + /** The possible answers for a Question (for Multiple Choice questions) */ + options: string[]; + /** The actually correct answer expected */ + expected: string; + /** How many points this question is worth, roughly indicating its importance and difficulty */ + points: number; + /** Whether or not this question is ready to display to students */ + published: boolean; +} + +/** + * Create a new blank question with the given `id`, `name`, and `type. The `body` and + * `expected` should be empty strings, the `options` should be an empty list, the `points` + * should default to 1, and `published` should default to false. + */ +export function makeBlankQuestion( + id: number, + name: string, + type: QuestionType +): Question { + return {}; +} + +/** + * Consumes a question and a potential `answer`, and returns whether or not + * the `answer` is correct. You should check that the `answer` is equal to + * the `expected`, ignoring capitalization and trimming any whitespace. + * + * HINT: Look up the `trim` and `toLowerCase` functions. + */ +export function isCorrect(question: Question, answer: string): boolean { + return false; +} + +/** + * Consumes a question and a potential `answer`, and returns whether or not + * the `answer` is valid (but not necessarily correct). For a `short_answer_question`, + * any answer is valid. But for a `multiple_choice_question`, the `answer` must + * be exactly one of the options. + */ +export function isValid(question: Question, answer: string): boolean { + return false; +} + +/** + * Consumes a question and produces a string representation combining the + * `id` and first 10 characters of the `name`. The two strings should be + * separated by ": ". So for example, the question with id 9 and the + * name "My First Question" would become "9: My First Q". + */ +export function toShortForm(question: Question): string { + return ""; +} + +/** + * Consumes a question and returns a formatted string representation as follows: + * - The first line should be a hash sign, a space, and then the `name` + * - The second line should be the `body` + * - If the question is a `multiple_choice_question`, then the following lines + * need to show each option on its line, preceded by a dash and space. + * + * The example below might help, but don't include the border! + * ----------Example------------- + * |# Name | + * |The body goes here! | + * |- Option 1 | + * |- Option 2 | + * |- Option 3 | + * ------------------------------ + * Check the unit tests for more examples of what this looks like! + */ +export function toMarkdown(question: Question): string { + return ""; +} + +/** + * Return a new version of the given question, except the name should now be + * `newName`. + */ +export function renameQuestion(question: Question, newName: string): Question { + return question; +} + +/** + * Return a new version of the given question, except the `published` field + * should be inverted. If the question was not published, now it should be + * published; if it was published, now it should be not published. + */ +export function publishQuestion(question: Question): Question { + return question; +} + +/** + * Create a new question based on the old question, copying over its `body`, `type`, + * `options`, `expected`, and `points` without changes. The `name` should be copied + * over as "Copy of ORIGINAL NAME" (e.g., so "Question 1" would become "Copy of Question 1"). + * The `published` field should be reset to false. + */ +export function duplicateQuestion(id: number, oldQuestion: Question): Question { + return oldQuestion; +} + +/** + * Return a new version of the given question, with the `newOption` added to + * the list of existing `options`. Remember that the new Question MUST have + * its own separate copy of the `options` list, rather than the same reference + * to the original question's list! + * Check out the subsection about "Nested Fields" for more information. + */ +export function addOption(question: Question, newOption: string): Question { + return question; +} + +/** + * Consumes an id, name, and two questions, and produces a new question. + * The new question will use the `body`, `type`, `options`, and `expected` of the + * `contentQuestion`. The second question will provide the `points`. + * The `published` status should be set to false. + * Notice that the second Question is provided as just an object with a `points` + * field; but the function call would be the same as if it were a `Question` type! + */ +export function mergeQuestion( + id: number, + name: string, + contentQuestion: Question, + { points }: { points: number } +): Question { + return contentQuestion; +} From 406ffb2b572cb14e885af2a2fddc8e9cc42c97dd Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 6 Feb 2022 18:33:46 -0500 Subject: [PATCH 31/81] Move Question interface to separate file --- src/interfaces/question.ts | 21 +++++++++++++++++++++ src/objects.test.ts | 2 +- src/objects.ts | 22 +--------------------- 3 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 src/interfaces/question.ts diff --git a/src/interfaces/question.ts b/src/interfaces/question.ts new file mode 100644 index 0000000000..a39431565e --- /dev/null +++ b/src/interfaces/question.ts @@ -0,0 +1,21 @@ +/** QuestionType influences how a question is asked and what kinds of answers are possible */ +export type QuestionType = "multiple_choice_question" | "short_answer_question"; + +export interface Question { + /** A unique identifier for the question */ + id: number; + /** The human-friendly title of the question */ + name: string; + /** The instructions and content of the Question */ + body: string; + /** The kind of Question; influences how the user answers and what options are displayed */ + type: QuestionType; + /** The possible answers for a Question (for Multiple Choice questions) */ + options: string[]; + /** The actually correct answer expected */ + expected: string; + /** How many points this question is worth, roughly indicating its importance and difficulty */ + points: number; + /** Whether or not this question is ready to display to students */ + published: boolean; +} diff --git a/src/objects.test.ts b/src/objects.test.ts index bcff7ab176..a9c76a334e 100644 --- a/src/objects.test.ts +++ b/src/objects.test.ts @@ -1,7 +1,7 @@ +import { Question } from "./interfaces/question"; import { makeBlankQuestion, isCorrect, - Question, isValid, toShortForm, toMarkdown, diff --git a/src/objects.ts b/src/objects.ts index d03dd473e3..3fd2072e5e 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -1,24 +1,4 @@ -/** QuestionType influences how a question is asked and what kinds of answers are possible */ -export type QuestionType = "multiple_choice_question" | "short_answer_question"; - -export interface Question { - /** A unique identifier for the question */ - id: number; - /** The human-friendly title of the question */ - name: string; - /** The instructions and content of the Question */ - body: string; - /** The kind of Question; influences how the user answers and what options are displayed */ - type: QuestionType; - /** The possible answers for a Question (for Multiple Choice questions) */ - options: string[]; - /** The actually correct answer expected */ - expected: string; - /** How many points this question is worth, roughly indicating its importance and difficulty */ - points: number; - /** Whether or not this question is ready to display to students */ - published: boolean; -} +import { Question, QuestionType } from "./interfaces/question"; /** * Create a new blank question with the given `id`, `name`, and `type. The `body` and From 9b9adb6f2ccbd1113a09cb8e13186d6d4f829928 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:27:44 -0400 Subject: [PATCH 32/81] Fix formatting --- src/objects.test.ts | 70 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/src/objects.test.ts b/src/objects.test.ts index a9c76a334e..4d3117405d 100644 --- a/src/objects.test.ts +++ b/src/objects.test.ts @@ -9,7 +9,7 @@ import { renameQuestion, publishQuestion, addOption, - mergeQuestion + mergeQuestion, } from "./objects"; import testQuestionData from "./data/questions.json"; import backupQuestionData from "./data/questions.json"; @@ -25,7 +25,7 @@ const { BLANK_QUESTIONS, SIMPLE_QUESTIONS }: Record = // We have backup versions of the data to make sure all changes are immutable const { BLANK_QUESTIONS: BACKUP_BLANK_QUESTIONS, - SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS + SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS, }: Record = backupQuestionData as Record< string, Question[] @@ -38,7 +38,7 @@ const [ BACKUP_ADDITION_QUESTION, BACKUP_LETTER_QUESTION, BACKUP_COLOR_QUESTION, - BACKUP_SHAPE_QUESTION + BACKUP_SHAPE_QUESTION, ] = BACKUP_SIMPLE_QUESTIONS; //////////////////////////////////////////// @@ -48,21 +48,25 @@ describe("Testing the object functions", () => { ////////////////////////////////// // makeBlankQuestion - test("Testing the makeBlankQuestion function", () => { + test("(3 pts) Testing the makeBlankQuestion function", () => { expect( - makeBlankQuestion(1, "Question 1", "multiple_choice_question") + makeBlankQuestion(1, "Question 1", "multiple_choice_question"), ).toEqual(BLANK_QUESTIONS[0]); expect( - makeBlankQuestion(47, "My New Question", "multiple_choice_question") + makeBlankQuestion( + 47, + "My New Question", + "multiple_choice_question", + ), ).toEqual(BLANK_QUESTIONS[1]); expect( - makeBlankQuestion(2, "Question 2", "short_answer_question") + makeBlankQuestion(2, "Question 2", "short_answer_question"), ).toEqual(BLANK_QUESTIONS[2]); }); /////////////////////////////////// // isCorrect - test("Testing the isCorrect function", () => { + test("(3 pts) Testing the isCorrect function", () => { expect(isCorrect(ADDITION_QUESTION, "4")).toEqual(true); expect(isCorrect(ADDITION_QUESTION, "2")).toEqual(false); expect(isCorrect(ADDITION_QUESTION, " 4\n")).toEqual(true); @@ -81,7 +85,7 @@ describe("Testing the object functions", () => { /////////////////////////////////// // isValid - test("Testing the isValid function", () => { + test("(3 pts) Testing the isValid function", () => { expect(isValid(ADDITION_QUESTION, "4")).toEqual(true); expect(isValid(ADDITION_QUESTION, "2")).toEqual(true); expect(isValid(ADDITION_QUESTION, " 4\n")).toEqual(true); @@ -104,7 +108,7 @@ describe("Testing the object functions", () => { /////////////////////////////////// // toShortForm - test("Testing the toShortForm function", () => { + test("(3 pts) Testing the toShortForm function", () => { expect(toShortForm(ADDITION_QUESTION)).toEqual("1: Addition"); expect(toShortForm(LETTER_QUESTION)).toEqual("2: Letters"); expect(toShortForm(COLOR_QUESTION)).toEqual("5: Colors"); @@ -114,7 +118,7 @@ describe("Testing the object functions", () => { /////////////////////////////////// // toMarkdown - test("Testing the toMarkdown function", () => { + test("(3 pts) Testing the toMarkdown function", () => { expect(toMarkdown(ADDITION_QUESTION)).toEqual(`# Addition What is 2+2?`); expect(toMarkdown(LETTER_QUESTION)).toEqual(`# Letters @@ -141,9 +145,9 @@ What shape can you make with one line? /////////////////////////////////// // renameQuestion - test("Testing the renameQuestion function", () => { + test("(3 pts) Testing the renameQuestion function", () => { expect( - renameQuestion(ADDITION_QUESTION, "My Addition Question") + renameQuestion(ADDITION_QUESTION, "My Addition Question"), ).toEqual({ id: 1, name: "My Addition Question", @@ -152,10 +156,10 @@ What shape can you make with one line? options: [], expected: "4", points: 1, - published: true + published: true, }); expect( - renameQuestion(SHAPE_QUESTION, "I COMPLETELY CHANGED THIS NAME") + renameQuestion(SHAPE_QUESTION, "I COMPLETELY CHANGED THIS NAME"), ).toEqual({ id: 9, name: "I COMPLETELY CHANGED THIS NAME", @@ -164,13 +168,13 @@ What shape can you make with one line? options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: false + published: false, }); }); /////////////////////////////////// // publishQuestion - test("Testing the publishQuestion function", () => { + test("(3 pts) Testing the publishQuestion function", () => { expect(publishQuestion(ADDITION_QUESTION)).toEqual({ id: 1, name: "Addition", @@ -179,7 +183,7 @@ What shape can you make with one line? options: [], expected: "4", points: 1, - published: false + published: false, }); expect(publishQuestion(LETTER_QUESTION)).toEqual({ id: 2, @@ -189,7 +193,7 @@ What shape can you make with one line? options: [], expected: "Z", points: 1, - published: true + published: true, }); expect(publishQuestion(publishQuestion(ADDITION_QUESTION))).toEqual({ id: 1, @@ -199,13 +203,13 @@ What shape can you make with one line? options: [], expected: "4", points: 1, - published: true + published: true, }); }); /////////////////////////////////// // duplicateQuestion - test("Testing the duplicateQuestion function", () => { + test("(3 pts) Testing the duplicateQuestion function", () => { expect(duplicateQuestion(9, ADDITION_QUESTION)).toEqual({ id: 9, name: "Copy of Addition", @@ -214,7 +218,7 @@ What shape can you make with one line? options: [], expected: "4", points: 1, - published: false + published: false, }); expect(duplicateQuestion(55, LETTER_QUESTION)).toEqual({ id: 55, @@ -224,13 +228,13 @@ What shape can you make with one line? options: [], expected: "Z", points: 1, - published: false + published: false, }); }); /////////////////////////////////// // addOption - test("Testing the addOption function", () => { + test("(3 pts) Testing the addOption function", () => { expect(addOption(SHAPE_QUESTION, "heptagon")).toEqual({ id: 9, name: "Shapes", @@ -239,7 +243,7 @@ What shape can you make with one line? options: ["square", "triangle", "circle", "heptagon"], expected: "circle", points: 2, - published: false + published: false, }); expect(addOption(COLOR_QUESTION, "squiggles")).toEqual({ id: 5, @@ -249,20 +253,20 @@ What shape can you make with one line? options: ["red", "apple", "firetruck", "squiggles"], expected: "red", points: 1, - published: true + published: true, }); }); /////////////////////////////////// // mergeQuestion - test("Testing the mergeQuestion function", () => { + test("(3 pts) Testing the mergeQuestion function", () => { expect( mergeQuestion( 192, "More Points Addition", ADDITION_QUESTION, - SHAPE_QUESTION - ) + SHAPE_QUESTION, + ), ).toEqual({ id: 192, name: "More Points Addition", @@ -271,7 +275,7 @@ What shape can you make with one line? options: [], expected: "4", points: 2, - published: false + published: false, }); expect( @@ -279,8 +283,8 @@ What shape can you make with one line? 99, "Less Points Shape", SHAPE_QUESTION, - ADDITION_QUESTION - ) + ADDITION_QUESTION, + ), ).toEqual({ id: 99, name: "Less Points Shape", @@ -289,7 +293,7 @@ What shape can you make with one line? options: ["square", "triangle", "circle"], expected: "circle", points: 1, - published: false + published: false, }); }); }); From 3660252c2f3f53f262fadb91e8d14d0eeffa6cd2 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 2 Feb 2022 13:12:40 -0500 Subject: [PATCH 33/81] First stab at questions --- public/tasks/task-objects.md | 5 + src/data/questions.json | 79 ++++++++++ src/objects.test.ts | 295 +++++++++++++++++++++++++++++++++++ src/objects.ts | 141 +++++++++++++++++ 4 files changed, 520 insertions(+) create mode 100644 public/tasks/task-objects.md create mode 100644 src/data/questions.json create mode 100644 src/objects.test.ts create mode 100644 src/objects.ts diff --git a/public/tasks/task-objects.md b/public/tasks/task-objects.md new file mode 100644 index 0000000000..480889da0d --- /dev/null +++ b/public/tasks/task-objects.md @@ -0,0 +1,5 @@ +# Task - Objects + +Version: 0.0.1 + +Implement functions that work with objects immutably. diff --git a/src/data/questions.json b/src/data/questions.json new file mode 100644 index 0000000000..3b19537526 --- /dev/null +++ b/src/data/questions.json @@ -0,0 +1,79 @@ +{ + "BLANK_QUESTIONS": [ + { + "id": 1, + "name": "Question 1", + "body": "", + "type": "multiple_choice_question", + "options": [], + "expected": "", + "points": 1, + "published": false + }, + { + "id": 47, + "name": "My New Question", + "body": "", + "type": "multiple_choice_question", + "options": [], + "expected": "", + "points": 1, + "published": false + }, + { + "id": 2, + "name": "Question 2", + "body": "", + "type": "short_answer_question", + "options": [], + "expected": "", + "points": 1, + "published": false + } + ], + "SIMPLE_QUESTIONS": [ + { + "id": 1, + "name": "Addition", + "body": "What is 2+2?", + "type": "short_answer_question", + "options": [], + "expected": "4", + "points": 1, + "published": true + }, + { + "id": 2, + "name": "Letters", + "body": "What is the last letter of the English alphabet?", + "type": "short_answer_question", + "options": [], + "expected": "Z", + "points": 1, + "published": false + }, + { + "id": 5, + "name": "Colors", + "body": "Which of these is a color?", + "type": "multiple_choice_question", + "options": ["red", "apple", "firetruck"], + "expected": "red", + "points": 1, + "published": true + }, + { + "id": 9, + "name": "Shapes", + "body": "What shape can you make with one line?", + "type": "multiple_choice_question", + "options": ["square", "triangle", "circle"], + "expected": "circle", + "points": 2, + "published": false + } + ], + "SIMPLE_QUESTIONS_2": [], + "EMPTY_QUESTIONS": [], + "TRIVIA_QUESTIONS": [] +} diff --git a/src/objects.test.ts b/src/objects.test.ts new file mode 100644 index 0000000000..bcff7ab176 --- /dev/null +++ b/src/objects.test.ts @@ -0,0 +1,295 @@ +import { + makeBlankQuestion, + isCorrect, + Question, + isValid, + toShortForm, + toMarkdown, + duplicateQuestion, + renameQuestion, + publishQuestion, + addOption, + mergeQuestion +} from "./objects"; +import testQuestionData from "./data/questions.json"; +import backupQuestionData from "./data/questions.json"; + +//////////////////////////////////////////// +// Setting up the test data + +const { BLANK_QUESTIONS, SIMPLE_QUESTIONS }: Record = + // Typecast the test data that we imported to be a record matching + // strings to the question list + testQuestionData as Record; + +// We have backup versions of the data to make sure all changes are immutable +const { + BLANK_QUESTIONS: BACKUP_BLANK_QUESTIONS, + SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS +}: Record = backupQuestionData as Record< + string, + Question[] +>; + +// Unpack the list of simple questions into convenient constants +const [ADDITION_QUESTION, LETTER_QUESTION, COLOR_QUESTION, SHAPE_QUESTION] = + SIMPLE_QUESTIONS; +const [ + BACKUP_ADDITION_QUESTION, + BACKUP_LETTER_QUESTION, + BACKUP_COLOR_QUESTION, + BACKUP_SHAPE_QUESTION +] = BACKUP_SIMPLE_QUESTIONS; + +//////////////////////////////////////////// +// Actual tests + +describe("Testing the object functions", () => { + ////////////////////////////////// + // makeBlankQuestion + + test("Testing the makeBlankQuestion function", () => { + expect( + makeBlankQuestion(1, "Question 1", "multiple_choice_question") + ).toEqual(BLANK_QUESTIONS[0]); + expect( + makeBlankQuestion(47, "My New Question", "multiple_choice_question") + ).toEqual(BLANK_QUESTIONS[1]); + expect( + makeBlankQuestion(2, "Question 2", "short_answer_question") + ).toEqual(BLANK_QUESTIONS[2]); + }); + + /////////////////////////////////// + // isCorrect + test("Testing the isCorrect function", () => { + expect(isCorrect(ADDITION_QUESTION, "4")).toEqual(true); + expect(isCorrect(ADDITION_QUESTION, "2")).toEqual(false); + expect(isCorrect(ADDITION_QUESTION, " 4\n")).toEqual(true); + expect(isCorrect(LETTER_QUESTION, "Z")).toEqual(true); + expect(isCorrect(LETTER_QUESTION, "z")).toEqual(true); + expect(isCorrect(LETTER_QUESTION, "4")).toEqual(false); + expect(isCorrect(LETTER_QUESTION, "0")).toEqual(false); + expect(isCorrect(LETTER_QUESTION, "zed")).toEqual(false); + expect(isCorrect(COLOR_QUESTION, "red")).toEqual(true); + expect(isCorrect(COLOR_QUESTION, "apple")).toEqual(false); + expect(isCorrect(COLOR_QUESTION, "firetruck")).toEqual(false); + expect(isCorrect(SHAPE_QUESTION, "square")).toEqual(false); + expect(isCorrect(SHAPE_QUESTION, "triangle")).toEqual(false); + expect(isCorrect(SHAPE_QUESTION, "circle")).toEqual(true); + }); + + /////////////////////////////////// + // isValid + test("Testing the isValid function", () => { + expect(isValid(ADDITION_QUESTION, "4")).toEqual(true); + expect(isValid(ADDITION_QUESTION, "2")).toEqual(true); + expect(isValid(ADDITION_QUESTION, " 4\n")).toEqual(true); + expect(isValid(LETTER_QUESTION, "Z")).toEqual(true); + expect(isValid(LETTER_QUESTION, "z")).toEqual(true); + expect(isValid(LETTER_QUESTION, "4")).toEqual(true); + expect(isValid(LETTER_QUESTION, "0")).toEqual(true); + expect(isValid(LETTER_QUESTION, "zed")).toEqual(true); + expect(isValid(COLOR_QUESTION, "red")).toEqual(true); + expect(isValid(COLOR_QUESTION, "apple")).toEqual(true); + expect(isValid(COLOR_QUESTION, "firetruck")).toEqual(true); + expect(isValid(COLOR_QUESTION, "RED")).toEqual(false); + expect(isValid(COLOR_QUESTION, "orange")).toEqual(false); + expect(isValid(SHAPE_QUESTION, "square")).toEqual(true); + expect(isValid(SHAPE_QUESTION, "triangle")).toEqual(true); + expect(isValid(SHAPE_QUESTION, "circle")).toEqual(true); + expect(isValid(SHAPE_QUESTION, "circle ")).toEqual(false); + expect(isValid(SHAPE_QUESTION, "rhombus")).toEqual(false); + }); + + /////////////////////////////////// + // toShortForm + test("Testing the toShortForm function", () => { + expect(toShortForm(ADDITION_QUESTION)).toEqual("1: Addition"); + expect(toShortForm(LETTER_QUESTION)).toEqual("2: Letters"); + expect(toShortForm(COLOR_QUESTION)).toEqual("5: Colors"); + expect(toShortForm(SHAPE_QUESTION)).toEqual("9: Shapes"); + expect(toShortForm(BLANK_QUESTIONS[1])).toEqual("47: My New Que"); + }); + + /////////////////////////////////// + // toMarkdown + test("Testing the toMarkdown function", () => { + expect(toMarkdown(ADDITION_QUESTION)).toEqual(`# Addition +What is 2+2?`); + expect(toMarkdown(LETTER_QUESTION)).toEqual(`# Letters +What is the last letter of the English alphabet?`); + expect(toMarkdown(COLOR_QUESTION)).toEqual(`# Colors +Which of these is a color? +- red +- apple +- firetruck`); + expect(toMarkdown(SHAPE_QUESTION)).toEqual(`# Shapes +What shape can you make with one line? +- square +- triangle +- circle`); + }); + + afterEach(() => { + expect(ADDITION_QUESTION).toEqual(BACKUP_ADDITION_QUESTION); + expect(LETTER_QUESTION).toEqual(BACKUP_LETTER_QUESTION); + expect(SHAPE_QUESTION).toEqual(BACKUP_SHAPE_QUESTION); + expect(COLOR_QUESTION).toEqual(BACKUP_COLOR_QUESTION); + expect(BLANK_QUESTIONS).toEqual(BACKUP_BLANK_QUESTIONS); + }); + + /////////////////////////////////// + // renameQuestion + test("Testing the renameQuestion function", () => { + expect( + renameQuestion(ADDITION_QUESTION, "My Addition Question") + ).toEqual({ + id: 1, + name: "My Addition Question", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }); + expect( + renameQuestion(SHAPE_QUESTION, "I COMPLETELY CHANGED THIS NAME") + ).toEqual({ + id: 9, + name: "I COMPLETELY CHANGED THIS NAME", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + }); + }); + + /////////////////////////////////// + // publishQuestion + test("Testing the publishQuestion function", () => { + expect(publishQuestion(ADDITION_QUESTION)).toEqual({ + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: false + }); + expect(publishQuestion(LETTER_QUESTION)).toEqual({ + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: true + }); + expect(publishQuestion(publishQuestion(ADDITION_QUESTION))).toEqual({ + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }); + }); + + /////////////////////////////////// + // duplicateQuestion + test("Testing the duplicateQuestion function", () => { + expect(duplicateQuestion(9, ADDITION_QUESTION)).toEqual({ + id: 9, + name: "Copy of Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: false + }); + expect(duplicateQuestion(55, LETTER_QUESTION)).toEqual({ + id: 55, + name: "Copy of Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }); + }); + + /////////////////////////////////// + // addOption + test("Testing the addOption function", () => { + expect(addOption(SHAPE_QUESTION, "heptagon")).toEqual({ + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle", "heptagon"], + expected: "circle", + points: 2, + published: false + }); + expect(addOption(COLOR_QUESTION, "squiggles")).toEqual({ + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck", "squiggles"], + expected: "red", + points: 1, + published: true + }); + }); + + /////////////////////////////////// + // mergeQuestion + test("Testing the mergeQuestion function", () => { + expect( + mergeQuestion( + 192, + "More Points Addition", + ADDITION_QUESTION, + SHAPE_QUESTION + ) + ).toEqual({ + id: 192, + name: "More Points Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 2, + published: false + }); + + expect( + mergeQuestion( + 99, + "Less Points Shape", + SHAPE_QUESTION, + ADDITION_QUESTION + ) + ).toEqual({ + id: 99, + name: "Less Points Shape", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 1, + published: false + }); + }); +}); diff --git a/src/objects.ts b/src/objects.ts new file mode 100644 index 0000000000..d03dd473e3 --- /dev/null +++ b/src/objects.ts @@ -0,0 +1,141 @@ +/** QuestionType influences how a question is asked and what kinds of answers are possible */ +export type QuestionType = "multiple_choice_question" | "short_answer_question"; + +export interface Question { + /** A unique identifier for the question */ + id: number; + /** The human-friendly title of the question */ + name: string; + /** The instructions and content of the Question */ + body: string; + /** The kind of Question; influences how the user answers and what options are displayed */ + type: QuestionType; + /** The possible answers for a Question (for Multiple Choice questions) */ + options: string[]; + /** The actually correct answer expected */ + expected: string; + /** How many points this question is worth, roughly indicating its importance and difficulty */ + points: number; + /** Whether or not this question is ready to display to students */ + published: boolean; +} + +/** + * Create a new blank question with the given `id`, `name`, and `type. The `body` and + * `expected` should be empty strings, the `options` should be an empty list, the `points` + * should default to 1, and `published` should default to false. + */ +export function makeBlankQuestion( + id: number, + name: string, + type: QuestionType +): Question { + return {}; +} + +/** + * Consumes a question and a potential `answer`, and returns whether or not + * the `answer` is correct. You should check that the `answer` is equal to + * the `expected`, ignoring capitalization and trimming any whitespace. + * + * HINT: Look up the `trim` and `toLowerCase` functions. + */ +export function isCorrect(question: Question, answer: string): boolean { + return false; +} + +/** + * Consumes a question and a potential `answer`, and returns whether or not + * the `answer` is valid (but not necessarily correct). For a `short_answer_question`, + * any answer is valid. But for a `multiple_choice_question`, the `answer` must + * be exactly one of the options. + */ +export function isValid(question: Question, answer: string): boolean { + return false; +} + +/** + * Consumes a question and produces a string representation combining the + * `id` and first 10 characters of the `name`. The two strings should be + * separated by ": ". So for example, the question with id 9 and the + * name "My First Question" would become "9: My First Q". + */ +export function toShortForm(question: Question): string { + return ""; +} + +/** + * Consumes a question and returns a formatted string representation as follows: + * - The first line should be a hash sign, a space, and then the `name` + * - The second line should be the `body` + * - If the question is a `multiple_choice_question`, then the following lines + * need to show each option on its line, preceded by a dash and space. + * + * The example below might help, but don't include the border! + * ----------Example------------- + * |# Name | + * |The body goes here! | + * |- Option 1 | + * |- Option 2 | + * |- Option 3 | + * ------------------------------ + * Check the unit tests for more examples of what this looks like! + */ +export function toMarkdown(question: Question): string { + return ""; +} + +/** + * Return a new version of the given question, except the name should now be + * `newName`. + */ +export function renameQuestion(question: Question, newName: string): Question { + return question; +} + +/** + * Return a new version of the given question, except the `published` field + * should be inverted. If the question was not published, now it should be + * published; if it was published, now it should be not published. + */ +export function publishQuestion(question: Question): Question { + return question; +} + +/** + * Create a new question based on the old question, copying over its `body`, `type`, + * `options`, `expected`, and `points` without changes. The `name` should be copied + * over as "Copy of ORIGINAL NAME" (e.g., so "Question 1" would become "Copy of Question 1"). + * The `published` field should be reset to false. + */ +export function duplicateQuestion(id: number, oldQuestion: Question): Question { + return oldQuestion; +} + +/** + * Return a new version of the given question, with the `newOption` added to + * the list of existing `options`. Remember that the new Question MUST have + * its own separate copy of the `options` list, rather than the same reference + * to the original question's list! + * Check out the subsection about "Nested Fields" for more information. + */ +export function addOption(question: Question, newOption: string): Question { + return question; +} + +/** + * Consumes an id, name, and two questions, and produces a new question. + * The new question will use the `body`, `type`, `options`, and `expected` of the + * `contentQuestion`. The second question will provide the `points`. + * The `published` status should be set to false. + * Notice that the second Question is provided as just an object with a `points` + * field; but the function call would be the same as if it were a `Question` type! + */ +export function mergeQuestion( + id: number, + name: string, + contentQuestion: Question, + { points }: { points: number } +): Question { + return contentQuestion; +} From 09d3d4f104a2cacab2641271c5c6cab55424efd1 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 6 Feb 2022 18:33:46 -0500 Subject: [PATCH 34/81] Move Question interface to separate file --- src/interfaces/question.ts | 21 +++++++++++++++++++++ src/objects.test.ts | 2 +- src/objects.ts | 22 +--------------------- 3 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 src/interfaces/question.ts diff --git a/src/interfaces/question.ts b/src/interfaces/question.ts new file mode 100644 index 0000000000..a39431565e --- /dev/null +++ b/src/interfaces/question.ts @@ -0,0 +1,21 @@ +/** QuestionType influences how a question is asked and what kinds of answers are possible */ +export type QuestionType = "multiple_choice_question" | "short_answer_question"; + +export interface Question { + /** A unique identifier for the question */ + id: number; + /** The human-friendly title of the question */ + name: string; + /** The instructions and content of the Question */ + body: string; + /** The kind of Question; influences how the user answers and what options are displayed */ + type: QuestionType; + /** The possible answers for a Question (for Multiple Choice questions) */ + options: string[]; + /** The actually correct answer expected */ + expected: string; + /** How many points this question is worth, roughly indicating its importance and difficulty */ + points: number; + /** Whether or not this question is ready to display to students */ + published: boolean; +} diff --git a/src/objects.test.ts b/src/objects.test.ts index bcff7ab176..a9c76a334e 100644 --- a/src/objects.test.ts +++ b/src/objects.test.ts @@ -1,7 +1,7 @@ +import { Question } from "./interfaces/question"; import { makeBlankQuestion, isCorrect, - Question, isValid, toShortForm, toMarkdown, diff --git a/src/objects.ts b/src/objects.ts index d03dd473e3..3fd2072e5e 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -1,24 +1,4 @@ -/** QuestionType influences how a question is asked and what kinds of answers are possible */ -export type QuestionType = "multiple_choice_question" | "short_answer_question"; - -export interface Question { - /** A unique identifier for the question */ - id: number; - /** The human-friendly title of the question */ - name: string; - /** The instructions and content of the Question */ - body: string; - /** The kind of Question; influences how the user answers and what options are displayed */ - type: QuestionType; - /** The possible answers for a Question (for Multiple Choice questions) */ - options: string[]; - /** The actually correct answer expected */ - expected: string; - /** How many points this question is worth, roughly indicating its importance and difficulty */ - points: number; - /** Whether or not this question is ready to display to students */ - published: boolean; -} +import { Question, QuestionType } from "./interfaces/question"; /** * Create a new blank question with the given `id`, `name`, and `type. The `body` and From 9a2402444e847b2c05ce0c9a6887534a249d7c46 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 8 Feb 2022 00:36:21 -0500 Subject: [PATCH 35/81] Create answer interface --- src/interfaces/answer.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/interfaces/answer.ts diff --git a/src/interfaces/answer.ts b/src/interfaces/answer.ts new file mode 100644 index 0000000000..743ee8dff9 --- /dev/null +++ b/src/interfaces/answer.ts @@ -0,0 +1,13 @@ +/*** + * A representation of a students' answer in a quizzing game + */ +export interface Answer { + /** The ID of the question being answered. */ + questionId: number; + /** The text that the student entered for their answer. */ + text: string; + /** Whether or not the student has submitted this answer. */ + submitted: boolean; + /** Whether or not the students' answer matched the expected. */ + correct: boolean; +} From 879fe177e356794eedf9f893fe0e865e49f36eb7 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 8 Feb 2022 00:36:37 -0500 Subject: [PATCH 36/81] First stab at nested tasks --- src/nested.test.ts | 57 +++++++++++++++ src/nested.ts | 178 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 src/nested.test.ts create mode 100644 src/nested.ts diff --git a/src/nested.test.ts b/src/nested.test.ts new file mode 100644 index 0000000000..1e3ff24b5c --- /dev/null +++ b/src/nested.test.ts @@ -0,0 +1,57 @@ +import { Question } from "./interfaces/question"; +import { getPublishedQuestions } from "./nested"; +import testQuestionData from "./data/questions.json"; +import backupQuestionData from "./data/questions.json"; + +const { BLANK_QUESTIONS, SIMPLE_QUESTIONS }: Record = + // Typecast the test data that we imported to be a record matching + // strings to the question list + testQuestionData as Record; + +// We have backup versions of the data to make sure all changes are immutable +const { + BLANK_QUESTIONS: BACKUP_BLANK_QUESTIONS, + SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS +}: Record = backupQuestionData as Record< + string, + Question[] +>; + +//////////////////////////////////////////// +// Actual tests + +describe("Testing the Question[] functions", () => { + ////////////////////////////////// + // getPublishedQuestions + + test("Testing the getPublishedQuestions function", () => { + expect(getPublishedQuestions(BLANK_QUESTIONS)).toEqual([]); + expect(getPublishedQuestions(SIMPLE_QUESTIONS)).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck"], + expected: "red", + points: 1, + published: true + } + ]); + }); + + afterEach(() => { + expect(BLANK_QUESTIONS).toEqual(BACKUP_BLANK_QUESTIONS); + expect(SIMPLE_QUESTIONS).toEqual(BACKUP_SIMPLE_QUESTIONS); + }); +}); diff --git a/src/nested.ts b/src/nested.ts new file mode 100644 index 0000000000..b9fb13f3cf --- /dev/null +++ b/src/nested.ts @@ -0,0 +1,178 @@ +import { Answer } from "./interfaces/answer"; +import { Question, QuestionType } from "./interfaces/question"; + +/** + * Consumes an array of questions and returns a new array with only the questions + * that are `published`. + */ +export function getPublishedQuestions(questions: Question[]): Question[] { + return []; +} + +/** + * Consumes an array of questions and returns a new array of only the questions that are + * considered "non-empty". An empty question has an empty string for its `body` and + * `expected`, and an empty array for its `options`. + */ +export function getNonEmptyQuestions(questions: Question[]): Question[] { + return []; +} + +/*** + * Consumes an array of questions and returns the question with the given `id`. If the + * question is not found, return `null` instead. + */ +export function findQuestion( + questions: Question[], + id: number +): Question | null { + return null; +} + +/** + * Consumes an array of questions and returns a new array that does not contain the question + * with the given `id`. + */ +export function removeQuestion(questions: Question[], id: number): Question[] { + return []; +} + +/*** + * Consumes an array of questions and returns a new array containing just the names of the + * questions, as an array. + */ +export function getNames(questions: Question[]): string[] { + return []; +} + +/*** + * Consumes an array of questions and returns the sum total of all their points added together. + */ +export function sumPoints(questions: Question[]): number { + return 0; +} + +/*** + * Consumes an array of questions and returns the sum total of the PUBLISHED questions. + */ +export function sumPublishedPoints(questions: Question[]): number { + return 0; +} + +/*** + * Consumes an array of questions, and produces a Comma-Separated Value (CSV) string representation. + * A CSV is a type of file frequently used to share tabular data; we will use a single string + * to represent the entire file. The first line of the file is the headers "id", "name", "options", + * "points", and "published". The following line contains the value for each question, separated by + * commas. For the `options` field, use the NUMBER of options. + * + * Here is an example of what this will look like (do not include the border). + *` +id,name,options,points,published +1,Addition,0,1,true +2,Letters,0,1,false +5,Colors,3,1,true +9,Shapes,3,2,false +` * + * Check the unit tests for more examples! + */ +export function toCSV(questions: Question[]): string { + return ""; +} + +/** + * Consumes an array of Questions and produces a corresponding array of + * Answers. Each Question gets its own Answer, copying over the `id` as the `questionId`, + * making the `text` an empty string, and using false for both `submitted` and `correct`. + */ +export function makeAnswers(questions: Question[]): Answer[] { + return []; +} + +/*** + * Consumes an array of Questions and produces a new array of questions, where + * each question is now published, regardless of its previous published status. + */ +export function publishAll(questions: Question[]): Question[] { + return []; +} + +/*** + * Consumes an array of Questions and produces whether or not all the questions + * are the same type. They can be any type, as long as they are all the SAME type. + */ +export function sameType(questions: Question[]): boolean { + return false; +} + +/*** + * Consumes an array of Questions and produces a new array of the same Questions, + * except that a blank question has been added onto the end. Reuse the `makeBlankQuestion` + * you defined in the `objects.ts` file. + */ +export function addNewQuestion( + questions: Question[], + id: number, + name: string, + type: QuestionType +): Question[] { + return []; +} + +/*** + * Consumes an array of Questions and produces a new array of Questions, where all + * the Questions are the same EXCEPT for the one with the given `targetId`. That + * Question should be the same EXCEPT that its name should now be `newName`. + */ +export function renameQuestionById( + questions: Question[], + targetId: number, + newName: string +): Question[] { + return []; +} + +/*** + * Consumes an array of Questions and produces a new array of Questions, where all + * the Questions are the same EXCEPT for the one with the given `targetId`. That + * Question should be the same EXCEPT that its `type` should now be the `newQuestionType` + * AND if the `newQuestionType` is no longer "multiple_choice_question" than the `options` + * must be set to an empty list. + */ +export function changeQuestionTypeById( + questions: Question[], + targetId: number, + newQuestionType: QuestionType +): Question[] { + return []; +} + +/** + * Consumes an array of Questions and produces a new array of Questions, where all + * the Questions are the same EXCEPT for the one with the given `targetId`. That + * Question should be the same EXCEPT that its `option` array should have a new element. + * If the `targetOptionIndex` is -1, the `newOption` should be added to the end of the list. + * Otherwise, it should *replace* the existing element at the `targetOptionIndex`. + */ +export function editOption( + questions: Question[], + targetId: number, + targetOptionIndex: number, + newOption: string +) { + return []; +} + +/*** + * Consumes an array of questions, and produces a new array based on the original array. + * The only difference is that the question with id `targetId` should now be duplicated, with + * the duplicate inserted directly after the original question. Use the `duplicateQuestion` + * function you defined previously; the `newId` is the parameter to use for the duplicate's ID. + */ +export function duplicateQuestionInArray( + questions: Question[], + targetId: number, + newId: number +): Question[] { + return []; +} From 4d29d2132a060f7f91420d71eea4e80ab72e7727 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:20:35 -0500 Subject: [PATCH 37/81] Document Question interface --- src/interfaces/question.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interfaces/question.ts b/src/interfaces/question.ts index a39431565e..5def48f2f7 100644 --- a/src/interfaces/question.ts +++ b/src/interfaces/question.ts @@ -1,6 +1,7 @@ /** QuestionType influences how a question is asked and what kinds of answers are possible */ export type QuestionType = "multiple_choice_question" | "short_answer_question"; +/** A representation of a Question in a quizzing application */ export interface Question { /** A unique identifier for the question */ id: number; From d71d9fcc94831dc1aea8d2aa847feeadeed6b9c4 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:20:46 -0500 Subject: [PATCH 38/81] Expand questions test data --- src/data/questions.json | 147 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) diff --git a/src/data/questions.json b/src/data/questions.json index 3b19537526..0411f30afe 100644 --- a/src/data/questions.json +++ b/src/data/questions.json @@ -73,7 +73,148 @@ "published": false } ], - "SIMPLE_QUESTIONS_2": [], - "EMPTY_QUESTIONS": [], - "TRIVIA_QUESTIONS": [] + "TRIVIA_QUESTIONS": [ + { + "id": 1, + "name": "Mascot", + "body": "What is the name of the UD Mascot?", + "type": "multiple_choice_question", + "options": ["Bluey", "YoUDee", "Charles the Wonder Dog"], + "expected": "YoUDee", + "points": 7, + "published": false + }, + { + "id": 2, + "name": "Motto", + "body": "What is the University of Delaware's motto?", + "type": "multiple_choice_question", + "options": [ + "Knowledge is the light of the mind", + "Just U Do it", + "Nothing, what's the motto with you?" + ], + "expected": "Knowledge is the light of the mind", + "points": 3, + "published": false + }, + { + "id": 3, + "name": "Goats", + "body": "How many goats are there usually on the Green?", + "type": "multiple_choice_question", + "options": [ + "Zero, why would there be goats on the green?", + "18420", + "Two" + ], + "expected": "Two", + "points": 10, + "published": false + } + ], + "EMPTY_QUESTIONS": [ + { + "id": 1, + "name": "Empty 1", + "body": "This question is not empty, right?", + "type": "multiple_choice_question", + "options": ["correct", "it is", "not"], + "expected": "correct", + "points": 5, + "published": true + }, + { + "id": 2, + "name": "Empty 2", + "body": "", + "type": "multiple_choice_question", + "options": ["this", "one", "is", "not", "empty", "either"], + "expected": "one", + "points": 5, + "published": true + }, + { + "id": 3, + "name": "Empty 3", + "body": "This questions is not empty either!", + "type": "short_answer_question", + "options": [], + "expected": "", + "points": 5, + "published": true + }, + { + "id": 4, + "name": "Empty 4", + "body": "", + "type": "short_answer_question", + "options": [], + "expected": "Even this one is not empty", + "points": 5, + "published": true + }, + { + "id": 5, + "name": "Empty 5 (Actual)", + "body": "", + "type": "short_answer_question", + "options": [], + "expected": "", + "points": 5, + "published": false + } + ], + "SIMPLE_QUESTIONS_2": [ + { + "id": 478, + "name": "Students", + "body": "How many students are taking CISC275 this semester?", + "type": "short_answer_question", + "options": [], + "expected": "90", + "points": 53, + "published": true + }, + { + "id": 1937, + "name": "Importance", + "body": "On a scale of 1 to 10, how important is this quiz for them?", + "type": "short_answer_question", + "options": [], + "expected": "10", + "points": 47, + "published": true + }, + { + "id": 479, + "name": "Sentience", + "body": "Is it technically possible for this quiz to become sentient?", + "type": "short_answer_question", + "options": [], + "expected": "Yes", + "points": 40, + "published": true + }, + { + "id": 777, + "name": "Danger", + "body": "If this quiz became sentient, would it pose a danger to others?", + "type": "short_answer_question", + "options": [], + "expected": "Yes", + "points": 60, + "published": true + }, + { + "id": 1937, + "name": "Listening", + "body": "Is this quiz listening to us right now?", + "type": "short_answer_question", + "options": [], + "expected": "Yes", + "points": 100, + "published": true + } + ] } From c955718b2a52fe88f0f3b27b00b8fcb74e8be0ca Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:21:43 -0500 Subject: [PATCH 39/81] Add a little hint for a tough one --- src/nested.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nested.ts b/src/nested.ts index b9fb13f3cf..7934ec1741 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -153,6 +153,9 @@ export function changeQuestionTypeById( * Question should be the same EXCEPT that its `option` array should have a new element. * If the `targetOptionIndex` is -1, the `newOption` should be added to the end of the list. * Otherwise, it should *replace* the existing element at the `targetOptionIndex`. + * + * Remember, if a function starts getting too complicated, think about how a helper function + * can make it simpler! Break down complicated tasks into little pieces. */ export function editOption( questions: Question[], From c574699cc746d22d95223bfc85d2e0cb8d5843e8 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:22:01 -0500 Subject: [PATCH 40/81] Nested tests (phew) --- src/nested.test.ts | 1187 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1184 insertions(+), 3 deletions(-) diff --git a/src/nested.test.ts b/src/nested.test.ts index 1e3ff24b5c..3d2b75406d 100644 --- a/src/nested.test.ts +++ b/src/nested.test.ts @@ -1,9 +1,32 @@ import { Question } from "./interfaces/question"; -import { getPublishedQuestions } from "./nested"; +import { + getPublishedQuestions, + getNonEmptyQuestions, + findQuestion, + removeQuestion, + getNames, + sumPoints, + sumPublishedPoints, + toCSV, + makeAnswers, + publishAll, + sameType, + addNewQuestion, + renameQuestionById, + changeQuestionTypeById, + editOption, + duplicateQuestionInArray +} from "./nested"; import testQuestionData from "./data/questions.json"; import backupQuestionData from "./data/questions.json"; -const { BLANK_QUESTIONS, SIMPLE_QUESTIONS }: Record = +const { + BLANK_QUESTIONS, + SIMPLE_QUESTIONS, + TRIVIA_QUESTIONS, + EMPTY_QUESTIONS, + SIMPLE_QUESTIONS_2 +}: Record = // Typecast the test data that we imported to be a record matching // strings to the question list testQuestionData as Record; @@ -11,12 +34,41 @@ const { BLANK_QUESTIONS, SIMPLE_QUESTIONS }: Record = // We have backup versions of the data to make sure all changes are immutable const { BLANK_QUESTIONS: BACKUP_BLANK_QUESTIONS, - SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS + SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS, + TRIVIA_QUESTIONS: BACKUP_TRIVIA_QUESTIONS, + EMPTY_QUESTIONS: BACKUP_EMPTY_QUESTIONS, + SIMPLE_QUESTIONS_2: BACKUP_SIMPLE_QUESTIONS_2 }: Record = backupQuestionData as Record< string, Question[] >; +const NEW_BLANK_QUESTION = { + id: 142, + name: "A new question", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false +}; + +const NEW_TRIVIA_QUESTION = { + id: 449, + name: "Colors", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + /*body: "The official colors of UD are Blue and ...?", + type: "multiple_choice_question", + options: ["Black, like my soul", "Blue again, we're tricky.", "#FFD200"], + expected: "#FFD200",*/ + points: 1, + published: false +}; + //////////////////////////////////////////// // Actual tests @@ -48,10 +100,1139 @@ describe("Testing the Question[] functions", () => { published: true } ]); + expect(getPublishedQuestions(TRIVIA_QUESTIONS)).toEqual([]); + expect(getPublishedQuestions(SIMPLE_QUESTIONS_2)).toEqual( + BACKUP_SIMPLE_QUESTIONS_2 + ); + expect(getPublishedQuestions(EMPTY_QUESTIONS)).toEqual([ + { + id: 1, + name: "Empty 1", + body: "This question is not empty, right?", + type: "multiple_choice_question", + options: ["correct", "it is", "not"], + expected: "correct", + points: 5, + published: true + }, + { + id: 2, + name: "Empty 2", + body: "", + type: "multiple_choice_question", + options: ["this", "one", "is", "not", "empty", "either"], + expected: "one", + points: 5, + published: true + }, + { + id: 3, + name: "Empty 3", + body: "This questions is not empty either!", + type: "short_answer_question", + options: [], + expected: "", + points: 5, + published: true + }, + { + id: 4, + name: "Empty 4", + body: "", + type: "short_answer_question", + options: [], + expected: "Even this one is not empty", + points: 5, + published: true + } + ]); + }); + + test("Testing the getNonEmptyQuestions functions", () => { + expect(getNonEmptyQuestions(BLANK_QUESTIONS)).toEqual([]); + expect(getNonEmptyQuestions(SIMPLE_QUESTIONS)).toEqual( + BACKUP_SIMPLE_QUESTIONS + ); + expect(getNonEmptyQuestions(TRIVIA_QUESTIONS)).toEqual( + BACKUP_TRIVIA_QUESTIONS + ); + expect(getNonEmptyQuestions(SIMPLE_QUESTIONS_2)).toEqual( + BACKUP_SIMPLE_QUESTIONS_2 + ); + expect(getNonEmptyQuestions(EMPTY_QUESTIONS)).toEqual([ + { + id: 1, + name: "Empty 1", + body: "This question is not empty, right?", + type: "multiple_choice_question", + options: ["correct", "it is", "not"], + expected: "correct", + points: 5, + published: true + }, + { + id: 2, + name: "Empty 2", + body: "", + type: "multiple_choice_question", + options: ["this", "one", "is", "not", "empty", "either"], + expected: "one", + points: 5, + published: true + }, + { + id: 3, + name: "Empty 3", + body: "This questions is not empty either!", + type: "short_answer_question", + options: [], + expected: "", + points: 5, + published: true + }, + { + id: 4, + name: "Empty 4", + body: "", + type: "short_answer_question", + options: [], + expected: "Even this one is not empty", + points: 5, + published: true + } + ]); + }); + + test("Testing the findQuestion function", () => { + expect(findQuestion(BLANK_QUESTIONS, 1)).toEqual(BLANK_QUESTIONS[0]); + expect(findQuestion(BLANK_QUESTIONS, 47)).toEqual(BLANK_QUESTIONS[1]); + expect(findQuestion(BLANK_QUESTIONS, 2)).toEqual(BLANK_QUESTIONS[2]); + expect(findQuestion(BLANK_QUESTIONS, 3)).toEqual(null); + expect(findQuestion(SIMPLE_QUESTIONS, 1)).toEqual(SIMPLE_QUESTIONS[0]); + expect(findQuestion(SIMPLE_QUESTIONS, 2)).toEqual(SIMPLE_QUESTIONS[1]); + expect(findQuestion(SIMPLE_QUESTIONS, 5)).toEqual(SIMPLE_QUESTIONS[2]); + expect(findQuestion(SIMPLE_QUESTIONS, 9)).toEqual(SIMPLE_QUESTIONS[3]); + expect(findQuestion(SIMPLE_QUESTIONS, 6)).toEqual(null); + expect(findQuestion(SIMPLE_QUESTIONS_2, 478)).toEqual( + SIMPLE_QUESTIONS_2[0] + ); + expect(findQuestion([], 0)).toEqual(null); + }); + + test("Testing the removeQuestion", () => { + expect(removeQuestion(BLANK_QUESTIONS, 1)).toEqual([ + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(removeQuestion(BLANK_QUESTIONS, 47)).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(removeQuestion(BLANK_QUESTIONS, 2)).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(removeQuestion(SIMPLE_QUESTIONS, 9)).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }, + { + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck"], + expected: "red", + points: 1, + published: true + } + ]); + expect(removeQuestion(SIMPLE_QUESTIONS, 5)).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }, + { + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + } + ]); + }); + + test("Testing the getNames function", () => { + expect(getNames(BLANK_QUESTIONS)).toEqual([ + "Question 1", + "My New Question", + "Question 2" + ]); + expect(getNames(SIMPLE_QUESTIONS)).toEqual([ + "Addition", + "Letters", + "Colors", + "Shapes" + ]); + expect(getNames(TRIVIA_QUESTIONS)).toEqual([ + "Mascot", + "Motto", + "Goats" + ]); + expect(getNames(SIMPLE_QUESTIONS_2)).toEqual([ + "Students", + "Importance", + "Sentience", + "Danger", + "Listening" + ]); + expect(getNames(EMPTY_QUESTIONS)).toEqual([ + "Empty 1", + "Empty 2", + "Empty 3", + "Empty 4", + "Empty 5 (Actual)" + ]); + }); + + test("Testing the sumPoints function", () => { + expect(sumPoints(BLANK_QUESTIONS)).toEqual(3); + expect(sumPoints(SIMPLE_QUESTIONS)).toEqual(5); + expect(sumPoints(TRIVIA_QUESTIONS)).toEqual(20); + expect(sumPoints(EMPTY_QUESTIONS)).toEqual(25); + expect(sumPoints(SIMPLE_QUESTIONS_2)).toEqual(300); + }); + + test("Testing the sumPublishedPoints function", () => { + expect(sumPublishedPoints(BLANK_QUESTIONS)).toEqual(0); + expect(sumPublishedPoints(SIMPLE_QUESTIONS)).toEqual(2); + expect(sumPublishedPoints(TRIVIA_QUESTIONS)).toEqual(0); + expect(sumPublishedPoints(EMPTY_QUESTIONS)).toEqual(20); + expect(sumPublishedPoints(SIMPLE_QUESTIONS_2)).toEqual(300); + }); + + test("Testing the toCSV function", () => { + expect(toCSV(BLANK_QUESTIONS)).toEqual(`id,name,options,points,published +1,Question 1,0,1,false +47,My New Question,0,1,false +2,Question 2,0,1,false`); + expect(toCSV(SIMPLE_QUESTIONS)) + .toEqual(`id,name,options,points,published +1,Addition,0,1,true +2,Letters,0,1,false +5,Colors,3,1,true +9,Shapes,3,2,false`); + expect(toCSV(TRIVIA_QUESTIONS)) + .toEqual(`id,name,options,points,published +1,Mascot,3,7,false +2,Motto,3,3,false +3,Goats,3,10,false`); + expect(toCSV(EMPTY_QUESTIONS)).toEqual(`id,name,options,points,published +1,Empty 1,3,5,true +2,Empty 2,6,5,true +3,Empty 3,0,5,true +4,Empty 4,0,5,true +5,Empty 5 (Actual),0,5,false`); + expect(toCSV(SIMPLE_QUESTIONS_2)) + .toEqual(`id,name,options,points,published +478,Students,0,53,true +1937,Importance,0,47,true +479,Sentience,0,40,true +777,Danger,0,60,true +1937,Listening,0,100,true`); + }); + + test("Testing the makeAnswers function", () => { + expect(makeAnswers(BLANK_QUESTIONS)).toEqual([ + { questionId: 1, correct: false, text: "", submitted: false }, + { questionId: 47, correct: false, text: "", submitted: false }, + { questionId: 2, correct: false, text: "", submitted: false } + ]); + expect(makeAnswers(SIMPLE_QUESTIONS)).toEqual([ + { questionId: 1, correct: false, text: "", submitted: false }, + { questionId: 2, correct: false, text: "", submitted: false }, + { questionId: 5, correct: false, text: "", submitted: false }, + { questionId: 9, correct: false, text: "", submitted: false } + ]); + expect(makeAnswers(TRIVIA_QUESTIONS)).toEqual([ + { questionId: 1, correct: false, text: "", submitted: false }, + { questionId: 2, correct: false, text: "", submitted: false }, + { questionId: 3, correct: false, text: "", submitted: false } + ]); + expect(makeAnswers(SIMPLE_QUESTIONS_2)).toEqual([ + { questionId: 478, correct: false, text: "", submitted: false }, + { questionId: 1937, correct: false, text: "", submitted: false }, + { questionId: 479, correct: false, text: "", submitted: false }, + { questionId: 777, correct: false, text: "", submitted: false }, + { questionId: 1937, correct: false, text: "", submitted: false } + ]); + expect(makeAnswers(EMPTY_QUESTIONS)).toEqual([ + { questionId: 1, correct: false, text: "", submitted: false }, + { questionId: 2, correct: false, text: "", submitted: false }, + { questionId: 3, correct: false, text: "", submitted: false }, + { questionId: 4, correct: false, text: "", submitted: false }, + { questionId: 5, correct: false, text: "", submitted: false } + ]); + }); + + test("Testing the publishAll function", () => { + expect(publishAll(BLANK_QUESTIONS)).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: true + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: true + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: true + } + ]); + expect(publishAll(SIMPLE_QUESTIONS)).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: true + }, + { + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck"], + expected: "red", + points: 1, + published: true + }, + { + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: true + } + ]); + expect(publishAll(TRIVIA_QUESTIONS)).toEqual([ + { + id: 1, + name: "Mascot", + body: "What is the name of the UD Mascot?", + type: "multiple_choice_question", + options: ["Bluey", "YoUDee", "Charles the Wonder Dog"], + expected: "YoUDee", + points: 7, + published: true + }, + { + id: 2, + name: "Motto", + body: "What is the University of Delaware's motto?", + type: "multiple_choice_question", + options: [ + "Knowledge is the light of the mind", + "Just U Do it", + "Nothing, what's the motto with you?" + ], + expected: "Knowledge is the light of the mind", + points: 3, + published: true + }, + { + id: 3, + name: "Goats", + body: "How many goats are there usually on the Green?", + type: "multiple_choice_question", + options: [ + "Zero, why would there be goats on the green?", + "18420", + "Two" + ], + expected: "Two", + points: 10, + published: true + } + ]); + expect(publishAll(EMPTY_QUESTIONS)).toEqual([ + { + id: 1, + name: "Empty 1", + body: "This question is not empty, right?", + type: "multiple_choice_question", + options: ["correct", "it is", "not"], + expected: "correct", + points: 5, + published: true + }, + { + id: 2, + name: "Empty 2", + body: "", + type: "multiple_choice_question", + options: ["this", "one", "is", "not", "empty", "either"], + expected: "one", + points: 5, + published: true + }, + { + id: 3, + name: "Empty 3", + body: "This questions is not empty either!", + type: "short_answer_question", + options: [], + expected: "", + points: 5, + published: true + }, + { + id: 4, + name: "Empty 4", + body: "", + type: "short_answer_question", + options: [], + expected: "Even this one is not empty", + points: 5, + published: true + }, + { + id: 5, + name: "Empty 5 (Actual)", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 5, + published: true + } + ]); + expect(publishAll(SIMPLE_QUESTIONS_2)).toEqual(SIMPLE_QUESTIONS_2); + }); + + test("Testing the sameType function", () => { + expect(sameType([])).toEqual(true); + expect(sameType(BLANK_QUESTIONS)).toEqual(false); + expect(sameType(SIMPLE_QUESTIONS)).toEqual(false); + expect(sameType(TRIVIA_QUESTIONS)).toEqual(true); + expect(sameType(EMPTY_QUESTIONS)).toEqual(false); + expect(sameType(SIMPLE_QUESTIONS_2)).toEqual(true); + }); + + test("Testing the addNewQuestion function", () => { + expect( + addNewQuestion([], 142, "A new question", "short_answer_question") + ).toEqual([NEW_BLANK_QUESTION]); + expect( + addNewQuestion( + BLANK_QUESTIONS, + 142, + "A new question", + "short_answer_question" + ) + ).toEqual([...BLANK_QUESTIONS, NEW_BLANK_QUESTION]); + expect( + addNewQuestion( + TRIVIA_QUESTIONS, + 449, + "Colors", + "multiple_choice_question" + ) + ).toEqual([...TRIVIA_QUESTIONS, NEW_TRIVIA_QUESTION]); + }); + + test("Testing the renameQuestionById function", () => { + expect(renameQuestionById(BLANK_QUESTIONS, 1, "New Name")).toEqual([ + { + id: 1, + name: "New Name", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(renameQuestionById(BLANK_QUESTIONS, 47, "Another Name")).toEqual( + [ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "Another Name", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ] + ); + expect(renameQuestionById(SIMPLE_QUESTIONS, 5, "Colours")).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }, + { + id: 5, + name: "Colours", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck"], + expected: "red", + points: 1, + published: true + }, + { + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + } + ]); + }); + + test("Test the changeQuestionTypeById function", () => { + expect( + changeQuestionTypeById( + BLANK_QUESTIONS, + 1, + "multiple_choice_question" + ) + ).toEqual(BLANK_QUESTIONS); + expect( + changeQuestionTypeById(BLANK_QUESTIONS, 1, "short_answer_question") + ).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect( + changeQuestionTypeById(BLANK_QUESTIONS, 47, "short_answer_question") + ).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect( + changeQuestionTypeById(TRIVIA_QUESTIONS, 3, "short_answer_question") + ).toEqual([ + { + id: 1, + name: "Mascot", + body: "What is the name of the UD Mascot?", + type: "multiple_choice_question", + options: ["Bluey", "YoUDee", "Charles the Wonder Dog"], + expected: "YoUDee", + points: 7, + published: false + }, + { + id: 2, + name: "Motto", + body: "What is the University of Delaware's motto?", + type: "multiple_choice_question", + options: [ + "Knowledge is the light of the mind", + "Just U Do it", + "Nothing, what's the motto with you?" + ], + expected: "Knowledge is the light of the mind", + points: 3, + published: false + }, + { + id: 3, + name: "Goats", + body: "How many goats are there usually on the Green?", + type: "short_answer_question", + options: [], + expected: "Two", + points: 10, + published: false + } + ]); + }); + + test("Testing the addEditQuestionOption function", () => { + expect(editOption(BLANK_QUESTIONS, 1, -1, "NEW OPTION")).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: ["NEW OPTION"], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(editOption(BLANK_QUESTIONS, 47, -1, "Another option")).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: ["Another option"], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(editOption(SIMPLE_QUESTIONS, 5, -1, "newspaper")).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }, + { + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "firetruck", "newspaper"], + expected: "red", + points: 1, + published: true + }, + { + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + } + ]); + expect(editOption(SIMPLE_QUESTIONS, 5, 0, "newspaper")).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }, + { + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["newspaper", "apple", "firetruck"], + expected: "red", + points: 1, + published: true + }, + { + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + } + ]); + + expect(editOption(SIMPLE_QUESTIONS, 5, 2, "newspaper")).toEqual([ + { + id: 1, + name: "Addition", + body: "What is 2+2?", + type: "short_answer_question", + options: [], + expected: "4", + points: 1, + published: true + }, + { + id: 2, + name: "Letters", + body: "What is the last letter of the English alphabet?", + type: "short_answer_question", + options: [], + expected: "Z", + points: 1, + published: false + }, + { + id: 5, + name: "Colors", + body: "Which of these is a color?", + type: "multiple_choice_question", + options: ["red", "apple", "newspaper"], + expected: "red", + points: 1, + published: true + }, + { + id: 9, + name: "Shapes", + body: "What shape can you make with one line?", + type: "multiple_choice_question", + options: ["square", "triangle", "circle"], + expected: "circle", + points: 2, + published: false + } + ]); + }); + + test("Testing the duplicateQuestionInArray function", () => { + expect(duplicateQuestionInArray(BLANK_QUESTIONS, 1, 27)).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 27, + name: "Copy of Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(duplicateQuestionInArray(BLANK_QUESTIONS, 47, 19)).toEqual([ + { + id: 1, + name: "Question 1", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 47, + name: "My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 19, + name: "Copy of My New Question", + body: "", + type: "multiple_choice_question", + options: [], + expected: "", + points: 1, + published: false + }, + { + id: 2, + name: "Question 2", + body: "", + type: "short_answer_question", + options: [], + expected: "", + points: 1, + published: false + } + ]); + expect(duplicateQuestionInArray(TRIVIA_QUESTIONS, 3, 111)).toEqual([ + { + id: 1, + name: "Mascot", + body: "What is the name of the UD Mascot?", + type: "multiple_choice_question", + options: ["Bluey", "YoUDee", "Charles the Wonder Dog"], + expected: "YoUDee", + points: 7, + published: false + }, + { + id: 2, + name: "Motto", + body: "What is the University of Delaware's motto?", + type: "multiple_choice_question", + options: [ + "Knowledge is the light of the mind", + "Just U Do it", + "Nothing, what's the motto with you?" + ], + expected: "Knowledge is the light of the mind", + points: 3, + published: false + }, + { + id: 3, + name: "Goats", + body: "How many goats are there usually on the Green?", + type: "multiple_choice_question", + options: [ + "Zero, why would there be goats on the green?", + "18420", + "Two" + ], + expected: "Two", + points: 10, + published: false + }, + { + id: 111, + name: "Copy of Goats", + body: "How many goats are there usually on the Green?", + type: "multiple_choice_question", + options: [ + "Zero, why would there be goats on the green?", + "18420", + "Two" + ], + expected: "Two", + points: 10, + published: false + } + ]); }); afterEach(() => { expect(BLANK_QUESTIONS).toEqual(BACKUP_BLANK_QUESTIONS); expect(SIMPLE_QUESTIONS).toEqual(BACKUP_SIMPLE_QUESTIONS); + expect(TRIVIA_QUESTIONS).toEqual(BACKUP_TRIVIA_QUESTIONS); + expect(SIMPLE_QUESTIONS_2).toEqual(BACKUP_SIMPLE_QUESTIONS_2); + expect(EMPTY_QUESTIONS).toEqual(BACKUP_EMPTY_QUESTIONS); }); }); From a368ad06a9847e4cb04fc2d544ff49997db54e90 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 19 Feb 2022 13:52:24 -0500 Subject: [PATCH 41/81] Forgot the task record! --- public/tasks/task-nested.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 public/tasks/task-nested.md diff --git a/public/tasks/task-nested.md b/public/tasks/task-nested.md new file mode 100644 index 0000000000..6d29f9369f --- /dev/null +++ b/public/tasks/task-nested.md @@ -0,0 +1,5 @@ +# Task - Nested + +Version: 0.0.1 + +Implement functions that work with nested arrays and objects immutably. From 304184e9c70c1ed35eff2a7e522c3e71d9204d17 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 1 Mar 2022 16:38:02 -0500 Subject: [PATCH 42/81] Fix typo in editOption test, and missing return type for editOption --- src/nested.test.ts | 2 +- src/nested.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nested.test.ts b/src/nested.test.ts index 3d2b75406d..572a7a028d 100644 --- a/src/nested.test.ts +++ b/src/nested.test.ts @@ -893,7 +893,7 @@ describe("Testing the Question[] functions", () => { ]); }); - test("Testing the addEditQuestionOption function", () => { + test("Testing the editOption function", () => { expect(editOption(BLANK_QUESTIONS, 1, -1, "NEW OPTION")).toEqual([ { id: 1, diff --git a/src/nested.ts b/src/nested.ts index 7934ec1741..562b6ca0df 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -162,7 +162,7 @@ export function editOption( targetId: number, targetOptionIndex: number, newOption: string -) { +): Question[] { return []; } From 1b76b8050daddd7c26e8cb372b2ad710974a66be Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:33:40 -0400 Subject: [PATCH 43/81] Fix formatting --- src/nested.test.ts | 338 +++++++++++++++++++++++---------------------- 1 file changed, 173 insertions(+), 165 deletions(-) diff --git a/src/nested.test.ts b/src/nested.test.ts index 572a7a028d..7f52bfdf94 100644 --- a/src/nested.test.ts +++ b/src/nested.test.ts @@ -15,7 +15,7 @@ import { renameQuestionById, changeQuestionTypeById, editOption, - duplicateQuestionInArray + duplicateQuestionInArray, } from "./nested"; import testQuestionData from "./data/questions.json"; import backupQuestionData from "./data/questions.json"; @@ -25,7 +25,7 @@ const { SIMPLE_QUESTIONS, TRIVIA_QUESTIONS, EMPTY_QUESTIONS, - SIMPLE_QUESTIONS_2 + SIMPLE_QUESTIONS_2, }: Record = // Typecast the test data that we imported to be a record matching // strings to the question list @@ -37,7 +37,7 @@ const { SIMPLE_QUESTIONS: BACKUP_SIMPLE_QUESTIONS, TRIVIA_QUESTIONS: BACKUP_TRIVIA_QUESTIONS, EMPTY_QUESTIONS: BACKUP_EMPTY_QUESTIONS, - SIMPLE_QUESTIONS_2: BACKUP_SIMPLE_QUESTIONS_2 + SIMPLE_QUESTIONS_2: BACKUP_SIMPLE_QUESTIONS_2, }: Record = backupQuestionData as Record< string, Question[] @@ -51,7 +51,7 @@ const NEW_BLANK_QUESTION = { options: [], expected: "", points: 1, - published: false + published: false, }; const NEW_TRIVIA_QUESTION = { @@ -66,7 +66,7 @@ const NEW_TRIVIA_QUESTION = { options: ["Black, like my soul", "Blue again, we're tricky.", "#FFD200"], expected: "#FFD200",*/ points: 1, - published: false + published: false, }; //////////////////////////////////////////// @@ -76,7 +76,7 @@ describe("Testing the Question[] functions", () => { ////////////////////////////////// // getPublishedQuestions - test("Testing the getPublishedQuestions function", () => { + test("(3 pts) Testing the getPublishedQuestions function", () => { expect(getPublishedQuestions(BLANK_QUESTIONS)).toEqual([]); expect(getPublishedQuestions(SIMPLE_QUESTIONS)).toEqual([ { @@ -87,7 +87,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 5, @@ -97,12 +97,12 @@ describe("Testing the Question[] functions", () => { options: ["red", "apple", "firetruck"], expected: "red", points: 1, - published: true - } + published: true, + }, ]); expect(getPublishedQuestions(TRIVIA_QUESTIONS)).toEqual([]); expect(getPublishedQuestions(SIMPLE_QUESTIONS_2)).toEqual( - BACKUP_SIMPLE_QUESTIONS_2 + BACKUP_SIMPLE_QUESTIONS_2, ); expect(getPublishedQuestions(EMPTY_QUESTIONS)).toEqual([ { @@ -113,7 +113,7 @@ describe("Testing the Question[] functions", () => { options: ["correct", "it is", "not"], expected: "correct", points: 5, - published: true + published: true, }, { id: 2, @@ -123,7 +123,7 @@ describe("Testing the Question[] functions", () => { options: ["this", "one", "is", "not", "empty", "either"], expected: "one", points: 5, - published: true + published: true, }, { id: 3, @@ -133,7 +133,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 5, - published: true + published: true, }, { id: 4, @@ -143,21 +143,21 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Even this one is not empty", points: 5, - published: true - } + published: true, + }, ]); }); - test("Testing the getNonEmptyQuestions functions", () => { + test("(3 pts) Testing the getNonEmptyQuestions functions", () => { expect(getNonEmptyQuestions(BLANK_QUESTIONS)).toEqual([]); expect(getNonEmptyQuestions(SIMPLE_QUESTIONS)).toEqual( - BACKUP_SIMPLE_QUESTIONS + BACKUP_SIMPLE_QUESTIONS, ); expect(getNonEmptyQuestions(TRIVIA_QUESTIONS)).toEqual( - BACKUP_TRIVIA_QUESTIONS + BACKUP_TRIVIA_QUESTIONS, ); expect(getNonEmptyQuestions(SIMPLE_QUESTIONS_2)).toEqual( - BACKUP_SIMPLE_QUESTIONS_2 + BACKUP_SIMPLE_QUESTIONS_2, ); expect(getNonEmptyQuestions(EMPTY_QUESTIONS)).toEqual([ { @@ -168,7 +168,7 @@ describe("Testing the Question[] functions", () => { options: ["correct", "it is", "not"], expected: "correct", points: 5, - published: true + published: true, }, { id: 2, @@ -178,7 +178,7 @@ describe("Testing the Question[] functions", () => { options: ["this", "one", "is", "not", "empty", "either"], expected: "one", points: 5, - published: true + published: true, }, { id: 3, @@ -188,7 +188,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 5, - published: true + published: true, }, { id: 4, @@ -198,12 +198,12 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Even this one is not empty", points: 5, - published: true - } + published: true, + }, ]); }); - test("Testing the findQuestion function", () => { + test("(3 pts) Testing the findQuestion function", () => { expect(findQuestion(BLANK_QUESTIONS, 1)).toEqual(BLANK_QUESTIONS[0]); expect(findQuestion(BLANK_QUESTIONS, 47)).toEqual(BLANK_QUESTIONS[1]); expect(findQuestion(BLANK_QUESTIONS, 2)).toEqual(BLANK_QUESTIONS[2]); @@ -214,12 +214,12 @@ describe("Testing the Question[] functions", () => { expect(findQuestion(SIMPLE_QUESTIONS, 9)).toEqual(SIMPLE_QUESTIONS[3]); expect(findQuestion(SIMPLE_QUESTIONS, 6)).toEqual(null); expect(findQuestion(SIMPLE_QUESTIONS_2, 478)).toEqual( - SIMPLE_QUESTIONS_2[0] + SIMPLE_QUESTIONS_2[0], ); expect(findQuestion([], 0)).toEqual(null); }); - test("Testing the removeQuestion", () => { + test("(3 pts) Testing the removeQuestion", () => { expect(removeQuestion(BLANK_QUESTIONS, 1)).toEqual([ { id: 47, @@ -229,7 +229,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -239,8 +239,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(removeQuestion(BLANK_QUESTIONS, 47)).toEqual([ { @@ -251,7 +251,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -261,8 +261,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(removeQuestion(BLANK_QUESTIONS, 2)).toEqual([ { @@ -273,7 +273,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -283,8 +283,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(removeQuestion(SIMPLE_QUESTIONS, 9)).toEqual([ { @@ -295,7 +295,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -305,7 +305,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: false + published: false, }, { id: 5, @@ -315,8 +315,8 @@ describe("Testing the Question[] functions", () => { options: ["red", "apple", "firetruck"], expected: "red", points: 1, - published: true - } + published: true, + }, ]); expect(removeQuestion(SIMPLE_QUESTIONS, 5)).toEqual([ { @@ -327,7 +327,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -337,7 +337,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: false + published: false, }, { id: 9, @@ -347,45 +347,45 @@ describe("Testing the Question[] functions", () => { options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: false - } + published: false, + }, ]); }); - test("Testing the getNames function", () => { + test("(3 pts) Testing the getNames function", () => { expect(getNames(BLANK_QUESTIONS)).toEqual([ "Question 1", "My New Question", - "Question 2" + "Question 2", ]); expect(getNames(SIMPLE_QUESTIONS)).toEqual([ "Addition", "Letters", "Colors", - "Shapes" + "Shapes", ]); expect(getNames(TRIVIA_QUESTIONS)).toEqual([ "Mascot", "Motto", - "Goats" + "Goats", ]); expect(getNames(SIMPLE_QUESTIONS_2)).toEqual([ "Students", "Importance", "Sentience", "Danger", - "Listening" + "Listening", ]); expect(getNames(EMPTY_QUESTIONS)).toEqual([ "Empty 1", "Empty 2", "Empty 3", "Empty 4", - "Empty 5 (Actual)" + "Empty 5 (Actual)", ]); }); - test("Testing the sumPoints function", () => { + test("(3 pts) Testing the sumPoints function", () => { expect(sumPoints(BLANK_QUESTIONS)).toEqual(3); expect(sumPoints(SIMPLE_QUESTIONS)).toEqual(5); expect(sumPoints(TRIVIA_QUESTIONS)).toEqual(20); @@ -393,7 +393,7 @@ describe("Testing the Question[] functions", () => { expect(sumPoints(SIMPLE_QUESTIONS_2)).toEqual(300); }); - test("Testing the sumPublishedPoints function", () => { + test("(3 pts) Testing the sumPublishedPoints function", () => { expect(sumPublishedPoints(BLANK_QUESTIONS)).toEqual(0); expect(sumPublishedPoints(SIMPLE_QUESTIONS)).toEqual(2); expect(sumPublishedPoints(TRIVIA_QUESTIONS)).toEqual(0); @@ -401,7 +401,7 @@ describe("Testing the Question[] functions", () => { expect(sumPublishedPoints(SIMPLE_QUESTIONS_2)).toEqual(300); }); - test("Testing the toCSV function", () => { + test("(3 pts) Testing the toCSV function", () => { expect(toCSV(BLANK_QUESTIONS)).toEqual(`id,name,options,points,published 1,Question 1,0,1,false 47,My New Question,0,1,false @@ -432,40 +432,40 @@ describe("Testing the Question[] functions", () => { 1937,Listening,0,100,true`); }); - test("Testing the makeAnswers function", () => { + test("(3 pts) Testing the makeAnswers function", () => { expect(makeAnswers(BLANK_QUESTIONS)).toEqual([ { questionId: 1, correct: false, text: "", submitted: false }, { questionId: 47, correct: false, text: "", submitted: false }, - { questionId: 2, correct: false, text: "", submitted: false } + { questionId: 2, correct: false, text: "", submitted: false }, ]); expect(makeAnswers(SIMPLE_QUESTIONS)).toEqual([ { questionId: 1, correct: false, text: "", submitted: false }, { questionId: 2, correct: false, text: "", submitted: false }, { questionId: 5, correct: false, text: "", submitted: false }, - { questionId: 9, correct: false, text: "", submitted: false } + { questionId: 9, correct: false, text: "", submitted: false }, ]); expect(makeAnswers(TRIVIA_QUESTIONS)).toEqual([ { questionId: 1, correct: false, text: "", submitted: false }, { questionId: 2, correct: false, text: "", submitted: false }, - { questionId: 3, correct: false, text: "", submitted: false } + { questionId: 3, correct: false, text: "", submitted: false }, ]); expect(makeAnswers(SIMPLE_QUESTIONS_2)).toEqual([ { questionId: 478, correct: false, text: "", submitted: false }, { questionId: 1937, correct: false, text: "", submitted: false }, { questionId: 479, correct: false, text: "", submitted: false }, { questionId: 777, correct: false, text: "", submitted: false }, - { questionId: 1937, correct: false, text: "", submitted: false } + { questionId: 1937, correct: false, text: "", submitted: false }, ]); expect(makeAnswers(EMPTY_QUESTIONS)).toEqual([ { questionId: 1, correct: false, text: "", submitted: false }, { questionId: 2, correct: false, text: "", submitted: false }, { questionId: 3, correct: false, text: "", submitted: false }, { questionId: 4, correct: false, text: "", submitted: false }, - { questionId: 5, correct: false, text: "", submitted: false } + { questionId: 5, correct: false, text: "", submitted: false }, ]); }); - test("Testing the publishAll function", () => { + test("(3 pts) Testing the publishAll function", () => { expect(publishAll(BLANK_QUESTIONS)).toEqual([ { id: 1, @@ -475,7 +475,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: true + published: true, }, { id: 47, @@ -485,7 +485,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: true + published: true, }, { id: 2, @@ -495,8 +495,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: true - } + published: true, + }, ]); expect(publishAll(SIMPLE_QUESTIONS)).toEqual([ { @@ -507,7 +507,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -517,7 +517,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: true + published: true, }, { id: 5, @@ -527,7 +527,7 @@ describe("Testing the Question[] functions", () => { options: ["red", "apple", "firetruck"], expected: "red", points: 1, - published: true + published: true, }, { id: 9, @@ -537,8 +537,8 @@ describe("Testing the Question[] functions", () => { options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: true - } + published: true, + }, ]); expect(publishAll(TRIVIA_QUESTIONS)).toEqual([ { @@ -549,7 +549,7 @@ describe("Testing the Question[] functions", () => { options: ["Bluey", "YoUDee", "Charles the Wonder Dog"], expected: "YoUDee", points: 7, - published: true + published: true, }, { id: 2, @@ -559,11 +559,11 @@ describe("Testing the Question[] functions", () => { options: [ "Knowledge is the light of the mind", "Just U Do it", - "Nothing, what's the motto with you?" + "Nothing, what's the motto with you?", ], expected: "Knowledge is the light of the mind", points: 3, - published: true + published: true, }, { id: 3, @@ -573,12 +573,12 @@ describe("Testing the Question[] functions", () => { options: [ "Zero, why would there be goats on the green?", "18420", - "Two" + "Two", ], expected: "Two", points: 10, - published: true - } + published: true, + }, ]); expect(publishAll(EMPTY_QUESTIONS)).toEqual([ { @@ -589,7 +589,7 @@ describe("Testing the Question[] functions", () => { options: ["correct", "it is", "not"], expected: "correct", points: 5, - published: true + published: true, }, { id: 2, @@ -599,7 +599,7 @@ describe("Testing the Question[] functions", () => { options: ["this", "one", "is", "not", "empty", "either"], expected: "one", points: 5, - published: true + published: true, }, { id: 3, @@ -609,7 +609,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 5, - published: true + published: true, }, { id: 4, @@ -619,7 +619,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Even this one is not empty", points: 5, - published: true + published: true, }, { id: 5, @@ -629,13 +629,13 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 5, - published: true - } + published: true, + }, ]); expect(publishAll(SIMPLE_QUESTIONS_2)).toEqual(SIMPLE_QUESTIONS_2); }); - test("Testing the sameType function", () => { + test("(3 pts) Testing the sameType function", () => { expect(sameType([])).toEqual(true); expect(sameType(BLANK_QUESTIONS)).toEqual(false); expect(sameType(SIMPLE_QUESTIONS)).toEqual(false); @@ -644,29 +644,29 @@ describe("Testing the Question[] functions", () => { expect(sameType(SIMPLE_QUESTIONS_2)).toEqual(true); }); - test("Testing the addNewQuestion function", () => { + test("(3 pts) Testing the addNewQuestion function", () => { expect( - addNewQuestion([], 142, "A new question", "short_answer_question") + addNewQuestion([], 142, "A new question", "short_answer_question"), ).toEqual([NEW_BLANK_QUESTION]); expect( addNewQuestion( BLANK_QUESTIONS, 142, "A new question", - "short_answer_question" - ) + "short_answer_question", + ), ).toEqual([...BLANK_QUESTIONS, NEW_BLANK_QUESTION]); expect( addNewQuestion( TRIVIA_QUESTIONS, 449, "Colors", - "multiple_choice_question" - ) + "multiple_choice_question", + ), ).toEqual([...TRIVIA_QUESTIONS, NEW_TRIVIA_QUESTION]); }); - test("Testing the renameQuestionById function", () => { + test("(3 pts) Testing the renameQuestionById function", () => { expect(renameQuestionById(BLANK_QUESTIONS, 1, "New Name")).toEqual([ { id: 1, @@ -676,7 +676,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -686,7 +686,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -696,8 +696,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(renameQuestionById(BLANK_QUESTIONS, 47, "Another Name")).toEqual( [ @@ -709,7 +709,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -719,7 +719,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -729,9 +729,9 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } - ] + published: false, + }, + ], ); expect(renameQuestionById(SIMPLE_QUESTIONS, 5, "Colours")).toEqual([ { @@ -742,7 +742,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -752,7 +752,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: false + published: false, }, { id: 5, @@ -762,7 +762,7 @@ describe("Testing the Question[] functions", () => { options: ["red", "apple", "firetruck"], expected: "red", points: 1, - published: true + published: true, }, { id: 9, @@ -772,21 +772,21 @@ describe("Testing the Question[] functions", () => { options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: false - } + published: false, + }, ]); }); - test("Test the changeQuestionTypeById function", () => { + test("(3 pts) Test the changeQuestionTypeById function", () => { expect( changeQuestionTypeById( BLANK_QUESTIONS, 1, - "multiple_choice_question" - ) + "multiple_choice_question", + ), ).toEqual(BLANK_QUESTIONS); expect( - changeQuestionTypeById(BLANK_QUESTIONS, 1, "short_answer_question") + changeQuestionTypeById(BLANK_QUESTIONS, 1, "short_answer_question"), ).toEqual([ { id: 1, @@ -796,7 +796,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -806,7 +806,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -816,11 +816,15 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect( - changeQuestionTypeById(BLANK_QUESTIONS, 47, "short_answer_question") + changeQuestionTypeById( + BLANK_QUESTIONS, + 47, + "short_answer_question", + ), ).toEqual([ { id: 1, @@ -830,7 +834,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -840,7 +844,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -850,11 +854,15 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect( - changeQuestionTypeById(TRIVIA_QUESTIONS, 3, "short_answer_question") + changeQuestionTypeById( + TRIVIA_QUESTIONS, + 3, + "short_answer_question", + ), ).toEqual([ { id: 1, @@ -864,7 +872,7 @@ describe("Testing the Question[] functions", () => { options: ["Bluey", "YoUDee", "Charles the Wonder Dog"], expected: "YoUDee", points: 7, - published: false + published: false, }, { id: 2, @@ -874,11 +882,11 @@ describe("Testing the Question[] functions", () => { options: [ "Knowledge is the light of the mind", "Just U Do it", - "Nothing, what's the motto with you?" + "Nothing, what's the motto with you?", ], expected: "Knowledge is the light of the mind", points: 3, - published: false + published: false, }, { id: 3, @@ -888,12 +896,12 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Two", points: 10, - published: false - } + published: false, + }, ]); }); - test("Testing the editOption function", () => { + test("(3 pts) Testing the editOption function", () => { expect(editOption(BLANK_QUESTIONS, 1, -1, "NEW OPTION")).toEqual([ { id: 1, @@ -903,7 +911,7 @@ describe("Testing the Question[] functions", () => { options: ["NEW OPTION"], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -913,7 +921,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -923,8 +931,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(editOption(BLANK_QUESTIONS, 47, -1, "Another option")).toEqual([ { @@ -935,7 +943,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -945,7 +953,7 @@ describe("Testing the Question[] functions", () => { options: ["Another option"], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -955,8 +963,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(editOption(SIMPLE_QUESTIONS, 5, -1, "newspaper")).toEqual([ { @@ -967,7 +975,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -977,7 +985,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: false + published: false, }, { id: 5, @@ -987,7 +995,7 @@ describe("Testing the Question[] functions", () => { options: ["red", "apple", "firetruck", "newspaper"], expected: "red", points: 1, - published: true + published: true, }, { id: 9, @@ -997,8 +1005,8 @@ describe("Testing the Question[] functions", () => { options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: false - } + published: false, + }, ]); expect(editOption(SIMPLE_QUESTIONS, 5, 0, "newspaper")).toEqual([ { @@ -1009,7 +1017,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -1019,7 +1027,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: false + published: false, }, { id: 5, @@ -1029,7 +1037,7 @@ describe("Testing the Question[] functions", () => { options: ["newspaper", "apple", "firetruck"], expected: "red", points: 1, - published: true + published: true, }, { id: 9, @@ -1039,8 +1047,8 @@ describe("Testing the Question[] functions", () => { options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: false - } + published: false, + }, ]); expect(editOption(SIMPLE_QUESTIONS, 5, 2, "newspaper")).toEqual([ @@ -1052,7 +1060,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "4", points: 1, - published: true + published: true, }, { id: 2, @@ -1062,7 +1070,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "Z", points: 1, - published: false + published: false, }, { id: 5, @@ -1072,7 +1080,7 @@ describe("Testing the Question[] functions", () => { options: ["red", "apple", "newspaper"], expected: "red", points: 1, - published: true + published: true, }, { id: 9, @@ -1082,12 +1090,12 @@ describe("Testing the Question[] functions", () => { options: ["square", "triangle", "circle"], expected: "circle", points: 2, - published: false - } + published: false, + }, ]); }); - test("Testing the duplicateQuestionInArray function", () => { + test("(3 pts) Testing the duplicateQuestionInArray function", () => { expect(duplicateQuestionInArray(BLANK_QUESTIONS, 1, 27)).toEqual([ { id: 1, @@ -1097,7 +1105,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 27, @@ -1107,7 +1115,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -1117,7 +1125,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -1127,8 +1135,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(duplicateQuestionInArray(BLANK_QUESTIONS, 47, 19)).toEqual([ { @@ -1139,7 +1147,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 47, @@ -1149,7 +1157,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 19, @@ -1159,7 +1167,7 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false + published: false, }, { id: 2, @@ -1169,8 +1177,8 @@ describe("Testing the Question[] functions", () => { options: [], expected: "", points: 1, - published: false - } + published: false, + }, ]); expect(duplicateQuestionInArray(TRIVIA_QUESTIONS, 3, 111)).toEqual([ { @@ -1181,7 +1189,7 @@ describe("Testing the Question[] functions", () => { options: ["Bluey", "YoUDee", "Charles the Wonder Dog"], expected: "YoUDee", points: 7, - published: false + published: false, }, { id: 2, @@ -1191,11 +1199,11 @@ describe("Testing the Question[] functions", () => { options: [ "Knowledge is the light of the mind", "Just U Do it", - "Nothing, what's the motto with you?" + "Nothing, what's the motto with you?", ], expected: "Knowledge is the light of the mind", points: 3, - published: false + published: false, }, { id: 3, @@ -1205,11 +1213,11 @@ describe("Testing the Question[] functions", () => { options: [ "Zero, why would there be goats on the green?", "18420", - "Two" + "Two", ], expected: "Two", points: 10, - published: false + published: false, }, { id: 111, @@ -1219,12 +1227,12 @@ describe("Testing the Question[] functions", () => { options: [ "Zero, why would there be goats on the green?", "18420", - "Two" + "Two", ], expected: "Two", points: 10, - published: false - } + published: false, + }, ]); }); From 017584a64838253637158c4c2a6d0e261c035c84 Mon Sep 17 00:00:00 2001 From: Jacob Donn Date: Tue, 3 Feb 2026 09:57:39 -0500 Subject: [PATCH 44/81] Added name to App --- src/App.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index b77558eaac..bae62d13cb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,8 @@ function App(): React.JSX.Element { return (
- UD CISC275 with React Hooks and TypeScript + UD CISC275 with React Hooks and TypeScript. Jacob says Hello + world!

Edit src/App.tsx and save. This page will From 7272459e46bec8dd3e00f02f8cf5cbe04cc7edfd Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Thu, 5 Feb 2026 10:29:40 -0500 Subject: [PATCH 45/81] Passed all tests --- package-lock.json | 123 +++++++++++++++++++++------------------------- src/App.tsx | 4 +- 2 files changed, 59 insertions(+), 68 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8c3779f487..1e6922997e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2153,7 +2153,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -2166,7 +2166,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -3273,7 +3273,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" @@ -3436,7 +3436,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -3454,7 +3454,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3470,7 +3470,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -3487,7 +3487,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -3500,14 +3500,14 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -3517,7 +3517,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -3909,7 +3909,7 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@sinonjs/commons": { @@ -4222,7 +4222,6 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", @@ -4242,7 +4241,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -4258,7 +4256,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -4275,7 +4272,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4288,14 +4284,12 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/@testing-library/dom/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4305,7 +4299,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -4470,35 +4463,34 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, "license": "MIT" }, "node_modules/@types/babel__core": { @@ -4911,7 +4903,7 @@ "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -5508,7 +5500,7 @@ "version": "8.3.3", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -7210,7 +7202,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -7947,7 +7939,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -13021,7 +13013,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -13031,7 +13023,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -13949,7 +13941,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -13959,7 +13951,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chalk": "^4.0.0", @@ -13994,7 +13986,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -14010,7 +14002,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -14027,7 +14019,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -14040,14 +14032,14 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/jest-resolve/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -14057,7 +14049,7 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", @@ -14075,7 +14067,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -14518,7 +14510,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -14536,7 +14528,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -14552,7 +14544,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -14569,7 +14561,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -14582,14 +14574,14 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -14599,7 +14591,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -14612,7 +14604,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -14630,7 +14622,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -14646,7 +14638,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -14659,7 +14651,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -14676,7 +14668,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -14689,14 +14681,14 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/jest-validate/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -14706,7 +14698,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -14721,7 +14713,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -14734,14 +14726,14 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/jest-validate/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -14850,7 +14842,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -14866,7 +14858,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -14876,7 +14868,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -15368,7 +15360,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, "license": "MIT", "bin": { "lz-string": "bin/bin.js" @@ -15402,7 +15393,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/makeerror": { @@ -20668,7 +20659,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -22588,7 +22579,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -22632,7 +22623,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/tsconfig-paths": { @@ -23056,7 +23047,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -24118,7 +24109,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/src/App.tsx b/src/App.tsx index bae62d13cb..f9632b13aa 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,8 +5,8 @@ function App(): React.JSX.Element { return (

- UD CISC275 with React Hooks and TypeScript. Jacob says Hello - world! + UD CISC275 with React Hooks and TypeScript. Jacob Donn. Hello + World

Edit src/App.tsx and save. This page will From bd6f679a40fafa6f6aafd4bef4681046c40eb4fd Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 10 Feb 2026 09:55:50 -0500 Subject: [PATCH 46/81] Finish adding header & image --- src/App.tsx | 7 +++++++ src/images/budgies.jpg | Bin 0 -> 34074 bytes 2 files changed, 7 insertions(+) create mode 100644 src/images/budgies.jpg diff --git a/src/App.tsx b/src/App.tsx index f9632b13aa..05350ef5c0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,10 @@ import React from "react"; import "./App.css"; +import budgies from "./images/budgies.jpg"; + +export function Header(): React.JSX.Element { + return

This is my header

; +} function App(): React.JSX.Element { return ( @@ -12,6 +17,8 @@ function App(): React.JSX.Element { Edit src/App.tsx and save. This page will automatically reload.

+

This is a header!

+ A budgie couple
); } diff --git a/src/images/budgies.jpg b/src/images/budgies.jpg new file mode 100644 index 0000000000000000000000000000000000000000..904e239135fe6ebb0beccf28791fc295ded4a645 GIT binary patch literal 34074 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%0A%=}iRhcCc@} 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 literal 0 HcmV?d00001 From 255fdc6ac02332bb2f13cfb73fb11c8c93ca6488 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 10 Feb 2026 10:00:23 -0500 Subject: [PATCH 47/81] Finish adding (unordered) list --- src/App.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index 05350ef5c0..27cc5747f6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,8 +17,19 @@ function App(): React.JSX.Element { Edit src/App.tsx and save. This page will automatically reload.

+

This is a header!

+ A budgie couple + +
+ My go-to Dominos order: +
    +
  • Pepperoni
  • +
  • Sausage
  • +
  • Green peppers
  • +
+
); } From b20f96641d8ac277f1bc24d57d51720ff263a59c Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 10 Feb 2026 10:11:50 -0500 Subject: [PATCH 48/81] Finish adding "Hello World" logger button --- src/App.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 27cc5747f6..a7fe42ac11 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import React from "react"; import "./App.css"; import budgies from "./images/budgies.jpg"; +import { Button } from "react-bootstrap"; export function Header(): React.JSX.Element { return

This is my header

; @@ -19,9 +20,7 @@ function App(): React.JSX.Element {

This is a header!

- A budgie couple -
My go-to Dominos order:
    @@ -30,6 +29,15 @@ function App(): React.JSX.Element {
  • Green peppers
+
+ +
); } From 2720ca4f45e4d260601111aa01aea6336e05aa65 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 10 Feb 2026 10:39:56 -0500 Subject: [PATCH 49/81] Finish all tests --- src/App.css | 4 ++-- src/App.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App.css b/src/App.css index ad32fac073..bce3b2b3c0 100644 --- a/src/App.css +++ b/src/App.css @@ -15,14 +15,14 @@ .App-header { width: 100%; - background-color: #282c34; + background-color: rgb(255, 0, 0); min-height: 40vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); - color: white; + color: rgb(255, 255, 255); } .App-link { diff --git a/src/App.tsx b/src/App.tsx index a7fe42ac11..120223acf5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,7 +10,7 @@ export function Header(): React.JSX.Element { function App(): React.JSX.Element { return (
-
+
UD CISC275 with React Hooks and TypeScript. Jacob Donn. Hello World
From e5bfcf80542bf268c2f1cea495ea2e50dfd8ab98 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 11 Feb 2026 13:10:06 -0500 Subject: [PATCH 50/81] Finish first func --- src/functions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/functions.ts b/src/functions.ts index e614c81c0c..ddaa3af7b2 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -4,7 +4,8 @@ * C = (F - 32) * 5/9 */ export function fahrenheitToCelius(temperature: number): number { - return 0; + let celsiusTemp = (temperature - 32) * (5 / 9); + return celsiusTemp; } /** From dbf54332e0610cc470bdf3b34e814a601334cc63 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 11 Feb 2026 13:11:37 -0500 Subject: [PATCH 51/81] Finish second func --- src/functions.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/functions.ts b/src/functions.ts index ddaa3af7b2..375c2405be 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -13,7 +13,18 @@ export function fahrenheitToCelius(temperature: number): number { * if the number is greater than zero. */ export function add3(first: number, second: number, third: number): number { - return 0; + let sum = 0; + if (first > 0) { + sum += first; + } + if (second > 0) { + sum += second; + } + if (third > 0) { + sum += third; + } + + return sum; } /** From 40ad4321d99a1e3e969abb69ae694f1da896d573 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 11 Feb 2026 13:13:44 -0500 Subject: [PATCH 52/81] Finish third func --- src/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions.ts b/src/functions.ts index 375c2405be..3714b0fe97 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -32,7 +32,7 @@ export function add3(first: number, second: number, third: number): number { * mark added to the end. */ export function shout(message: string): string { - return ""; + return message.toUpperCase() + "!"; } /** From 1e40289eb54b544efedde2316963edec94b37a28 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 11 Feb 2026 13:17:26 -0500 Subject: [PATCH 53/81] Finish fourth func --- src/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions.ts b/src/functions.ts index 3714b0fe97..e99c4570de 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -40,7 +40,7 @@ export function shout(message: string): string { * mark. Do not use an `if` statement in solving this question. */ export function isQuestion(message: string): boolean { - return true; + return message.slice(-1) === "?"; } /** From e55ad1812f50683e908417ab5da184129c550eb6 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 11 Feb 2026 13:18:42 -0500 Subject: [PATCH 54/81] Finish 5th func --- src/functions.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/functions.ts b/src/functions.ts index e99c4570de..9acfb261f6 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -49,5 +49,11 @@ export function isQuestion(message: string): boolean { * upper or lower case), then return `false`. Otherwise, return `null`. */ export function convertYesNo(word: string): boolean | null { - return true; + if (word === "yes" || word === "YES") { + return true; + } else if (word === "no" || word === "NO") { + return false; + } + + return null; } From 026542958f838d52b300e7f0c7debb4319ea836e Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Thu, 19 Feb 2026 12:54:00 -0500 Subject: [PATCH 55/81] Finish all array funcs --- src/arrays.ts | 81 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/src/arrays.ts b/src/arrays.ts index 4a2ffe8e5b..2636138546 100644 --- a/src/arrays.ts +++ b/src/arrays.ts @@ -1,3 +1,5 @@ +//import { cursorTo } from "readline"; + /** * Consume an array of numbers, and return a new array containing * JUST the first and last number. If there are no elements, return @@ -5,7 +7,14 @@ * the number twice. */ export function bookEndList(numbers: number[]): number[] { - return numbers; + if (numbers.length === 0) { + return []; + } else if (numbers.length === 1) { + return [...numbers, ...numbers]; + } else { + const firstLast: number[] = [numbers[0], numbers[numbers.length - 1]]; + return firstLast; + } } /** @@ -13,7 +22,8 @@ export function bookEndList(numbers: number[]): number[] { * number has been tripled (multiplied by 3). */ export function tripleNumbers(numbers: number[]): number[] { - return numbers; + const tripled: number[] = numbers.map((num: number): number => num * 3); + return tripled; } /** @@ -21,7 +31,10 @@ export function tripleNumbers(numbers: number[]): number[] { * the number cannot be parsed as an integer, convert it to 0 instead. */ export function stringsToIntegers(numbers: string[]): number[] { - return []; + const ints: number[] = numbers.map((num: string): number => + !isNaN(+num) ? +num : 0, + ); + return ints; } /** @@ -32,7 +45,10 @@ export function stringsToIntegers(numbers: string[]): number[] { */ // Remember, you can write functions as lambdas too! They work exactly the same. export const removeDollars = (amounts: string[]): number[] => { - return []; + const justNums: number[] = amounts.map((amount: string): number => + +amount.replace("$", "") ? +amount.replace("$", "") : 0, + ); + return justNums; }; /** @@ -41,7 +57,12 @@ export const removeDollars = (amounts: string[]): number[] => { * in question marks ("?"). */ export const shoutIfExclaiming = (messages: string[]): string[] => { - return []; + const newMessages: string[] = messages + .map((message: string): string => + message.slice(-1) === "!" ? message.toUpperCase() : message, + ) + .filter((message: string): boolean => message.slice(-1) !== "?"); + return newMessages; }; /** @@ -49,7 +70,10 @@ export const shoutIfExclaiming = (messages: string[]): string[] => { * 4 letters long. */ export function countShortWords(words: string[]): number { - return 0; + const shortWords: string[] = words.filter( + (word: string): boolean => word.length < 4, + ); + return shortWords.length; } /** @@ -58,7 +82,13 @@ export function countShortWords(words: string[]): number { * then return true. */ export function allRGB(colors: string[]): boolean { - return false; + if (colors.length === 0) { + return true; + } + return colors.every( + (color: string): boolean => + color === "red" || color === "blue" || color === "green", + ); } /** @@ -69,7 +99,16 @@ export function allRGB(colors: string[]): boolean { * And the array [] would become "0=0". */ export function makeMath(addends: number[]): string { - return ""; + if (addends.length === 0) { + return "0=0"; + } + + const sum = addends.reduce( + (total: number, curr: number): number => (total += curr), + 0, + ); + const additionString: string = addends.join("+"); + return sum + "=" + additionString; } /** @@ -81,6 +120,30 @@ export function makeMath(addends: number[]): string { * For instance, the array [1, 9, -5, 7] would become [1, 9, -5, 10, 7] * And the array [1, 9, 7] would become [1, 9, 7, 17] */ + export function injectPositive(values: number[]): number[] { - return []; + const firstNeg: number | undefined = values.find( + (num: number): boolean => num < 0, + ); + + if (firstNeg === undefined) { + const sum = values.reduce( + (total: number, curr: number): number => total + curr, + 0, + ); + return [...values, sum]; + } + + const firstNegIndex = values.findIndex((num: number): boolean => num < 0); + const valuesUpToNeg = values.slice(0, firstNegIndex); + const sumBeforeNeg = valuesUpToNeg.reduce( + (total: number, num: number): number => total + num, + 0, + ); + const finalArr: number[] = [ + ...values.slice(0, firstNegIndex + 1), + sumBeforeNeg, + ...values.slice(firstNegIndex + 1), + ]; + return finalArr; } From 4d5511a5ef2792f01bd734dc4339e2958c1cf7b5 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 11:46:03 -0500 Subject: [PATCH 56/81] Finish makeBlankQuestion --- src/objects.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/objects.ts b/src/objects.ts index 3fd2072e5e..e2e467a374 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -8,9 +8,18 @@ import { Question, QuestionType } from "./interfaces/question"; export function makeBlankQuestion( id: number, name: string, - type: QuestionType + type: QuestionType, ): Question { - return {}; + return { + id: id, + name: name, + type: type, + body: "", + expected: "", + options: [], + points: 1, + published: false, + }; } /** @@ -115,7 +124,7 @@ export function mergeQuestion( id: number, name: string, contentQuestion: Question, - { points }: { points: number } + { points }: { points: number }, ): Question { return contentQuestion; } From b2fb1d05747b3dc9110fe6a0ad5fcdc0ba0d5811 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 11:50:44 -0500 Subject: [PATCH 57/81] Finish isCorrect() --- src/objects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index e2e467a374..695d0ca370 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -30,7 +30,7 @@ export function makeBlankQuestion( * HINT: Look up the `trim` and `toLowerCase` functions. */ export function isCorrect(question: Question, answer: string): boolean { - return false; + return question.expected.toLowerCase() === answer.toLowerCase().trim(); } /** From 553433f005d002286a6d6a31a3c67cf72aefe1e3 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 13:44:27 -0500 Subject: [PATCH 58/81] Finish toShortForm() --- src/objects.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/objects.ts b/src/objects.ts index 695d0ca370..1a352a12b9 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -40,7 +40,11 @@ export function isCorrect(question: Question, answer: string): boolean { * be exactly one of the options. */ export function isValid(question: Question, answer: string): boolean { - return false; + if (question.type === "multiple_choice_question") { + return question.expected === answer; + } + + return answer != ""; } /** @@ -50,7 +54,7 @@ export function isValid(question: Question, answer: string): boolean { * name "My First Question" would become "9: My First Q". */ export function toShortForm(question: Question): string { - return ""; + return `${question.id}: ${question.name.slice(0, 10)}`; } /** From 917c88598c699ed7b4470211ffb086335e368d97 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 13:48:39 -0500 Subject: [PATCH 59/81] Finish renameQuestion() --- src/objects.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index 1a352a12b9..4f4f1dd9c6 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -83,7 +83,8 @@ export function toMarkdown(question: Question): string { * `newName`. */ export function renameQuestion(question: Question, newName: string): Question { - return question; + const newQuestion: Question = { ...question, name: newName }; + return newQuestion; } /** From 3dbc6f18ffee883cf5ceac8e7f18f5a16871e294 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 13:51:50 -0500 Subject: [PATCH 60/81] Finish publishQuestion() --- src/objects.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index 4f4f1dd9c6..8ed3a7f271 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -93,7 +93,13 @@ export function renameQuestion(question: Question, newName: string): Question { * published; if it was published, now it should be not published. */ export function publishQuestion(question: Question): Question { - return question; + if (question.published) { + const newQuestion = { ...question, published: false }; + return newQuestion; + } + + const newQuestion = { ...question, published: true }; + return newQuestion; } /** From 1c80284f1345716fce712c5b00cda50509801306 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 14:03:25 -0500 Subject: [PATCH 61/81] Finish duplicateQuestion() --- src/objects.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index 8ed3a7f271..11957c1f8c 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -109,7 +109,13 @@ export function publishQuestion(question: Question): Question { * The `published` field should be reset to false. */ export function duplicateQuestion(id: number, oldQuestion: Question): Question { - return oldQuestion; + const newQuestion = { + ...oldQuestion, + id: id, + published: false, + name: `Copy of ${oldQuestion.name}`, + }; + return newQuestion; } /** From d8d09752cb79a5ebe0c82bbd10449f3bfe3afea0 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 14:12:57 -0500 Subject: [PATCH 62/81] Finish addOption() --- src/objects.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index 11957c1f8c..84a1770d32 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -126,7 +126,11 @@ export function duplicateQuestion(id: number, oldQuestion: Question): Question { * Check out the subsection about "Nested Fields" for more information. */ export function addOption(question: Question, newOption: string): Question { - return question; + const newQuestion = { + ...question, + options: [...question.options, newOption], + }; + return newQuestion; } /** From 907117cbc541ace73573373c67713ebd9c2bd1d4 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 17:14:28 -0500 Subject: [PATCH 63/81] Finish isValid() --- src/objects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index 84a1770d32..f88b41c144 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -41,7 +41,7 @@ export function isCorrect(question: Question, answer: string): boolean { */ export function isValid(question: Question, answer: string): boolean { if (question.type === "multiple_choice_question") { - return question.expected === answer; + return question.options.includes(answer); } return answer != ""; From 1ba4c3a2b2f31d1580e5ede9c418a30215605af4 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 17:19:39 -0500 Subject: [PATCH 64/81] Finish toMarkdown() --- src/objects.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index f88b41c144..bc0f36aa5c 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -75,7 +75,11 @@ export function toShortForm(question: Question): string { * Check the unit tests for more examples of what this looks like! */ export function toMarkdown(question: Question): string { - return ""; + if (question.type === "short_answer_question") { + return `# ${question.name}\n${question.body}`; + } + + return `# ${question.name}\n${question.body}\n- ${question.options[0]}\n- ${question.options[1]}\n- ${question.options[2]}`; } /** From e7461aef030cf771ca7d8135e215708efca195a9 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sun, 22 Feb 2026 17:26:38 -0500 Subject: [PATCH 65/81] Finish mergeQuestion --- src/objects.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/objects.ts b/src/objects.ts index bc0f36aa5c..3f94c14cb2 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -151,5 +151,12 @@ export function mergeQuestion( contentQuestion: Question, { points }: { points: number }, ): Question { - return contentQuestion; + const mergedQuestion = { + ...contentQuestion, + id: id, + name: name, + published: false, + points: { points }.points, + }; + return mergedQuestion; } From 293ef5fb891d4796a06f9282d60f9ac2e1219658 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 21:27:10 -0500 Subject: [PATCH 66/81] Finish getPublishedQuestions() --- src/nested.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/nested.ts b/src/nested.ts index 562b6ca0df..c0b5018ae5 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -6,7 +6,9 @@ import { Question, QuestionType } from "./interfaces/question"; * that are `published`. */ export function getPublishedQuestions(questions: Question[]): Question[] { - return []; + return questions.filter( + (question: Question): boolean => question.published, + ); } /** @@ -14,9 +16,7 @@ export function getPublishedQuestions(questions: Question[]): Question[] { * considered "non-empty". An empty question has an empty string for its `body` and * `expected`, and an empty array for its `options`. */ -export function getNonEmptyQuestions(questions: Question[]): Question[] { - return []; -} +export function getNonEmptyQuestions(questions: Question[]): Question[] {} /*** * Consumes an array of questions and returns the question with the given `id`. If the @@ -24,7 +24,7 @@ export function getNonEmptyQuestions(questions: Question[]): Question[] { */ export function findQuestion( questions: Question[], - id: number + id: number, ): Question | null { return null; } @@ -114,7 +114,7 @@ export function addNewQuestion( questions: Question[], id: number, name: string, - type: QuestionType + type: QuestionType, ): Question[] { return []; } @@ -127,7 +127,7 @@ export function addNewQuestion( export function renameQuestionById( questions: Question[], targetId: number, - newName: string + newName: string, ): Question[] { return []; } @@ -142,7 +142,7 @@ export function renameQuestionById( export function changeQuestionTypeById( questions: Question[], targetId: number, - newQuestionType: QuestionType + newQuestionType: QuestionType, ): Question[] { return []; } @@ -161,7 +161,7 @@ export function editOption( questions: Question[], targetId: number, targetOptionIndex: number, - newOption: string + newOption: string, ): Question[] { return []; } @@ -175,7 +175,7 @@ export function editOption( export function duplicateQuestionInArray( questions: Question[], targetId: number, - newId: number + newId: number, ): Question[] { return []; } From e82e13b486fb8624d6b13a192f413eda463b960f Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 21:29:52 -0500 Subject: [PATCH 67/81] Finish getNonEmptyQuestions --- src/nested.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index c0b5018ae5..4fedd00835 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -16,7 +16,16 @@ export function getPublishedQuestions(questions: Question[]): Question[] { * considered "non-empty". An empty question has an empty string for its `body` and * `expected`, and an empty array for its `options`. */ -export function getNonEmptyQuestions(questions: Question[]): Question[] {} +export function getNonEmptyQuestions(questions: Question[]): Question[] { + return questions.filter( + (question: Question): boolean => + !( + question.expected === "" && + question.body === "" && + question.options.length === 0 + ), + ); +} /*** * Consumes an array of questions and returns the question with the given `id`. If the From 159b7c9a2feae9155576cdaa249851dc419df68c Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 21:31:27 -0500 Subject: [PATCH 68/81] Finish findQuestion() --- src/nested.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index 4fedd00835..927b0285a0 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -35,7 +35,13 @@ export function findQuestion( questions: Question[], id: number, ): Question | null { - return null; + const foundQuestion = questions.find( + (question: Question): boolean => question.id === id, + ); + if (foundQuestion === undefined) { + return null; + } + return foundQuestion; } /** From f064245067c7bc4fc48880e7bb0cf90da96b16d5 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 21:33:49 -0500 Subject: [PATCH 69/81] Finish removeQuestion() --- src/nested.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index 927b0285a0..f896791977 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -49,7 +49,9 @@ export function findQuestion( * with the given `id`. */ export function removeQuestion(questions: Question[], id: number): Question[] { - return []; + return questions.filter( + (question: Question): boolean => question.id !== id, + ); } /*** From 700d14d2f7aced5536d8ee14f7c1d76763361132 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 21:35:10 -0500 Subject: [PATCH 70/81] Finish getNames() --- src/nested.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index f896791977..e89ec03c24 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -59,7 +59,7 @@ export function removeQuestion(questions: Question[], id: number): Question[] { * questions, as an array. */ export function getNames(questions: Question[]): string[] { - return []; + return questions.map((question: Question): string => question.name); } /*** From a5db038ba50e9db3e2c26bc2250f427fc8dc7e2f Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 21:54:16 -0500 Subject: [PATCH 71/81] Finish sumPoints() --- src/nested.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index e89ec03c24..a6a38ccd77 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -66,7 +66,10 @@ export function getNames(questions: Question[]): string[] { * Consumes an array of questions and returns the sum total of all their points added together. */ export function sumPoints(questions: Question[]): number { - return 0; + return questions.reduce( + (total: number, curr: Question) => total + curr.points, + 0, + ); } /*** From 05e2a930ff56789a2876ae70f748cce82d9b2fee Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Tue, 24 Feb 2026 22:07:19 -0500 Subject: [PATCH 72/81] Finish sumPublishedPoints() --- src/nested.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index a6a38ccd77..87d68c933f 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -76,7 +76,9 @@ export function sumPoints(questions: Question[]): number { * Consumes an array of questions and returns the sum total of the PUBLISHED questions. */ export function sumPublishedPoints(questions: Question[]): number { - return 0; + return questions + .filter((question: Question): boolean => question.published) + .reduce((total: number, curr: Question) => total + curr.points, 0); } /*** From a8b1bfb7f15150ec2fbf2d0a6bf2f68a72471d49 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 25 Feb 2026 20:45:48 -0500 Subject: [PATCH 73/81] Finish makeAnswers() --- src/nested.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/nested.ts b/src/nested.ts index 87d68c933f..4413d289b6 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -99,7 +99,7 @@ id,name,options,points,published * Check the unit tests for more examples! */ export function toCSV(questions: Question[]): string { - return ""; + const finalStr: string = "id,name,options,points,published\n"; } /** @@ -108,7 +108,14 @@ export function toCSV(questions: Question[]): string { * making the `text` an empty string, and using false for both `submitted` and `correct`. */ export function makeAnswers(questions: Question[]): Answer[] { - return []; + return questions.map( + (question: Question): Answer => ({ + questionId: question.id, + text: "", + submitted: false, + correct: false, + }), + ); } /*** From 2f65e820ac78c94233603600fd18e6debd50ecd7 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 25 Feb 2026 20:48:32 -0500 Subject: [PATCH 74/81] Finish publishAll() --- src/nested.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index 4413d289b6..575011522c 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -123,7 +123,9 @@ export function makeAnswers(questions: Question[]): Answer[] { * each question is now published, regardless of its previous published status. */ export function publishAll(questions: Question[]): Question[] { - return []; + return questions.map( + (question: Question): Question => ({ ...question, published: true }), + ); } /*** From 93cf6088ca78d2ad5b4a53f430f83cd4c99b75a2 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 25 Feb 2026 20:49:34 -0500 Subject: [PATCH 75/81] Finish sameType() --- src/nested.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index 575011522c..6687e238b2 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -133,7 +133,9 @@ export function publishAll(questions: Question[]): Question[] { * are the same type. They can be any type, as long as they are all the SAME type. */ export function sameType(questions: Question[]): boolean { - return false; + return questions.every( + (question: Question): boolean => question.type === questions[0].type, + ); } /*** From 8b2fdf25497792f28d43c17d3e6f63293af27d80 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 25 Feb 2026 20:52:42 -0500 Subject: [PATCH 76/81] Finish addNewQuestion() --- src/nested.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index 6687e238b2..93ad44dda1 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -1,5 +1,6 @@ import { Answer } from "./interfaces/answer"; import { Question, QuestionType } from "./interfaces/question"; +import { makeBlankQuestion } from "./objects"; /** * Consumes an array of questions and returns a new array with only the questions @@ -149,7 +150,8 @@ export function addNewQuestion( name: string, type: QuestionType, ): Question[] { - return []; + const newQuestion: Question = makeBlankQuestion(id, name, type); + return [...questions, newQuestion]; } /*** From 4040f179d6f49fa9354cb2ca1e4b5eaeae5d52d8 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 25 Feb 2026 21:40:57 -0500 Subject: [PATCH 77/81] Finish renameQuestionById() --- src/nested.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index 93ad44dda1..c450e5f1e7 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -164,7 +164,14 @@ export function renameQuestionById( targetId: number, newName: string, ): Question[] { - return []; + const targetIndex: number = questions.findIndex( + (question: Question): boolean => question.id === targetId, + ); + const questionsCopy: Question[] = questions.map( + (question: Question): Question => ({ ...question }), + ); + questionsCopy[targetIndex].name = newName; + return questionsCopy; } /*** From 253897e228c212e792638989200fbe28a8baf0a9 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Wed, 25 Feb 2026 21:47:11 -0500 Subject: [PATCH 78/81] Finish changeQuestionTypeById() --- src/nested.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/nested.ts b/src/nested.ts index c450e5f1e7..7923f7efc8 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -186,7 +186,18 @@ export function changeQuestionTypeById( targetId: number, newQuestionType: QuestionType, ): Question[] { - return []; + const targetIndex: number = questions.findIndex( + (question: Question): boolean => question.id === targetId, + ); + const questionsCopy: Question[] = questions.map( + (question: Question): Question => ({ ...question }), + ); + questionsCopy[targetIndex].options = + newQuestionType === "short_answer_question" ? + [] + : questionsCopy[targetIndex].options; + questionsCopy[targetIndex].type = newQuestionType; + return questionsCopy; } /** From cd21d81be9736edd8f4cde1c63d5ef8e3156a6e1 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Fri, 27 Feb 2026 15:40:54 -0500 Subject: [PATCH 79/81] Finish duplicateQuestionInArray() --- src/nested.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/nested.ts b/src/nested.ts index 7923f7efc8..21a5682cb2 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -1,6 +1,6 @@ import { Answer } from "./interfaces/answer"; import { Question, QuestionType } from "./interfaces/question"; -import { makeBlankQuestion } from "./objects"; +import { makeBlankQuestion, duplicateQuestion } from "./objects"; /** * Consumes an array of questions and returns a new array with only the questions @@ -216,7 +216,9 @@ export function editOption( targetOptionIndex: number, newOption: string, ): Question[] { - return []; + const targetQuestion = questions.find( + (question: Question): boolean => question.id === targetId, + ); } /*** @@ -230,5 +232,17 @@ export function duplicateQuestionInArray( targetId: number, newId: number, ): Question[] { - return []; + const targetQuestion: Question | undefined = questions.find( + (question: Question): boolean => question.id === targetId, + ); + const duplicatequestion: Question = duplicateQuestion( + newId, + targetQuestion!, + ); + const origQuestionIndex: number = questions.findIndex( + (question: Question): boolean => question.id === targetId, + ); + const newArr = [...questions]; + newArr.splice(origQuestionIndex + 1, 0, duplicatequestion); + return newArr; } From 3991aea0f9c659d4a047fea333ddbd822db21f6f Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sat, 28 Feb 2026 20:54:52 -0500 Subject: [PATCH 80/81] Finish editOption() --- src/nested.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/nested.ts b/src/nested.ts index 21a5682cb2..5decb9132b 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -219,6 +219,34 @@ export function editOption( const targetQuestion = questions.find( (question: Question): boolean => question.id === targetId, ); + + // if (targetOptionIndex === -1) { + // targetQuestion!.options = [...targetQuestion!.options, newOption]; + // } else { + // targetQuestion!.options.splice(targetOptionIndex, 1, newOption); + // } + + // return questions.map( + // (question: Question): Question => + // question.id === targetId ? targetQuestion! : question, + // ); + + let targetQuestionOptions: string[] = []; + if (targetOptionIndex === -1) { + targetQuestionOptions = [...targetQuestion!.options, newOption]; + } else { + targetQuestionOptions = [...targetQuestion!.options]; + targetQuestionOptions.splice(targetOptionIndex, 1, newOption); + } + + const newOptionQuestion: Question = { + ...targetQuestion!, + options: targetQuestionOptions, + }; + return questions.map( + (question: Question): Question => + question.id === targetId ? newOptionQuestion : question, + ); } /*** @@ -242,6 +270,7 @@ export function duplicateQuestionInArray( const origQuestionIndex: number = questions.findIndex( (question: Question): boolean => question.id === targetId, ); + const newArr = [...questions]; newArr.splice(origQuestionIndex + 1, 0, duplicatequestion); return newArr; From 9a7d427c529a2b8ff88b7a39cbc86afe717e6ca7 Mon Sep 17 00:00:00 2001 From: jacobdonn Date: Sat, 28 Feb 2026 21:23:53 -0500 Subject: [PATCH 81/81] Finish toCSV() --- src/nested.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/nested.ts b/src/nested.ts index 5decb9132b..7811e3fcc5 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -100,7 +100,14 @@ id,name,options,points,published * Check the unit tests for more examples! */ export function toCSV(questions: Question[]): string { - const finalStr: string = "id,name,options,points,published\n"; + const top: string = "id,name,options,points,published\n"; + const data: string[] = questions.map( + (question: Question): string => + `${question.id},${question.name},${question.options.length},${question.points},${question.published}\n`, + ); + + const final: string[] = [top, ...data]; + return final.join("").slice(0, -1); } /** @@ -220,17 +227,6 @@ export function editOption( (question: Question): boolean => question.id === targetId, ); - // if (targetOptionIndex === -1) { - // targetQuestion!.options = [...targetQuestion!.options, newOption]; - // } else { - // targetQuestion!.options.splice(targetOptionIndex, 1, newOption); - // } - - // return questions.map( - // (question: Question): Question => - // question.id === targetId ? targetQuestion! : question, - // ); - let targetQuestionOptions: string[] = []; if (targetOptionIndex === -1) { targetQuestionOptions = [...targetQuestion!.options, newOption];