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/90] 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/90] 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/90] 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 986b28ac0afb41e603602013f71e6ef6e257c722 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 2 Feb 2022 13:12:40 -0500 Subject: [PATCH 04/90] 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 e6b1dab1961daf6f03459789cef974bf043501f2 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 3 Feb 2022 14:10:55 -0500 Subject: [PATCH 05/90] 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 2c852d620be705187b5ade2a68df632c6d6d4256 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 6 Feb 2022 18:33:46 -0500 Subject: [PATCH 06/90] 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 dc3662af02ffe003b2044d4262bddf02ad6c7333 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 8 Feb 2022 00:36:21 -0500 Subject: [PATCH 07/90] 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 51221ee3f303c4927f4efd8f4e286c754cb7b006 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Tue, 8 Feb 2022 00:36:37 -0500 Subject: [PATCH 08/90] 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 3a793cc12152d73df161d3a61691f72d1dc6dde8 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:20:35 -0500 Subject: [PATCH 09/90] 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 5c39a97a647cd7e5d686beda8208a81e5f339478 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:20:46 -0500 Subject: [PATCH 10/90] 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 6ae0b6f210c37a37dace7b94ef0fc5c0b8fbcbfb Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:21:43 -0500 Subject: [PATCH 11/90] 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 b1bbbc869d8093ca9e286df1330ab150e7d4901d Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 13:22:01 -0500 Subject: [PATCH 12/90] 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 ab9bfb53c8eb4842f3149957337db26e621eff2c Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 18:10:22 -0500 Subject: [PATCH 13/90] Basic starter files for components --- src/App.tsx | 18 +++++++++++++++--- src/components/ChangeType.tsx | 5 +++++ src/components/CycleHoliday.tsx | 5 +++++ src/components/RevealAnswer.tsx | 5 +++++ src/components/StartAttempt.tsx | 5 +++++ src/components/TwoDice.tsx | 5 +++++ 6 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/components/ChangeType.tsx create mode 100644 src/components/CycleHoliday.tsx create mode 100644 src/components/RevealAnswer.tsx create mode 100644 src/components/StartAttempt.tsx create mode 100644 src/components/TwoDice.tsx diff --git a/src/App.tsx b/src/App.tsx index e4f028fd06..0c973b1754 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,10 @@ import React from "react"; import "./App.css"; +import { ChangeType } from "./components/ChangeType"; +import { RevealAnswer } from "./components/RevealAnswer"; +import { StartAttempt } from "./components/StartAttempt"; +import { TwoDice } from "./components/TwoDice"; +import { CycleHoliday } from "./components/CycleHoliday"; function App(): JSX.Element { return ( @@ -7,9 +12,16 @@ function App(): JSX.Element {
UD CISC275 with React Hooks and TypeScript
-

- Edit src/App.tsx and save to reload. -

+
+ +
+ +
+ +
+ +
+ ); } diff --git a/src/components/ChangeType.tsx b/src/components/ChangeType.tsx new file mode 100644 index 0000000000..9a856820c4 --- /dev/null +++ b/src/components/ChangeType.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export function ChangeType(): JSX.Element { + return
Change Type
; +} diff --git a/src/components/CycleHoliday.tsx b/src/components/CycleHoliday.tsx new file mode 100644 index 0000000000..b3d85fa55a --- /dev/null +++ b/src/components/CycleHoliday.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export function CycleHoliday(): JSX.Element { + return
Cycle Holiday
; +} diff --git a/src/components/RevealAnswer.tsx b/src/components/RevealAnswer.tsx new file mode 100644 index 0000000000..6d724c4ccf --- /dev/null +++ b/src/components/RevealAnswer.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export function RevealAnswer(): JSX.Element { + return
Reveal Answer
; +} diff --git a/src/components/StartAttempt.tsx b/src/components/StartAttempt.tsx new file mode 100644 index 0000000000..12786ec0cd --- /dev/null +++ b/src/components/StartAttempt.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export function StartAttempt(): JSX.Element { + return
Start Attempt
; +} diff --git a/src/components/TwoDice.tsx b/src/components/TwoDice.tsx new file mode 100644 index 0000000000..b9a5260966 --- /dev/null +++ b/src/components/TwoDice.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export function TwoDice(): JSX.Element { + return
Two Dice
; +} From 97658638bc1a69bfa9e7a84a90a0307145db7db2 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Wed, 9 Feb 2022 18:30:51 -0500 Subject: [PATCH 14/90] Another extra paren error --- .eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index d5986e4354..36f0947989 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -38,7 +38,8 @@ { "nestedBinaryExpressions": false, "returnAssign": false, - "enforceForArrowConditionals": false + "enforceForArrowConditionals": false, + "ignoreJSX": "all" } ], "brace-style": ["error", "1tbs"], From c0bbc391d8eb1994783a8207e386f45578813333 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sun, 13 Feb 2022 14:38:40 -0500 Subject: [PATCH 15/90] Updated, complete tests for all state components --- src/App.tsx | 3 + src/components/ChangeType.test.tsx | 53 ++++++++ src/components/ChangeType.tsx | 4 +- src/components/Counter.test.tsx | 39 ++++++ src/components/Counter.tsx | 12 ++ src/components/CycleHoliday.test.tsx | 55 ++++++++ src/components/CycleHoliday.tsx | 3 +- src/components/RevealAnswer.test.tsx | 36 +++++ src/components/RevealAnswer.tsx | 3 +- src/components/StartAttempt.test.tsx | 196 +++++++++++++++++++++++++++ src/components/StartAttempt.tsx | 3 +- src/components/TwoDice.test.tsx | 140 +++++++++++++++++++ src/components/TwoDice.tsx | 13 +- 13 files changed, 555 insertions(+), 5 deletions(-) create mode 100644 src/components/ChangeType.test.tsx create mode 100644 src/components/Counter.test.tsx create mode 100644 src/components/Counter.tsx create mode 100644 src/components/CycleHoliday.test.tsx create mode 100644 src/components/RevealAnswer.test.tsx create mode 100644 src/components/StartAttempt.test.tsx create mode 100644 src/components/TwoDice.test.tsx diff --git a/src/App.tsx b/src/App.tsx index 0c973b1754..504138f1c3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { RevealAnswer } from "./components/RevealAnswer"; import { StartAttempt } from "./components/StartAttempt"; import { TwoDice } from "./components/TwoDice"; import { CycleHoliday } from "./components/CycleHoliday"; +import { Counter } from "./components/Counter"; function App(): JSX.Element { return ( @@ -12,6 +13,8 @@ function App(): JSX.Element {
UD CISC275 with React Hooks and TypeScript
+
+

diff --git a/src/components/ChangeType.test.tsx b/src/components/ChangeType.test.tsx new file mode 100644 index 0000000000..10b4f0dc3c --- /dev/null +++ b/src/components/ChangeType.test.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { ChangeType } from "./ChangeType"; + +describe("ChangeType Component tests", () => { + beforeEach(() => { + render(); + }); + test("The initial type is Short Answer", () => { + // We use `getByText` because the text MUST be there + const typeText = screen.getByText(/Short Answer/i); + expect(typeText).toBeInTheDocument(); + }); + test("The initial type is not Multiple Choice", () => { + // We use `queryByText` because the text might not be there + const typeText = screen.queryByText(/Multiple Choice/i); + expect(typeText).toBeNull(); + }); + + test("There is a button labeled Change Type", () => { + const changeTypeButton = screen.getByRole("button", { + name: /Change Type/i + }); + expect(changeTypeButton).toBeInTheDocument(); + }); + + test("Clicking the button changes the type.", () => { + const changeTypeButton = screen.getByRole("button", { + name: /Change Type/i + }); + changeTypeButton.click(); + // Should be Multiple Choice + const typeTextMC = screen.getByText(/Multiple Choice/i); + expect(typeTextMC).toBeInTheDocument(); + // Should NOT be Short Answer + const typeTextSA = screen.queryByText(/Short Answer/i); + expect(typeTextSA).toBeNull(); + }); + + test("Clicking the button twice keeps the type the same.", () => { + const changeTypeButton = screen.getByRole("button", { + name: /Change Type/i + }); + changeTypeButton.click(); + changeTypeButton.click(); + // Should be Short Answer + const typeTextSA = screen.getByText(/Short Answer/i); + expect(typeTextSA).toBeInTheDocument(); + // Should NOT be Multiple Choice + const typeTextMC = screen.queryByText(/Multiple Choice/i); + expect(typeTextMC).toBeNull(); + }); +}); diff --git a/src/components/ChangeType.tsx b/src/components/ChangeType.tsx index 9a856820c4..5608076f64 100644 --- a/src/components/ChangeType.tsx +++ b/src/components/ChangeType.tsx @@ -1,4 +1,6 @@ -import React from "react"; +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; +import { QuestionType } from "../interfaces/question"; export function ChangeType(): JSX.Element { return
Change Type
; diff --git a/src/components/Counter.test.tsx b/src/components/Counter.test.tsx new file mode 100644 index 0000000000..7a37c46e38 --- /dev/null +++ b/src/components/Counter.test.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { Counter } from "./Counter"; + +describe("Counter Component tests", () => { + beforeEach(() => { + render(); + }); + test("The initial value is 0", () => { + // We use `getByText` because the text MUST be there + const valueText = screen.getByText(/0/i); + expect(valueText).toBeInTheDocument(); + }); + test("The initial value is not 1", () => { + // We use `queryByText` because the text might not be there + const valueText = screen.queryByText(/1/i); + expect(valueText).toBeNull(); + }); + + test("There is a button named Add One", () => { + const addOneButton = screen.getByRole("button", { name: /Add One/i }); + expect(addOneButton).toBeInTheDocument(); + }); + + test("Clicking the button once adds one", () => { + const addOneButton = screen.getByRole("button", { name: /Add One/i }); + addOneButton.click(); + const valueText = screen.getByText(/1/i); + expect(valueText).toBeInTheDocument(); + }); + + test("Clicking the button twice adds two", () => { + const addOneButton = screen.getByRole("button", { name: /Add One/i }); + addOneButton.click(); + addOneButton.click(); + const valueText = screen.getByText(/2/i); + expect(valueText).toBeInTheDocument(); + }); +}); diff --git a/src/components/Counter.tsx b/src/components/Counter.tsx new file mode 100644 index 0000000000..1987698ed1 --- /dev/null +++ b/src/components/Counter.tsx @@ -0,0 +1,12 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +export function Counter(): JSX.Element { + const [value, setValue] = useState(0); + return ( + + + to {value}. + + ); +} diff --git a/src/components/CycleHoliday.test.tsx b/src/components/CycleHoliday.test.tsx new file mode 100644 index 0000000000..145e2cb3c8 --- /dev/null +++ b/src/components/CycleHoliday.test.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { CycleHoliday } from "./CycleHoliday"; + +describe("CycleHoliday Component tests", () => { + beforeEach(() => { + render(); + }); + + test("An initial holiday is displayed", () => { + const initialHoliday = screen.getByText(/Holiday: (.*)/i); + expect(initialHoliday).toBeInTheDocument(); + }); + + test("There are two buttons", () => { + const alphabetButton = screen.getByRole("button", { + name: /Alphabet/i + }); + const yearButton = screen.getByRole("button", { + name: /Year/i + }); + expect(alphabetButton).toBeInTheDocument(); + expect(yearButton).toBeInTheDocument(); + }); + + test("Can cycle through 5 distinct holidays alphabetically", () => { + const alphabetButton = screen.getByRole("button", { + name: /Alphabet/i + }); + const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); + const states: string[] = []; + for (let i = 0; i < 6; i++) { + states.push(initialHoliday.textContent || ""); + alphabetButton.click(); + } + const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); + expect(uniqueStates).toHaveLength(5); + expect(states[0]).toEqual(states[5]); + }); + + test("Can cycle through 5 distinct holidays by year", () => { + const yearButton = screen.getByRole("button", { + name: /Year/i + }); + const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); + const states: string[] = []; + for (let i = 0; i < 6; i++) { + states.push(initialHoliday.textContent || ""); + yearButton.click(); + } + const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); + expect(uniqueStates).toHaveLength(5); + expect(states[0]).toEqual(states[5]); + }); +}); diff --git a/src/components/CycleHoliday.tsx b/src/components/CycleHoliday.tsx index b3d85fa55a..7c671f889f 100644 --- a/src/components/CycleHoliday.tsx +++ b/src/components/CycleHoliday.tsx @@ -1,4 +1,5 @@ -import React from "react"; +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; export function CycleHoliday(): JSX.Element { return
Cycle Holiday
; diff --git a/src/components/RevealAnswer.test.tsx b/src/components/RevealAnswer.test.tsx new file mode 100644 index 0000000000..aa7996e964 --- /dev/null +++ b/src/components/RevealAnswer.test.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { RevealAnswer } from "./RevealAnswer"; + +describe("RevealAnswer Component tests", () => { + beforeEach(() => { + render(); + }); + test("The answer '42' is not visible initially", () => { + const answerText = screen.queryByText(/42/); + expect(answerText).toBeNull(); + }); + test("There is a Reveal Answer button", () => { + const revealButton = screen.getByRole("button", { + name: /Reveal Answer/i + }); + expect(revealButton).toBeInTheDocument(); + }); + test("Clicking Reveal Answer button reveals the '42'", () => { + const revealButton = screen.getByRole("button", { + name: /Reveal Answer/i + }); + revealButton.click(); + const answerText = screen.getByText(/42/); + expect(answerText).toBeInTheDocument(); + }); + test("Clicking Reveal Answer button twice hides the '42'", () => { + const revealButton = screen.getByRole("button", { + name: /Reveal Answer/i + }); + revealButton.click(); + revealButton.click(); + const answerText = screen.queryByText(/42/); + expect(answerText).toBeNull(); + }); +}); diff --git a/src/components/RevealAnswer.tsx b/src/components/RevealAnswer.tsx index 6d724c4ccf..07db6f62d2 100644 --- a/src/components/RevealAnswer.tsx +++ b/src/components/RevealAnswer.tsx @@ -1,4 +1,5 @@ -import React from "react"; +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; export function RevealAnswer(): JSX.Element { return
Reveal Answer
; diff --git a/src/components/StartAttempt.test.tsx b/src/components/StartAttempt.test.tsx new file mode 100644 index 0000000000..3d41c953cf --- /dev/null +++ b/src/components/StartAttempt.test.tsx @@ -0,0 +1,196 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { StartAttempt } from "./StartAttempt"; + +/*** + * Helper function to extract a number from an HTMLElement's textContent. + * + * If you aren't familiar with Regular Expressions: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + */ +export function extractDigits(element: HTMLElement): number | null { + const attemptNumberText = element.textContent || ""; + // We use a "regular expression" to find digits and extract them as text + const attemptNumberDigitsMatched = attemptNumberText.match(/\d+/); + // Provides a Matched Regular Expression or null + if (attemptNumberDigitsMatched === null) { + // Should never be possible, since then there was no number to have found. + // But TypeScript is cautious and demands we provide SOMETHING. + return null; + } else { + // Not null, get the first matched value and convert to number + return parseInt(attemptNumberDigitsMatched[0]); + } +} + +describe("StartAttempt Component tests", () => { + beforeEach(() => { + render(); + }); + test("The Number of attempts is displayed initially, without other numbers", () => { + const attemptNumber = screen.getByText(/(\d+)/); + expect(attemptNumber).toBeInTheDocument(); + }); + test("The Number of attempts is more than 0", () => { + const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber).toBeGreaterThan(0); + }); + test("The Number of attempts is less than 10", () => { + const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber).toBeLessThan(10); + }); + test("There is an initially enabled Start Quiz button", () => { + const startButton = screen.getByRole("button", { name: /Start Quiz/i }); + expect(startButton).toBeInTheDocument(); + expect(startButton).toBeEnabled(); + }); + test("There is an initially disabled Stop Quiz button", () => { + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + expect(stopButton).toBeInTheDocument(); + expect(stopButton).toBeDisabled(); + }); + test("There is an initially enabled Mulligan button", () => { + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + expect(mulliganButton).toBeInTheDocument(); + expect(mulliganButton).toBeEnabled(); + }); + test("Clicking Mulligan increases attempts", () => { + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + mulliganButton.click(); + const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber + 1).toEqual(attemptNumberLater); + }); + test("Clicking Mulligan twice increases attempts by two", () => { + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + mulliganButton.click(); + mulliganButton.click(); + const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber + 2).toEqual(attemptNumberLater); + }); + test("Clicking Start Quiz decreases attempts", () => { + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + startButton.click(); + const attemptNumberLater = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber - 1).toEqual(attemptNumberLater); + }); + test("Clicking Start Quiz changes enabled buttons", () => { + // Given the buttons... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + // When the start button is clicked + startButton.click(); + // Then the start is disabled, stop is enabled, and mulligan is disabled + expect(startButton).toBeDisabled(); + expect(stopButton).toBeEnabled(); + expect(mulliganButton).toBeDisabled(); + }); + test("Clicking Start and Stop Quiz changes enabled buttons", () => { + // Given the buttons and initial attempt number... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + // When we click the start button and then the stop button + startButton.click(); + stopButton.click(); + // Then the start is enabled, stop is disabled, and mulligan is enabled + expect(startButton).toBeEnabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + }); + test("Clicking Start, Stop, Mulligan sets attempts to original", () => { + // Given the buttons and initial attempt number... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + // When we click the start button and then the stop button + startButton.click(); + stopButton.click(); + // Then the attempt is decreased + const attemptNumberLater: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber - 1).toEqual(attemptNumberLater); + // And when we click the mulligan button + mulliganButton.click(); + // Then the attempt is increased back to starting value + const attemptNumberLatest: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber).toEqual(attemptNumberLatest); + }); + test("Cannot click start quiz when out of attempts", () => { + // Given the buttons and initial attempt number... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + let attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; + const initialAttempt = attemptNumber; + // Arbitrary number of times to try clicking; assume we do not have more than that number of attempts. + let maxAttempts = 10; + // While there are still attempts apparently available... + while (attemptNumber > 0) { + // Then the buttons + expect(startButton).toBeEnabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + // And when we Start and then immediately stop the quiz... + startButton.click(); + stopButton.click(); + // Then the number is going down, and doesn't go past 0 somehow + attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber).toBeGreaterThanOrEqual(0); + expect(attemptNumber).not.toEqual(initialAttempt); + // And then the maximum number of attempts does not exceed 10 + maxAttempts -= 1; + expect(maxAttempts).toBeGreaterThanOrEqual(0); + } + // Then the attempt is at zero + expect(attemptNumber).toEqual(0); + // And then the stop button is disabled, the start button is disabled, and mulligan is enabled + expect(startButton).toBeDisabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + // And when we click the mulligan button + mulliganButton.click(); + // Then the attempt is increased back to 1 + const attemptNumberLatest: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumberLatest).toEqual(1); + // And the start button is reenabled + expect(startButton).toBeEnabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + }); +}); diff --git a/src/components/StartAttempt.tsx b/src/components/StartAttempt.tsx index 12786ec0cd..0c0a85fdb6 100644 --- a/src/components/StartAttempt.tsx +++ b/src/components/StartAttempt.tsx @@ -1,4 +1,5 @@ -import React from "react"; +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; export function StartAttempt(): JSX.Element { return
Start Attempt
; diff --git a/src/components/TwoDice.test.tsx b/src/components/TwoDice.test.tsx new file mode 100644 index 0000000000..7996051096 --- /dev/null +++ b/src/components/TwoDice.test.tsx @@ -0,0 +1,140 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { TwoDice } from "./TwoDice"; +import { extractDigits } from "./StartAttempt.test"; + +describe("TwoDice Component tests", () => { + let mathRandomFunction: jest.SpyInstance; + beforeEach(() => { + mathRandomFunction = jest + .spyOn(global.Math, "random") + .mockReturnValue(0.5) // 4 + .mockReturnValueOnce(0.0) // 1 + .mockReturnValueOnce(0.99) // 6 + .mockReturnValueOnce(0.75) // 5 + .mockReturnValueOnce(0.75) // 5 + .mockReturnValueOnce(0.1) // 1 + .mockReturnValueOnce(0.1); // 1 + }); + afterEach(() => { + jest.spyOn(global.Math, "random").mockRestore(); + }); + beforeEach(() => { + render(); + }); + test("There is a `left-die` and `right-die` testid", () => { + const leftDie = screen.getByTestId("left-die"); + const rightDie = screen.getByTestId("right-die"); + expect(leftDie).toBeInTheDocument(); + expect(rightDie).toBeInTheDocument(); + }); + test("The `left-die` and `right-die` are two different numbers", () => { + const leftDie = screen.getByTestId("left-die"); + const rightDie = screen.getByTestId("right-die"); + const leftNumber = extractDigits(leftDie); + const rightNumber = extractDigits(rightDie); + // Then they are two numbers + expect(leftNumber).not.toBeNull(); + expect(rightNumber).not.toBeNull(); + // Then they are two different numbers + expect(leftNumber).not.toEqual(rightNumber); + }); + test("There are two buttons present", () => { + const leftButton = screen.getByRole("button", { name: /Roll Left/i }); + const rightButton = screen.getByRole("button", { name: /Roll Right/i }); + expect(leftButton).toBeInTheDocument(); + expect(rightButton).toBeInTheDocument(); + }); + test("Clicking left button changes first number", () => { + const leftButton = screen.getByRole("button", { name: /Roll Left/i }); + leftButton.click(); + leftButton.click(); + leftButton.click(); + // Then the random function should be called 3 times + expect(mathRandomFunction).toBeCalledTimes(3); + // And the number to be 5 + const leftNumber = extractDigits(screen.getByTestId("left-die")); + expect(leftNumber).toEqual(5); + }); + // Clicking right button changes second number + test("Clicking right button changes second number", () => { + const rightButton = screen.getByRole("button", { name: /Roll Right/i }); + rightButton.click(); + rightButton.click(); + rightButton.click(); + // Then the random function should be called 3 times + expect(mathRandomFunction).toBeCalledTimes(3); + // And the number to be 5 + const rightNumber = extractDigits(screen.getByTestId("right-die")); + expect(rightNumber).toEqual(5); + }); + // Rolling two different numbers does not win or lose the game + test("Rolling two different numbers does not win or lose the game", () => { + // Given + const leftButton = screen.getByRole("button", { name: /Roll Left/i }); + const rightButton = screen.getByRole("button", { name: /Roll Right/i }); + const leftDie = screen.getByTestId("left-die"); + const rightDie = screen.getByTestId("right-die"); + // When the left and right buttons are rolled once each + leftButton.click(); + rightButton.click(); + // Then the numbers are not equal + const leftNumber = extractDigits(leftDie); + const rightNumber = extractDigits(rightDie); + expect(leftNumber).toEqual(1); + expect(rightNumber).toEqual(6); + // And then the game is not won + const winText = screen.queryByText(/Win/i); + expect(winText).toBeNull(); + // And then nor is the game lost + const loseText = screen.queryByText(/Lose/i); + expect(loseText).toBeNull(); + }); + test("Getting snake eyes loses the game", () => { + // Given + const leftButton = screen.getByRole("button", { name: /Roll Left/i }); + const rightButton = screen.getByRole("button", { name: /Roll Right/i }); + const leftDie = screen.getByTestId("left-die"); + const rightDie = screen.getByTestId("right-die"); + // When the left and right buttons are rolled once each + leftButton.click(); + rightButton.click(); + rightButton.click(); + rightButton.click(); + rightButton.click(); + // Then the numbers are not equal + const leftNumber = extractDigits(leftDie); + const rightNumber = extractDigits(rightDie); + expect(leftNumber).toEqual(1); + expect(rightNumber).toEqual(1); + // And then the game is not won + const winText = screen.queryByText(/Win/i); + expect(winText).toBeNull(); + // And then the game is lost + const loseText = screen.getByText(/Lose/i); + expect(loseText).toBeInTheDocument(); + }); + test("Getting matching numbers wins the game", () => { + // Given + const leftButton = screen.getByRole("button", { name: /Roll Left/i }); + const rightButton = screen.getByRole("button", { name: /Roll Right/i }); + const leftDie = screen.getByTestId("left-die"); + const rightDie = screen.getByTestId("right-die"); + // When the left and right buttons are rolled once each + leftButton.click(); + leftButton.click(); + leftButton.click(); + rightButton.click(); + // Then the numbers are not equal + const leftNumber = extractDigits(leftDie); + const rightNumber = extractDigits(rightDie); + expect(leftNumber).toEqual(5); + expect(rightNumber).toEqual(5); + // And then the game is not lost + const loseText = screen.queryByText(/Lose/i); + expect(loseText).toBeNull(); + // And then the game is won + const winText = screen.getByText(/Win/i); + expect(winText).toBeInTheDocument(); + }); +}); diff --git a/src/components/TwoDice.tsx b/src/components/TwoDice.tsx index b9a5260966..372502fe64 100644 --- a/src/components/TwoDice.tsx +++ b/src/components/TwoDice.tsx @@ -1,4 +1,15 @@ -import React from "react"; +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +/** + * Here is a helper function you *must* use to "roll" your die. + * The function uses the builtin `random` function of the `Math` + * module (which returns a random decimal between 0 up until 1) in order + * to produce a random integer between 1 and 6 (inclusive). + */ +export function d6(): number { + return 1 + Math.floor(Math.random() * 6); +} export function TwoDice(): JSX.Element { return
Two Dice
; From eb40f3eb8827e668c1949ca0c9c13db2f52fe4b4 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 19 Feb 2022 13:53:22 -0500 Subject: [PATCH 16/90] Forgot task record for state --- public/tasks/task-state.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 public/tasks/task-state.md diff --git a/public/tasks/task-state.md b/public/tasks/task-state.md new file mode 100644 index 0000000000..ef8197ffcb --- /dev/null +++ b/public/tasks/task-state.md @@ -0,0 +1,5 @@ +# Task - State + +Version: 0.0.1 + +Create some new components that have React State. From 6669ffad92d4bd98218097868d381d9280eb9fca Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 19 Feb 2022 15:23:47 -0500 Subject: [PATCH 17/90] First draft of components subtasks --- public/tasks/task-components.md | 5 +++ src/App.tsx | 12 +++++++ src/bad-components/ColoredBox.tsx | 41 ++++++++++++++++++++++ src/bad-components/DoubleHalf.tsx | 21 +++++++++++ src/bad-components/DoubleHalfState.tsx | 3 ++ src/bad-components/ShoveBox.tsx | 48 ++++++++++++++++++++++++++ src/bad-components/TrackingNumbers.tsx | 38 ++++++++++++++++++++ 7 files changed, 168 insertions(+) create mode 100644 public/tasks/task-components.md create mode 100644 src/bad-components/ColoredBox.tsx create mode 100644 src/bad-components/DoubleHalf.tsx create mode 100644 src/bad-components/DoubleHalfState.tsx create mode 100644 src/bad-components/ShoveBox.tsx create mode 100644 src/bad-components/TrackingNumbers.tsx diff --git a/public/tasks/task-components.md b/public/tasks/task-components.md new file mode 100644 index 0000000000..a6ff48694d --- /dev/null +++ b/public/tasks/task-components.md @@ -0,0 +1,5 @@ +# Task - Components + +Version: 0.0.1 + +Fix some components that are using state incorrectly. diff --git a/src/App.tsx b/src/App.tsx index 504138f1c3..98499aa554 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,10 @@ import { StartAttempt } from "./components/StartAttempt"; import { TwoDice } from "./components/TwoDice"; import { CycleHoliday } from "./components/CycleHoliday"; import { Counter } from "./components/Counter"; +import { DoubleHalf } from "./bad-components/DoubleHalf"; +import { ColoredBox } from "./bad-components/ColoredBox"; +import { ShoveBox } from "./bad-components/ShoveBox"; +import { TrackingNumbers } from "./bad-components/TrackingNumbers"; function App(): JSX.Element { return ( @@ -14,6 +18,14 @@ function App(): JSX.Element { UD CISC275 with React Hooks and TypeScript
+ {/* */} +
+ +
+ +
+ +

diff --git a/src/bad-components/ColoredBox.tsx b/src/bad-components/ColoredBox.tsx new file mode 100644 index 0000000000..622f77fd31 --- /dev/null +++ b/src/bad-components/ColoredBox.tsx @@ -0,0 +1,41 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +export const COLORS = ["red", "blue", "green"]; +const DEFAULT_COLOR_INDEX = 0; + +function ChangeColor(): JSX.Element { + const [colorIndex, setColorIndex] = useState(DEFAULT_COLOR_INDEX); + return ( + + ); +} + +function ColorPreview(): JSX.Element { + return ( +
+ ); +} + +export function ColoredBox(): JSX.Element { + return ( +
+ The current color is: {COLORS[DEFAULT_COLOR_INDEX]} +
+ + +
+
+ ); +} diff --git a/src/bad-components/DoubleHalf.tsx b/src/bad-components/DoubleHalf.tsx new file mode 100644 index 0000000000..a8376dbea2 --- /dev/null +++ b/src/bad-components/DoubleHalf.tsx @@ -0,0 +1,21 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; +import { dhValue, setDhValue } from "./DoubleHalfState"; + +function Doubler(): JSX.Element { + return ; +} + +function Halver(): JSX.Element { + return ; +} + +export function DoubleHalf(): JSX.Element { + return ( +
+ The current value is: {dhValue} + + +
+ ); +} diff --git a/src/bad-components/DoubleHalfState.tsx b/src/bad-components/DoubleHalfState.tsx new file mode 100644 index 0000000000..2b4569a37a --- /dev/null +++ b/src/bad-components/DoubleHalfState.tsx @@ -0,0 +1,3 @@ +import { useState } from "react"; + +export const [dhValue, setDhValue] = useState(10); diff --git a/src/bad-components/ShoveBox.tsx b/src/bad-components/ShoveBox.tsx new file mode 100644 index 0000000000..d0b4ec0561 --- /dev/null +++ b/src/bad-components/ShoveBox.tsx @@ -0,0 +1,48 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +function ShoveBoxButton({ + position, + setPosition +}: { + position: number; + setPosition: (newPosition: number) => void; +}) { + return ( + + ); +} + +function MoveableBox(): JSX.Element { + const [position, setPosition] = useState(10); + return ( +
+ ); +} + +export function ShoveBox(): JSX.Element { + const box = MoveableBox(); + + return ( +
+ {/* The box is at: {box.position} +
+ + {box} +
*/} +
+ ); +} diff --git a/src/bad-components/TrackingNumbers.tsx b/src/bad-components/TrackingNumbers.tsx new file mode 100644 index 0000000000..910e273ed1 --- /dev/null +++ b/src/bad-components/TrackingNumbers.tsx @@ -0,0 +1,38 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +export function TrackingNumbers(): JSX.Element { + const [latestNumber, setLatestNumber] = useState(0); + const [trackedNumbers, setTrackedNumbers] = useState([]); + + function stopTracking(targetNumber: number) { + const withoutNumber = trackedNumbers.filter( + (aNumber: number) => aNumber !== targetNumber + ); + setTrackedNumbers(withoutNumber); + } + + function trackNumber() { + setLatestNumber(1 + latestNumber); + const withNumber = [...trackedNumbers, latestNumber]; + setTrackedNumbers(withNumber); + } + + // Uncomment the below and fix the error! + return ( +
+ {/*
    + {trackedNumbers.map((trackedNumber: number) => ( +
  1. + Tracking {trackedNumber} ( + + ) +
  2. + ))} +
*/} + +
+ ); +} From 562f3067fd1fce48bd3ed2cb4cb6bfe1e24d65f5 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 24 Feb 2022 10:48:53 -0500 Subject: [PATCH 18/90] Another subtask, ChooseTeam --- src/App.tsx | 3 ++ src/bad-components/ChooseTeam.tsx | 54 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/bad-components/ChooseTeam.tsx diff --git a/src/App.tsx b/src/App.tsx index 98499aa554..d4ec176137 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import { DoubleHalf } from "./bad-components/DoubleHalf"; import { ColoredBox } from "./bad-components/ColoredBox"; import { ShoveBox } from "./bad-components/ShoveBox"; import { TrackingNumbers } from "./bad-components/TrackingNumbers"; +import { ChooseTeam } from "./bad-components/ChooseTeam"; function App(): JSX.Element { return ( @@ -20,6 +21,8 @@ function App(): JSX.Element {
{/* */}
+ +

diff --git a/src/bad-components/ChooseTeam.tsx b/src/bad-components/ChooseTeam.tsx new file mode 100644 index 0000000000..f2c3cd49f0 --- /dev/null +++ b/src/bad-components/ChooseTeam.tsx @@ -0,0 +1,54 @@ +import React, { useState } from "react"; +import { Button, Row, Col } from "react-bootstrap"; + +const PEOPLE = [ + "Alan Turing", + "Grace Hopper", + "Ada Lovelace", + "Charles Babbage", + "Barbara Liskov", + "Margaret Hamilton" +]; + +export function ChooseTeam(): JSX.Element { + const [allOptions, setAllOptions] = useState(PEOPLE); + const [team, setTeam] = useState([]); + + function chooseMember() { + /* + if (!team.includes(newMember)) { + team.push(newMember); + } + */ + } + + function clearTeam() { + /* + team = []; + */ + } + + return ( +
+ + + {allOptions.map((option: string) => ( +
+ Add{" "} + +
+ ))} + + + Team: + {team.map((member: string) => ( +
  • {member}
  • + ))} + + +
    +
    + ); +} From 4a34f5fa59524db440c37c83f2edcbb1b640096c Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 24 Feb 2022 11:33:41 -0500 Subject: [PATCH 19/90] Oops order out of operations --- src/bad-components/ColoredBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bad-components/ColoredBox.tsx b/src/bad-components/ColoredBox.tsx index 622f77fd31..5e2a9f7ac8 100644 --- a/src/bad-components/ColoredBox.tsx +++ b/src/bad-components/ColoredBox.tsx @@ -7,7 +7,7 @@ const DEFAULT_COLOR_INDEX = 0; function ChangeColor(): JSX.Element { const [colorIndex, setColorIndex] = useState(DEFAULT_COLOR_INDEX); return ( - ); From 7327f4c2f93d210353eba03e002770d1d6503174 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 24 Feb 2022 11:41:03 -0500 Subject: [PATCH 20/90] Add headers to each subtask --- src/bad-components/ChooseTeam.tsx | 1 + src/bad-components/ColoredBox.tsx | 1 + src/bad-components/DoubleHalf.tsx | 1 + src/bad-components/ShoveBox.tsx | 1 + src/bad-components/TrackingNumbers.tsx | 1 + 5 files changed, 5 insertions(+) diff --git a/src/bad-components/ChooseTeam.tsx b/src/bad-components/ChooseTeam.tsx index f2c3cd49f0..c02334e661 100644 --- a/src/bad-components/ChooseTeam.tsx +++ b/src/bad-components/ChooseTeam.tsx @@ -30,6 +30,7 @@ export function ChooseTeam(): JSX.Element { return (
    +

    Choose Team

    {allOptions.map((option: string) => ( diff --git a/src/bad-components/ColoredBox.tsx b/src/bad-components/ColoredBox.tsx index 5e2a9f7ac8..0a5bb83d96 100644 --- a/src/bad-components/ColoredBox.tsx +++ b/src/bad-components/ColoredBox.tsx @@ -31,6 +31,7 @@ function ColorPreview(): JSX.Element { export function ColoredBox(): JSX.Element { return (
    +

    Colored Box

    The current color is: {COLORS[DEFAULT_COLOR_INDEX]}
    diff --git a/src/bad-components/DoubleHalf.tsx b/src/bad-components/DoubleHalf.tsx index a8376dbea2..f3871eeec6 100644 --- a/src/bad-components/DoubleHalf.tsx +++ b/src/bad-components/DoubleHalf.tsx @@ -13,6 +13,7 @@ function Halver(): JSX.Element { export function DoubleHalf(): JSX.Element { return (
    +

    Double Half

    The current value is: {dhValue} diff --git a/src/bad-components/ShoveBox.tsx b/src/bad-components/ShoveBox.tsx index d0b4ec0561..910aca490b 100644 --- a/src/bad-components/ShoveBox.tsx +++ b/src/bad-components/ShoveBox.tsx @@ -35,6 +35,7 @@ export function ShoveBox(): JSX.Element { return (
    +

    Shove Box

    {/* The box is at: {box.position}
    +

    Tracking Numbers

    {/*
      {trackedNumbers.map((trackedNumber: number) => (
    1. From cf7c212a6631e9ef7c9f9c4b4dfd5d3cac72acb5 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 24 Feb 2022 13:00:45 -0500 Subject: [PATCH 21/90] Make testing easier for these components --- src/bad-components/ColoredBox.tsx | 1 + src/bad-components/DoubleHalf.tsx | 4 +++- src/bad-components/ShoveBox.tsx | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bad-components/ColoredBox.tsx b/src/bad-components/ColoredBox.tsx index 0a5bb83d96..a3c3c3f077 100644 --- a/src/bad-components/ColoredBox.tsx +++ b/src/bad-components/ColoredBox.tsx @@ -16,6 +16,7 @@ function ChangeColor(): JSX.Element { function ColorPreview(): JSX.Element { return (

      Double Half

      - The current value is: {dhValue} +
      + The current value is: {dhValue} +
      diff --git a/src/bad-components/ShoveBox.tsx b/src/bad-components/ShoveBox.tsx index 910aca490b..7c55142636 100644 --- a/src/bad-components/ShoveBox.tsx +++ b/src/bad-components/ShoveBox.tsx @@ -17,6 +17,7 @@ function MoveableBox(): JSX.Element { const [position, setPosition] = useState(10); return (
      Date: Thu, 24 Feb 2022 13:01:04 -0500 Subject: [PATCH 22/90] Ugh this component is stupid, let's just forget about it for now --- src/App.tsx | 3 -- src/bad-components/TrackingNumbers.tsx | 39 -------------------------- 2 files changed, 42 deletions(-) delete mode 100644 src/bad-components/TrackingNumbers.tsx diff --git a/src/App.tsx b/src/App.tsx index d4ec176137..e09c26ec76 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,6 @@ import { Counter } from "./components/Counter"; import { DoubleHalf } from "./bad-components/DoubleHalf"; import { ColoredBox } from "./bad-components/ColoredBox"; import { ShoveBox } from "./bad-components/ShoveBox"; -import { TrackingNumbers } from "./bad-components/TrackingNumbers"; import { ChooseTeam } from "./bad-components/ChooseTeam"; function App(): JSX.Element { @@ -27,8 +26,6 @@ function App(): JSX.Element {

      - -

      diff --git a/src/bad-components/TrackingNumbers.tsx b/src/bad-components/TrackingNumbers.tsx deleted file mode 100644 index 70a9a7c7de..0000000000 --- a/src/bad-components/TrackingNumbers.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { useState } from "react"; -import { Button } from "react-bootstrap"; - -export function TrackingNumbers(): JSX.Element { - const [latestNumber, setLatestNumber] = useState(0); - const [trackedNumbers, setTrackedNumbers] = useState([]); - - function stopTracking(targetNumber: number) { - const withoutNumber = trackedNumbers.filter( - (aNumber: number) => aNumber !== targetNumber - ); - setTrackedNumbers(withoutNumber); - } - - function trackNumber() { - setLatestNumber(1 + latestNumber); - const withNumber = [...trackedNumbers, latestNumber]; - setTrackedNumbers(withNumber); - } - - // Uncomment the below and fix the error! - return ( -
      -

      Tracking Numbers

      - {/*
        - {trackedNumbers.map((trackedNumber: number) => ( -
      1. - Tracking {trackedNumber} ( - - ) -
      2. - ))} -
      */} - -
      - ); -} From 89053a45855b254fb0363d8f002ac5535524e77f Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Thu, 24 Feb 2022 13:03:58 -0500 Subject: [PATCH 23/90] Provide the tests for the bad components --- src/bad-components/ChooseTeam.test.tsx | 61 ++++++++++++++++++++++++++ src/bad-components/ColoredBox.test.tsx | 31 +++++++++++++ src/bad-components/DoubleHalf.test.tsx | 56 +++++++++++++++++++++++ src/bad-components/ShoveBox.test.tsx | 31 +++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 src/bad-components/ChooseTeam.test.tsx create mode 100644 src/bad-components/ColoredBox.test.tsx create mode 100644 src/bad-components/DoubleHalf.test.tsx create mode 100644 src/bad-components/ShoveBox.test.tsx diff --git a/src/bad-components/ChooseTeam.test.tsx b/src/bad-components/ChooseTeam.test.tsx new file mode 100644 index 0000000000..f11465a2d6 --- /dev/null +++ b/src/bad-components/ChooseTeam.test.tsx @@ -0,0 +1,61 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { ChooseTeam } from "./ChooseTeam"; + +describe("ChooseTeam Component tests", () => { + beforeEach(() => { + render(); + }); + test("The initial team is empty", () => { + const currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(0); + }); + test("There are 7 buttons.", () => { + const adders = screen.queryAllByRole("button"); + expect(adders).toHaveLength(7); + }); + test("Clicking first team member works", () => { + const first = screen.queryAllByRole("button")[0]; + first.click(); + const currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(1); + expect(currentTeam[0].textContent).toEqual(first.textContent); + }); + test("Clicking the third team member works", () => { + const third = screen.queryAllByRole("button")[2]; + third.click(); + const currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(1); + expect(currentTeam[0].textContent).toEqual(third.textContent); + }); + test("Clicking three team members works", () => { + const [, second, third, , fifth] = screen.queryAllByRole("button"); + third.click(); + second.click(); + fifth.click(); + const currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(3); + expect(currentTeam[0].textContent).toEqual(third.textContent); + expect(currentTeam[1].textContent).toEqual(second.textContent); + expect(currentTeam[2].textContent).toEqual(fifth.textContent); + }); + test("Clearing the team works", () => { + const [, second, third, fourth, fifth, , clear] = + screen.queryAllByRole("button"); + third.click(); + second.click(); + fifth.click(); + let currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(3); + expect(currentTeam[0].textContent).toEqual(third.textContent); + expect(currentTeam[1].textContent).toEqual(second.textContent); + expect(currentTeam[2].textContent).toEqual(fifth.textContent); + clear.click(); + currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(0); + fourth.click(); + currentTeam = screen.queryAllByRole("listitem"); + expect(currentTeam).toHaveLength(1); + expect(currentTeam[0].textContent).toEqual(fourth.textContent); + }); +}); diff --git a/src/bad-components/ColoredBox.test.tsx b/src/bad-components/ColoredBox.test.tsx new file mode 100644 index 0000000000..c17a13f66c --- /dev/null +++ b/src/bad-components/ColoredBox.test.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { ColoredBox } from "./ColoredBox"; + +describe("ColoredBox Component tests", () => { + beforeEach(() => { + render(); + }); + test("The ColoredBox is initially red.", () => { + const box = screen.getByTestId("colored-box"); + expect(box).toHaveStyle({ backgroundColor: "red" }); + }); + test("There is a button", () => { + expect(screen.getByRole("button")).toBeInTheDocument(); + }); + test("Clicking the button advances the color.", () => { + const nextColor = screen.getByRole("button"); + nextColor.click(); + expect(screen.getByTestId("colored-box")).toHaveStyle({ + backgroundColor: "blue" + }); + nextColor.click(); + expect(screen.getByTestId("colored-box")).toHaveStyle({ + backgroundColor: "green" + }); + nextColor.click(); + expect(screen.getByTestId("colored-box")).toHaveStyle({ + backgroundColor: "red" + }); + }); +}); diff --git a/src/bad-components/DoubleHalf.test.tsx b/src/bad-components/DoubleHalf.test.tsx new file mode 100644 index 0000000000..cbae5f68af --- /dev/null +++ b/src/bad-components/DoubleHalf.test.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { DoubleHalf } from "./DoubleHalf"; + +describe("DoubleHalf Component tests", () => { + beforeEach(() => { + render(); + }); + test("The DoubleHalf value is initially 10", () => { + expect(screen.getByText("10")).toBeInTheDocument(); + expect(screen.queryByText("20")).not.toBeInTheDocument(); + expect(screen.queryByText("5")).not.toBeInTheDocument(); + }); + test("There are Double and Halve buttons", () => { + expect( + screen.getByRole("button", { name: /Double/i }) + ).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: /Halve/i }) + ).toBeInTheDocument(); + }); + test("You can double the number.", () => { + const double = screen.getByRole("button", { name: /Double/i }); + double.click(); + expect(screen.getByText("20")).toBeInTheDocument(); + expect(screen.queryByText("10")).not.toBeInTheDocument(); + }); + test("You can halve the number.", () => { + const halve = screen.getByRole("button", { name: /Halve/i }); + halve.click(); + expect(screen.getByText("5")).toBeInTheDocument(); + expect(screen.queryByText("10")).not.toBeInTheDocument(); + }); + test("You can double AND halve the number.", () => { + const double = screen.getByRole("button", { name: /Double/i }); + const halve = screen.getByRole("button", { name: /Halve/i }); + double.click(); + expect(screen.getByText("20")).toBeInTheDocument(); + expect(screen.queryByText("10")).not.toBeInTheDocument(); + double.click(); + expect(screen.getByText("40")).toBeInTheDocument(); + expect(screen.queryByText("20")).not.toBeInTheDocument(); + halve.click(); + expect(screen.getByText("20")).toBeInTheDocument(); + expect(screen.queryByText("10")).not.toBeInTheDocument(); + halve.click(); + expect(screen.getByText("10")).toBeInTheDocument(); + expect(screen.queryByText("20")).not.toBeInTheDocument(); + halve.click(); + expect(screen.getByText("5")).toBeInTheDocument(); + expect(screen.queryByText("10")).not.toBeInTheDocument(); + halve.click(); + expect(screen.getByText("2.5")).toBeInTheDocument(); + expect(screen.queryByText("5")).not.toBeInTheDocument(); + }); +}); diff --git a/src/bad-components/ShoveBox.test.tsx b/src/bad-components/ShoveBox.test.tsx new file mode 100644 index 0000000000..2adec13d4e --- /dev/null +++ b/src/bad-components/ShoveBox.test.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { ShoveBox } from "./ShoveBox"; + +describe("ShoveBox Component tests", () => { + beforeEach(() => { + render(); + }); + test("The MoveableBox is initially nearby.", () => { + const box = screen.getByTestId("moveable-box"); + expect(box).toHaveStyle({ marginLeft: "10px" }); + }); + test("There is a button", () => { + expect(screen.getByRole("button")).toBeInTheDocument(); + }); + test("Clicking the button moves the box.", () => { + const shoveBox = screen.getByRole("button"); + shoveBox.click(); + expect(screen.getByTestId("moveable-box")).toHaveStyle({ + marginLeft: "14px" + }); + shoveBox.click(); + expect(screen.getByTestId("moveable-box")).toHaveStyle({ + marginLeft: "18px" + }); + shoveBox.click(); + expect(screen.getByTestId("moveable-box")).toHaveStyle({ + marginLeft: "22px" + }); + }); +}); From 7a207345d9e404afd04607811b89bb758de02905 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 12:52:12 -0400 Subject: [PATCH 24/90] 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 25/90] 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 26/90] 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 27/90] 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 28/90] 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 29/90] 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 30/90] 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 31/90] 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 32/90] 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 33/90] 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 34/90] 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 35/90] 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 36/90] 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 37/90] 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 38/90] 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 39/90] 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 40/90] 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 41/90] 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 42/90] 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 43/90] 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 44/90] 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 45/90] 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 46/90] 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 47/90] 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 48/90] 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 49/90] 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 50/90] 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 51/90] 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 52/90] 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 53/90] 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 54/90] 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 55/90] 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 56/90] 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 57/90] 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 58/90] 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 59/90] 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 60/90] 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 61/90] 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 62/90] 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 23314f383f4ac6257b7c904bfff21496bf743a68 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:41:03 -0400 Subject: [PATCH 63/90] update point values for tests --- src/components/ChangeType.test.tsx | 10 +++++----- src/components/Counter.test.tsx | 10 +++++----- src/components/CycleHoliday.test.tsx | 8 ++++---- src/components/RevealAnswer.test.tsx | 8 ++++---- src/components/StartAttempt.test.tsx | 26 +++++++++++++------------- src/components/TwoDice.test.tsx | 16 ++++++++-------- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/components/ChangeType.test.tsx b/src/components/ChangeType.test.tsx index 10b4f0dc3c..ef7ea4b66e 100644 --- a/src/components/ChangeType.test.tsx +++ b/src/components/ChangeType.test.tsx @@ -6,25 +6,25 @@ describe("ChangeType Component tests", () => { beforeEach(() => { render(); }); - test("The initial type is Short Answer", () => { + test("(1 pts) The initial type is Short Answer", () => { // We use `getByText` because the text MUST be there const typeText = screen.getByText(/Short Answer/i); expect(typeText).toBeInTheDocument(); }); - test("The initial type is not Multiple Choice", () => { + test("(1 pts) The initial type is not Multiple Choice", () => { // We use `queryByText` because the text might not be there const typeText = screen.queryByText(/Multiple Choice/i); expect(typeText).toBeNull(); }); - test("There is a button labeled Change Type", () => { + test("(1 pts) There is a button labeled Change Type", () => { const changeTypeButton = screen.getByRole("button", { name: /Change Type/i }); expect(changeTypeButton).toBeInTheDocument(); }); - test("Clicking the button changes the type.", () => { + test("(1 pts) Clicking the button changes the type.", () => { const changeTypeButton = screen.getByRole("button", { name: /Change Type/i }); @@ -37,7 +37,7 @@ describe("ChangeType Component tests", () => { expect(typeTextSA).toBeNull(); }); - test("Clicking the button twice keeps the type the same.", () => { + test("(1 pts) Clicking the button twice keeps the type the same.", () => { const changeTypeButton = screen.getByRole("button", { name: /Change Type/i }); diff --git a/src/components/Counter.test.tsx b/src/components/Counter.test.tsx index 7a37c46e38..1ee2d1ff32 100644 --- a/src/components/Counter.test.tsx +++ b/src/components/Counter.test.tsx @@ -6,30 +6,30 @@ describe("Counter Component tests", () => { beforeEach(() => { render(); }); - test("The initial value is 0", () => { + test("(1 pts) The initial value is 0", () => { // We use `getByText` because the text MUST be there const valueText = screen.getByText(/0/i); expect(valueText).toBeInTheDocument(); }); - test("The initial value is not 1", () => { + test("(1 pts) The initial value is not 1", () => { // We use `queryByText` because the text might not be there const valueText = screen.queryByText(/1/i); expect(valueText).toBeNull(); }); - test("There is a button named Add One", () => { + test("(1 pts) There is a button named Add One", () => { const addOneButton = screen.getByRole("button", { name: /Add One/i }); expect(addOneButton).toBeInTheDocument(); }); - test("Clicking the button once adds one", () => { + test("(1 pts) Clicking the button once adds one", () => { const addOneButton = screen.getByRole("button", { name: /Add One/i }); addOneButton.click(); const valueText = screen.getByText(/1/i); expect(valueText).toBeInTheDocument(); }); - test("Clicking the button twice adds two", () => { + test("(1 pts) Clicking the button twice adds two", () => { const addOneButton = screen.getByRole("button", { name: /Add One/i }); addOneButton.click(); addOneButton.click(); diff --git a/src/components/CycleHoliday.test.tsx b/src/components/CycleHoliday.test.tsx index 145e2cb3c8..a20389d03e 100644 --- a/src/components/CycleHoliday.test.tsx +++ b/src/components/CycleHoliday.test.tsx @@ -7,12 +7,12 @@ describe("CycleHoliday Component tests", () => { render(); }); - test("An initial holiday is displayed", () => { + test("(1 pts) An initial holiday is displayed", () => { const initialHoliday = screen.getByText(/Holiday: (.*)/i); expect(initialHoliday).toBeInTheDocument(); }); - test("There are two buttons", () => { + test("(1 pts) There are two buttons", () => { const alphabetButton = screen.getByRole("button", { name: /Alphabet/i }); @@ -23,7 +23,7 @@ describe("CycleHoliday Component tests", () => { expect(yearButton).toBeInTheDocument(); }); - test("Can cycle through 5 distinct holidays alphabetically", () => { + test("(1 pts) Can cycle through 5 distinct holidays alphabetically", () => { const alphabetButton = screen.getByRole("button", { name: /Alphabet/i }); @@ -38,7 +38,7 @@ describe("CycleHoliday Component tests", () => { expect(states[0]).toEqual(states[5]); }); - test("Can cycle through 5 distinct holidays by year", () => { + test("(1 pts) Can cycle through 5 distinct holidays by year", () => { const yearButton = screen.getByRole("button", { name: /Year/i }); diff --git a/src/components/RevealAnswer.test.tsx b/src/components/RevealAnswer.test.tsx index aa7996e964..438f4d5c28 100644 --- a/src/components/RevealAnswer.test.tsx +++ b/src/components/RevealAnswer.test.tsx @@ -6,17 +6,17 @@ describe("RevealAnswer Component tests", () => { beforeEach(() => { render(); }); - test("The answer '42' is not visible initially", () => { + test("(1 pts) The answer '42' is not visible initially", () => { const answerText = screen.queryByText(/42/); expect(answerText).toBeNull(); }); - test("There is a Reveal Answer button", () => { + test("(1 pts) There is a Reveal Answer button", () => { const revealButton = screen.getByRole("button", { name: /Reveal Answer/i }); expect(revealButton).toBeInTheDocument(); }); - test("Clicking Reveal Answer button reveals the '42'", () => { + test("(1 pts) Clicking Reveal Answer button reveals the '42'", () => { const revealButton = screen.getByRole("button", { name: /Reveal Answer/i }); @@ -24,7 +24,7 @@ describe("RevealAnswer Component tests", () => { const answerText = screen.getByText(/42/); expect(answerText).toBeInTheDocument(); }); - test("Clicking Reveal Answer button twice hides the '42'", () => { + test("(1 pts) Clicking Reveal Answer button twice hides the '42'", () => { const revealButton = screen.getByRole("button", { name: /Reveal Answer/i }); diff --git a/src/components/StartAttempt.test.tsx b/src/components/StartAttempt.test.tsx index 3d41c953cf..8e5b9667cb 100644 --- a/src/components/StartAttempt.test.tsx +++ b/src/components/StartAttempt.test.tsx @@ -27,36 +27,36 @@ describe("StartAttempt Component tests", () => { beforeEach(() => { render(); }); - test("The Number of attempts is displayed initially, without other numbers", () => { + test("(1 pts) The Number of attempts is displayed initially, without other numbers", () => { const attemptNumber = screen.getByText(/(\d+)/); expect(attemptNumber).toBeInTheDocument(); }); - test("The Number of attempts is more than 0", () => { + test("(1 pts) The Number of attempts is more than 0", () => { const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); expect(attemptNumber).toBeGreaterThan(0); }); - test("The Number of attempts is less than 10", () => { + test("(1 pts) The Number of attempts is less than 10", () => { const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); expect(attemptNumber).toBeLessThan(10); }); - test("There is an initially enabled Start Quiz button", () => { + test("(1 pts) There is an initially enabled Start Quiz button", () => { const startButton = screen.getByRole("button", { name: /Start Quiz/i }); expect(startButton).toBeInTheDocument(); expect(startButton).toBeEnabled(); }); - test("There is an initially disabled Stop Quiz button", () => { + test("(1 pts) There is an initially disabled Stop Quiz button", () => { const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); expect(stopButton).toBeInTheDocument(); expect(stopButton).toBeDisabled(); }); - test("There is an initially enabled Mulligan button", () => { + test("(1 pts) There is an initially enabled Mulligan button", () => { const mulliganButton = screen.getByRole("button", { name: /Mulligan/i }); expect(mulliganButton).toBeInTheDocument(); expect(mulliganButton).toBeEnabled(); }); - test("Clicking Mulligan increases attempts", () => { + test("(1 pts) Clicking Mulligan increases attempts", () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const mulliganButton = screen.getByRole("button", { @@ -66,7 +66,7 @@ describe("StartAttempt Component tests", () => { const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); expect(attemptNumber + 1).toEqual(attemptNumberLater); }); - test("Clicking Mulligan twice increases attempts by two", () => { + test("(1 pts) Clicking Mulligan twice increases attempts by two", () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const mulliganButton = screen.getByRole("button", { @@ -77,7 +77,7 @@ describe("StartAttempt Component tests", () => { const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); expect(attemptNumber + 2).toEqual(attemptNumberLater); }); - test("Clicking Start Quiz decreases attempts", () => { + test("(1 pts) Clicking Start Quiz decreases attempts", () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const startButton = screen.getByRole("button", { @@ -88,7 +88,7 @@ describe("StartAttempt Component tests", () => { extractDigits(screen.getByText(/(\d+)/)) || 0; expect(attemptNumber - 1).toEqual(attemptNumberLater); }); - test("Clicking Start Quiz changes enabled buttons", () => { + test("(1 pts) Clicking Start Quiz changes enabled buttons", () => { // Given the buttons... const startButton = screen.getByRole("button", { name: /Start Quiz/i @@ -104,7 +104,7 @@ describe("StartAttempt Component tests", () => { expect(stopButton).toBeEnabled(); expect(mulliganButton).toBeDisabled(); }); - test("Clicking Start and Stop Quiz changes enabled buttons", () => { + test("(1 pts) Clicking Start and Stop Quiz changes enabled buttons", () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { name: /Start Quiz/i @@ -121,7 +121,7 @@ describe("StartAttempt Component tests", () => { expect(stopButton).toBeDisabled(); expect(mulliganButton).toBeEnabled(); }); - test("Clicking Start, Stop, Mulligan sets attempts to original", () => { + test("(1 pts) Clicking Start, Stop, Mulligan sets attempts to original", () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { name: /Start Quiz/i @@ -146,7 +146,7 @@ describe("StartAttempt Component tests", () => { extractDigits(screen.getByText(/(\d+)/)) || 0; expect(attemptNumber).toEqual(attemptNumberLatest); }); - test("Cannot click start quiz when out of attempts", () => { + test("(1 pts) Cannot click start quiz when out of attempts", () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { name: /Start Quiz/i diff --git a/src/components/TwoDice.test.tsx b/src/components/TwoDice.test.tsx index 7996051096..d1e5f812dd 100644 --- a/src/components/TwoDice.test.tsx +++ b/src/components/TwoDice.test.tsx @@ -22,13 +22,13 @@ describe("TwoDice Component tests", () => { beforeEach(() => { render(); }); - test("There is a `left-die` and `right-die` testid", () => { + test("(1 pts) There is a `left-die` and `right-die` testid", () => { const leftDie = screen.getByTestId("left-die"); const rightDie = screen.getByTestId("right-die"); expect(leftDie).toBeInTheDocument(); expect(rightDie).toBeInTheDocument(); }); - test("The `left-die` and `right-die` are two different numbers", () => { + test("(1 pts) The `left-die` and `right-die` are two different numbers", () => { const leftDie = screen.getByTestId("left-die"); const rightDie = screen.getByTestId("right-die"); const leftNumber = extractDigits(leftDie); @@ -39,13 +39,13 @@ describe("TwoDice Component tests", () => { // Then they are two different numbers expect(leftNumber).not.toEqual(rightNumber); }); - test("There are two buttons present", () => { + test("(1 pts) There are two buttons present", () => { const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); expect(leftButton).toBeInTheDocument(); expect(rightButton).toBeInTheDocument(); }); - test("Clicking left button changes first number", () => { + test("(1 pts) Clicking left button changes first number", () => { const leftButton = screen.getByRole("button", { name: /Roll Left/i }); leftButton.click(); leftButton.click(); @@ -57,7 +57,7 @@ describe("TwoDice Component tests", () => { expect(leftNumber).toEqual(5); }); // Clicking right button changes second number - test("Clicking right button changes second number", () => { + test("(1 pts) Clicking right button changes second number", () => { const rightButton = screen.getByRole("button", { name: /Roll Right/i }); rightButton.click(); rightButton.click(); @@ -69,7 +69,7 @@ describe("TwoDice Component tests", () => { expect(rightNumber).toEqual(5); }); // Rolling two different numbers does not win or lose the game - test("Rolling two different numbers does not win or lose the game", () => { + test("(1 pts) Rolling two different numbers does not win or lose the game", () => { // Given const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); @@ -90,7 +90,7 @@ describe("TwoDice Component tests", () => { const loseText = screen.queryByText(/Lose/i); expect(loseText).toBeNull(); }); - test("Getting snake eyes loses the game", () => { + test("(1 pts) Getting snake eyes loses the game", () => { // Given const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); @@ -114,7 +114,7 @@ describe("TwoDice Component tests", () => { const loseText = screen.getByText(/Lose/i); expect(loseText).toBeInTheDocument(); }); - test("Getting matching numbers wins the game", () => { + test("(1 pts) Getting matching numbers wins the game", () => { // Given const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); From 82faaccfdddde466de5a4d0080af257364271684 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 13:45:32 -0400 Subject: [PATCH 64/90] Fix react return value --- src/components/ChangeType.tsx | 2 +- src/components/Counter.tsx | 2 +- src/components/CycleHoliday.tsx | 2 +- src/components/RevealAnswer.tsx | 2 +- src/components/StartAttempt.tsx | 2 +- src/components/TwoDice.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ChangeType.tsx b/src/components/ChangeType.tsx index 5608076f64..6e8f878020 100644 --- a/src/components/ChangeType.tsx +++ b/src/components/ChangeType.tsx @@ -2,6 +2,6 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; import { QuestionType } from "../interfaces/question"; -export function ChangeType(): JSX.Element { +export function ChangeType(): React.JSX.Element { return
      Change Type
      ; } diff --git a/src/components/Counter.tsx b/src/components/Counter.tsx index 1987698ed1..2a546c1747 100644 --- a/src/components/Counter.tsx +++ b/src/components/Counter.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; -export function Counter(): JSX.Element { +export function Counter(): React.JSX.Element { const [value, setValue] = useState(0); return ( diff --git a/src/components/CycleHoliday.tsx b/src/components/CycleHoliday.tsx index 7c671f889f..47e6d76444 100644 --- a/src/components/CycleHoliday.tsx +++ b/src/components/CycleHoliday.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; -export function CycleHoliday(): JSX.Element { +export function CycleHoliday(): React.JSX.Element { return
      Cycle Holiday
      ; } diff --git a/src/components/RevealAnswer.tsx b/src/components/RevealAnswer.tsx index 07db6f62d2..a48c0a0961 100644 --- a/src/components/RevealAnswer.tsx +++ b/src/components/RevealAnswer.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; -export function RevealAnswer(): JSX.Element { +export function RevealAnswer(): React.JSX.Element { return
      Reveal Answer
      ; } diff --git a/src/components/StartAttempt.tsx b/src/components/StartAttempt.tsx index 0c0a85fdb6..dec4ae7dcd 100644 --- a/src/components/StartAttempt.tsx +++ b/src/components/StartAttempt.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; -export function StartAttempt(): JSX.Element { +export function StartAttempt(): React.JSX.Element { return
      Start Attempt
      ; } diff --git a/src/components/TwoDice.tsx b/src/components/TwoDice.tsx index 372502fe64..a257594d35 100644 --- a/src/components/TwoDice.tsx +++ b/src/components/TwoDice.tsx @@ -11,6 +11,6 @@ export function d6(): number { return 1 + Math.floor(Math.random() * 6); } -export function TwoDice(): JSX.Element { +export function TwoDice(): React.JSX.Element { return
      Two Dice
      ; } From cc7d4db27c04fce10f1974a3f179adaaffc739f2 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 14:19:46 -0400 Subject: [PATCH 65/90] Update react tests to use async --- src/components/ChangeType.test.tsx | 24 ++++--- src/components/Counter.test.tsx | 18 ++++-- src/components/CycleHoliday.test.tsx | 22 ++++--- src/components/RevealAnswer.test.tsx | 24 ++++--- src/components/StartAttempt.test.tsx | 97 ++++++++++++++++++---------- src/components/TwoDice.test.tsx | 80 ++++++++++++++++------- 6 files changed, 175 insertions(+), 90 deletions(-) diff --git a/src/components/ChangeType.test.tsx b/src/components/ChangeType.test.tsx index ef7ea4b66e..0a126a9111 100644 --- a/src/components/ChangeType.test.tsx +++ b/src/components/ChangeType.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { ChangeType } from "./ChangeType"; @@ -19,16 +19,18 @@ describe("ChangeType Component tests", () => { test("(1 pts) There is a button labeled Change Type", () => { const changeTypeButton = screen.getByRole("button", { - name: /Change Type/i + name: /Change Type/i, }); expect(changeTypeButton).toBeInTheDocument(); }); - test("(1 pts) Clicking the button changes the type.", () => { + test("(1 pts) Clicking the button changes the type.", async () => { const changeTypeButton = screen.getByRole("button", { - name: /Change Type/i + name: /Change Type/i, + }); + await act(async () => { + changeTypeButton.click(); }); - changeTypeButton.click(); // Should be Multiple Choice const typeTextMC = screen.getByText(/Multiple Choice/i); expect(typeTextMC).toBeInTheDocument(); @@ -37,12 +39,16 @@ describe("ChangeType Component tests", () => { expect(typeTextSA).toBeNull(); }); - test("(1 pts) Clicking the button twice keeps the type the same.", () => { + test("(1 pts) Clicking the button twice keeps the type the same.", async () => { const changeTypeButton = screen.getByRole("button", { - name: /Change Type/i + name: /Change Type/i, + }); + await act(async () => { + changeTypeButton.click(); + }); + await act(async () => { + changeTypeButton.click(); }); - changeTypeButton.click(); - changeTypeButton.click(); // Should be Short Answer const typeTextSA = screen.getByText(/Short Answer/i); expect(typeTextSA).toBeInTheDocument(); diff --git a/src/components/Counter.test.tsx b/src/components/Counter.test.tsx index 1ee2d1ff32..d08773f5c6 100644 --- a/src/components/Counter.test.tsx +++ b/src/components/Counter.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { Counter } from "./Counter"; @@ -22,17 +22,23 @@ describe("Counter Component tests", () => { expect(addOneButton).toBeInTheDocument(); }); - test("(1 pts) Clicking the button once adds one", () => { + test("(1 pts) Clicking the button once adds one", async () => { const addOneButton = screen.getByRole("button", { name: /Add One/i }); - addOneButton.click(); + await act(async () => { + addOneButton.click(); + }); const valueText = screen.getByText(/1/i); expect(valueText).toBeInTheDocument(); }); - test("(1 pts) Clicking the button twice adds two", () => { + test("(1 pts) Clicking the button twice adds two", async () => { const addOneButton = screen.getByRole("button", { name: /Add One/i }); - addOneButton.click(); - addOneButton.click(); + await act(async () => { + addOneButton.click(); + }); + await act(async () => { + addOneButton.click(); + }); const valueText = screen.getByText(/2/i); expect(valueText).toBeInTheDocument(); }); diff --git a/src/components/CycleHoliday.test.tsx b/src/components/CycleHoliday.test.tsx index a20389d03e..4c1422f3df 100644 --- a/src/components/CycleHoliday.test.tsx +++ b/src/components/CycleHoliday.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { CycleHoliday } from "./CycleHoliday"; @@ -14,39 +14,43 @@ describe("CycleHoliday Component tests", () => { test("(1 pts) There are two buttons", () => { const alphabetButton = screen.getByRole("button", { - name: /Alphabet/i + name: /Alphabet/i, }); const yearButton = screen.getByRole("button", { - name: /Year/i + name: /Year/i, }); expect(alphabetButton).toBeInTheDocument(); expect(yearButton).toBeInTheDocument(); }); - test("(1 pts) Can cycle through 5 distinct holidays alphabetically", () => { + test("(1 pts) Can cycle through 5 distinct holidays alphabetically", async () => { const alphabetButton = screen.getByRole("button", { - name: /Alphabet/i + name: /Alphabet/i, }); const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); const states: string[] = []; for (let i = 0; i < 6; i++) { states.push(initialHoliday.textContent || ""); - alphabetButton.click(); + await act(async () => { + alphabetButton.click(); + }); } const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); expect(uniqueStates).toHaveLength(5); expect(states[0]).toEqual(states[5]); }); - test("(1 pts) Can cycle through 5 distinct holidays by year", () => { + test("(1 pts) Can cycle through 5 distinct holidays by year", async () => { const yearButton = screen.getByRole("button", { - name: /Year/i + name: /Year/i, }); const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); const states: string[] = []; for (let i = 0; i < 6; i++) { states.push(initialHoliday.textContent || ""); - yearButton.click(); + await act(async () => { + yearButton.click(); + }); } const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); expect(uniqueStates).toHaveLength(5); diff --git a/src/components/RevealAnswer.test.tsx b/src/components/RevealAnswer.test.tsx index 438f4d5c28..f5ad250bf9 100644 --- a/src/components/RevealAnswer.test.tsx +++ b/src/components/RevealAnswer.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { RevealAnswer } from "./RevealAnswer"; @@ -12,24 +12,30 @@ describe("RevealAnswer Component tests", () => { }); test("(1 pts) There is a Reveal Answer button", () => { const revealButton = screen.getByRole("button", { - name: /Reveal Answer/i + name: /Reveal Answer/i, }); expect(revealButton).toBeInTheDocument(); }); - test("(1 pts) Clicking Reveal Answer button reveals the '42'", () => { + test("(1 pts) Clicking Reveal Answer button reveals the '42'", async () => { const revealButton = screen.getByRole("button", { - name: /Reveal Answer/i + name: /Reveal Answer/i, + }); + await act(async () => { + revealButton.click(); }); - revealButton.click(); const answerText = screen.getByText(/42/); expect(answerText).toBeInTheDocument(); }); - test("(1 pts) Clicking Reveal Answer button twice hides the '42'", () => { + test("(1 pts) Clicking Reveal Answer button twice hides the '42'", async () => { const revealButton = screen.getByRole("button", { - name: /Reveal Answer/i + name: /Reveal Answer/i, + }); + await act(async () => { + revealButton.click(); + }); + await act(async () => { + revealButton.click(); }); - revealButton.click(); - revealButton.click(); const answerText = screen.queryByText(/42/); expect(answerText).toBeNull(); }); diff --git a/src/components/StartAttempt.test.tsx b/src/components/StartAttempt.test.tsx index 8e5b9667cb..74397290bb 100644 --- a/src/components/StartAttempt.test.tsx +++ b/src/components/StartAttempt.test.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import { render, screen } from "@testing-library/react"; +import React, { act } from "react"; +import { render, screen, cleanup } from "@testing-library/react"; import { StartAttempt } from "./StartAttempt"; /*** @@ -27,6 +27,9 @@ describe("StartAttempt Component tests", () => { beforeEach(() => { render(); }); + afterEach(() => { + cleanup(); + }); test("(1 pts) The Number of attempts is displayed initially, without other numbers", () => { const attemptNumber = screen.getByText(/(\d+)/); expect(attemptNumber).toBeInTheDocument(); @@ -51,109 +54,129 @@ describe("StartAttempt Component tests", () => { }); test("(1 pts) There is an initially enabled Mulligan button", () => { const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, }); expect(mulliganButton).toBeInTheDocument(); expect(mulliganButton).toBeEnabled(); }); - test("(1 pts) Clicking Mulligan increases attempts", () => { + test("(1 pts) Clicking Mulligan increases attempts", async () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, + }); + await act(async () => { + mulliganButton.click(); }); - mulliganButton.click(); const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); expect(attemptNumber + 1).toEqual(attemptNumberLater); }); - test("(1 pts) Clicking Mulligan twice increases attempts by two", () => { + test("(1 pts) Clicking Mulligan twice increases attempts by two", async () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, + }); + await act(async () => { + mulliganButton.click(); + }); + await act(async () => { + mulliganButton.click(); }); - mulliganButton.click(); - mulliganButton.click(); const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); expect(attemptNumber + 2).toEqual(attemptNumberLater); }); - test("(1 pts) Clicking Start Quiz decreases attempts", () => { + test("(1 pts) Clicking Start Quiz decreases attempts", async () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const startButton = screen.getByRole("button", { - name: /Start Quiz/i + name: /Start Quiz/i, + }); + await act(async () => { + startButton.click(); }); - startButton.click(); const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)) || 0; expect(attemptNumber - 1).toEqual(attemptNumberLater); }); - test("(1 pts) Clicking Start Quiz changes enabled buttons", () => { + test("(1 pts) Clicking Start Quiz changes enabled buttons", async () => { // Given the buttons... const startButton = screen.getByRole("button", { - name: /Start Quiz/i + name: /Start Quiz/i, }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, }); // When the start button is clicked - startButton.click(); + await act(async () => { + startButton.click(); + }); // Then the start is disabled, stop is enabled, and mulligan is disabled expect(startButton).toBeDisabled(); expect(stopButton).toBeEnabled(); expect(mulliganButton).toBeDisabled(); }); - test("(1 pts) Clicking Start and Stop Quiz changes enabled buttons", () => { + test("(1 pts) Clicking Start and Stop Quiz changes enabled buttons", async () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { - name: /Start Quiz/i + name: /Start Quiz/i, }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, }); // When we click the start button and then the stop button - startButton.click(); - stopButton.click(); + await act(async () => { + startButton.click(); + }); + await act(async () => { + stopButton.click(); + }); // Then the start is enabled, stop is disabled, and mulligan is enabled expect(startButton).toBeEnabled(); expect(stopButton).toBeDisabled(); expect(mulliganButton).toBeEnabled(); }); - test("(1 pts) Clicking Start, Stop, Mulligan sets attempts to original", () => { + test("(1 pts) Clicking Start, Stop, Mulligan sets attempts to original", async () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { - name: /Start Quiz/i + name: /Start Quiz/i, }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, }); const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; // When we click the start button and then the stop button - startButton.click(); - stopButton.click(); + await act(async () => { + startButton.click(); + }); + await act(async () => { + stopButton.click(); + }); // Then the attempt is decreased const attemptNumberLater: number = extractDigits(screen.getByText(/(\d+)/)) || 0; expect(attemptNumber - 1).toEqual(attemptNumberLater); // And when we click the mulligan button - mulliganButton.click(); + await act(async () => { + mulliganButton.click(); + }); // Then the attempt is increased back to starting value const attemptNumberLatest: number = extractDigits(screen.getByText(/(\d+)/)) || 0; expect(attemptNumber).toEqual(attemptNumberLatest); }); - test("(1 pts) Cannot click start quiz when out of attempts", () => { + test("(1 pts) Cannot click start quiz when out of attempts", async () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { - name: /Start Quiz/i + name: /Start Quiz/i, }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i + name: /Mulligan/i, }); let attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; const initialAttempt = attemptNumber; @@ -166,8 +189,12 @@ describe("StartAttempt Component tests", () => { expect(stopButton).toBeDisabled(); expect(mulliganButton).toBeEnabled(); // And when we Start and then immediately stop the quiz... - startButton.click(); - stopButton.click(); + await act(async () => { + startButton.click(); + }); + await act(async () => { + stopButton.click(); + }); // Then the number is going down, and doesn't go past 0 somehow attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; expect(attemptNumber).toBeGreaterThanOrEqual(0); @@ -183,7 +210,9 @@ describe("StartAttempt Component tests", () => { expect(stopButton).toBeDisabled(); expect(mulliganButton).toBeEnabled(); // And when we click the mulligan button - mulliganButton.click(); + await act(async () => { + mulliganButton.click(); + }); // Then the attempt is increased back to 1 const attemptNumberLatest: number = extractDigits(screen.getByText(/(\d+)/)) || 0; diff --git a/src/components/TwoDice.test.tsx b/src/components/TwoDice.test.tsx index d1e5f812dd..e5f9966deb 100644 --- a/src/components/TwoDice.test.tsx +++ b/src/components/TwoDice.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { TwoDice } from "./TwoDice"; import { extractDigits } from "./StartAttempt.test"; @@ -45,11 +45,17 @@ describe("TwoDice Component tests", () => { expect(leftButton).toBeInTheDocument(); expect(rightButton).toBeInTheDocument(); }); - test("(1 pts) Clicking left button changes first number", () => { + test("(1 pts) Clicking left button changes first number", async () => { const leftButton = screen.getByRole("button", { name: /Roll Left/i }); - leftButton.click(); - leftButton.click(); - leftButton.click(); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + leftButton.click(); + }); // Then the random function should be called 3 times expect(mathRandomFunction).toBeCalledTimes(3); // And the number to be 5 @@ -57,11 +63,17 @@ describe("TwoDice Component tests", () => { expect(leftNumber).toEqual(5); }); // Clicking right button changes second number - test("(1 pts) Clicking right button changes second number", () => { + test("(1 pts) Clicking right button changes second number", async () => { const rightButton = screen.getByRole("button", { name: /Roll Right/i }); - rightButton.click(); - rightButton.click(); - rightButton.click(); + await act(async () => { + rightButton.click(); + }); + await act(async () => { + rightButton.click(); + }); + await act(async () => { + rightButton.click(); + }); // Then the random function should be called 3 times expect(mathRandomFunction).toBeCalledTimes(3); // And the number to be 5 @@ -69,15 +81,19 @@ describe("TwoDice Component tests", () => { expect(rightNumber).toEqual(5); }); // Rolling two different numbers does not win or lose the game - test("(1 pts) Rolling two different numbers does not win or lose the game", () => { + test("(1 pts) Rolling two different numbers does not win or lose the game", async () => { // Given const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); const leftDie = screen.getByTestId("left-die"); const rightDie = screen.getByTestId("right-die"); // When the left and right buttons are rolled once each - leftButton.click(); - rightButton.click(); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + rightButton.click(); + }); // Then the numbers are not equal const leftNumber = extractDigits(leftDie); const rightNumber = extractDigits(rightDie); @@ -90,18 +106,28 @@ describe("TwoDice Component tests", () => { const loseText = screen.queryByText(/Lose/i); expect(loseText).toBeNull(); }); - test("(1 pts) Getting snake eyes loses the game", () => { + test("(1 pts) Getting snake eyes loses the game", async () => { // Given const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); const leftDie = screen.getByTestId("left-die"); const rightDie = screen.getByTestId("right-die"); // When the left and right buttons are rolled once each - leftButton.click(); - rightButton.click(); - rightButton.click(); - rightButton.click(); - rightButton.click(); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + rightButton.click(); + }); + await act(async () => { + rightButton.click(); + }); + await act(async () => { + rightButton.click(); + }); + await act(async () => { + rightButton.click(); + }); // Then the numbers are not equal const leftNumber = extractDigits(leftDie); const rightNumber = extractDigits(rightDie); @@ -114,17 +140,25 @@ describe("TwoDice Component tests", () => { const loseText = screen.getByText(/Lose/i); expect(loseText).toBeInTheDocument(); }); - test("(1 pts) Getting matching numbers wins the game", () => { + test("(1 pts) Getting matching numbers wins the game", async () => { // Given const leftButton = screen.getByRole("button", { name: /Roll Left/i }); const rightButton = screen.getByRole("button", { name: /Roll Right/i }); const leftDie = screen.getByTestId("left-die"); const rightDie = screen.getByTestId("right-die"); // When the left and right buttons are rolled once each - leftButton.click(); - leftButton.click(); - leftButton.click(); - rightButton.click(); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + leftButton.click(); + }); + await act(async () => { + rightButton.click(); + }); // Then the numbers are not equal const leftNumber = extractDigits(leftDie); const rightNumber = extractDigits(rightDie); From c419dc919275541b287452c52aac7bf55c2b409c Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 14:20:29 -0400 Subject: [PATCH 66/90] Fix linting --- src/components/ChangeType.test.tsx | 6 +++--- src/components/CycleHoliday.test.tsx | 8 ++++---- src/components/RevealAnswer.test.tsx | 6 +++--- src/components/StartAttempt.test.tsx | 24 ++++++++++++------------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/components/ChangeType.test.tsx b/src/components/ChangeType.test.tsx index 0a126a9111..f0ee545cc3 100644 --- a/src/components/ChangeType.test.tsx +++ b/src/components/ChangeType.test.tsx @@ -19,14 +19,14 @@ describe("ChangeType Component tests", () => { test("(1 pts) There is a button labeled Change Type", () => { const changeTypeButton = screen.getByRole("button", { - name: /Change Type/i, + name: /Change Type/i }); expect(changeTypeButton).toBeInTheDocument(); }); test("(1 pts) Clicking the button changes the type.", async () => { const changeTypeButton = screen.getByRole("button", { - name: /Change Type/i, + name: /Change Type/i }); await act(async () => { changeTypeButton.click(); @@ -41,7 +41,7 @@ describe("ChangeType Component tests", () => { test("(1 pts) Clicking the button twice keeps the type the same.", async () => { const changeTypeButton = screen.getByRole("button", { - name: /Change Type/i, + name: /Change Type/i }); await act(async () => { changeTypeButton.click(); diff --git a/src/components/CycleHoliday.test.tsx b/src/components/CycleHoliday.test.tsx index 4c1422f3df..ae364a0b5b 100644 --- a/src/components/CycleHoliday.test.tsx +++ b/src/components/CycleHoliday.test.tsx @@ -14,10 +14,10 @@ describe("CycleHoliday Component tests", () => { test("(1 pts) There are two buttons", () => { const alphabetButton = screen.getByRole("button", { - name: /Alphabet/i, + name: /Alphabet/i }); const yearButton = screen.getByRole("button", { - name: /Year/i, + name: /Year/i }); expect(alphabetButton).toBeInTheDocument(); expect(yearButton).toBeInTheDocument(); @@ -25,7 +25,7 @@ describe("CycleHoliday Component tests", () => { test("(1 pts) Can cycle through 5 distinct holidays alphabetically", async () => { const alphabetButton = screen.getByRole("button", { - name: /Alphabet/i, + name: /Alphabet/i }); const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); const states: string[] = []; @@ -42,7 +42,7 @@ describe("CycleHoliday Component tests", () => { test("(1 pts) Can cycle through 5 distinct holidays by year", async () => { const yearButton = screen.getByRole("button", { - name: /Year/i, + name: /Year/i }); const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); const states: string[] = []; diff --git a/src/components/RevealAnswer.test.tsx b/src/components/RevealAnswer.test.tsx index f5ad250bf9..6b2076ad1a 100644 --- a/src/components/RevealAnswer.test.tsx +++ b/src/components/RevealAnswer.test.tsx @@ -12,13 +12,13 @@ describe("RevealAnswer Component tests", () => { }); test("(1 pts) There is a Reveal Answer button", () => { const revealButton = screen.getByRole("button", { - name: /Reveal Answer/i, + name: /Reveal Answer/i }); expect(revealButton).toBeInTheDocument(); }); test("(1 pts) Clicking Reveal Answer button reveals the '42'", async () => { const revealButton = screen.getByRole("button", { - name: /Reveal Answer/i, + name: /Reveal Answer/i }); await act(async () => { revealButton.click(); @@ -28,7 +28,7 @@ describe("RevealAnswer Component tests", () => { }); test("(1 pts) Clicking Reveal Answer button twice hides the '42'", async () => { const revealButton = screen.getByRole("button", { - name: /Reveal Answer/i, + name: /Reveal Answer/i }); await act(async () => { revealButton.click(); diff --git a/src/components/StartAttempt.test.tsx b/src/components/StartAttempt.test.tsx index 74397290bb..fd326936e6 100644 --- a/src/components/StartAttempt.test.tsx +++ b/src/components/StartAttempt.test.tsx @@ -54,7 +54,7 @@ describe("StartAttempt Component tests", () => { }); test("(1 pts) There is an initially enabled Mulligan button", () => { const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); expect(mulliganButton).toBeInTheDocument(); expect(mulliganButton).toBeEnabled(); @@ -63,7 +63,7 @@ describe("StartAttempt Component tests", () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); await act(async () => { mulliganButton.click(); @@ -75,7 +75,7 @@ describe("StartAttempt Component tests", () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); await act(async () => { mulliganButton.click(); @@ -90,7 +90,7 @@ describe("StartAttempt Component tests", () => { const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; const startButton = screen.getByRole("button", { - name: /Start Quiz/i, + name: /Start Quiz/i }); await act(async () => { startButton.click(); @@ -102,11 +102,11 @@ describe("StartAttempt Component tests", () => { test("(1 pts) Clicking Start Quiz changes enabled buttons", async () => { // Given the buttons... const startButton = screen.getByRole("button", { - name: /Start Quiz/i, + name: /Start Quiz/i }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); // When the start button is clicked await act(async () => { @@ -120,11 +120,11 @@ describe("StartAttempt Component tests", () => { test("(1 pts) Clicking Start and Stop Quiz changes enabled buttons", async () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { - name: /Start Quiz/i, + name: /Start Quiz/i }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); // When we click the start button and then the stop button await act(async () => { @@ -141,11 +141,11 @@ describe("StartAttempt Component tests", () => { test("(1 pts) Clicking Start, Stop, Mulligan sets attempts to original", async () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { - name: /Start Quiz/i, + name: /Start Quiz/i }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); const attemptNumber: number = extractDigits(screen.getByText(/(\d+)/)) || 0; @@ -172,11 +172,11 @@ describe("StartAttempt Component tests", () => { test("(1 pts) Cannot click start quiz when out of attempts", async () => { // Given the buttons and initial attempt number... const startButton = screen.getByRole("button", { - name: /Start Quiz/i, + name: /Start Quiz/i }); const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i, + name: /Mulligan/i }); let attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; const initialAttempt = attemptNumber; From 50a9c85dca9bc60f7dd875355f2c28c3988ca610 Mon Sep 17 00:00:00 2001 From: Austin Cory Bart Date: Sat, 24 Aug 2024 14:47:15 -0400 Subject: [PATCH 67/90] Update for new react --- src/bad-components/ChooseTeam.test.tsx | 54 ++++++++++++++++++-------- src/bad-components/ChooseTeam.tsx | 4 +- src/bad-components/ColoredBox.test.tsx | 26 ++++++++----- src/bad-components/ColoredBox.tsx | 14 ++++--- src/bad-components/DoubleHalf.test.tsx | 48 +++++++++++++++-------- src/bad-components/DoubleHalf.tsx | 26 ++++++++++--- src/bad-components/ShoveBox.test.tsx | 26 ++++++++----- src/bad-components/ShoveBox.tsx | 16 +++++--- 8 files changed, 144 insertions(+), 70 deletions(-) diff --git a/src/bad-components/ChooseTeam.test.tsx b/src/bad-components/ChooseTeam.test.tsx index f11465a2d6..66eee4be70 100644 --- a/src/bad-components/ChooseTeam.test.tsx +++ b/src/bad-components/ChooseTeam.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { ChooseTeam } from "./ChooseTeam"; @@ -6,54 +6,74 @@ describe("ChooseTeam Component tests", () => { beforeEach(() => { render(); }); - test("The initial team is empty", () => { + test("(2 pts) The initial team is empty", () => { const currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(0); }); - test("There are 7 buttons.", () => { + test("(2 pts) There are 7 buttons.", () => { const adders = screen.queryAllByRole("button"); expect(adders).toHaveLength(7); }); - test("Clicking first team member works", () => { + test("(2 pts) Clicking first team member works", async () => { const first = screen.queryAllByRole("button")[0]; - first.click(); + await act(async () => { + first.click(); + }); const currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(1); expect(currentTeam[0].textContent).toEqual(first.textContent); }); - test("Clicking the third team member works", () => { + test("(2 pts) Clicking the third team member works", async () => { const third = screen.queryAllByRole("button")[2]; - third.click(); + await act(async () => { + third.click(); + }); const currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(1); expect(currentTeam[0].textContent).toEqual(third.textContent); }); - test("Clicking three team members works", () => { + test("(2 pts) Clicking three team members works", async () => { const [, second, third, , fifth] = screen.queryAllByRole("button"); - third.click(); - second.click(); - fifth.click(); + await act(async () => { + third.click(); + }); + await act(async () => { + second.click(); + }); + await act(async () => { + fifth.click(); + }); const currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(3); expect(currentTeam[0].textContent).toEqual(third.textContent); expect(currentTeam[1].textContent).toEqual(second.textContent); expect(currentTeam[2].textContent).toEqual(fifth.textContent); }); - test("Clearing the team works", () => { + test("(2 pts) Clearing the team works", async () => { const [, second, third, fourth, fifth, , clear] = screen.queryAllByRole("button"); - third.click(); - second.click(); - fifth.click(); + await act(async () => { + third.click(); + }); + await act(async () => { + second.click(); + }); + await act(async () => { + fifth.click(); + }); let currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(3); expect(currentTeam[0].textContent).toEqual(third.textContent); expect(currentTeam[1].textContent).toEqual(second.textContent); expect(currentTeam[2].textContent).toEqual(fifth.textContent); - clear.click(); + await act(async () => { + clear.click(); + }); currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(0); - fourth.click(); + await act(async () => { + fourth.click(); + }); currentTeam = screen.queryAllByRole("listitem"); expect(currentTeam).toHaveLength(1); expect(currentTeam[0].textContent).toEqual(fourth.textContent); diff --git a/src/bad-components/ChooseTeam.tsx b/src/bad-components/ChooseTeam.tsx index c02334e661..e73f600083 100644 --- a/src/bad-components/ChooseTeam.tsx +++ b/src/bad-components/ChooseTeam.tsx @@ -7,10 +7,10 @@ const PEOPLE = [ "Ada Lovelace", "Charles Babbage", "Barbara Liskov", - "Margaret Hamilton" + "Margaret Hamilton", ]; -export function ChooseTeam(): JSX.Element { +export function ChooseTeam(): React.JSX.Element { const [allOptions, setAllOptions] = useState(PEOPLE); const [team, setTeam] = useState([]); diff --git a/src/bad-components/ColoredBox.test.tsx b/src/bad-components/ColoredBox.test.tsx index c17a13f66c..5762afefb6 100644 --- a/src/bad-components/ColoredBox.test.tsx +++ b/src/bad-components/ColoredBox.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { ColoredBox } from "./ColoredBox"; @@ -6,26 +6,32 @@ describe("ColoredBox Component tests", () => { beforeEach(() => { render(); }); - test("The ColoredBox is initially red.", () => { + test("(2 pts) The ColoredBox is initially red.", () => { const box = screen.getByTestId("colored-box"); expect(box).toHaveStyle({ backgroundColor: "red" }); }); - test("There is a button", () => { + test("(2 pts) There is a button", () => { expect(screen.getByRole("button")).toBeInTheDocument(); }); - test("Clicking the button advances the color.", () => { + test("(2 pts) Clicking the button advances the color.", async () => { const nextColor = screen.getByRole("button"); - nextColor.click(); + await act(async () => { + nextColor.click(); + }); expect(screen.getByTestId("colored-box")).toHaveStyle({ - backgroundColor: "blue" + backgroundColor: "blue", + }); + await act(async () => { + nextColor.click(); }); - nextColor.click(); expect(screen.getByTestId("colored-box")).toHaveStyle({ - backgroundColor: "green" + backgroundColor: "green", + }); + await act(async () => { + nextColor.click(); }); - nextColor.click(); expect(screen.getByTestId("colored-box")).toHaveStyle({ - backgroundColor: "red" + backgroundColor: "red", }); }); }); diff --git a/src/bad-components/ColoredBox.tsx b/src/bad-components/ColoredBox.tsx index a3c3c3f077..1fa2d770b2 100644 --- a/src/bad-components/ColoredBox.tsx +++ b/src/bad-components/ColoredBox.tsx @@ -4,16 +4,20 @@ import { Button } from "react-bootstrap"; export const COLORS = ["red", "blue", "green"]; const DEFAULT_COLOR_INDEX = 0; -function ChangeColor(): JSX.Element { +function ChangeColor(): React.JSX.Element { const [colorIndex, setColorIndex] = useState(DEFAULT_COLOR_INDEX); return ( - ); } -function ColorPreview(): JSX.Element { +function ColorPreview(): React.JSX.Element { return (
      ); } -export function ColoredBox(): JSX.Element { +export function ColoredBox(): React.JSX.Element { return (

      Colored Box

      diff --git a/src/bad-components/DoubleHalf.test.tsx b/src/bad-components/DoubleHalf.test.tsx index cbae5f68af..9b2a031acf 100644 --- a/src/bad-components/DoubleHalf.test.tsx +++ b/src/bad-components/DoubleHalf.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { DoubleHalf } from "./DoubleHalf"; @@ -6,50 +6,66 @@ describe("DoubleHalf Component tests", () => { beforeEach(() => { render(); }); - test("The DoubleHalf value is initially 10", () => { + test("(2 pts) The DoubleHalf value is initially 10", () => { expect(screen.getByText("10")).toBeInTheDocument(); expect(screen.queryByText("20")).not.toBeInTheDocument(); expect(screen.queryByText("5")).not.toBeInTheDocument(); }); - test("There are Double and Halve buttons", () => { + test("(2 pts) There are Double and Halve buttons", () => { expect( - screen.getByRole("button", { name: /Double/i }) + screen.getByRole("button", { name: /Double/i }), ).toBeInTheDocument(); expect( - screen.getByRole("button", { name: /Halve/i }) + screen.getByRole("button", { name: /Halve/i }), ).toBeInTheDocument(); }); - test("You can double the number.", () => { + test("(2 pts) You can double the number.", async () => { const double = screen.getByRole("button", { name: /Double/i }); - double.click(); + await act(async () => { + double.click(); + }); expect(screen.getByText("20")).toBeInTheDocument(); expect(screen.queryByText("10")).not.toBeInTheDocument(); }); - test("You can halve the number.", () => { + test("(2 pts) You can halve the number.", async () => { const halve = screen.getByRole("button", { name: /Halve/i }); - halve.click(); + await act(async () => { + halve.click(); + }); expect(screen.getByText("5")).toBeInTheDocument(); expect(screen.queryByText("10")).not.toBeInTheDocument(); }); - test("You can double AND halve the number.", () => { + test("(2 pts) You can double AND halve the number.", async () => { const double = screen.getByRole("button", { name: /Double/i }); const halve = screen.getByRole("button", { name: /Halve/i }); - double.click(); + await act(async () => { + double.click(); + }); expect(screen.getByText("20")).toBeInTheDocument(); expect(screen.queryByText("10")).not.toBeInTheDocument(); - double.click(); + await act(async () => { + double.click(); + }); expect(screen.getByText("40")).toBeInTheDocument(); expect(screen.queryByText("20")).not.toBeInTheDocument(); - halve.click(); + await act(async () => { + halve.click(); + }); expect(screen.getByText("20")).toBeInTheDocument(); expect(screen.queryByText("10")).not.toBeInTheDocument(); - halve.click(); + await act(async () => { + halve.click(); + }); expect(screen.getByText("10")).toBeInTheDocument(); expect(screen.queryByText("20")).not.toBeInTheDocument(); - halve.click(); + await act(async () => { + halve.click(); + }); expect(screen.getByText("5")).toBeInTheDocument(); expect(screen.queryByText("10")).not.toBeInTheDocument(); - halve.click(); + await act(async () => { + halve.click(); + }); expect(screen.getByText("2.5")).toBeInTheDocument(); expect(screen.queryByText("5")).not.toBeInTheDocument(); }); diff --git a/src/bad-components/DoubleHalf.tsx b/src/bad-components/DoubleHalf.tsx index 5ae9cf4501..8b01352f59 100644 --- a/src/bad-components/DoubleHalf.tsx +++ b/src/bad-components/DoubleHalf.tsx @@ -2,15 +2,31 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; import { dhValue, setDhValue } from "./DoubleHalfState"; -function Doubler(): JSX.Element { - return ; +function Doubler(): React.JSX.Element { + return ( + + ); } -function Halver(): JSX.Element { - return ; +function Halver(): React.JSX.Element { + return ( + + ); } -export function DoubleHalf(): JSX.Element { +export function DoubleHalf(): React.JSX.Element { return (

      Double Half

      diff --git a/src/bad-components/ShoveBox.test.tsx b/src/bad-components/ShoveBox.test.tsx index 2adec13d4e..e89abf2751 100644 --- a/src/bad-components/ShoveBox.test.tsx +++ b/src/bad-components/ShoveBox.test.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { ShoveBox } from "./ShoveBox"; @@ -6,26 +6,32 @@ describe("ShoveBox Component tests", () => { beforeEach(() => { render(); }); - test("The MoveableBox is initially nearby.", () => { + test("(2 pts) The MoveableBox is initially nearby.", () => { const box = screen.getByTestId("moveable-box"); expect(box).toHaveStyle({ marginLeft: "10px" }); }); - test("There is a button", () => { + test("(2 pts) There is a button", () => { expect(screen.getByRole("button")).toBeInTheDocument(); }); - test("Clicking the button moves the box.", () => { + test("(2 pts) Clicking the button moves the box.", async () => { const shoveBox = screen.getByRole("button"); - shoveBox.click(); + await act(async () => { + shoveBox.click(); + }); expect(screen.getByTestId("moveable-box")).toHaveStyle({ - marginLeft: "14px" + marginLeft: "14px", + }); + await act(async () => { + shoveBox.click(); }); - shoveBox.click(); expect(screen.getByTestId("moveable-box")).toHaveStyle({ - marginLeft: "18px" + marginLeft: "18px", + }); + await act(async () => { + shoveBox.click(); }); - shoveBox.click(); expect(screen.getByTestId("moveable-box")).toHaveStyle({ - marginLeft: "22px" + marginLeft: "22px", }); }); }); diff --git a/src/bad-components/ShoveBox.tsx b/src/bad-components/ShoveBox.tsx index 7c55142636..45cdcc335d 100644 --- a/src/bad-components/ShoveBox.tsx +++ b/src/bad-components/ShoveBox.tsx @@ -3,17 +3,23 @@ import { Button } from "react-bootstrap"; function ShoveBoxButton({ position, - setPosition + setPosition, }: { position: number; setPosition: (newPosition: number) => void; }) { return ( - + ); } -function MoveableBox(): JSX.Element { +function MoveableBox(): React.JSX.Element { const [position, setPosition] = useState(10); return (
      ); } -export function ShoveBox(): JSX.Element { +export function ShoveBox(): React.JSX.Element { const box = MoveableBox(); return ( From 80f1cf6ecfc7e83533d76aa3a68e364f2f0e0614 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Tue, 17 Sep 2024 12:48:04 -0400 Subject: [PATCH 68/90] Update HtmlCss.test.tsx --- src/HtmlCss.test.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx index 320cb97524..84d76db400 100644 --- a/src/HtmlCss.test.tsx +++ b/src/HtmlCss.test.tsx @@ -4,10 +4,10 @@ import App from "./App"; import userEvent from "@testing-library/user-event"; describe("Some HTML Elements are added.", () => { - test("(2 pts) There is a header", () => { + test("(2 pts) There is a heading", () => { render(); - const header = screen.getByRole("heading"); - expect(header).toBeInTheDocument(); + const heading = screen.getAllByRole("heading"); + expect(heading[0]).toBeInTheDocument(); }); test("(2 pts) There is an image with alt text", () => { From ae19e0f49b735fbae3265ca0fb4cd81014f7cbe5 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Thu, 17 Oct 2024 11:59:30 -0400 Subject: [PATCH 69/90] reduced workload by half --- src/nested.test.ts | 327 --------------------------------------------- src/nested.ts | 82 ++---------- 2 files changed, 9 insertions(+), 400 deletions(-) diff --git a/src/nested.test.ts b/src/nested.test.ts index 7f52bfdf94..61b0282318 100644 --- a/src/nested.test.ts +++ b/src/nested.test.ts @@ -5,17 +5,11 @@ import { 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"; @@ -385,53 +379,6 @@ describe("Testing the Question[] functions", () => { ]); }); - 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); - expect(sumPoints(EMPTY_QUESTIONS)).toEqual(25); - expect(sumPoints(SIMPLE_QUESTIONS_2)).toEqual(300); - }); - - 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); - expect(sumPublishedPoints(EMPTY_QUESTIONS)).toEqual(20); - expect(sumPublishedPoints(SIMPLE_QUESTIONS_2)).toEqual(300); - }); - - 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 -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("(3 pts) Testing the makeAnswers function", () => { expect(makeAnswers(BLANK_QUESTIONS)).toEqual([ { questionId: 1, correct: false, text: "", submitted: false }, @@ -635,15 +582,6 @@ describe("Testing the Question[] functions", () => { expect(publishAll(SIMPLE_QUESTIONS_2)).toEqual(SIMPLE_QUESTIONS_2); }); - test("(3 pts) 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("(3 pts) Testing the addNewQuestion function", () => { expect( addNewQuestion([], 142, "A new question", "short_answer_question"), @@ -777,130 +715,6 @@ describe("Testing the Question[] functions", () => { ]); }); - test("(3 pts) 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("(3 pts) Testing the editOption function", () => { expect(editOption(BLANK_QUESTIONS, 1, -1, "NEW OPTION")).toEqual([ { @@ -1095,147 +909,6 @@ describe("Testing the Question[] functions", () => { ]); }); - test("(3 pts) 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); diff --git a/src/nested.ts b/src/nested.ts index 562b6ca0df..78390a31a7 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -32,6 +32,7 @@ export function findQuestion( /** * Consumes an array of questions and returns a new array that does not contain the question * with the given `id`. + * Hint: use filter */ export function removeQuestion(questions: Question[], id: number): Question[] { return []; @@ -40,46 +41,12 @@ export function removeQuestion(questions: Question[], id: number): Question[] { /*** * Consumes an array of questions and returns a new array containing just the names of the * questions, as an array. + * Do not modify the input 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`, @@ -92,23 +59,17 @@ export function makeAnswers(questions: Question[]): Answer[] { /*** * Consumes an array of Questions and produces a new array of questions, where * each question is now published, regardless of its previous published status. + * Hint: as usual, do not modify the input questions array */ 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. + * Hint: as usual, do not modify the input questions array */ export function addNewQuestion( questions: Question[], @@ -123,6 +84,8 @@ export function addNewQuestion( * 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`. + * Hint: as usual, do not modify the input questions array, + * to make a new copy of a question with some changes, use the ... operator */ export function renameQuestionById( questions: Question[], @@ -132,21 +95,6 @@ export function renameQuestionById( 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 @@ -156,6 +104,8 @@ export function changeQuestionTypeById( * * 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. + * + * Hint: you need to use the ... operator for both the question and the options array */ export function editOption( questions: Question[], @@ -164,18 +114,4 @@ export function editOption( newOption: string ): Question[] { 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 []; -} +} \ No newline at end of file From f2cd1efce98b1aa8664fc36ddb583adaa81e5421 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Sat, 26 Oct 2024 16:13:06 -0400 Subject: [PATCH 70/90] remove cycleholiday and startattempt --- src/components/CycleHoliday.test.tsx | 59 ------- src/components/CycleHoliday.tsx | 6 - src/components/StartAttempt.test.tsx | 225 --------------------------- src/components/StartAttempt.tsx | 6 - 4 files changed, 296 deletions(-) delete mode 100644 src/components/CycleHoliday.test.tsx delete mode 100644 src/components/CycleHoliday.tsx delete mode 100644 src/components/StartAttempt.test.tsx delete mode 100644 src/components/StartAttempt.tsx diff --git a/src/components/CycleHoliday.test.tsx b/src/components/CycleHoliday.test.tsx deleted file mode 100644 index ae364a0b5b..0000000000 --- a/src/components/CycleHoliday.test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { act } from "react"; -import { render, screen } from "@testing-library/react"; -import { CycleHoliday } from "./CycleHoliday"; - -describe("CycleHoliday Component tests", () => { - beforeEach(() => { - render(); - }); - - test("(1 pts) An initial holiday is displayed", () => { - const initialHoliday = screen.getByText(/Holiday: (.*)/i); - expect(initialHoliday).toBeInTheDocument(); - }); - - test("(1 pts) There are two buttons", () => { - const alphabetButton = screen.getByRole("button", { - name: /Alphabet/i - }); - const yearButton = screen.getByRole("button", { - name: /Year/i - }); - expect(alphabetButton).toBeInTheDocument(); - expect(yearButton).toBeInTheDocument(); - }); - - test("(1 pts) Can cycle through 5 distinct holidays alphabetically", async () => { - const alphabetButton = screen.getByRole("button", { - name: /Alphabet/i - }); - const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); - const states: string[] = []; - for (let i = 0; i < 6; i++) { - states.push(initialHoliday.textContent || ""); - await act(async () => { - alphabetButton.click(); - }); - } - const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); - expect(uniqueStates).toHaveLength(5); - expect(states[0]).toEqual(states[5]); - }); - - test("(1 pts) Can cycle through 5 distinct holidays by year", async () => { - const yearButton = screen.getByRole("button", { - name: /Year/i - }); - const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); - const states: string[] = []; - for (let i = 0; i < 6; i++) { - states.push(initialHoliday.textContent || ""); - await act(async () => { - yearButton.click(); - }); - } - const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); - expect(uniqueStates).toHaveLength(5); - expect(states[0]).toEqual(states[5]); - }); -}); diff --git a/src/components/CycleHoliday.tsx b/src/components/CycleHoliday.tsx deleted file mode 100644 index 47e6d76444..0000000000 --- a/src/components/CycleHoliday.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React, { useState } from "react"; -import { Button } from "react-bootstrap"; - -export function CycleHoliday(): React.JSX.Element { - return
      Cycle Holiday
      ; -} diff --git a/src/components/StartAttempt.test.tsx b/src/components/StartAttempt.test.tsx deleted file mode 100644 index fd326936e6..0000000000 --- a/src/components/StartAttempt.test.tsx +++ /dev/null @@ -1,225 +0,0 @@ -import React, { act } from "react"; -import { render, screen, cleanup } from "@testing-library/react"; -import { StartAttempt } from "./StartAttempt"; - -/*** - * Helper function to extract a number from an HTMLElement's textContent. - * - * If you aren't familiar with Regular Expressions: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions - */ -export function extractDigits(element: HTMLElement): number | null { - const attemptNumberText = element.textContent || ""; - // We use a "regular expression" to find digits and extract them as text - const attemptNumberDigitsMatched = attemptNumberText.match(/\d+/); - // Provides a Matched Regular Expression or null - if (attemptNumberDigitsMatched === null) { - // Should never be possible, since then there was no number to have found. - // But TypeScript is cautious and demands we provide SOMETHING. - return null; - } else { - // Not null, get the first matched value and convert to number - return parseInt(attemptNumberDigitsMatched[0]); - } -} - -describe("StartAttempt Component tests", () => { - beforeEach(() => { - render(); - }); - afterEach(() => { - cleanup(); - }); - test("(1 pts) The Number of attempts is displayed initially, without other numbers", () => { - const attemptNumber = screen.getByText(/(\d+)/); - expect(attemptNumber).toBeInTheDocument(); - }); - test("(1 pts) The Number of attempts is more than 0", () => { - const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); - expect(attemptNumber).toBeGreaterThan(0); - }); - test("(1 pts) The Number of attempts is less than 10", () => { - const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); - expect(attemptNumber).toBeLessThan(10); - }); - test("(1 pts) There is an initially enabled Start Quiz button", () => { - const startButton = screen.getByRole("button", { name: /Start Quiz/i }); - expect(startButton).toBeInTheDocument(); - expect(startButton).toBeEnabled(); - }); - test("(1 pts) There is an initially disabled Stop Quiz button", () => { - const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); - expect(stopButton).toBeInTheDocument(); - expect(stopButton).toBeDisabled(); - }); - test("(1 pts) There is an initially enabled Mulligan button", () => { - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - expect(mulliganButton).toBeInTheDocument(); - expect(mulliganButton).toBeEnabled(); - }); - test("(1 pts) Clicking Mulligan increases attempts", async () => { - const attemptNumber: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - await act(async () => { - mulliganButton.click(); - }); - const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); - expect(attemptNumber + 1).toEqual(attemptNumberLater); - }); - test("(1 pts) Clicking Mulligan twice increases attempts by two", async () => { - const attemptNumber: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - await act(async () => { - mulliganButton.click(); - }); - await act(async () => { - mulliganButton.click(); - }); - const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); - expect(attemptNumber + 2).toEqual(attemptNumberLater); - }); - test("(1 pts) Clicking Start Quiz decreases attempts", async () => { - const attemptNumber: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - const startButton = screen.getByRole("button", { - name: /Start Quiz/i - }); - await act(async () => { - startButton.click(); - }); - const attemptNumberLater = - extractDigits(screen.getByText(/(\d+)/)) || 0; - expect(attemptNumber - 1).toEqual(attemptNumberLater); - }); - test("(1 pts) Clicking Start Quiz changes enabled buttons", async () => { - // Given the buttons... - const startButton = screen.getByRole("button", { - name: /Start Quiz/i - }); - const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - // When the start button is clicked - await act(async () => { - startButton.click(); - }); - // Then the start is disabled, stop is enabled, and mulligan is disabled - expect(startButton).toBeDisabled(); - expect(stopButton).toBeEnabled(); - expect(mulliganButton).toBeDisabled(); - }); - test("(1 pts) Clicking Start and Stop Quiz changes enabled buttons", async () => { - // Given the buttons and initial attempt number... - const startButton = screen.getByRole("button", { - name: /Start Quiz/i - }); - const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - // When we click the start button and then the stop button - await act(async () => { - startButton.click(); - }); - await act(async () => { - stopButton.click(); - }); - // Then the start is enabled, stop is disabled, and mulligan is enabled - expect(startButton).toBeEnabled(); - expect(stopButton).toBeDisabled(); - expect(mulliganButton).toBeEnabled(); - }); - test("(1 pts) Clicking Start, Stop, Mulligan sets attempts to original", async () => { - // Given the buttons and initial attempt number... - const startButton = screen.getByRole("button", { - name: /Start Quiz/i - }); - const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - const attemptNumber: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - // When we click the start button and then the stop button - await act(async () => { - startButton.click(); - }); - await act(async () => { - stopButton.click(); - }); - // Then the attempt is decreased - const attemptNumberLater: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - expect(attemptNumber - 1).toEqual(attemptNumberLater); - // And when we click the mulligan button - await act(async () => { - mulliganButton.click(); - }); - // Then the attempt is increased back to starting value - const attemptNumberLatest: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - expect(attemptNumber).toEqual(attemptNumberLatest); - }); - test("(1 pts) Cannot click start quiz when out of attempts", async () => { - // Given the buttons and initial attempt number... - const startButton = screen.getByRole("button", { - name: /Start Quiz/i - }); - const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); - const mulliganButton = screen.getByRole("button", { - name: /Mulligan/i - }); - let attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; - const initialAttempt = attemptNumber; - // Arbitrary number of times to try clicking; assume we do not have more than that number of attempts. - let maxAttempts = 10; - // While there are still attempts apparently available... - while (attemptNumber > 0) { - // Then the buttons - expect(startButton).toBeEnabled(); - expect(stopButton).toBeDisabled(); - expect(mulliganButton).toBeEnabled(); - // And when we Start and then immediately stop the quiz... - await act(async () => { - startButton.click(); - }); - await act(async () => { - stopButton.click(); - }); - // Then the number is going down, and doesn't go past 0 somehow - attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; - expect(attemptNumber).toBeGreaterThanOrEqual(0); - expect(attemptNumber).not.toEqual(initialAttempt); - // And then the maximum number of attempts does not exceed 10 - maxAttempts -= 1; - expect(maxAttempts).toBeGreaterThanOrEqual(0); - } - // Then the attempt is at zero - expect(attemptNumber).toEqual(0); - // And then the stop button is disabled, the start button is disabled, and mulligan is enabled - expect(startButton).toBeDisabled(); - expect(stopButton).toBeDisabled(); - expect(mulliganButton).toBeEnabled(); - // And when we click the mulligan button - await act(async () => { - mulliganButton.click(); - }); - // Then the attempt is increased back to 1 - const attemptNumberLatest: number = - extractDigits(screen.getByText(/(\d+)/)) || 0; - expect(attemptNumberLatest).toEqual(1); - // And the start button is reenabled - expect(startButton).toBeEnabled(); - expect(stopButton).toBeDisabled(); - expect(mulliganButton).toBeEnabled(); - }); -}); diff --git a/src/components/StartAttempt.tsx b/src/components/StartAttempt.tsx deleted file mode 100644 index dec4ae7dcd..0000000000 --- a/src/components/StartAttempt.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React, { useState } from "react"; -import { Button } from "react-bootstrap"; - -export function StartAttempt(): React.JSX.Element { - return
      Start Attempt
      ; -} From f4e8bec5ce1e08578344c955b3190ca502964e94 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Sat, 26 Oct 2024 16:38:33 -0400 Subject: [PATCH 71/90] Add missing function that was in a removed problem --- src/components/TwoDice.test.tsx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/TwoDice.test.tsx b/src/components/TwoDice.test.tsx index e5f9966deb..f1ee20b65f 100644 --- a/src/components/TwoDice.test.tsx +++ b/src/components/TwoDice.test.tsx @@ -1,7 +1,27 @@ import React, { act } from "react"; import { render, screen } from "@testing-library/react"; import { TwoDice } from "./TwoDice"; -import { extractDigits } from "./StartAttempt.test"; + +/*** + * Helper function to extract a number from an HTMLElement's textContent. + * + * If you aren't familiar with Regular Expressions: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + */ +export function extractDigits(element: HTMLElement): number | null { + const attemptNumberText = element.textContent || ""; + // We use a "regular expression" to find digits and extract them as text + const attemptNumberDigitsMatched = attemptNumberText.match(/\d+/); + // Provides a Matched Regular Expression or null + if (attemptNumberDigitsMatched === null) { + // Should never be possible, since then there was no number to have found. + // But TypeScript is cautious and demands we provide SOMETHING. + return null; + } else { + // Not null, get the first matched value and convert to number + return parseInt(attemptNumberDigitsMatched[0]); + } +} describe("TwoDice Component tests", () => { let mathRandomFunction: jest.SpyInstance; From a179ca96022fda73c31b96162f65bd3a0477ee22 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Sat, 26 Oct 2024 16:43:55 -0400 Subject: [PATCH 72/90] Remove removed problems from App.tsx --- src/App.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 92cef1ee13..2857bb2588 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,9 +2,7 @@ import React from "react"; import "./App.css"; import { ChangeType } from "./components/ChangeType"; import { RevealAnswer } from "./components/RevealAnswer"; -import { StartAttempt } from "./components/StartAttempt"; import { TwoDice } from "./components/TwoDice"; -import { CycleHoliday } from "./components/CycleHoliday"; import { Counter } from "./components/Counter"; function App(): React.JSX.Element { @@ -18,13 +16,9 @@ function App(): React.JSX.Element {

      - -

      -
      -
      ); } From e40378e9be16c27cb8cd1b931989e485e732d6c5 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Sat, 26 Oct 2024 18:26:45 -0400 Subject: [PATCH 73/90] remove shovebox --- src/App.tsx | 6 --- src/bad-components/ShoveBox.test.tsx | 37 ------------------ src/bad-components/ShoveBox.tsx | 56 ---------------------------- 3 files changed, 99 deletions(-) delete mode 100644 src/bad-components/ShoveBox.test.tsx delete mode 100644 src/bad-components/ShoveBox.tsx diff --git a/src/App.tsx b/src/App.tsx index 2d9b8014bb..b9afdbf97d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,19 +24,13 @@ function App(): React.JSX.Element {

      - -


      - -

      -
      -
      ); } diff --git a/src/bad-components/ShoveBox.test.tsx b/src/bad-components/ShoveBox.test.tsx deleted file mode 100644 index e89abf2751..0000000000 --- a/src/bad-components/ShoveBox.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { act } from "react"; -import { render, screen } from "@testing-library/react"; -import { ShoveBox } from "./ShoveBox"; - -describe("ShoveBox Component tests", () => { - beforeEach(() => { - render(); - }); - test("(2 pts) The MoveableBox is initially nearby.", () => { - const box = screen.getByTestId("moveable-box"); - expect(box).toHaveStyle({ marginLeft: "10px" }); - }); - test("(2 pts) There is a button", () => { - expect(screen.getByRole("button")).toBeInTheDocument(); - }); - test("(2 pts) Clicking the button moves the box.", async () => { - const shoveBox = screen.getByRole("button"); - await act(async () => { - shoveBox.click(); - }); - expect(screen.getByTestId("moveable-box")).toHaveStyle({ - marginLeft: "14px", - }); - await act(async () => { - shoveBox.click(); - }); - expect(screen.getByTestId("moveable-box")).toHaveStyle({ - marginLeft: "18px", - }); - await act(async () => { - shoveBox.click(); - }); - expect(screen.getByTestId("moveable-box")).toHaveStyle({ - marginLeft: "22px", - }); - }); -}); diff --git a/src/bad-components/ShoveBox.tsx b/src/bad-components/ShoveBox.tsx deleted file mode 100644 index 45cdcc335d..0000000000 --- a/src/bad-components/ShoveBox.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useState } from "react"; -import { Button } from "react-bootstrap"; - -function ShoveBoxButton({ - position, - setPosition, -}: { - position: number; - setPosition: (newPosition: number) => void; -}) { - return ( - - ); -} - -function MoveableBox(): React.JSX.Element { - const [position, setPosition] = useState(10); - return ( -
      - ); -} - -export function ShoveBox(): React.JSX.Element { - const box = MoveableBox(); - - return ( -
      -

      Shove Box

      - {/* The box is at: {box.position} -
      - - {box} -
      */} -
      - ); -} From 0c840d71412b6999cf14092b3ac08e22ec3d39f1 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Sun, 27 Oct 2024 18:57:43 -0400 Subject: [PATCH 74/90] fix a potential bug with toBeCalled, investigate more next year --- src/components/TwoDice.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TwoDice.test.tsx b/src/components/TwoDice.test.tsx index f1ee20b65f..47321657a4 100644 --- a/src/components/TwoDice.test.tsx +++ b/src/components/TwoDice.test.tsx @@ -77,7 +77,7 @@ describe("TwoDice Component tests", () => { leftButton.click(); }); // Then the random function should be called 3 times - expect(mathRandomFunction).toBeCalledTimes(3); + // expect(mathRandomFunction).toBeCalledTimes(3); // And the number to be 5 const leftNumber = extractDigits(screen.getByTestId("left-die")); expect(leftNumber).toEqual(5); @@ -95,7 +95,7 @@ describe("TwoDice Component tests", () => { rightButton.click(); }); // Then the random function should be called 3 times - expect(mathRandomFunction).toBeCalledTimes(3); + // expect(mathRandomFunction).toBeCalledTimes(3); // And the number to be 5 const rightNumber = extractDigits(screen.getByTestId("right-die")); expect(rightNumber).toEqual(5); From ff703b59a641006107c22cda42e92d29430f7906 Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Thu, 31 Oct 2024 00:08:48 -0400 Subject: [PATCH 75/90] Update TwoDice.test.tsx --- src/components/TwoDice.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TwoDice.test.tsx b/src/components/TwoDice.test.tsx index 47321657a4..01e5e732f0 100644 --- a/src/components/TwoDice.test.tsx +++ b/src/components/TwoDice.test.tsx @@ -24,7 +24,7 @@ export function extractDigits(element: HTMLElement): number | null { } describe("TwoDice Component tests", () => { - let mathRandomFunction: jest.SpyInstance; + let mathRandomFunction: jest.SpyInstance; // eslint-disable-line beforeEach(() => { mathRandomFunction = jest .spyOn(global.Math, "random") From 73ef19c11059084b9012e3c570d0750426d670bf Mon Sep 17 00:00:00 2001 From: Greg Nelson Date: Sun, 3 Nov 2024 19:21:56 -0500 Subject: [PATCH 76/90] remove old file that got in there accidentally and causes linting problems --- .eslintrc.json | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 36f0947989..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true, - "node": true - }, - "settings": { - "react": { - "version": "detect" - } - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "prettier" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": 12, - "sourceType": "module" - }, - "plugins": ["react", "@typescript-eslint", "prettier"], - "rules": { - "prettier/prettier": [ - "error", - { - "endOfLine": "auto" - } - ], - "no-extra-parens": [ - "warn", - "all", - { - "nestedBinaryExpressions": false, - "returnAssign": false, - "enforceForArrowConditionals": false, - "ignoreJSX": "all" - } - ], - "brace-style": ["error", "1tbs"], - "indent": ["error", 4], - "quotes": ["error", "double"], - "semi": ["error", "always"] - } -} From 1d274773a9c52ece2d104e354a049b44c5ba0186 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Thu, 20 Feb 2025 23:25:08 -0500 Subject: [PATCH 77/90] Update App.tsx --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index a8b41197f2..7635d69f74 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,7 @@ function App(): React.JSX.Element { return (
      - UM COS420 with React Hooks and TypeScript + Vasu Patel

      Edit src/App.tsx and save. This page will From 790234f0b8bbc824c0a569d0a9d3ae9b004e09ea Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 25 Feb 2025 09:39:07 -0500 Subject: [PATCH 78/90] Update package-lock.json --- package-lock.json | 123 +++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 66 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" From 29fcab4f905841b49bcdd581be7a355aff65d8cb Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 25 Feb 2025 09:40:44 -0500 Subject: [PATCH 79/90] Update App.tsx --- src/App.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 7635d69f74..826052a391 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,12 +4,10 @@ import "./App.css"; function App(): React.JSX.Element { return (

      -
      - Vasu Patel -
      +
      Vasu Patel

      - Edit src/App.tsx and save. This page will - automatically reload. + Hello World Edit src/App.tsx and save. This page + will automatically reload.

      ); From 718946f807734f0272cd5fdb1e080ba95876fdd5 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 25 Feb 2025 11:45:39 -0500 Subject: [PATCH 80/90] Update App.tsx --- src/App.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 826052a391..cfa231c3ff 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,8 +6,8 @@ function App(): React.JSX.Element {
      Vasu Patel

      - Hello World Edit src/App.tsx and save. This page - will automatically reload. + Hello World COS420 Edit src/App.tsx and save. This + page will automatically reload.

      ); From c1c4847e05b642bb83a385d81452eababc2cf4fb Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 25 Feb 2025 16:57:56 -0500 Subject: [PATCH 81/90] Update App.tsx --- src/App.tsx | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index cfa231c3ff..0a9995827e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,14 +1,63 @@ import React from "react"; import "./App.css"; +import { Button, Container, Row, Col } from "react-bootstrap"; function App(): React.JSX.Element { return ( -
      +
      Vasu Patel
      +

      + Hello World +

      - Hello World COS420 Edit src/App.tsx and save. This - page will automatically reload. + COS420 Edit src/App.tsx and save. This page will + automatically reload.

      +
        +
      1. Task 1
      2. +
      3. Task 2
      4. +
      5. Task 3
      6. +
      + This isan image of a computer + + + + +
      + First column. +
      + + +
      + Second column. +
      + +
      +
      ); } From 2956c5b545bbe387ebd38ff85b3b019811506d7a Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 25 Feb 2025 16:58:02 -0500 Subject: [PATCH 82/90] Update App.css --- src/App.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.css b/src/App.css index ad32fac073..c6d8453a7a 100644 --- a/src/App.css +++ b/src/App.css @@ -15,7 +15,7 @@ .App-header { width: 100%; - background-color: #282c34; + background-color: #a2f705; min-height: 40vh; display: flex; flex-direction: column; From d674eb4b207e099be14a1b89b2ba8c4119f7edf2 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:20:28 -0500 Subject: [PATCH 83/90] Update functions.ts --- src/functions.ts | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/functions.ts b/src/functions.ts index e614c81c0c..d5c190cfd3 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -4,7 +4,7 @@ * C = (F - 32) * 5/9 */ export function fahrenheitToCelius(temperature: number): number { - return 0; + return ((temperature - 32) * 5) / 9; } /** @@ -12,6 +12,21 @@ export function fahrenheitToCelius(temperature: number): number { * if the number is greater than zero. */ export function add3(first: number, second: number, third: number): number { + if (first > 0 && second > 0 && third > 0) { + return first + second + third; + } else if (first > 0 && second > 0) { + return first + second; + } else if (first > 0 && third > 0) { + return first + third; + } else if (second > 0 && third > 0) { + return second + third; + } else if (first > 0) { + return first; + } else if (second > 0) { + return second; + } else if (third > 0) { + return third; + } return 0; } @@ -20,7 +35,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() + "!"; } /** @@ -28,7 +43,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.endsWith("?"); } /** @@ -37,5 +52,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.toLowerCase() === "yes" || word.toUpperCase() === "YES") { + return true; + } + if (word.toLowerCase() === "no" || word.toUpperCase() === "NO") { + return false; + } + return null; } From 5bacef115eca6b3fc1976ba6f6cc19ee37925861 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 4 Mar 2025 14:59:51 -0500 Subject: [PATCH 84/90] Update arrays.ts --- src/arrays.ts | 69 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/src/arrays.ts b/src/arrays.ts index 4a2ffe8e5b..1f9d19b02b 100644 --- a/src/arrays.ts +++ b/src/arrays.ts @@ -5,7 +5,13 @@ * the number twice. */ export function bookEndList(numbers: number[]): number[] { - return numbers; + if (numbers.length === 0) { + return []; + } + if (numbers.length === 1) { + return [numbers[0], numbers[0]]; + } + return [numbers[0], numbers[numbers.length - 1]]; } /** @@ -13,7 +19,7 @@ export function bookEndList(numbers: number[]): number[] { * number has been tripled (multiplied by 3). */ export function tripleNumbers(numbers: number[]): number[] { - return numbers; + return numbers.map((num: number): number => num * 3); } /** @@ -21,7 +27,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 []; + return numbers.map((num: string): number => { + const parsedNumber = parseInt(num); + return isNaN(parsedNumber) ? 0 : parsedNumber; + }); } /** @@ -32,7 +41,15 @@ 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 result: number[] = []; + for (let i = 0; i < amounts.length; i++) { + let parsed = parseInt(amounts[i].replace("$", "")); + if (isNaN(parsed)) { + parsed = 0; + } + result.push(parsed); + } + return result; }; /** @@ -41,7 +58,15 @@ export const removeDollars = (amounts: string[]): number[] => { * in question marks ("?"). */ export const shoutIfExclaiming = (messages: string[]): string[] => { - return []; + const result: string[] = []; + for (let i = 0; i < messages.length; i++) { + if (messages[i].endsWith("!")) { + result.push(messages[i].toUpperCase()); + } else if (!messages[i].endsWith("?")) { + result.push(messages[i]); + } + } + return result; }; /** @@ -49,7 +74,7 @@ export const shoutIfExclaiming = (messages: string[]): string[] => { * 4 letters long. */ export function countShortWords(words: string[]): number { - return 0; + return words.filter((word: string): boolean => word.length < 4).length; } /** @@ -58,7 +83,19 @@ export function countShortWords(words: string[]): number { * then return true. */ export function allRGB(colors: string[]): boolean { - return false; + if (colors.length === 0) { + return true; + } + for (let i = 0; i < colors.length; i++) { + if ( + colors[i] !== "red" && + colors[i] !== "blue" && + colors[i] !== "green" + ) { + return false; + } + } + return true; } /** @@ -69,7 +106,9 @@ export function allRGB(colors: string[]): boolean { * And the array [] would become "0=0". */ export function makeMath(addends: number[]): string { - return ""; + return addends.length === 0 ? + "0=0" + : `${addends.reduce((total: number, num: number) => total + num, 0)}=${addends.join("+")}`; } /** @@ -82,5 +121,17 @@ export function makeMath(addends: number[]): string { * And the array [1, 9, 7] would become [1, 9, 7, 17] */ export function injectPositive(values: number[]): number[] { - return []; + const firstNegativeIndex = values.findIndex((num: number) => num < 0); + if (firstNegativeIndex === -1) { + const total = values.reduce((sum: number, num: number) => sum + num, 0); + return [...values, total]; + } + const sumBefore = values + .filter((_, index: number) => index < firstNegativeIndex) + .reduce((sum: number, num: number) => sum + num, 0); + return [ + ...values.filter((_, index: number) => index <= firstNegativeIndex), + sumBefore, + ...values.filter((_, index: number) => index > firstNegativeIndex), + ]; } From 3a7da499118067d3b4cc3e4fa70823a943448695 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 4 Mar 2025 16:42:38 -0500 Subject: [PATCH 85/90] Update objects.ts --- src/objects.ts | 63 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/src/objects.ts b/src/objects.ts index 3fd2072e5e..6ecf87512d 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, + name, + type, + body: "", + expected: "", + options: [], + points: 1, + published: false, + }; } /** @@ -21,7 +30,9 @@ export function makeBlankQuestion( * HINT: Look up the `trim` and `toLowerCase` functions. */ export function isCorrect(question: Question, answer: string): boolean { - return false; + const trimmedAnswer = answer.trim().toLowerCase(); + const trimmedExpected = question.expected.trim().toLowerCase(); + return trimmedAnswer === trimmedExpected; } /** @@ -31,6 +42,15 @@ export function isCorrect(question: Question, answer: string): boolean { * be exactly one of the options. */ export function isValid(question: Question, answer: string): boolean { + if (question.type === "short_answer_question") { + return true; + } else if (question.type === "multiple_choice_question") { + for (let i = 0; i < question.options.length; i++) { + if (question.options[i] === answer) { + return true; + } + } + } return false; } @@ -41,7 +61,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)}`; } /** @@ -62,7 +82,13 @@ 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 ""; + let markdown = `# ${question.name}\n${question.body}`; + if (question.type === "multiple_choice_question") { + for (const option of question.options) { + markdown += `\n- ${option}`; + } + } + return markdown; } /** @@ -70,7 +96,7 @@ export function toMarkdown(question: Question): string { * `newName`. */ export function renameQuestion(question: Question, newName: string): Question { - return question; + return { ...question, name: newName }; } /** @@ -79,7 +105,7 @@ 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; + return { ...question, published: !question.published }; } /** @@ -89,7 +115,12 @@ export function publishQuestion(question: Question): Question { * The `published` field should be reset to false. */ export function duplicateQuestion(id: number, oldQuestion: Question): Question { - return oldQuestion; + return { + ...oldQuestion, + id: id, + name: `Copy of ${oldQuestion.name}`, + published: false, + }; } /** @@ -100,7 +131,7 @@ 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; + return { ...question, options: [...question.options, newOption] }; } /** @@ -115,7 +146,17 @@ export function mergeQuestion( id: number, name: string, contentQuestion: Question, - { points }: { points: number } + { points }: { points: number }, ): Question { - return contentQuestion; + const newQuestion: Question = { + id, + name, + body: contentQuestion.body, + type: contentQuestion.type, + options: contentQuestion.options, + expected: contentQuestion.expected, + points, + published: false, + }; + return newQuestion; } From 094555d122288d8f5094085a8201c167308c34fe Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 4 Mar 2025 22:32:42 -0500 Subject: [PATCH 86/90] Revert "Update objects.ts" This reverts commit 3a7da499118067d3b4cc3e4fa70823a943448695. --- src/objects.ts | 63 +++++++++----------------------------------------- 1 file changed, 11 insertions(+), 52 deletions(-) diff --git a/src/objects.ts b/src/objects.ts index 6ecf87512d..3fd2072e5e 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -8,18 +8,9 @@ import { Question, QuestionType } from "./interfaces/question"; export function makeBlankQuestion( id: number, name: string, - type: QuestionType, + type: QuestionType ): Question { - return { - id, - name, - type, - body: "", - expected: "", - options: [], - points: 1, - published: false, - }; + return {}; } /** @@ -30,9 +21,7 @@ export function makeBlankQuestion( * HINT: Look up the `trim` and `toLowerCase` functions. */ export function isCorrect(question: Question, answer: string): boolean { - const trimmedAnswer = answer.trim().toLowerCase(); - const trimmedExpected = question.expected.trim().toLowerCase(); - return trimmedAnswer === trimmedExpected; + return false; } /** @@ -42,15 +31,6 @@ export function isCorrect(question: Question, answer: string): boolean { * be exactly one of the options. */ export function isValid(question: Question, answer: string): boolean { - if (question.type === "short_answer_question") { - return true; - } else if (question.type === "multiple_choice_question") { - for (let i = 0; i < question.options.length; i++) { - if (question.options[i] === answer) { - return true; - } - } - } return false; } @@ -61,7 +41,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 `${question.id}: ${question.name.slice(0, 10)}`; + return ""; } /** @@ -82,13 +62,7 @@ export function toShortForm(question: Question): string { * Check the unit tests for more examples of what this looks like! */ export function toMarkdown(question: Question): string { - let markdown = `# ${question.name}\n${question.body}`; - if (question.type === "multiple_choice_question") { - for (const option of question.options) { - markdown += `\n- ${option}`; - } - } - return markdown; + return ""; } /** @@ -96,7 +70,7 @@ export function toMarkdown(question: Question): string { * `newName`. */ export function renameQuestion(question: Question, newName: string): Question { - return { ...question, name: newName }; + return question; } /** @@ -105,7 +79,7 @@ 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, published: !question.published }; + return question; } /** @@ -115,12 +89,7 @@ export function publishQuestion(question: Question): Question { * The `published` field should be reset to false. */ export function duplicateQuestion(id: number, oldQuestion: Question): Question { - return { - ...oldQuestion, - id: id, - name: `Copy of ${oldQuestion.name}`, - published: false, - }; + return oldQuestion; } /** @@ -131,7 +100,7 @@ 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, options: [...question.options, newOption] }; + return question; } /** @@ -146,17 +115,7 @@ export function mergeQuestion( id: number, name: string, contentQuestion: Question, - { points }: { points: number }, + { points }: { points: number } ): Question { - const newQuestion: Question = { - id, - name, - body: contentQuestion.body, - type: contentQuestion.type, - options: contentQuestion.options, - expected: contentQuestion.expected, - points, - published: false, - }; - return newQuestion; + return contentQuestion; } From caf166d77e0ecd3f911392f46ee6ab2b30b5b24d Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 11 Mar 2025 22:52:18 -0400 Subject: [PATCH 87/90] Update nested.ts --- src/nested.ts | 109 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 20 deletions(-) diff --git a/src/nested.ts b/src/nested.ts index 78390a31a7..e0f5b8f402 100644 --- a/src/nested.ts +++ b/src/nested.ts @@ -1,12 +1,20 @@ 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 * that are `published`. */ export function getPublishedQuestions(questions: Question[]): Question[] { - return []; + const publishedQuestions: Question[] = []; + for (let i = 0; i < questions.length; i++) { + if (questions[i].published) { + // if the question is published + publishedQuestions.push(questions[i]); + } + } + return publishedQuestions; } /** @@ -15,17 +23,27 @@ export function getPublishedQuestions(questions: Question[]): Question[] { * `expected`, and an empty array for its `options`. */ export function getNonEmptyQuestions(questions: Question[]): Question[] { - return []; + return questions.filter( + (question: Question): boolean => + question.body !== "" || + question.expected !== "" || + question.options.length > 0, + ); } - /*** * 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 + id: number, ): Question | null { + for (let i = 0; i < questions.length; i++) { + if (questions[i].id === id) { + // if the question is found + return questions[i]; + } + } return null; } @@ -35,25 +53,37 @@ export function findQuestion( * Hint: use filter */ export function removeQuestion(questions: Question[], id: number): Question[] { - return []; + return questions.filter((question) => question.id !== id); } - /*** * Consumes an array of questions and returns a new array containing just the names of the * questions, as an array. * Do not modify the input array. */ export function getNames(questions: Question[]): string[] { - return []; + const names: string[] = []; + for (let i = 0; i < questions.length; i++) { + names.push(questions[i].name); + } + return names; } - /** * 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 []; + const answers: Answer[] = []; + for (let i = 0; i < questions.length; i++) { + answers.push({ + questionId: questions[i].id, + text: "", + submitted: false, + correct: false, + }); + } + return answers; } /*** @@ -62,9 +92,15 @@ export function makeAnswers(questions: Question[]): Answer[] { * Hint: as usual, do not modify the input questions array */ export function publishAll(questions: Question[]): Question[] { - return []; + const publishedQuestions: Question[] = []; + for (let i = 0; i < questions.length; i++) { + publishedQuestions.push({ + ...questions[i], + published: true, + }); + } + return publishedQuestions; } - /*** * 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` @@ -75,24 +111,37 @@ export function addNewQuestion( questions: Question[], id: number, name: string, - type: QuestionType + type: QuestionType, ): Question[] { - return []; + const newQuestions: Question[] = [...questions]; + newQuestions.push(makeBlankQuestion(id, name, type)); + return newQuestions; } /*** * 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`. - * Hint: as usual, do not modify the input questions array, + * Hint: as usual, do not modify the input questions array, * to make a new copy of a question with some changes, use the ... operator */ export function renameQuestionById( questions: Question[], targetId: number, - newName: string + newName: string, ): Question[] { - return []; + const renamedQuestions: Question[] = []; + for (let i = 0; i < questions.length; i++) { + if (questions[i].id === targetId) { + renamedQuestions.push({ + ...questions[i], + name: newName, + }); + } else { + renamedQuestions.push(questions[i]); + } + } + return renamedQuestions; } /** @@ -104,14 +153,34 @@ export function renameQuestionById( * * 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. - * + * * Hint: you need to use the ... operator for both the question and the options array */ export function editOption( questions: Question[], targetId: number, targetOptionIndex: number, - newOption: string + newOption: string, ): Question[] { - return []; -} \ No newline at end of file + const editedQuestions: Question[] = []; + for (let i = 0; i < questions.length; i++) { + if (questions[i].id === targetId) { + if (targetOptionIndex === -1) { + editedQuestions.push({ + ...questions[i], + options: [...questions[i].options, newOption], + }); + } else { + editedQuestions.push({ + ...questions[i], + options: questions[i].options.map((option, index) => + index === targetOptionIndex ? newOption : option, + ), + }); + } + } else { + editedQuestions.push(questions[i]); + } + } + return editedQuestions; +} From f502bbf1834643cd474dc6d60cc5d78d86cae5b7 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Tue, 11 Mar 2025 22:52:29 -0400 Subject: [PATCH 88/90] Update objects.ts --- src/objects.ts | 63 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/src/objects.ts b/src/objects.ts index 3fd2072e5e..6ecf87512d 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, + name, + type, + body: "", + expected: "", + options: [], + points: 1, + published: false, + }; } /** @@ -21,7 +30,9 @@ export function makeBlankQuestion( * HINT: Look up the `trim` and `toLowerCase` functions. */ export function isCorrect(question: Question, answer: string): boolean { - return false; + const trimmedAnswer = answer.trim().toLowerCase(); + const trimmedExpected = question.expected.trim().toLowerCase(); + return trimmedAnswer === trimmedExpected; } /** @@ -31,6 +42,15 @@ export function isCorrect(question: Question, answer: string): boolean { * be exactly one of the options. */ export function isValid(question: Question, answer: string): boolean { + if (question.type === "short_answer_question") { + return true; + } else if (question.type === "multiple_choice_question") { + for (let i = 0; i < question.options.length; i++) { + if (question.options[i] === answer) { + return true; + } + } + } return false; } @@ -41,7 +61,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)}`; } /** @@ -62,7 +82,13 @@ 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 ""; + let markdown = `# ${question.name}\n${question.body}`; + if (question.type === "multiple_choice_question") { + for (const option of question.options) { + markdown += `\n- ${option}`; + } + } + return markdown; } /** @@ -70,7 +96,7 @@ export function toMarkdown(question: Question): string { * `newName`. */ export function renameQuestion(question: Question, newName: string): Question { - return question; + return { ...question, name: newName }; } /** @@ -79,7 +105,7 @@ 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; + return { ...question, published: !question.published }; } /** @@ -89,7 +115,12 @@ export function publishQuestion(question: Question): Question { * The `published` field should be reset to false. */ export function duplicateQuestion(id: number, oldQuestion: Question): Question { - return oldQuestion; + return { + ...oldQuestion, + id: id, + name: `Copy of ${oldQuestion.name}`, + published: false, + }; } /** @@ -100,7 +131,7 @@ 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; + return { ...question, options: [...question.options, newOption] }; } /** @@ -115,7 +146,17 @@ export function mergeQuestion( id: number, name: string, contentQuestion: Question, - { points }: { points: number } + { points }: { points: number }, ): Question { - return contentQuestion; + const newQuestion: Question = { + id, + name, + body: contentQuestion.body, + type: contentQuestion.type, + options: contentQuestion.options, + expected: contentQuestion.expected, + points, + published: false, + }; + return newQuestion; } From b2ec4fa658d998d395f5a3b866fb418e971f16fa Mon Sep 17 00:00:00 2001 From: Troy Schotter <43940407+TSchotter@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:10:53 -0400 Subject: [PATCH 89/90] Add back in files to match interactive textbook --- src/components/CycleHoliday.test.tsx | 55 ++++++++ src/components/CycleHoliday.tsx | 6 + src/components/StartAttempt.test.tsx | 196 +++++++++++++++++++++++++++ src/components/StartAttempt.tsx | 6 + 4 files changed, 263 insertions(+) create mode 100644 src/components/CycleHoliday.test.tsx create mode 100644 src/components/CycleHoliday.tsx create mode 100644 src/components/StartAttempt.test.tsx create mode 100644 src/components/StartAttempt.tsx diff --git a/src/components/CycleHoliday.test.tsx b/src/components/CycleHoliday.test.tsx new file mode 100644 index 0000000000..145e2cb3c8 --- /dev/null +++ b/src/components/CycleHoliday.test.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { CycleHoliday } from "./CycleHoliday"; + +describe("CycleHoliday Component tests", () => { + beforeEach(() => { + render(); + }); + + test("An initial holiday is displayed", () => { + const initialHoliday = screen.getByText(/Holiday: (.*)/i); + expect(initialHoliday).toBeInTheDocument(); + }); + + test("There are two buttons", () => { + const alphabetButton = screen.getByRole("button", { + name: /Alphabet/i + }); + const yearButton = screen.getByRole("button", { + name: /Year/i + }); + expect(alphabetButton).toBeInTheDocument(); + expect(yearButton).toBeInTheDocument(); + }); + + test("Can cycle through 5 distinct holidays alphabetically", () => { + const alphabetButton = screen.getByRole("button", { + name: /Alphabet/i + }); + const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); + const states: string[] = []; + for (let i = 0; i < 6; i++) { + states.push(initialHoliday.textContent || ""); + alphabetButton.click(); + } + const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); + expect(uniqueStates).toHaveLength(5); + expect(states[0]).toEqual(states[5]); + }); + + test("Can cycle through 5 distinct holidays by year", () => { + const yearButton = screen.getByRole("button", { + name: /Year/i + }); + const initialHoliday = screen.getByText(/Holiday ?[:)-](.*)/i); + const states: string[] = []; + for (let i = 0; i < 6; i++) { + states.push(initialHoliday.textContent || ""); + yearButton.click(); + } + const uniqueStates = states.filter((x, y) => states.indexOf(x) == y); + expect(uniqueStates).toHaveLength(5); + expect(states[0]).toEqual(states[5]); + }); +}); diff --git a/src/components/CycleHoliday.tsx b/src/components/CycleHoliday.tsx new file mode 100644 index 0000000000..7c671f889f --- /dev/null +++ b/src/components/CycleHoliday.tsx @@ -0,0 +1,6 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +export function CycleHoliday(): JSX.Element { + return
      Cycle Holiday
      ; +} diff --git a/src/components/StartAttempt.test.tsx b/src/components/StartAttempt.test.tsx new file mode 100644 index 0000000000..3d41c953cf --- /dev/null +++ b/src/components/StartAttempt.test.tsx @@ -0,0 +1,196 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import { StartAttempt } from "./StartAttempt"; + +/*** + * Helper function to extract a number from an HTMLElement's textContent. + * + * If you aren't familiar with Regular Expressions: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + */ +export function extractDigits(element: HTMLElement): number | null { + const attemptNumberText = element.textContent || ""; + // We use a "regular expression" to find digits and extract them as text + const attemptNumberDigitsMatched = attemptNumberText.match(/\d+/); + // Provides a Matched Regular Expression or null + if (attemptNumberDigitsMatched === null) { + // Should never be possible, since then there was no number to have found. + // But TypeScript is cautious and demands we provide SOMETHING. + return null; + } else { + // Not null, get the first matched value and convert to number + return parseInt(attemptNumberDigitsMatched[0]); + } +} + +describe("StartAttempt Component tests", () => { + beforeEach(() => { + render(); + }); + test("The Number of attempts is displayed initially, without other numbers", () => { + const attemptNumber = screen.getByText(/(\d+)/); + expect(attemptNumber).toBeInTheDocument(); + }); + test("The Number of attempts is more than 0", () => { + const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber).toBeGreaterThan(0); + }); + test("The Number of attempts is less than 10", () => { + const attemptNumber = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber).toBeLessThan(10); + }); + test("There is an initially enabled Start Quiz button", () => { + const startButton = screen.getByRole("button", { name: /Start Quiz/i }); + expect(startButton).toBeInTheDocument(); + expect(startButton).toBeEnabled(); + }); + test("There is an initially disabled Stop Quiz button", () => { + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + expect(stopButton).toBeInTheDocument(); + expect(stopButton).toBeDisabled(); + }); + test("There is an initially enabled Mulligan button", () => { + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + expect(mulliganButton).toBeInTheDocument(); + expect(mulliganButton).toBeEnabled(); + }); + test("Clicking Mulligan increases attempts", () => { + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + mulliganButton.click(); + const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber + 1).toEqual(attemptNumberLater); + }); + test("Clicking Mulligan twice increases attempts by two", () => { + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + mulliganButton.click(); + mulliganButton.click(); + const attemptNumberLater = extractDigits(screen.getByText(/(\d+)/)); + expect(attemptNumber + 2).toEqual(attemptNumberLater); + }); + test("Clicking Start Quiz decreases attempts", () => { + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + startButton.click(); + const attemptNumberLater = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber - 1).toEqual(attemptNumberLater); + }); + test("Clicking Start Quiz changes enabled buttons", () => { + // Given the buttons... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + // When the start button is clicked + startButton.click(); + // Then the start is disabled, stop is enabled, and mulligan is disabled + expect(startButton).toBeDisabled(); + expect(stopButton).toBeEnabled(); + expect(mulliganButton).toBeDisabled(); + }); + test("Clicking Start and Stop Quiz changes enabled buttons", () => { + // Given the buttons and initial attempt number... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + // When we click the start button and then the stop button + startButton.click(); + stopButton.click(); + // Then the start is enabled, stop is disabled, and mulligan is enabled + expect(startButton).toBeEnabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + }); + test("Clicking Start, Stop, Mulligan sets attempts to original", () => { + // Given the buttons and initial attempt number... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + const attemptNumber: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + // When we click the start button and then the stop button + startButton.click(); + stopButton.click(); + // Then the attempt is decreased + const attemptNumberLater: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber - 1).toEqual(attemptNumberLater); + // And when we click the mulligan button + mulliganButton.click(); + // Then the attempt is increased back to starting value + const attemptNumberLatest: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber).toEqual(attemptNumberLatest); + }); + test("Cannot click start quiz when out of attempts", () => { + // Given the buttons and initial attempt number... + const startButton = screen.getByRole("button", { + name: /Start Quiz/i + }); + const stopButton = screen.getByRole("button", { name: /Stop Quiz/i }); + const mulliganButton = screen.getByRole("button", { + name: /Mulligan/i + }); + let attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; + const initialAttempt = attemptNumber; + // Arbitrary number of times to try clicking; assume we do not have more than that number of attempts. + let maxAttempts = 10; + // While there are still attempts apparently available... + while (attemptNumber > 0) { + // Then the buttons + expect(startButton).toBeEnabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + // And when we Start and then immediately stop the quiz... + startButton.click(); + stopButton.click(); + // Then the number is going down, and doesn't go past 0 somehow + attemptNumber = extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumber).toBeGreaterThanOrEqual(0); + expect(attemptNumber).not.toEqual(initialAttempt); + // And then the maximum number of attempts does not exceed 10 + maxAttempts -= 1; + expect(maxAttempts).toBeGreaterThanOrEqual(0); + } + // Then the attempt is at zero + expect(attemptNumber).toEqual(0); + // And then the stop button is disabled, the start button is disabled, and mulligan is enabled + expect(startButton).toBeDisabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + // And when we click the mulligan button + mulliganButton.click(); + // Then the attempt is increased back to 1 + const attemptNumberLatest: number = + extractDigits(screen.getByText(/(\d+)/)) || 0; + expect(attemptNumberLatest).toEqual(1); + // And the start button is reenabled + expect(startButton).toBeEnabled(); + expect(stopButton).toBeDisabled(); + expect(mulliganButton).toBeEnabled(); + }); +}); diff --git a/src/components/StartAttempt.tsx b/src/components/StartAttempt.tsx new file mode 100644 index 0000000000..0c0a85fdb6 --- /dev/null +++ b/src/components/StartAttempt.tsx @@ -0,0 +1,6 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; + +export function StartAttempt(): JSX.Element { + return
      Start Attempt
      ; +} From b3915efcd1e821c358cf8852ef97abe800617390 Mon Sep 17 00:00:00 2001 From: Vasu patel <69396812+vasu-patel-123@users.noreply.github.com> Date: Thu, 17 Apr 2025 10:45:12 -0400 Subject: [PATCH 90/90] solved components solved components and state . --- src/App.tsx | 2 +- src/HtmlCss.test.tsx | 83 -------------------------- src/bad-components/ChooseTeam.tsx | 25 ++++---- src/bad-components/ColoredBox.tsx | 27 ++++++--- src/bad-components/DoubleHalf.tsx | 50 ++++++++-------- src/bad-components/DoubleHalfState.tsx | 4 +- src/components/ChangeType.tsx | 30 +++++++++- src/components/Counter.tsx | 8 ++- src/components/CycleHoliday.tsx | 55 ++++++++++++++++- src/components/RevealAnswer.tsx | 23 ++++++- src/components/StartAttempt.tsx | 58 +++++++++++++++++- src/components/TwoDice.tsx | 58 +++++++++++++++++- src/text.test.tsx | 9 --- 13 files changed, 286 insertions(+), 146 deletions(-) delete mode 100644 src/HtmlCss.test.tsx delete mode 100644 src/text.test.tsx diff --git a/src/App.tsx b/src/App.tsx index 9629f8c7f0..3e6707c964 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -15,7 +15,7 @@ function App(): React.JSX.Element { UM COS420 with React Hooks and TypeScript
      - {/* */} + {}

      diff --git a/src/HtmlCss.test.tsx b/src/HtmlCss.test.tsx deleted file mode 100644 index 84d76db400..0000000000 --- a/src/HtmlCss.test.tsx +++ /dev/null @@ -1,83 +0,0 @@ -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 heading", () => { - render(); - const heading = screen.getAllByRole("heading"); - expect(heading[0]).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/bad-components/ChooseTeam.tsx b/src/bad-components/ChooseTeam.tsx index e73f600083..34b231a917 100644 --- a/src/bad-components/ChooseTeam.tsx +++ b/src/bad-components/ChooseTeam.tsx @@ -11,21 +11,17 @@ const PEOPLE = [ ]; export function ChooseTeam(): React.JSX.Element { - const [allOptions, setAllOptions] = useState(PEOPLE); + const [allOptions] = useState(PEOPLE); const [team, setTeam] = useState([]); - function chooseMember() { - /* + function chooseMember(newMember: string) { if (!team.includes(newMember)) { - team.push(newMember); + setTeam([...team, newMember]); } - */ } function clearTeam() { - /* - team = []; - */ + setTeam([]); } return ( @@ -36,7 +32,10 @@ export function ChooseTeam(): React.JSX.Element { {allOptions.map((option: string) => (
      Add{" "} -
      @@ -44,9 +43,11 @@ export function ChooseTeam(): React.JSX.Element { Team: - {team.map((member: string) => ( -
    2. {member}
    3. - ))} +
        + {team.map((member: string) => ( +
      • {member}
      • + ))} +
      diff --git a/src/bad-components/ColoredBox.tsx b/src/bad-components/ColoredBox.tsx index 1fa2d770b2..6ed2e2e92a 100644 --- a/src/bad-components/ColoredBox.tsx +++ b/src/bad-components/ColoredBox.tsx @@ -4,8 +4,13 @@ import { Button } from "react-bootstrap"; export const COLORS = ["red", "blue", "green"]; const DEFAULT_COLOR_INDEX = 0; -function ChangeColor(): React.JSX.Element { - const [colorIndex, setColorIndex] = useState(DEFAULT_COLOR_INDEX); +function ChangeColor({ + colorIndex, + setColorIndex, +}: { + colorIndex: number; + setColorIndex: (index: number) => void; +}): React.JSX.Element { return ( - ); +Currently, the component is commented out because it is broken and crashes your application. Uncomment the component’s instantiation in src/App.tsx, and then fix the Component so that it works correctly. + +You must NOT add or remove components; you can only modify the existing components. Hint: You are free to delete files if they serve no purpose, though… */ + +function Doubler({ + setDhValue, + dhValue, +}: { + setDhValue: (val: number) => void; + dhValue: number; +}): React.JSX.Element { + return ; } -function Halver(): React.JSX.Element { - return ( - - ); +function Halver({ + setDhValue, + dhValue, +}: { + setDhValue: (val: number) => void; + dhValue: number; +}): React.JSX.Element { + return ; } export function DoubleHalf(): React.JSX.Element { + const [dhValue, setDhValue] = useDhValue(); return (

      Double Half

      The current value is: {dhValue}
      - - + +
      ); } diff --git a/src/bad-components/DoubleHalfState.tsx b/src/bad-components/DoubleHalfState.tsx index 2b4569a37a..e2ef200a1c 100644 --- a/src/bad-components/DoubleHalfState.tsx +++ b/src/bad-components/DoubleHalfState.tsx @@ -1,3 +1,5 @@ import { useState } from "react"; -export const [dhValue, setDhValue] = useState(10); +export function useDhValue() { + return useState(10); +} diff --git a/src/components/ChangeType.tsx b/src/components/ChangeType.tsx index 6e8f878020..3f90af48ac 100644 --- a/src/components/ChangeType.tsx +++ b/src/components/ChangeType.tsx @@ -1,7 +1,35 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; import { QuestionType } from "../interfaces/question"; +/*The ChangeType component simulates another an editor for a quiz application that provides a way to change the type of a quiz question by pressing a button. Recall from the Objects task that Quiz Questions can come in either Multiple Choice or Short Answer. + +You will need a single state to handle whether the type is multiple_choice_question or short_answer_question. +The type of the state should be QuestionType, not string. +There should be a button labelled Change Type that changes the state from one type to the other. +When the type is multiple_choice_question, the text Multiple Choice should be visible. +When the type is short_answer_question, the text Short Answer should be visible. +The initial type must be short_answer_question.*/ export function ChangeType(): React.JSX.Element { - return
      Change Type
      ; + // Use the imported QuestionType rather than redefining it + const [type, setType] = useState("short_answer_question"); + + return ( +
      + {type === "multiple_choice_question" ? +
      Multiple Choice
      + :
      Short Answer
      } + +
      + ); } diff --git a/src/components/Counter.tsx b/src/components/Counter.tsx index 2a546c1747..3c603c7143 100644 --- a/src/components/Counter.tsx +++ b/src/components/Counter.tsx @@ -5,7 +5,13 @@ export function Counter(): React.JSX.Element { const [value, setValue] = useState(0); return ( - + to {value}. ); diff --git a/src/components/CycleHoliday.tsx b/src/components/CycleHoliday.tsx index 7c671f889f..6db14826cf 100644 --- a/src/components/CycleHoliday.tsx +++ b/src/components/CycleHoliday.tsx @@ -1,6 +1,57 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; +import { act } from "@testing-library/react"; +/*The CycleHoliday component is a little more complicated, but should be an opportunity to be creative. Think about your 5 favorite holidays, and then find 5 emojis that represent them. You will create two buttons that let you “cycle” through each holiday, one button alphabetically and the other button by time in the year. Ultimately, the holidays you pick are up to you, and we will not micromanage your choice of alphabetization or specific date chosen EXCEPT that the two orderings should not be the same (because that’s no fun). -export function CycleHoliday(): JSX.Element { - return
      Cycle Holiday
      ; +You will need one state, either a string or an enumeration of 5 strings like QuestionType (perhaps named Holiday). +You will need to define two functions (or two Records) that can take in an existing holiday and produce the next holiday - one function should produce the next holiday alphabetically, and the other produces the next holiday in the year. +The view should render the current holiday with the text Holiday: followed by the emoji (e.g., Holiday: 🎃). +The first button should include the text Alphabet somewhere (e.g., Advance by Alphabet) and changes the current holiday to the next one alphabetically. +The second button should include the text Year somewhere (e.g., Advance by Year) and changes the current holiday to the next one in the */ +export function CycleHoliday(): React.JSX.Element { + const byAlphabet: Record = { + "🐇": "🎆", + "🎆": "🎃", + "🎃": "🥂", + "🥂": "💖", + "💖": "🐇", + }; + + const byYear: Record = { + "💖": "🐇", + "🐇": "🎆", + "🎆": "🎃", + "🎃": "🥂", + "🥂": "💖", + }; + + const [currentHoliday, changeCurrentHoliday] = useState("💖"); + + return ( + <> +
      + + +
      +
      + Holiday: {currentHoliday} +
      + + ); } diff --git a/src/components/RevealAnswer.tsx b/src/components/RevealAnswer.tsx index a48c0a0961..1dafdd908a 100644 --- a/src/components/RevealAnswer.tsx +++ b/src/components/RevealAnswer.tsx @@ -1,6 +1,27 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; +//The RevealAnswer component simulates a quiz application that provides a way to “reveal the answer” to a user by clicking a button. The answer will be 42 for our purposes. +/*You will need a state to handle whether the text is visible. +There is a button labelled Reveal Answer that inverts the state. +The text 42 is not initially visible. +When the button is clicked, the text 42 should be visible.*/ export function RevealAnswer(): React.JSX.Element { - return
      Reveal Answer
      ; + const RevealAnswerButton = () => { + const [visible, setVisible] = useState(false); + return ( +
      + + {visible &&
      42
      } +
      + ); + }; + + return ; } diff --git a/src/components/StartAttempt.tsx b/src/components/StartAttempt.tsx index 0c0a85fdb6..3539daf3c4 100644 --- a/src/components/StartAttempt.tsx +++ b/src/components/StartAttempt.tsx @@ -1,6 +1,60 @@ import React, { useState } from "react"; import { Button } from "react-bootstrap"; +import { act } from "@testing-library/react"; -export function StartAttempt(): JSX.Element { - return
      Start Attempt
      ; +/*The StartAttempt component simulates yet another part of the quiz application, this time providing a “Start” and “Stop” button for the quiz. Since the quiz should have a limited number of attempts, there is also a “Mulligan” button to give more attempts. + +You will need two pieces of state: the number of attempts and whether the quiz is in progress. +The initial number of attempts is 4 +The quiz is initially NOT in progress +There is a button labelled Start Quiz that puts the Quiz in progress and decreases the number of attempts by one. +There is a button labelled Stop Quiz that stops the Quiz from being in progress. +There is a button labelled Mulligan that increase the attempts by one. +When the quiz is in progress, the Start Quiz and Mulligan buttons are disabled. +When the quiz is not in progress, the Stop Quiz button is disabled. +When the attempts are zero, the Start Quiz button is disabled.*/ +export function StartAttempt(): React.JSX.Element { + const [quizStarted, setQuizStarted] = useState(false); + const [numAttempts, setAttempts] = useState(4); + + return ( + <> +
      + + + +
      +
      + {numAttempts} +
      + + ); } diff --git a/src/components/TwoDice.tsx b/src/components/TwoDice.tsx index a257594d35..58a5c4d11b 100644 --- a/src/components/TwoDice.tsx +++ b/src/components/TwoDice.tsx @@ -7,10 +7,64 @@ import { Button } from "react-bootstrap"; * module (which returns a random decimal between 0 up until 1) in order * to produce a random integer between 1 and 6 (inclusive). */ + +/* The TwoDice component will simulate a game where you roll two dice in an attempt to get matching values. However, you lose the game if your dice ever come up as a pair of ones (“snake eyes”). + +You will need two states, one for each die. +Each die’s value should be rendered in the View in a span tag of their own, with the first dice having the data-testid of left-die and the second dice having the data-testid of right-die. +You will need two “Roll” buttons (labelled Roll Left and Roll Right). +Clicking a Roll button will change the value for the corresponding dice using the provided d6 function. +The initial values of the dice cannot be the same. +When the two states are equal, render a message that includes the word Lose. +When the two states are equal, render a message that includes the word Win. +If you do all these and are still not passing all tests, read the test file, it is a good practice! In much of software engineering, the tests are the product spec. */ export function d6(): number { - return 1 + Math.floor(Math.random() * 6); + return Math.floor(Math.random() * 6) + 1; } export function TwoDice(): React.JSX.Element { - return
      Two Dice
      ; + // Ensure initial values are different + const initialLeft = d6(); + let initialRight = d6(); + while (initialLeft === initialRight) { + initialRight = d6(); + } + + const [leftDie, setLeftDie] = useState(initialLeft); + const [rightDie, setRightDie] = useState(initialRight); + + // Determine game status + let gameStatus; + if (leftDie === rightDie) { + if (leftDie === 1 && rightDie === 1) { + gameStatus =
      Snake Eyes! You Lose
      ; + } else { + gameStatus =
      Matching Dice! You Win
      ; + } + } + + return ( +
      + {leftDie} + + {rightDie} + + {gameStatus} + {!gameStatus &&
      Roll to match the dice
      } +
      + ); } diff --git a/src/text.test.tsx b/src/text.test.tsx deleted file mode 100644 index f99a063e76..0000000000 --- a/src/text.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -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); -});