Skip to content

Add tests for NetworkButton component #138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { render, screen } from "@testing-library/react";
import NetworkHeader from "components/NetworkHeader";

export const testNetwork = {
id: "0d303702cd0f1fc6",
clock: 1672834445703,
Expand Down Expand Up @@ -73,25 +70,3 @@ export const testNetwork = {
},
},
};

describe("NetworkHeader", () => {
test("renders NetworkHeader with a test network", () => {
render(<NetworkHeader network={testNetwork} />);

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();
});
});
7 changes: 0 additions & 7 deletions frontend/__tests__/unit/HomeLoggedOut.snapshot.jsx

This file was deleted.

8 changes: 0 additions & 8 deletions frontend/__tests__/unit/NetworkHeader.snapshot.jsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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(<HomeLoggedOut />);
expect(container).toMatchSnapshot();
});

test("renders HomeLoggedOut when authentication is enabled", () => {
let mock = new MockAdapter(axios);

const history = createMemoryHistory();
const goSpy = jest.spyOn(history, "go");

Expand All @@ -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");

Expand Down
39 changes: 39 additions & 0 deletions frontend/__tests__/unit/components/NetworkButton.test.jsx
Original file line number Diff line number Diff line change
@@ -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(
<Router history={history}>
<NetworkButton network={testNetwork} />
</Router>
);
expect(container).toMatchSnapshot();
});

test("renders NetworkHeader with a test network", () => {
const history = createMemoryHistory();

render(
<Router history={history}>
<NetworkButton network={testNetwork} />
</Router>
);

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();
});
});
30 changes: 30 additions & 0 deletions frontend/__tests__/unit/components/NetworkHeader.test.jsx
Original file line number Diff line number Diff line change
@@ -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(<NetworkHeader network={testNetwork} />);
expect(container).toMatchSnapshot();
});

test("renders NetworkHeader with a test network", () => {
render(<NetworkHeader network={testNetwork} />);

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();
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders HomeLoggedOut unchanged 1`] = `
exports[`HomeLoggedOut renders HomeLoggedOut unchanged 1`] = `
<div>
<div
class="MuiGrid-root MuiGrid-container MuiGrid-direction-xs-column MuiGrid-align-items-xs-center MuiGrid-justify-content-xs-center"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NetworkHeader renders NetworkButton unchanged 1`] = `
<div>
<div
class="netBtn"
role="button"
>
<a
class="makeStyles-link-1"
href="/network/0d303702cd0f1fc6"
>
<ul
class="MuiList-root makeStyles-flexContainer-2 MuiList-padding"
>
<li
class="MuiListItem-root makeStyles-nwid-4 MuiListItem-gutters"
>
0d303702cd0f1fc6
</li>
<li
class="MuiListItem-root makeStyles-name-3 MuiListItem-gutters"
>
new-net-11166
</li>
</ul>
</a>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders HomeLoggedOut unchanged 1`] = `
exports[`NetworkHeader renders NetworkHeader unchanged 1`] = `
<div>
<div
class="MuiGrid-root MuiGrid-item"
Expand Down
149 changes: 149 additions & 0 deletions frontend/__tests__/unit/utils/IP.test.js
Original file line number Diff line number Diff line change
@@ -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 '<start with last character changed to 0>/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);
});
});
});
2 changes: 1 addition & 1 deletion frontend/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: ["<rootDir>/cypress/"],
};
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/utils/IP.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ 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;
if (binaryXOR === 0) {
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;
Expand Down