Skip to content

Commit 13b9cbb

Browse files
authored
Merge pull request #136 from davidlag0/test/front_end_tests
test: add support for automated tests for frontend with Jest and tests for HomeLoggedOut and NetworkHeader components
2 parents 8785b94 + 9b35150 commit 13b9cbb

10 files changed

+2157
-31
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { render } from "@testing-library/react";
2+
import HomeLoggedOut from "components/HomeLoggedOut";
3+
4+
it("renders HomeLoggedOut unchanged", () => {
5+
const { container } = render(<HomeLoggedOut />);
6+
expect(container).toMatchSnapshot();
7+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { render, screen } from "@testing-library/react";
2+
import HomeLoggedOut from "components/HomeLoggedOut";
3+
import { Router } from "react-router-dom";
4+
import { createMemoryHistory } from "history";
5+
import { act } from "react-dom/test-utils";
6+
import axios from "axios";
7+
import MockAdapter from "axios-mock-adapter";
8+
9+
let mock = new MockAdapter(axios);
10+
11+
describe("HomeLoggedOut", () => {
12+
test("renders HomeLoggedOut when authentication is enabled", () => {
13+
const history = createMemoryHistory();
14+
const goSpy = jest.spyOn(history, "go");
15+
16+
mock.onGet("/auth/login").reply(200, { enabled: true });
17+
18+
render(
19+
<Router history={history}>
20+
<HomeLoggedOut />
21+
</Router>
22+
);
23+
24+
const projectDescription = screen.getByRole("heading", {
25+
name: "ZeroUI - ZeroTier Controller Web UI - is a web user interface for a self-hosted ZeroTier network controller.",
26+
});
27+
28+
const loginMessage = screen.getByText(/Please Log In to continue/i);
29+
30+
expect(projectDescription).toBeInTheDocument();
31+
expect(loginMessage).toBeInTheDocument();
32+
expect(goSpy).not.toHaveBeenCalled();
33+
});
34+
35+
test("renders HomeLoggedOut when authentication is disabled", async () => {
36+
const history = createMemoryHistory();
37+
const goSpy = jest.spyOn(history, "go");
38+
39+
mock.onGet("/auth/login").reply(200, { enabled: false });
40+
41+
await act(async () => {
42+
render(
43+
<Router history={history}>
44+
<HomeLoggedOut />
45+
</Router>
46+
);
47+
});
48+
49+
const projectDescription = screen.getByRole("heading", {
50+
name: "ZeroUI - ZeroTier Controller Web UI - is a web user interface for a self-hosted ZeroTier network controller.",
51+
});
52+
53+
const loginMessage = screen.getByText(/Please Log In to continue/i);
54+
55+
expect(projectDescription).toBeInTheDocument();
56+
expect(loginMessage).toBeInTheDocument();
57+
expect(goSpy).toHaveBeenCalled();
58+
});
59+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { render } from "@testing-library/react";
2+
import NetworkHeader from "components/NetworkHeader";
3+
import { testNetwork } from "./NetworkHeader.test";
4+
5+
it("renders HomeLoggedOut unchanged", () => {
6+
const { container } = render(<NetworkHeader network={testNetwork} />);
7+
expect(container).toMatchSnapshot();
8+
});
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { render, screen } from "@testing-library/react";
2+
import NetworkHeader from "components/NetworkHeader";
3+
4+
export const testNetwork = {
5+
id: "0d303702cd0f1fc6",
6+
clock: 1672834445703,
7+
description: "Test Network",
8+
rulesSource:
9+
"\n# This is a default rule set that allows IPv4 and IPv6 traffic but otherwise\n# behaves like a standard Ethernet switch.\n\n#\n# Allow only IPv4, IPv4 ARP, and IPv6 Ethernet frames.\n#\ndrop\n not ethertype ipv4\n and not ethertype arp\n and not ethertype ipv6\n;\n\n#\n# Uncomment to drop non-ZeroTier issued and managed IP addresses.\n#\n# This prevents IP spoofing but also blocks manual IP management at the OS level and\n# bridging unless special rules to exempt certain hosts or traffic are added before\n# this rule.\n#\n#drop\n# not chr ipauth\n#;\n\n# Accept anything else. This is required since default is 'drop'.\naccept;\n",
10+
tagsByName: {},
11+
capabilitiesByName: {},
12+
config: {
13+
authTokens: [null],
14+
authorizationEndpoint: "",
15+
capabilities: [],
16+
clientId: "",
17+
creationTime: 1672676611179,
18+
dns: [],
19+
enableBroadcast: true,
20+
id: "0d303702cd0f1fc6",
21+
ipAssignmentPools: [
22+
{
23+
ipRangeEnd: "172.30.101.254",
24+
ipRangeStart: "172.30.101.1",
25+
},
26+
],
27+
mtu: 2800,
28+
multicastLimit: 32,
29+
name: "new-net-11166",
30+
nwid: "0d303702cd0f1fc6",
31+
private: true,
32+
routes: [
33+
{
34+
target: "172.30.101.0/24",
35+
via: null,
36+
},
37+
],
38+
rules: [
39+
{
40+
etherType: 2048,
41+
not: true,
42+
or: false,
43+
type: "MATCH_ETHERTYPE",
44+
},
45+
{
46+
etherType: 2054,
47+
not: true,
48+
or: false,
49+
type: "MATCH_ETHERTYPE",
50+
},
51+
{
52+
etherType: 34525,
53+
not: true,
54+
or: false,
55+
type: "MATCH_ETHERTYPE",
56+
},
57+
{
58+
type: "ACTION_DROP",
59+
},
60+
{
61+
type: "ACTION_ACCEPT",
62+
},
63+
],
64+
ssoEnabled: false,
65+
tags: [],
66+
v4AssignMode: {
67+
zt: true,
68+
},
69+
v6AssignMode: {
70+
"6plane": false,
71+
rfc4193: false,
72+
zt: false,
73+
},
74+
},
75+
};
76+
77+
describe("NetworkHeader", () => {
78+
test("renders NetworkHeader with a test network", () => {
79+
render(<NetworkHeader network={testNetwork} />);
80+
81+
const networkId = screen.getByRole("heading", {
82+
name: "0d303702cd0f1fc6",
83+
level: 5,
84+
});
85+
86+
const networkName = screen.getByRole("heading", {
87+
name: "new-net-11166",
88+
level: 6,
89+
});
90+
91+
const networkDescription = screen.getByText(/Test Network/);
92+
93+
expect(networkId).toBeInTheDocument();
94+
expect(networkName).toBeInTheDocument();
95+
expect(networkDescription).toBeInTheDocument();
96+
});
97+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders HomeLoggedOut unchanged 1`] = `
4+
<div>
5+
<div
6+
class="MuiGrid-root MuiGrid-container MuiGrid-direction-xs-column MuiGrid-align-items-xs-center MuiGrid-justify-content-xs-center"
7+
style="min-height: 50vh;"
8+
>
9+
<div
10+
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-10"
11+
>
12+
<h5
13+
class="MuiTypography-root MuiTypography-h5"
14+
>
15+
<span>
16+
ZeroUI - ZeroTier Controller Web UI - is a web user interface for a self-hosted ZeroTier network controller.
17+
</span>
18+
</h5>
19+
<p
20+
class="MuiTypography-root MuiTypography-body1"
21+
>
22+
<span>
23+
Please Log In to continue
24+
</span>
25+
</p>
26+
</div>
27+
</div>
28+
</div>
29+
`;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders HomeLoggedOut unchanged 1`] = `
4+
<div>
5+
<div
6+
class="MuiGrid-root MuiGrid-item"
7+
>
8+
<h5
9+
class="MuiTypography-root MuiTypography-h5"
10+
>
11+
<span>
12+
0d303702cd0f1fc6
13+
</span>
14+
</h5>
15+
<h6
16+
class="MuiTypography-root MuiTypography-h6"
17+
style="font-style: italic;"
18+
>
19+
<span>
20+
new-net-11166
21+
</span>
22+
</h6>
23+
<span>
24+
Test Network
25+
</span>
26+
</div>
27+
</div>
28+
`;

frontend/jest.config.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Add any custom config to be passed to Jest
2+
const customJestConfig = {
3+
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
4+
moduleDirectories: ["node_modules", "<rootDir>/", "src"],
5+
transform: {
6+
// Use babel-jest to transpile tests with the below presets
7+
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
8+
"^.+\\.(js|jsx|ts|tsx)$": [
9+
"babel-jest",
10+
{
11+
presets: [
12+
"@babel/preset-env",
13+
[
14+
"@babel/preset-react",
15+
{
16+
runtime: "automatic",
17+
},
18+
],
19+
],
20+
},
21+
],
22+
},
23+
testEnvironment: "jest-environment-jsdom",
24+
moduleNameMapper: {
25+
"^uuid$": require.resolve("uuid"),
26+
"^@fontsource/roboto$": "identity-obj-proxy",
27+
"\\.(png)$": "identity-obj-proxy",
28+
},
29+
testPathIgnorePatterns: ["<rootDir>/cypress/"],
30+
};
31+
32+
module.exports = customJestConfig;

frontend/jest.setup.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Optional: configure or set up a testing framework before each test.
2+
// If you delete this file, remove `setupFilesAfterEnv` from `jest.config.js`
3+
4+
// Used for __tests__/testing-library.js
5+
// Learn more: https://github.com/testing-library/jest-dom
6+
import "@testing-library/jest-dom/extend-expect";

frontend/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,19 @@
2323
"styled-components": "^5.3.5"
2424
},
2525
"devDependencies": {
26+
"@testing-library/jest-dom": "^5.16.5",
27+
"@testing-library/react": "12.1.5",
28+
"axios-mock-adapter": "^1.21.2",
29+
"jest": "^29.3.1",
30+
"jest-environment-jsdom": "^29.3.1",
31+
"jest-transform-css": "^6.0.0",
2632
"source-map-explorer": "^2.5.2"
2733
},
2834
"scripts": {
2935
"start": "BROWSER=none react-scripts start",
3036
"build": "react-scripts build",
31-
"analyze": "source-map-explorer 'build/static/js/*.js'"
37+
"analyze": "source-map-explorer 'build/static/js/*.js'",
38+
"test:unit": "jest --coverage --testPathPattern='unit'"
3239
},
3340
"homepage": "/app",
3441
"proxy": "http://127.0.0.1:4000",

0 commit comments

Comments
 (0)