diff --git a/projects/from-javascript-to-typescript/the-typeinator/01-syntactic-sugar/index.test.js b/projects/from-javascript-to-typescript/the-typeinator/01-syntactic-sugar/index.test.js new file mode 100644 index 00000000..544307ac --- /dev/null +++ b/projects/from-javascript-to-typescript/the-typeinator/01-syntactic-sugar/index.test.js @@ -0,0 +1,53 @@ +const { announceMachines } = process.env.TEST_SOLUTIONS + ? require("./solution") + : require("./index"); + +describe(announceMachines, () => { + it("announces a machine's label when the label exists", () => { + const announce = jest.fn(); + const label = "test label"; + + announceMachines(announce, { label }); + + expect(announce).toHaveBeenCalledWith(label); + }); + + it("announces a machine's make and model when it does not have a label", () => { + const announce = jest.fn(); + const make = "test make"; + const model = "test model"; + + announceMachines(announce, { make, model }); + + expect(announce).toHaveBeenCalledWith(`Make: test make; Model: test model`); + }); + + it("returns an increased count when a machine has a label", () => { + const announce = jest.fn(); + + const labelsCount = announceMachines(announce, { label: "test label" }); + + expect(labelsCount).toBe(1); + }); + + it("returns a non-increased count when a machine does not has a label", () => { + const announce = jest.fn(); + + const labelsCount = announceMachines(announce, { make: "", model: "" }); + + expect(labelsCount).toBe(0); + }); + + it("returns an increased count for labels when only some machines have label", () => { + const announce = jest.fn(); + + const labelsCount = announceMachines( + announce, + { label: "test label" }, + { make: "", model: "" }, + { label: "test label" }, + ); + + expect(labelsCount).toBe(2); + }); +}); diff --git a/projects/from-javascript-to-typescript/the-typeinator/02-prototypes-to-classes/index.test.js b/projects/from-javascript-to-typescript/the-typeinator/02-prototypes-to-classes/index.test.js new file mode 100644 index 00000000..8b7e9092 --- /dev/null +++ b/projects/from-javascript-to-typescript/the-typeinator/02-prototypes-to-classes/index.test.js @@ -0,0 +1,102 @@ +const { Robot, Humanoid } = process.env.TEST_SOLUTIONS + ? require("./solution") + : require("./index"); + +const log = (console.log = jest.fn()); + +beforeEach(() => { + log.mockClear(); +}); + +describe(Robot, () => { + describe("announce", () => { + it("announces name and abilities", () => { + const robot = new Robot("The Typeinator", ["refactor", "transpile"]); + + robot.announce(); + + expect(log).toHaveBeenCalledWith("Greetings. I am The Typeinator."); + expect(log).toHaveBeenCalledWith("I am able to refactor."); + expect(log).toHaveBeenCalledWith("I am able to transpile."); + }); + }); + + describe("charge", () => { + it("does not recharge if power is already at 100", () => { + const robot = new Robot("", []); + + robot.charge(1); + + expect(robot.power).toBe(100); + expect(log).toHaveBeenCalledWith("I am at optimal operational capacity."); + expect(log).not.toHaveBeenCalledWith("Recharged power supplies to 100."); + }); + + it("recharges by the amount if it would not increase to 100", () => { + const robot = new Robot("", []); + robot.move(50); + + robot.charge(25); + expect(log).toHaveBeenCalledWith("Recharged power supplies to 75."); + }); + + it("recharges to 100 amount if it would increase beyond 100", () => { + const robot = new Robot("", []); + robot.move(25); + + robot.charge(50); + expect(log).toHaveBeenCalledWith("Recharged power supplies to 100."); + }); + }); + + describe("move", () => { + it("does not move if there is not enough power", () => { + const robot = new Robot("", []); + + robot.move(101); + + expect(log).toHaveBeenCalledWith( + "I do not have enough power to move 101 units.", + ); + }); + + it("moves and decreases power if there is enough power", () => { + const robot = new Robot("", []); + + robot.move(99); + + expect(log).toHaveBeenCalledWith("Moving 99 units."); + }); + + it("does not move a second time after decreasing power from a first.", () => { + const robot = new Robot("", []); + + robot.move(50); + robot.move(51); + + expect(log).toHaveBeenCalledWith("Moving 50 units."); + expect(log).toHaveBeenCalledWith( + "I do not have enough power to move 51 units.", + ); + }); + }); +}); + +describe(Humanoid, () => { + describe("announce", () => { + it("announces name, abilities, and catchphrase", () => { + const humanoid = new Humanoid( + "The Typeinator", + ["refactor", "transpile"], + "Come with me if you want types.", + ); + + humanoid.announce(); + + expect(log).toHaveBeenCalledWith("Greetings. I am The Typeinator."); + expect(log).toHaveBeenCalledWith("I am able to refactor."); + expect(log).toHaveBeenCalledWith("I am able to transpile."); + expect(log).toHaveBeenCalledWith(" > Come with me if you want types. <"); + }); + }); +}); diff --git a/projects/from-javascript-to-typescript/the-typeinator/03-callbacks-to-async-await/index.test.js b/projects/from-javascript-to-typescript/the-typeinator/03-callbacks-to-async-await/index.test.js new file mode 100644 index 00000000..89367cc5 --- /dev/null +++ b/projects/from-javascript-to-typescript/the-typeinator/03-callbacks-to-async-await/index.test.js @@ -0,0 +1,75 @@ +const { checkEmotion, speak } = process.env.TEST_SOLUTIONS + ? require("./solution") + : require("./index"); + +const simulateSetTimeoutResolve = async (time) => { + jest.advanceTimersByTime(time); + + // Wait for a seemingly larger than needed number of resolves, + // just in case the code does more async/await than it needs... + await Promise.resolve(); + await Promise.resolve(); + await Promise.resolve(); +}; + +describe(checkEmotion, () => { + it("does not process the emotion before a second", async () => { + const knownEmotions = new Set(); + let result; + checkEmotion(knownEmotions, "joy").then( + (hasEmotion) => (result = hasEmotion), + ); + + await simulateSetTimeoutResolve(999); + + expect(result).toBe(undefined); + }); + + it("processes a missing emotion as false after a second", async () => { + const knownEmotions = new Set(); + let result; + checkEmotion(knownEmotions, "joy").then( + (hasEmotion) => (result = hasEmotion), + ); + + await simulateSetTimeoutResolve(1000); + + expect(result).toBe(false); + }); + + it("processes a known emotion as true after a second", async () => { + const knownEmotions = new Set(["joy"]); + let result; + checkEmotion(knownEmotions, "joy").then( + (hasEmotion) => (result = hasEmotion), + ); + + await simulateSetTimeoutResolve(1000); + + expect(result).toBe(true); + }); +}); + +describe(speak, () => { + it("rejects if the emotion is not known", async () => { + const knownEmotions = new Set([]); + + const result = speak(knownEmotions, "joy", ""); + + await simulateSetTimeoutResolve(1000); + + return expect(result).rejects.toThrow( + new Error(`Does not compute. I do not understand joy.`), + ); + }); + + it("returns the phrase and emotion if the emotion is known", async () => { + const knownEmotions = new Set(["joy"]); + + const result = speak(knownEmotions, "joy", "Hello, world!"); + + await simulateSetTimeoutResolve(1000); + + return expect(result).resolves.toEqual(`"Hello, world!" (joy)`); + }); +});