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",
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/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.
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/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/App.css b/src/App.css
index ad32fac073..5dd9b895b5 100644
--- a/src/App.css
+++ b/src/App.css
@@ -15,7 +15,7 @@
.App-header {
width: 100%;
- background-color: #282c34;
+ background-color: #7f00ff;
min-height: 40vh;
display: flex;
flex-direction: column;
diff --git a/src/App.tsx b/src/App.tsx
index a8b41197f2..1192e1dd24 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,16 +1,49 @@
import React from "react";
import "./App.css";
+import { Button, Col, Container, Row } from "react-bootstrap";
function App(): React.JSX.Element {
+ const rectangleStyle = {
+ width: "50%",
+ height: "100px",
+ backgroundColor: "red",
+ };
+
return (
- UM COS420 with React Hooks and TypeScript
+ Noah Moring is Doing This Thing.
UM COS420 with React
+ Hooks and TypeScript
-
- Edit src/App.tsx
and save. This page will
- automatically reload.
-
+
+
+
+
+
+ Edit src/App.tsx
and save. This page
+ will automatically reload. Noah Moring Hello World
+
+
+ - This is element one
+ - This is element two
+ - This is element three
+
+
+
+
+
+
+
+
);
}
diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx
new file mode 100644
index 0000000000..320cb97524
--- /dev/null
+++ b/src/HtmlCss.test.tsx
@@ -0,0 +1,83 @@
+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("(2 pts) There is a header", () => {
+ render();
+ const header = screen.getByRole("heading");
+ expect(header).toBeInTheDocument();
+ });
+
+ test("(2 pts) There is an image with alt text", () => {
+ render();
+ const image = screen.getByRole("img");
+ expect(image).toBeInTheDocument();
+ expect(image).toHaveAttribute("alt");
+ });
+
+ test("(2 pts) 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("(2 pts) Some basic CSS is added.", () => {
+ 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("(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 });
+ expect(button).toBeInTheDocument();
+ expect(button).toHaveClass("btn");
+ expect(button).toHaveClass("btn-primary");
+ });
+
+ 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("(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 });
+ userEvent.click(button);
+ expect(consoleSpy).toHaveBeenCalledWith("Hello World!");
+ });
+});
+
+describe("Some additional CSS was added", () => {
+ 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("*");
+
+ // 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);
+ });
+});
diff --git a/src/arrays.test.ts b/src/arrays.test.ts
new file mode 100644
index 0000000000..c2847517bd
--- /dev/null
+++ b/src/arrays.test.ts
@@ -0,0 +1,273 @@
+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("(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]);
+ expect(bookEndList(NUMBERS_4)).toEqual([]);
+ expect(bookEndList(NUMBERS_5)).toEqual([100, 3]);
+ expect(bookEndList(NUMBERS_6)).toEqual([-100, 200]);
+ });
+
+ 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]);
+ 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("(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]);
+ 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("(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]);
+ 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("(3 pts) 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("(3 pts) 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("(3 pts) 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("(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");
+ expect(makeMath(NUMBERS_4)).toEqual("0=0");
+ expect(makeMath(NUMBERS_7)).toEqual("1000=199+1+550+50+200");
+ });
+
+ //////////////////////////////////
+ // injectPositive
+ 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]);
+ 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]);
+ });
+});
diff --git a/src/arrays.ts b/src/arrays.ts
new file mode 100644
index 0000000000..586cf1ab06
--- /dev/null
+++ b/src/arrays.ts
@@ -0,0 +1,120 @@
+/**
+ * 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[] {
+ if (numbers.length === 0) {
+ return [];
+ } else if (numbers.length === 1) {
+ return [numbers[0], numbers[0]];
+ } else {
+ return [numbers[0], numbers[numbers.length - 1]];
+ }
+}
+
+/**
+ * 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.map((n: number): number => n * 3);
+}
+
+/**
+ * Consume an array of strings and convert them to integers. If
+ * the number cannot be parsed as an integer, convert it to 0 instead.
+ */
+export function stringsToIntegers(numbers: string[]): number[] {
+ return numbers.map((s: string): number =>
+ isNaN(parseInt(s)) ? 0 : parseInt(s)
+ );
+}
+
+/**
+ * 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 0 instead.
+ */
+// Remember, you can write functions as lambdas too! They work exactly the same.
+export const removeDollars = (amounts: string[]): number[] => {
+ return amounts.map((s: string): number => {
+ const noDollar = s.startsWith("$") ? s.slice(1) : s;
+ const parsed = parseInt(noDollar);
+ return isNaN(parsed) ? 0 : parsed;
+ });
+};
+
+/**
+ * Consume an array of messages and return a new list of the messages. However, any
+ * string that ends in "!" should be made uppercase. Also, remove any strings that end
+ * in question marks ("?").
+ */
+export const shoutIfExclaiming = (messages: string[]): string[] => {
+ return messages
+ .filter((msg: string): boolean => !msg.endsWith("?"))
+ .map((msg: string): string =>
+ msg.endsWith("!") ? msg.toUpperCase() : msg
+ );
+};
+
+/**
+ * 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 words.filter((w: string): boolean => w.length < 4).length;
+}
+
+/**
+ * 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 colors.every((color: string): boolean =>
+ ["red", "green", "blue"].includes(color)
+ );
+}
+
+/**
+ * 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".
+ * And the array [] would become "0=0".
+ */
+export function makeMath(addends: number[]): string {
+ if (addends.length === 0) {
+ return "0=0";
+ }
+ const sum = addends.reduce((total: number, n: number): number => total + n, 0);
+ const expr = addends.join("+");
+ return `${sum}=${expr}`;
+}
+
+/**
+ * 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
+ * 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, 7, 17]
+ */
+export function injectPositive(values: number[]): number[] {
+ const firstNegativeIndex = values.findIndex((n: number) => n < 0);
+ const sumBeforeNegative = values
+ .slice(0, firstNegativeIndex === -1 ? values.length : firstNegativeIndex)
+ .reduce((total: number, n: number): number => total + n, 0);
+
+ if (firstNegativeIndex === -1) {
+ return [...values, sumBeforeNegative];
+ }
+
+ const before = values.slice(0, firstNegativeIndex + 1);
+ const after = values.slice(firstNegativeIndex + 1);
+ return [...before, sumBeforeNegative, ...after];
+}
diff --git a/src/functions.test.ts b/src/functions.test.ts
new file mode 100644
index 0000000000..3d921f5d64
--- /dev/null
+++ b/src/functions.test.ts
@@ -0,0 +1,59 @@
+import {
+ add3,
+ fahrenheitToCelius,
+ shout,
+ isQuestion,
+ convertYesNo,
+} from "./functions";
+
+describe("Testing the basic functions", () => {
+ test("(3 pts) 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);
+ });
+
+ 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);
+ expect(add3(10, 1, -9)).toBe(11);
+ expect(add3(-9, -100, -4)).toBe(0);
+ expect(add3(-1, -1, 1)).toBe(1);
+ });
+
+ test("(3 pts) 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!");
+ });
+
+ 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);
+ 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);
+ });
+
+ test("(3 pts) 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..492b31855f
--- /dev/null
+++ b/src/functions.ts
@@ -0,0 +1,72 @@
+/**
+ * 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 ((temperature - 32) * 5) / 9;
+}
+
+/**
+ * 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 {
+ let total = 0;
+ if (first < 0) {
+ first = 0;
+ total += first;
+ } else {
+ total += first;
+ }
+ if (second < 0) {
+ second = 0;
+ total += second;
+ } else {
+ total += second;
+ }
+ if (third < 0) {
+ third = 0;
+ total += third;
+ } else {
+ total += third;
+ }
+
+ return total;
+
+}
+
+/**
+ * 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 message.toUpperCase() + "!";
+}
+
+/**
+ * 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 /\?$/.test(message) ? true : false;
+}
+
+/**
+ * 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 {
+ const yLetter = ["YES", "yes"];
+ const nLetter = ["NO", "no"];
+
+ if (yLetter[0] === word || yLetter[1] === word) {
+ return true;
+ } else if (nLetter[0] === word || nLetter[1] === word) {
+ return false;
+ } else {
+ return null;
+ }
+
+}
diff --git a/src/text.test.tsx b/src/text.test.tsx
new file mode 100644
index 0000000000..f99a063e76
--- /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 texts = screen.getAllByText(/Hello World/);
+ expect(texts.length).toBeGreaterThanOrEqual(1);
+});