Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7b0488c
Start porting over some SignIn components
bryphe-coder Jan 20, 2022
747d2b2
Add formik
bryphe-coder Jan 20, 2022
0f3fcd6
Add yup
bryphe-coder Jan 20, 2022
fbd079b
Initial API scaffolding
bryphe-coder Jan 20, 2022
2c1adc4
Port over necessary form components
bryphe-coder Jan 20, 2022
e58c824
Implement sign-in flow
bryphe-coder Jan 20, 2022
e2e5a6f
Remove unnecessary return type from login
bryphe-coder Jan 20, 2022
891261d
Add AuthenticatedRouter helper
bryphe-coder Jan 20, 2022
84e89df
Filter out built nextjs files for code coverage
bryphe-coder Jan 20, 2022
01e3f52
Formatting
bryphe-coder Jan 20, 2022
ebffefe
Fix issue with 'variant' property
bryphe-coder Jan 20, 2022
2bca1eb
Formatting
bryphe-coder Jan 20, 2022
3098440
Add test for PasswordField
bryphe-coder Jan 20, 2022
dde041c
Add FullScreenLoader + test
bryphe-coder Jan 20, 2022
b9580c3
Add API to ignore list
bryphe-coder Jan 20, 2022
8f52ae2
Add test case for success/failure logging in
bryphe-coder Jan 20, 2022
9c9456b
Formatting
bryphe-coder Jan 20, 2022
48c8803
Fix SignIn test
bryphe-coder Jan 21, 2022
763c067
Pull in FormFieldProps into FormTextField for now
bryphe-coder Jan 21, 2022
e32be0f
Fix spinner to be centered
bryphe-coder Jan 21, 2022
4a0e4e5
Add LoadingButton
bryphe-coder Jan 21, 2022
5ab009f
Formatting
bryphe-coder Jan 21, 2022
f215dde
Add test case for LoadingButton
bryphe-coder Jan 21, 2022
6aea767
Fix login flow
bryphe-coder Jan 21, 2022
ba6d215
Add test case for AuthenticatedRouter, using next-router-mock
bryphe-coder Jan 21, 2022
da37ea6
Fix SignIn tests
bryphe-coder Jan 21, 2022
50537a5
Fix duplicated line
bryphe-coder Jan 21, 2022
0f4133e
Merge main
bryphe-coder Jan 21, 2022
1341033
Add browserslist, to remove extraneous lint warnings about opera and …
bryphe-coder Jan 21, 2022
544bd1e
Fix lint issues
bryphe-coder Jan 21, 2022
8073f65
Switch to same auth strategy as link
bryphe-coder Jan 21, 2022
bb71e0e
Fix up login flow to work with new strategy
bryphe-coder Jan 21, 2022
78cf45b
Remove now-unused AuthenticatedRouter
bryphe-coder Jan 21, 2022
2d6f791
Remove AuthenticatedRouter; add tests UserContext
bryphe-coder Jan 21, 2022
ec7e15d
Add test case for UserContext
bryphe-coder Jan 21, 2022
708c509
Clean up test
bryphe-coder Jan 21, 2022
fba5f79
Fix build error
bryphe-coder Jan 21, 2022
bf2a9af
Fix error structure
bryphe-coder Jan 21, 2022
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
7 changes: 7 additions & 0 deletions _jest/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Global setup for our Jest tests
*/

// Set up 'next-router-mock' to with our front-end tests:
// https://github.com/scottrippey/next-router-mock#quick-start
jest.mock("next/router", () => require("next-router-mock"))
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
displayName: "test",
preset: "ts-jest",
roots: ["<rootDir>/site"],
setupFilesAfterEnv: ["<rootDir>/_jest/setupTests.ts"],
transform: {
"^.+\\.tsx?$": "ts-jest",
},
Expand All @@ -26,8 +27,10 @@ module.exports = {
"<rootDir>/site/**/*.tsx",
"!<rootDir>/site/**/*.stories.tsx",
"!<rootDir>/site/.next/**/*.*",
"!<rootDir>/site/api.ts",
"!<rootDir>/site/dev.ts",
"!<rootDir>/site/next-env.d.ts",
"!<rootDir>/site/next.config.js",
"!<rootDir>/site/out/**/*.*",
],
}
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,28 @@
"eslint-plugin-react": "7.28.0",
"eslint-plugin-react-hooks": "4.3.0",
"express": "4.17.2",
"formik": "2.2.9",
"http-proxy-middleware": "2.0.1",
"jest": "27.4.7",
"jest-runner-eslint": "1.0.0",
"next": "12.0.7",
"next-router-mock": "^0.6.5",
"prettier": "2.5.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"sql-formatter": "^4.0.2",
"swr": "1.1.2",
"ts-jest": "27.1.2",
"ts-loader": "9.2.6",
"ts-node": "10.4.0",
"typescript": "4.5.4"
"typescript": "4.5.4",
"yup": "0.32.11"
},
"dependencies": {}
"dependencies": {},
"browserslist": [
"chrome 66",
"firefox 63",
"edge 79",
"safari 13.1"
]
}
23 changes: 23 additions & 0 deletions site/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
interface LoginResponse {
session_token: string
}

export const login = async (email: string, password: string): Promise<LoginResponse> => {
const response = await fetch("/api/v2/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
})

const body = await response.json()
if (!response.ok) {
throw new Error(body.message)
}

return body
}
23 changes: 23 additions & 0 deletions site/components/Button/LoadingButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { render, screen } from "@testing-library/react"
import React from "react"
import { LoadingButton } from "./LoadingButton"

describe("LoadingButton", () => {
it("renders", async () => {
// When
render(<LoadingButton>Sign In</LoadingButton>)

// Then
const element = await screen.findByText("Sign In")
expect(element).toBeDefined()
})

it("shows spinner if loading is set to true", async () => {
// When
render(<LoadingButton loading>Sign in</LoadingButton>)

// Then
const spinnerElement = await screen.findByRole("progressbar")
expect(spinnerElement).toBeDefined()
})
})
45 changes: 45 additions & 0 deletions site/components/Button/LoadingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Button, { ButtonProps } from "@material-ui/core/Button"
import CircularProgress from "@material-ui/core/CircularProgress"
import { makeStyles } from "@material-ui/core/styles"
import * as React from "react"

export interface LoadingButtonProps extends ButtonProps {
/** Whether or not to disable the button and show a spinner */
loading?: boolean
}

/**
* LoadingButton is a small wrapper around Material-UI's button to show a loading spinner
*
* In Material-UI 5+ - this is built-in, but since we're on an earlier version,
* we have to roll our own.
*/
export const LoadingButton: React.FC<LoadingButtonProps> = ({ loading = false, children, ...rest }) => {
const styles = useStyles()
const hidden = loading ? { opacity: 0 } : undefined

return (
<Button {...rest} disabled={rest.disabled || loading}>
<span style={hidden}>{children}</span>
{loading && (
<div className={styles.loader}>
<CircularProgress size={18} className={styles.spinner} />
</div>
)}
</Button>
)
}

const useStyles = makeStyles((theme) => ({
loader: {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
height: 18,
width: 18,
},
spinner: {
color: theme.palette.text.disabled,
},
}))
3 changes: 2 additions & 1 deletion site/components/Button/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { SplitButton } from "./SplitButton"
export * from "./SplitButton"
export * from "./LoadingButton"
77 changes: 77 additions & 0 deletions site/components/Form/FormTextField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { act, fireEvent, render, screen } from "@testing-library/react"
import { useFormik } from "formik"
import React from "react"
import * as yup from "yup"
import { formTextFieldFactory, FormTextFieldProps } from "./FormTextField"

namespace Helpers {
export interface FormValues {
name: string
}

export const requiredValidationMsg = "required"

const FormTextField = formTextFieldFactory<FormValues>()

export const Component: React.FC<Omit<FormTextFieldProps<FormValues>, "form" | "formFieldName">> = (props) => {
const form = useFormik<FormValues>({
initialValues: {
name: "",
},
onSubmit: (values, helpers) => {
return helpers.setSubmitting(false)
},
validationSchema: yup.object({
name: yup.string().required(requiredValidationMsg),
}),
})

return <FormTextField {...props} form={form} formFieldName="name" />
}
}

describe("FormTextField", () => {
describe("helperText", () => {
it("uses helperText prop when there are no errors", () => {
// Given
const props = {
helperText: "testing",
}

// When
const { queryByText } = render(<Helpers.Component {...props} />)

// Then
expect(queryByText(props.helperText)).toBeDefined()
})

it("uses validation message when there are errors", () => {
// Given
const props = {}

// When
const { container } = render(<Helpers.Component {...props} />)
const el = container.firstChild

// Then
expect(el).toBeDefined()
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeNull()

// When
act(() => {
fireEvent.focus(el as Element)
})

// Then
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeNull()

// When
act(() => {
fireEvent.blur(el as Element)
})

// Then
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeDefined()
})
})
})
Loading