From 4bc2a251cf73c4917c5857e9f79f1b9780fd14b4 Mon Sep 17 00:00:00 2001 From: David Laganiere <40720561+davidlag0@users.noreply.github.com> Date: Sat, 29 Apr 2023 11:44:59 -0400 Subject: [PATCH 1/4] test(NetworkConfig): fully cover NetworkConfig.js --- .../unit/utils/NetworkConfig.test.js | 30 +++++++++++++++++++ frontend/src/utils/NetworkConfig.js | 4 +-- 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 frontend/__tests__/unit/utils/NetworkConfig.test.js diff --git a/frontend/__tests__/unit/utils/NetworkConfig.test.js b/frontend/__tests__/unit/utils/NetworkConfig.test.js new file mode 100644 index 00000000..5bf2dcac --- /dev/null +++ b/frontend/__tests__/unit/utils/NetworkConfig.test.js @@ -0,0 +1,30 @@ +import * as NetworkConfig from "utils/NetworkConfig"; + +jest.spyOn(Math, "random").mockReturnValue(0.5); +jest.spyOn(Date, "now").mockImplementation(() => 1487076708000); + +describe("NetworkConfig", () => { + it("getRandomInt()", () => { + expect(NetworkConfig.getRandomInt(1, 10)).toBe(5); + expect(NetworkConfig.getRandomInt(2, 2)).toBe(2); + expect(NetworkConfig.getRandomInt("test", 10)).toBe(NaN); + expect(NetworkConfig.getRandomInt(1, "test")).toBe(NaN); + expect(NetworkConfig.getRandomInt("test", "test")).toBe(NaN); + }); + + it("generateNetworkConfig()", () => { + expect(NetworkConfig.generateNetworkConfig()).toStrictEqual({ + config: { + name: "new-net-08000", + private: true, + v6AssignMode: { "6plane": false, rfc4193: false, zt: false }, + v4AssignMode: { zt: true }, + routes: [{ flags: 0, metric: 0, target: "172.30.127.0/24", via: null }], + ipAssignmentPools: [ + { ipRangeEnd: "172.30.127.254", ipRangeStart: "172.30.127.1" }, + ], + enableBroadcast: true, + }, + }); + }); +}); diff --git a/frontend/src/utils/NetworkConfig.js b/frontend/src/utils/NetworkConfig.js index 7a34c05e..ace86ae6 100644 --- a/frontend/src/utils/NetworkConfig.js +++ b/frontend/src/utils/NetworkConfig.js @@ -1,6 +1,6 @@ export function generateNetworkConfig() { const randSubnetPart = getRandomInt(0, 254).toString(); - const randNamePart = new Date().getTime(); + const randNamePart = new Date(Date.now()).getTime(); return { config: { name: "new-net-" + randNamePart.toString().substring(8), @@ -26,7 +26,7 @@ export function generateNetworkConfig() { }; } -function getRandomInt(min, max) { +export function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; From e2e3d303c1a977a4e51da0c5e2444839a1336b21 Mon Sep 17 00:00:00 2001 From: David Laganiere <40720561+davidlag0@users.noreply.github.com> Date: Mon, 12 Jun 2023 08:26:48 -0400 Subject: [PATCH 2/4] test(Bar): add tests to almost fully cover --- .../__tests__/unit/components/Bar.test.jsx | 100 +++++++++++++++++- .../__snapshots__/Bar.test.jsx.snap | 67 ++++++++++++ 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/frontend/__tests__/unit/components/Bar.test.jsx b/frontend/__tests__/unit/components/Bar.test.jsx index 446d349c..3ea3c39b 100644 --- a/frontend/__tests__/unit/components/Bar.test.jsx +++ b/frontend/__tests__/unit/components/Bar.test.jsx @@ -1,7 +1,8 @@ -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import Bar from "components/Bar"; -import { Router } from "react-router-dom"; +import { MemoryRouter, Route, Router } from "react-router-dom"; import { createMemoryHistory } from "history"; +import userEvent from "@testing-library/user-event"; // Useful reference: https://bholmes.dev/blog/mocking-browser-apis-fetch-localstorage-dates-the-easy-way-with-jest/ @@ -10,10 +11,10 @@ let mockStorage = {}; describe("Bar", () => { beforeAll(() => { global.Storage.prototype.getItem = jest.fn((key) => mockStorage[key]); + global.Storage.prototype.clear = jest.fn(() => (mockStorage = {})); }); beforeEach(() => { - // make sure the fridge starts out empty for each test mockStorage = {}; }); @@ -44,4 +45,97 @@ describe("Bar", () => { ); expect(container).toMatchSnapshot(); }); + + it("renders Bar unchanged when logged in, after clicking button to open menu", async () => { + const history = createMemoryHistory(); + const user = userEvent.setup(); + mockStorage["loggedIn"] = true; + + const { container } = render( + + + + ); + + const menuButton = screen.getByRole("button", { + name: "", + }); + + await user.click(menuButton); + + const logOutMenuItem = screen.getByRole("menuitem", { + name: "Log out", + }); + expect(logOutMenuItem).toBeInTheDocument(); + + expect(container).toMatchSnapshot(); + }); + + test("open and close menu when logged in", async () => { + const history = createMemoryHistory(); + const user = userEvent.setup(); + mockStorage["loggedIn"] = true; + + render( + + + + ); + + const menuButton = screen.getByRole("button", { + name: "", + }); + + // Open menu + await user.click(menuButton); + + const logOutMenuItem = screen.getByRole("menuitem", { + name: "Log out", + }); + expect(logOutMenuItem).toBeInTheDocument(); + + // Close menu + await user.keyboard("{Escape}"); + + expect(logOutMenuItem).not.toBeInTheDocument(); + }); + + test("open menu and click on 'Log out'", async () => { + const user = userEvent.setup(); + mockStorage["loggedIn"] = true; + let testLocation; + + render( + + + + + { + testLocation = location; + return null; + }} + /> + + ); + + const menuButton = screen.getByRole("button", { + name: "", + }); + + // Open menu + await user.click(menuButton); + + const logOutMenuItem = screen.getByRole("menuitem", { + name: "Log out", + }); + expect(logOutMenuItem).toBeInTheDocument(); + + // Click on 'Log out' + await user.click(logOutMenuItem); + + expect(Object.keys(mockStorage).length).toBe(0); + expect(testLocation.pathname).toBe("/"); + }); }); diff --git a/frontend/__tests__/unit/components/__snapshots__/Bar.test.jsx.snap b/frontend/__tests__/unit/components/__snapshots__/Bar.test.jsx.snap index 6a4346cd..305795d3 100644 --- a/frontend/__tests__/unit/components/__snapshots__/Bar.test.jsx.snap +++ b/frontend/__tests__/unit/components/__snapshots__/Bar.test.jsx.snap @@ -56,6 +56,73 @@ exports[`Bar renders Bar unchanged when logged in 1`] = ` `; +exports[`Bar renders Bar unchanged when logged in, after clicking button to open menu 1`] = ` + +`; + exports[`Bar renders Bar unchanged when logged out 1`] = `
Date: Sun, 13 Aug 2023 14:14:26 -0400 Subject: [PATCH 3/4] chore: update scripts for tests --- frontend/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 11846814..875358a2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,7 +37,8 @@ "start": "BROWSER=none react-scripts start", "build": "react-scripts build", "analyze": "source-map-explorer 'build/static/js/*.js'", - "test:unit": "jest --coverage --testPathPattern='unit'" + "test:unit": "jest --coverage --testPathPattern='unit' --silent", + "test": "jest --coverage" }, "homepage": "/app", "proxy": "http://127.0.0.1:4000", From 514a86831fb04aed6207537bfa80859c55564ef9 Mon Sep 17 00:00:00 2001 From: David Laganiere <40720561+davidlag0@users.noreply.github.com> Date: Sun, 13 Aug 2023 14:21:21 -0400 Subject: [PATCH 4/4] test(HomeLoggedIn): add test for 100% coverage --- .../unit/components/HomeLoggedIn.test.jsx | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/frontend/__tests__/unit/components/HomeLoggedIn.test.jsx b/frontend/__tests__/unit/components/HomeLoggedIn.test.jsx index 28779523..5a8734da 100644 --- a/frontend/__tests__/unit/components/HomeLoggedIn.test.jsx +++ b/frontend/__tests__/unit/components/HomeLoggedIn.test.jsx @@ -1,9 +1,11 @@ import { render, screen } from "@testing-library/react"; import HomeLoggedIn from "components/HomeLoggedIn"; -import { Router } from "react-router-dom"; +import { MemoryRouter, Route, Router } from "react-router-dom"; import { createMemoryHistory } from "history"; import { testNetwork } from "../../data/network"; +import userEvent from "@testing-library/user-event"; import API from "utils/API"; +import { act } from "react-dom/test-utils"; import MockAdapter from "axios-mock-adapter"; describe("HomeLoggedIn", () => { @@ -43,4 +45,44 @@ describe("HomeLoggedIn", () => { expect(container).toMatchSnapshot(); }); + + it("creates a new network when the 'Create A Network' button is clicked", async () => { + jest.spyOn(Math, "random").mockReturnValue(0.5); + jest.spyOn(Date, "now").mockImplementation(() => 1487076708000); + + let mock = new MockAdapter(API); + const user = userEvent.setup(); + let testLocation; + const networkId = "testid"; + + // For the API call with the initial render + mock.onGet("network").reply(200, []); + + // For the API call after the 'Create A Network' button is clicked + mock.onPost("/network").reply(200, { config: { id: "testid" } }); + + await act(async () => { + render( + + + + + { + testLocation = location; + return null; + }} + /> + + ); + }); + + const createANetworkButton = screen.getByRole("button", { + name: "Create A Network", + }); + + await user.click(createANetworkButton); + expect(testLocation.pathname).toBe("/network/testid"); + }); });