Skip to content

Commit 97ea40c

Browse files
dependabot[bot]ynonp
authored andcommitted
Add Front End Testing:
1. Added JEST test support 2. Upgraded some dependencies (mainly typescript and eslint-typescript) 3. Replaced mocha with jest (as jest works better with TS) 4. Fixed .eslintrc to match the new eslint-typescript version 5. ADD two sample tests (footer.test.tsx and shortener.test.tsx)
1 parent d0c4fba commit 97ea40c

15 files changed

+13785
-7333
lines changed

.eslintrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"extends": [
33
"eslint:recommended",
4-
"plugin:@typescript-eslint/recommended",
4+
"plugin:@typescript-eslint/eslint-recommended",
55
"plugin:prettier/recommended"
66
],
77
"parser": "@typescript-eslint/parser",
@@ -14,6 +14,7 @@
1414
"no-useless-return": "warn",
1515
"no-var": "warn",
1616
"no-console": "warn",
17+
"no-unused-vars": "off",
1718
"max-len": ["warn", { "comments": 80 }],
1819
"no-param-reassign": 0,
1920
"require-atomic-updates": 0,

client/components/Input.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from 'react';
12
import { Flex, BoxProps } from "reflexbox/styled-components";
23
import styled, { css, keyframes } from "styled-components";
34
import { withProp, prop, ifProp } from "styled-tools";

client/components/Layout.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from "react";
12
import { Flex } from "reflexbox/styled-components";
23
import { FC } from "react";
34

client/components/Shortener.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ const Shortener = () => {
204204
placeholder="Paste your long URL"
205205
placeholderSize={[16, 17, 18]}
206206
fontSize={[18, 20, 22]}
207+
aria-label="target"
207208
width={1}
208209
height={[58, 64, 72]}
209210
px={0}
@@ -212,7 +213,7 @@ const Shortener = () => {
212213
autoFocus
213214
data-lpignore
214215
/>
215-
<SubmitIconWrapper onClick={onSubmit}>
216+
<SubmitIconWrapper onClick={onSubmit} role="button" aria-label="submit">
216217
<Icon
217218
name={loading ? "spinner" : "send"}
218219
size={[22, 26, 28]}

client/components/Text.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import React from "react";
12
import { switchProp, ifNotProp, ifProp } from "styled-tools";
23
import { Box, BoxProps } from "reflexbox/styled-components";
34
import styled, { css } from "styled-components";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from "react";
2+
import { render } from "@testing-library/react";
3+
import { StoreProvider } from "easy-peasy";
4+
import { initializeStore } from "../../store";
5+
import Footer from "../Footer";
6+
import getConfig from "next/config";
7+
8+
describe("<Footer /> component test", () => {
9+
let app;
10+
11+
beforeEach(() => {
12+
const store = initializeStore();
13+
app = (
14+
<StoreProvider store={store}>
15+
<Footer />
16+
</StoreProvider>
17+
);
18+
});
19+
20+
it("should contain a github link", () => {
21+
const screen = render(app);
22+
const githubLink = screen.getByRole("link", { name: "GitHub" });
23+
expect(githubLink).toHaveAttribute("href", "https://github.com/thedevs-network/kutt");
24+
});
25+
26+
it("should contain a TOS link", () => {
27+
const config = getConfig();
28+
const screen = render(app);
29+
const tosLink = screen.getByRole("link", { name: "Terms of Service" });
30+
31+
expect(tosLink).toHaveAttribute("href", "/terms");
32+
});
33+
34+
it("should show contact email if defined", () => {
35+
const config = getConfig();
36+
config.publicRuntimeConfig.CONTACT_EMAIL = 'foobar';
37+
const screen = render(app);
38+
const emailLink = screen.getByRole("link", { name: "Contact us" });
39+
40+
expect(emailLink).toHaveAttribute("href", "mailto:foobar");
41+
});
42+
43+
it("should NOT show contact email if none is defined", () => {
44+
const config = getConfig();
45+
delete(config.publicRuntimeConfig.CONTACT_EMAIL);
46+
const screen = render(app);
47+
const emailLink= screen.queryByRole("link", { name: "Contact us" });
48+
49+
expect(emailLink).toBeNull();
50+
});
51+
})
52+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from "react";
2+
import { render } from "@testing-library/react";
3+
import { StoreProvider, createStore, thunk } from "easy-peasy";
4+
import userEvent from "@testing-library/user-event"
5+
import { store } from "../../store";
6+
import Shortener from "../Shortener";
7+
8+
describe("<Shortener /> component test", () => {
9+
let app;
10+
11+
beforeEach(() => {
12+
store.links = {
13+
...store.links,
14+
submit: thunk(async (actions, payload) => {
15+
return {
16+
id: "0",
17+
address: "localhost:3000/foobar",
18+
banned: false,
19+
created_at: "now",
20+
link: "localhost:3000/foobar",
21+
target: "",
22+
updated_at: "now",
23+
visit_count: 0
24+
};
25+
})
26+
};
27+
const testStore = createStore(store);
28+
app = (
29+
<StoreProvider store={testStore}>
30+
<Shortener />
31+
</StoreProvider>
32+
);
33+
});
34+
35+
it("Should show the short URL", async () => {
36+
const screen = render(app);
37+
const urlInput = screen.getByRole("textbox", { name: "target" });
38+
userEvent.type(urlInput, "https://easy-peasy.now.sh/docs/api/thunk.html");
39+
const submitButton = screen.getByRole("button", { name: "submit" });
40+
userEvent.click(submitButton);
41+
const msg = await screen.findByText(/localhost:3000\/foobar/i);
42+
expect(msg).toBeInTheDocument();
43+
});
44+
45+
it("Should empty target input", async () => {
46+
const screen = render(app);
47+
let urlInput: HTMLInputElement = screen.getByRole("textbox", {
48+
name: "target"
49+
}) as HTMLInputElement;
50+
userEvent.type(urlInput, "https://easy-peasy.now.sh/docs/api/thunk.html");
51+
const submitButton = screen.getByRole("button", { name: "submit" });
52+
userEvent.click(submitButton);
53+
await screen.findByText(/localhost:3000\/foobar/i);
54+
urlInput = screen.getByRole("textbox", {
55+
name: "target"
56+
}) as HTMLInputElement;
57+
expect(urlInput.value).toEqual("");
58+
});
59+
});

client/pages/stats.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const StatsPage: NextPage<Props> = ({ id }) => {
2626
const { isAuthenticated } = useStoreState(s => s.auth);
2727
const [loading, setLoading] = useState(true);
2828
const [error, setError] = useState(false);
29-
const [data, setData] = useState();
29+
const [data, setData] = useState<Record<string, any> | undefined>();
3030
const [period, setPeriod] = useState("lastDay");
3131

3232
const stats = data && data[period];

client/store/store.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export interface StoreModel {
1010
links: Links;
1111
loading: Loading;
1212
settings: Settings;
13-
reset: Action;
13+
reset: Action<StoreModel>;
1414
}
1515

1616
let initState: any = {};

jest-setup.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import "@testing-library/jest-dom";
2+
import nextConfig from "./next.config";
3+
4+
jest.mock('next/config', () => () => nextConfig);
5+

jest.config.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = {
2+
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
3+
"preset": "ts-jest",
4+
"transform": {
5+
"^.+\\.js$": "babel-jest"
6+
},
7+
"testEnvironment": "jsdom",
8+
"globals": {
9+
"ts-jest": {
10+
"tsconfig": "<rootDir>/tsconfig.test.json"
11+
}
12+
}
13+
};

0 commit comments

Comments
 (0)