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/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/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`] = `
+`; diff --git a/frontend/__tests__/unit/__snapshots__/NetworkHeader.snapshot.jsx.snap b/frontend/__tests__/unit/components/__snapshots__/NetworkHeader.test.jsx.snap similarity index 87% rename from frontend/__tests__/unit/__snapshots__/NetworkHeader.snapshot.jsx.snap rename to frontend/__tests__/unit/components/__snapshots__/NetworkHeader.test.jsx.snap index 0221d49f..4bfcd5ae 100644 --- a/frontend/__tests__/unit/__snapshots__/NetworkHeader.snapshot.jsx.snap +++ b/frontend/__tests__/unit/components/__snapshots__/NetworkHeader.test.jsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders HomeLoggedOut unchanged 1`] = ` +exports[`NetworkHeader renders NetworkHeader unchanged 1`] = `
{ + 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/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/"], }; 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;