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 c2134077..73948c2f 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 243ec502..9d7d87ae 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 0749d1a3..00000000 --- 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 10a81863..00000000 --- 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 0ce149c9..7ff07218 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 00000000..52d01717 --- /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 8afbec29..28452c94 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 00000000..c931262d --- /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 00000000..ce09ca66 --- /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 00000000..4a792aef --- /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 47742ad0..8e872af2 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;