From 186cacee4744b0b89842f0498bd4d4389661c54e Mon Sep 17 00:00:00 2001 From: David Laganiere <40720561+davidlag0@users.noreply.github.com> Date: Sun, 15 Jan 2023 10:33:00 -0500 Subject: [PATCH 1/3] test: ignore css imports with jest --- frontend/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/jest.config.js b/frontend/jest.config.js index c213407..73948c2 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -24,7 +24,7 @@ const customJestConfig = { moduleNameMapper: { "^uuid$": require.resolve("uuid"), "^@fontsource/roboto$": "identity-obj-proxy", - "\\.(png)$": "identity-obj-proxy", + "\\.(png|css)$": "identity-obj-proxy", }, testPathIgnorePatterns: ["/cypress/"], }; From 8931a780aa6572f4942ba238c0e5f4f579b92098 Mon Sep 17 00:00:00 2001 From: David Laganiere <40720561+davidlag0@users.noreply.github.com> Date: Sun, 15 Jan 2023 10:39:35 -0500 Subject: [PATCH 2/3] test: reorganize folder structure and files The specific test files used for snapshots only have been integrated in each component's test file so that all tests, including the snapshot are located in a single test file. Also as more tests were added, it seems like a better idea to have test data in a separate file on its own rather than import test data from another test file. FInally, with all these changes, Jest wanted to have snapshots taken again thus why the snapshot files were updated too. --- .../network.jsx} | 25 ---------------- .../__tests__/unit/HomeLoggedOut.snapshot.jsx | 7 ----- .../__tests__/unit/NetworkHeader.snapshot.jsx | 8 ----- .../{ => components}/HomeLoggedOut.test.jsx | 11 +++++-- .../unit/components/NetworkHeader.test.jsx | 30 +++++++++++++++++++ .../HomeLoggedOut.test.jsx.snap} | 2 +- .../NetworkHeader.test.jsx.snap} | 2 +- 7 files changed, 41 insertions(+), 44 deletions(-) rename frontend/__tests__/{unit/NetworkHeader.test.jsx => data/network.jsx} (74%) delete mode 100644 frontend/__tests__/unit/HomeLoggedOut.snapshot.jsx delete mode 100644 frontend/__tests__/unit/NetworkHeader.snapshot.jsx rename frontend/__tests__/unit/{ => components}/HomeLoggedOut.test.jsx (89%) create mode 100644 frontend/__tests__/unit/components/NetworkHeader.test.jsx rename frontend/__tests__/unit/{__snapshots__/HomeLoggedOut.snapshot.jsx.snap => components/__snapshots__/HomeLoggedOut.test.jsx.snap} (91%) rename frontend/__tests__/unit/{__snapshots__/NetworkHeader.snapshot.jsx.snap => components/__snapshots__/NetworkHeader.test.jsx.snap} (87%) diff --git a/frontend/__tests__/unit/NetworkHeader.test.jsx b/frontend/__tests__/data/network.jsx similarity index 74% rename from frontend/__tests__/unit/NetworkHeader.test.jsx rename to frontend/__tests__/data/network.jsx index 243ec50..9d7d87a 100644 --- a/frontend/__tests__/unit/NetworkHeader.test.jsx +++ b/frontend/__tests__/data/network.jsx @@ -1,6 +1,3 @@ -import { render, screen } from "@testing-library/react"; -import NetworkHeader from "components/NetworkHeader"; - export const testNetwork = { id: "0d303702cd0f1fc6", clock: 1672834445703, @@ -73,25 +70,3 @@ export const testNetwork = { }, }, }; - -describe("NetworkHeader", () => { - test("renders NetworkHeader with a test network", () => { - render(); - - const networkId = screen.getByRole("heading", { - name: "0d303702cd0f1fc6", - level: 5, - }); - - const networkName = screen.getByRole("heading", { - name: "new-net-11166", - level: 6, - }); - - const networkDescription = screen.getByText(/Test Network/); - - expect(networkId).toBeInTheDocument(); - expect(networkName).toBeInTheDocument(); - expect(networkDescription).toBeInTheDocument(); - }); -}); diff --git a/frontend/__tests__/unit/HomeLoggedOut.snapshot.jsx b/frontend/__tests__/unit/HomeLoggedOut.snapshot.jsx deleted file mode 100644 index 0749d1a..0000000 --- a/frontend/__tests__/unit/HomeLoggedOut.snapshot.jsx +++ /dev/null @@ -1,7 +0,0 @@ -import { render } from "@testing-library/react"; -import HomeLoggedOut from "components/HomeLoggedOut"; - -it("renders HomeLoggedOut unchanged", () => { - const { container } = render(); - expect(container).toMatchSnapshot(); -}); diff --git a/frontend/__tests__/unit/NetworkHeader.snapshot.jsx b/frontend/__tests__/unit/NetworkHeader.snapshot.jsx deleted file mode 100644 index 10a8186..0000000 --- a/frontend/__tests__/unit/NetworkHeader.snapshot.jsx +++ /dev/null @@ -1,8 +0,0 @@ -import { render } from "@testing-library/react"; -import NetworkHeader from "components/NetworkHeader"; -import { testNetwork } from "./NetworkHeader.test"; - -it("renders HomeLoggedOut unchanged", () => { - const { container } = render(); - expect(container).toMatchSnapshot(); -}); diff --git a/frontend/__tests__/unit/HomeLoggedOut.test.jsx b/frontend/__tests__/unit/components/HomeLoggedOut.test.jsx similarity index 89% rename from frontend/__tests__/unit/HomeLoggedOut.test.jsx rename to frontend/__tests__/unit/components/HomeLoggedOut.test.jsx index 0ce149c..7ff0721 100644 --- a/frontend/__tests__/unit/HomeLoggedOut.test.jsx +++ b/frontend/__tests__/unit/components/HomeLoggedOut.test.jsx @@ -6,10 +6,15 @@ import { act } from "react-dom/test-utils"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; -let mock = new MockAdapter(axios); - describe("HomeLoggedOut", () => { + it("renders HomeLoggedOut unchanged", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + test("renders HomeLoggedOut when authentication is enabled", () => { + let mock = new MockAdapter(axios); + const history = createMemoryHistory(); const goSpy = jest.spyOn(history, "go"); @@ -33,6 +38,8 @@ describe("HomeLoggedOut", () => { }); test("renders HomeLoggedOut when authentication is disabled", async () => { + let mock = new MockAdapter(axios); + const history = createMemoryHistory(); const goSpy = jest.spyOn(history, "go"); diff --git a/frontend/__tests__/unit/components/NetworkHeader.test.jsx b/frontend/__tests__/unit/components/NetworkHeader.test.jsx new file mode 100644 index 0000000..52d0171 --- /dev/null +++ b/frontend/__tests__/unit/components/NetworkHeader.test.jsx @@ -0,0 +1,30 @@ +import { render, screen } from "@testing-library/react"; +import NetworkHeader from "components/NetworkHeader"; +import { testNetwork } from "../../data/network"; + +describe("NetworkHeader", () => { + it("renders NetworkHeader unchanged", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + test("renders NetworkHeader with a test network", () => { + render(); + + const networkId = screen.getByRole("heading", { + name: "0d303702cd0f1fc6", + level: 5, + }); + + const networkName = screen.getByRole("heading", { + name: "new-net-11166", + level: 6, + }); + + const networkDescription = screen.getByText(/Test Network/); + + expect(networkId).toBeInTheDocument(); + expect(networkName).toBeInTheDocument(); + expect(networkDescription).toBeInTheDocument(); + }); +}); diff --git a/frontend/__tests__/unit/__snapshots__/HomeLoggedOut.snapshot.jsx.snap b/frontend/__tests__/unit/components/__snapshots__/HomeLoggedOut.test.jsx.snap similarity index 91% rename from frontend/__tests__/unit/__snapshots__/HomeLoggedOut.snapshot.jsx.snap rename to frontend/__tests__/unit/components/__snapshots__/HomeLoggedOut.test.jsx.snap index 8afbec2..28452c9 100644 --- a/frontend/__tests__/unit/__snapshots__/HomeLoggedOut.snapshot.jsx.snap +++ b/frontend/__tests__/unit/components/__snapshots__/HomeLoggedOut.test.jsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders HomeLoggedOut unchanged 1`] = ` +exports[`HomeLoggedOut renders HomeLoggedOut unchanged 1`] = `
Date: Sun, 15 Jan 2023 10:40:56 -0500 Subject: [PATCH 3/3] test: add tests for NetworkButton component --- .../unit/components/NetworkButton.test.jsx | 39 +++++ .../__snapshots__/NetworkButton.test.jsx.snap | 30 ++++ frontend/__tests__/unit/utils/IP.test.js | 149 ++++++++++++++++++ frontend/src/utils/IP.js | 6 +- 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 frontend/__tests__/unit/components/NetworkButton.test.jsx create mode 100644 frontend/__tests__/unit/components/__snapshots__/NetworkButton.test.jsx.snap create mode 100644 frontend/__tests__/unit/utils/IP.test.js diff --git a/frontend/__tests__/unit/components/NetworkButton.test.jsx b/frontend/__tests__/unit/components/NetworkButton.test.jsx new file mode 100644 index 0000000..c931262 --- /dev/null +++ b/frontend/__tests__/unit/components/NetworkButton.test.jsx @@ -0,0 +1,39 @@ +import { render, screen } from "@testing-library/react"; +import NetworkButton from "components/HomeLoggedIn/components/NetworkButton"; +import { testNetwork } from "../../data/network"; +import { Router } from "react-router-dom"; +import { createMemoryHistory } from "history"; + +describe("NetworkHeader", () => { + it("renders NetworkButton unchanged", () => { + const history = createMemoryHistory(); + + const { container } = render( + + + + ); + expect(container).toMatchSnapshot(); + }); + + test("renders NetworkHeader with a test network", () => { + const history = createMemoryHistory(); + + render( + + + + ); + + const networkButton = screen.getByRole("button", { + name: "0d303702cd0f1fc6 new-net-11166", + }); + + const networkLink = screen.getByRole("link", { + name: "0d303702cd0f1fc6 new-net-11166", + }); + + expect(networkButton).toBeInTheDocument(); + expect(networkLink).toBeInTheDocument(); + }); +}); diff --git a/frontend/__tests__/unit/components/__snapshots__/NetworkButton.test.jsx.snap b/frontend/__tests__/unit/components/__snapshots__/NetworkButton.test.jsx.snap new file mode 100644 index 0000000..ce09ca6 --- /dev/null +++ b/frontend/__tests__/unit/components/__snapshots__/NetworkButton.test.jsx.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NetworkHeader renders NetworkButton unchanged 1`] = ` + +`; diff --git a/frontend/__tests__/unit/utils/IP.test.js b/frontend/__tests__/unit/utils/IP.test.js new file mode 100644 index 0000000..4a792ae --- /dev/null +++ b/frontend/__tests__/unit/utils/IP.test.js @@ -0,0 +1,149 @@ +import * as IP from "utils/IP"; + +describe("IP", () => { + describe("getCIDRAddress()", () => { + test("throws and error if start parameter is not a valid IPv4", () => { + expect(() => { + IP.getCIDRAddress(1, "1.1.1.1"); + }).toThrow("ipaddr: the address has neither IPv6 nor IPv4 format"); + }); + + test("throws and error if end parameter is not a valid IPv4", () => { + expect(() => { + IP.getCIDRAddress("1.1.1.1", 1); + }).toThrow("ipaddr: the address has neither IPv6 nor IPv4 format"); + }); + + test("returns /32 if both IPv4 addresses are the same", () => { + expect(IP.getCIDRAddress("1.1.1.1", "1.1.1.1")).toBe("1.1.1.0/32"); + }); + + test("returns different values depending on how many bits are different between start and end IPv4 addresses", () => { + expect(IP.getCIDRAddress("1.1.1.1", "1.1.1.0")).toBe("1.1.1.0/31"); + expect(IP.getCIDRAddress("1.1.1.1", "1.1.1.2")).toBe("1.1.1.0/30"); + expect(IP.getCIDRAddress("1.1.1.1", "1.1.1.4")).toBe("1.1.1.0/29"); + expect(IP.getCIDRAddress("1.1.1.1", "1.1.1.8")).toBe("1.1.1.0/28"); + expect(IP.getCIDRAddress("1.1.1.1", "1.1.2.1")).toBe("1.1.1.0/22"); + }); + + test("returns '/32' no matter what valid IPv6 addresses are provided for start and end", () => { + expect(IP.getCIDRAddress("2001:db8:1234::1", "2001:db8:1234::1")).toBe( + "2001:db8:1234::0/32" + ); + expect(IP.getCIDRAddress("2001:db8:1234::32", "2001:db8:1234::1")).toBe( + "2001:db8:1234::30/32" + ); + expect(IP.getCIDRAddress("2001:db8:1234::3000", "2001:db8:1234::1")).toBe( + "2001:db8:1234::3000/32" + ); + expect(IP.getCIDRAddress("2002:db8:1234::1", "2001:db8:1234::1")).toBe( + "2002:db8:1234::0/32" + ); + }); + }); + + describe("getCIDR()", () => { + test("throws and error if start parameter is not a valid IPv4", () => { + expect(() => { + IP.getCIDR(1, "1.1.1.1"); + }).toThrow("ipaddr: the address has neither IPv6 nor IPv4 format"); + }); + + test("throws and error if end parameter is not a valid IPv4", () => { + expect(() => { + IP.getCIDR("1.1.1.1", 1); + }).toThrow("ipaddr: the address has neither IPv6 nor IPv4 format"); + }); + + test("returns 32 if both IPv4 addresses are the same", () => { + expect(IP.getCIDR("1.1.1.1", "1.1.1.1")).toBe(32); + }); + + test("returns different values depending on how many bits are different between start and end IPv4 addresses", () => { + expect(IP.getCIDR("1.1.1.1", "1.1.1.0")).toBe(31); + expect(IP.getCIDR("1.1.1.1", "1.1.1.2")).toBe(30); + expect(IP.getCIDR("1.1.1.1", "1.1.1.4")).toBe(29); + expect(IP.getCIDR("1.1.1.1", "1.1.1.8")).toBe(28); + }); + + test("returns 32 no matter what valid IPv6 addresses are provided for start and end", () => { + expect(IP.getCIDR("2001:db8:1234::1", "2001:db8:1234::1")).toBe(32); + expect(IP.getCIDR("2001:db8:1234::1", "2001:db8:1234::0")).toBe(32); + expect(IP.getCIDR("2001:db8:1234::1", "2001:db8:1234::2")).toBe(32); + expect(IP.getCIDR("2001:db8:1234::1", "2001:db8:1235::1")).toBe(32); + expect(IP.getCIDR("2002:db8:1234::1", "2001:db8:1234::1")).toBe(32); + }); + }); + + describe("toInt()", () => { + test("returns an IP in integer format when given a valid IPv4", () => { + expect(IP.toInt("1.1.1.1")).toBe(16843009); + }); + + test("throw an error if a string that is not an IP is provided as input", () => { + expect(() => { + IP.toInt("some string that is not an IPv4 or IPv6"); + }).toThrow("ipaddr: the address has neither IPv6 nor IPv4 format"); + }); + + test("throw an error if addr is undefined", () => { + expect(IP.toInt).toThrow( + "ipaddr: the address has neither IPv6 nor IPv4 format" + ); + }); + + test("returns 0 when given a valid IPv6", () => { + expect(IP.toInt("2001:db8:1234::1")).toBe(0); + }); + }); + + describe("validateIP()", () => { + test("returns true if the provided string is a valid IPv4 address", () => { + expect(IP.validateIP("1.1.1.1")).toBe(true); + }); + + test("returns true if the provided string is a valid IPv6 address", () => { + expect(IP.validateIP("2001:db8:1234::1")).toBe(true); + }); + + test("returns false if the provided string is not a valid IPv4 or IPv6 address", () => { + expect( + IP.validateIP("some string that is not an IPv4 or IPv6 address") + ).toBe(false); + }); + }); + + describe("normilizeIP()", () => { + test("returns an IPv4 address with no leading 0's for each octet", () => { + expect(IP.normilizeIP("01.01.01.01")).toBe("1.1.1.1"); + }); + + test("returns an IPv6 address with explicit 0's octets (if any) and no leading 0's (if any)", () => { + expect(IP.normilizeIP("2001:0db8:1234::0001")).toBe( + "2001:db8:1234:0:0:0:0:1" + ); + }); + + test("throw an error if a string that is not an IP is provided as input", () => { + expect(() => { + IP.normilizeIP("some string that is not an IPv4 or IPv6"); + }).toThrow("ipaddr: the address has neither IPv6 nor IPv4 format"); + }); + }); + + describe("validateCIDR()", () => { + test("returns true if provided a valid IPv4 CIDR address", () => { + expect(IP.validateCIDR("1.1.1.0/24")).toBe(true); + }); + + test("returns true if provided a valid IPv6 CIDR address", () => { + expect(IP.validateCIDR("2001:0db8:1234::/64")).toBe(true); + }); + + test("throw an error if a string that is not an IPv4 or IPv6 CIDR is provided as input", () => { + expect( + IP.validateCIDR("some string that is not an IPv4 or IPv6 CIDR address") + ).toBe(false); + }); + }); +}); diff --git a/frontend/src/utils/IP.js b/frontend/src/utils/IP.js index 47742ad..8e872af 100644 --- a/frontend/src/utils/IP.js +++ b/frontend/src/utils/IP.js @@ -5,7 +5,7 @@ export function getCIDRAddress(start, end) { return start.replace(/.$/, 0) + "/" + cidr; } -function getCIDR(start, end) { +export function getCIDR(start, end) { const startInt = toInt(start); const endInt = toInt(end); const binaryXOR = startInt ^ endInt; @@ -13,13 +13,15 @@ function getCIDR(start, end) { return 32; } else { const binaryStr = binaryXOR.toString(2); + // TODO: Both types of bits are counted here so using the + // length of binaryStr would simplify the code. const zeroCount = binaryStr.split("0").length - 1; const oneCount = binaryStr.split("1").length - 1; return 32 - (zeroCount + oneCount); } } -function toInt(addr) { +export function toInt(addr) { const ip = ipaddr.parse(addr); const arr = ip.octets; let ipInt = 0;