Skip to content

Commit

Permalink
chore: Add initial jest tests + code coverage (#13)
Browse files Browse the repository at this point in the history
- Adds initial infra for running front-end tests (`jest`, `ts-jest`, `jest.config.js`, etc)
- Adds codecov integration front-end code
  • Loading branch information
bryphe-coder committed Jan 14, 2022
1 parent afc2fa3 commit 423611b
Show file tree
Hide file tree
Showing 20 changed files with 2,512 additions and 170 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/coder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./gotests.coverage
flags: ${{ matrix.os }}
flags: unittest-go-${{ matrix.os }}
fail_ci_if_error: true

test-js:
Expand All @@ -161,3 +161,12 @@ jobs:
- run: yarn install

- run: yarn build

- run: yarn test:coverage

- uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
flags: unittest-js
fail_ci_if_error: true
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ yarn-error.log

# Front-end ignore
.next/
site/.next/
site/.next/
coverage/
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ yarn-error.log

# Front-end ignore
.next/
site/.next/
site/.next/
coverage/
26 changes: 26 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = {
projects: [
{
coverageReporters: ["text", "lcov"],
displayName: "test",
preset: "ts-jest",
roots: ["<rootDir>/site"],
transform: {
"^.+\\.tsx?$": "ts-jest",
},
testEnvironment: "jsdom",
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
testPathIgnorePatterns: ["/node_modules/", "/__tests__/fakes"],
moduleDirectories: ["node_modules", "<rootDir>"],
},
],
collectCoverageFrom: [
"<rootDir>/site/**/*.js",
"<rootDir>/site/**/*.ts",
"<rootDir>/site/**/*.tsx",
"!<rootDir>/site/**/*.stories.tsx",
"!<rootDir>/site/.next/**/*.*",
"!<rootDir>/site/next-env.d.ts",
"!<rootDir>/site/next.config.js",
],
}
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,26 @@
"build:dev": "next build site",
"dev": "next dev site",
"format:check": "prettier --check '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}'",
"format:write": "prettier --write '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}'"
"format:write": "prettier --write '**/*.{css,html,js,json,jsx,md,ts,tsx,yaml,yml}'",
"test": "jest --selectProjects test",
"test:coverage": "jest --selectProjects test --collectCoverage"
},
"devDependencies": {
"@material-ui/core": "4.9.4",
"@material-ui/icons": "4.5.1",
"@material-ui/lab": "4.0.0-alpha.42",
"@testing-library/react": "12.1.2",
"@types/jest": "27.4.0",
"@types/node": "14.18.4",
"@types/react": "17.0.38",
"@types/react-dom": "17.0.11",
"@types/superagent": "4.1.14",
"jest": "27.4.7",
"next": "12.0.7",
"prettier": "2.5.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"ts-jest": "27.1.2",
"ts-loader": "9.2.6",
"typescript": "4.5.4"
}
Expand Down
58 changes: 58 additions & 0 deletions site/components/Button/SplitButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { fireEvent, render, screen } from "@testing-library/react"
import React from "react"
import { SplitButton, SplitButtonProps } from "./SplitButton"

namespace Helpers {
export type SplitButtonOptions = "a" | "b" | "c"

// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
export const callback = (selectedOption: SplitButtonOptions): void => {}

export const options: SplitButtonProps<SplitButtonOptions>["options"] = [
{
label: "test a",
value: "a",
},
{
label: "test b",
value: "b",
},
{
label: "test c",
value: "c",
},
]
}

describe("SplitButton", () => {
describe("onClick", () => {
it("is called when primary action is clicked", () => {
// Given
const mockedAndSpyedCallback = jest.fn(Helpers.callback)

// When
render(<SplitButton onClick={mockedAndSpyedCallback} options={Helpers.options} />)
fireEvent.click(screen.getByText("test a"))

// Then
expect(mockedAndSpyedCallback.mock.calls.length).toBe(1)
expect(mockedAndSpyedCallback.mock.calls[0][0]).toBe("a")
})

it("is called when clicking option in pop-up", () => {
// Given
const mockedAndSpyedCallback = jest.fn(Helpers.callback)

// When
render(<SplitButton onClick={mockedAndSpyedCallback} options={Helpers.options} />)
const buttons = screen.getAllByRole("button")
const dropdownButton = buttons[1]
fireEvent.click(dropdownButton)
fireEvent.click(screen.getByText("test c"))

// Then
expect(mockedAndSpyedCallback.mock.calls.length).toBe(1)
expect(mockedAndSpyedCallback.mock.calls[0][0]).toBe("c")
})
})
})
14 changes: 14 additions & 0 deletions site/components/EmptyState/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { screen } from "@testing-library/react"
import { render } from "../../test_helpers"
import React from "react"
import { EmptyState, EmptyStateProps } from "./index"

describe("EmptyState", () => {
it("renders (smoke test)", async () => {
// When
render(<EmptyState message="Hello, world" />)

// Then
await screen.findByText("Hello, world")
})
})
22 changes: 22 additions & 0 deletions site/components/Icons/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react"
import { SvgIcon } from "@material-ui/core"
import { render } from "./../../test_helpers"

import * as Icons from "./index"

const getAllIcons = (): [string, typeof SvgIcon][] => {
let k: keyof typeof Icons
let ret: [string, typeof SvgIcon][] = []
for (k in Icons) {
ret.push([k, Icons[k]])
}
return ret
}

describe("Icons", () => {
const allIcons = getAllIcons()

it.each(allIcons)(`rendering icon %p`, (_name, Icon) => {
render(<Icon />)
})
})
51 changes: 0 additions & 51 deletions site/components/Navbar/NavMenuEntry.tsx

This file was deleted.

15 changes: 15 additions & 0 deletions site/components/Navbar/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react"
import { screen } from "@testing-library/react"

import { render } from "../../test_helpers"
import { Navbar } from "./index"

describe("Navbar", () => {
it("renders content", async () => {
// When
render(<Navbar />)

// Then
await screen.findAllByText("Coder", { exact: false })
})
})
2 changes: 1 addition & 1 deletion site/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const Navbar: React.FC = () => {
</Link>
</div>
<div className={styles.fullWidth}>
<div className={styles.title}>Hello, World - Coder v2</div>
<div className={styles.title}>Coder v2</div>
</div>
<div className={styles.fixed}>
<List>
Expand Down
15 changes: 15 additions & 0 deletions site/components/Page/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react"
import { screen } from "@testing-library/react"

import { render } from "../../test_helpers"
import { Footer } from "./Footer"

describe("Footer", () => {
it("renders content", async () => {
// When
render(<Footer />)

// Then
await screen.findByText("Copyright", { exact: false })
})
})
51 changes: 1 addition & 50 deletions site/components/Page/index.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1 @@
import React from "react"
import { makeStyles } from "@material-ui/core/styles"

import { Footer } from "./Footer"
import { Navbar } from "../Navbar"

export const Page: React.FC<{ children: React.ReactNode }> = ({ children }) => {
// TODO: More interesting styling here!

const styles = useStyles()

const header = (
<div className={styles.header}>
<Navbar />
</div>
)

const footer = (
<div className={styles.footer}>
<Footer />
</div>
)

const body = <div className={styles.body}> {children}</div>

return (
<div className={styles.root}>
{header}
{body}
{footer}
</div>
)
}

const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexDirection: "column",
},
header: {
flex: 0,
},
body: {
height: "100%",
flex: 1,
},
footer: {
flex: 0,
},
}))
export * from "./Footer"
1 change: 0 additions & 1 deletion site/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require("path")

module.exports = {
env: {},
Expand Down

0 comments on commit 423611b

Please sign in to comment.