Files
coder/site/contexts/UserContext.test.tsx
T
Bryan 4183a4e01c feat: Initial Login flow (#42)
This just implements a basic sign-in flow, using the new endpoints in #29 :
![2022-01-20 12 35 30](https://user-images.githubusercontent.com/88213859/150418044-85900d1f-8890-4c60-baae-234342de71fa.gif)

This brings over several dependencies that are necessary:
- `formik`
- `yep`

Ports over some v1 code to bootstrap it:
- `FormTextField`
- `PasswordField`
- `CoderIcon`

And implements basic sign-in:
Fixes #37 
Fixes #43

This does not implement it navbar integration (importantly - there is no way to sign out yet, unless you manually delete your `session_token`). I'll do that in the next PR - figured this was big enough to get reviewed.
2022-01-21 11:34:26 -08:00

101 lines
3.1 KiB
TypeScript

import singletonRouter from "next/router"
import mockRouter from "next-router-mock"
import React from "react"
import { SWRConfig } from "swr"
import { render, screen, waitFor } from "@testing-library/react"
import { User, UserProvider, useUser } from "./UserContext"
namespace Helpers {
// Helper component that renders out the state of the `useUser` hook.
// It just renders simple text in the 'error', 'me', and 'loading' states,
// so that the test can get a peak at the state of the hook.
const TestComponent: React.FC<{ redirectOnFailure: boolean }> = ({ redirectOnFailure }) => {
const { me, error } = useUser(redirectOnFailure)
if (error) {
return <div>{`Error: ${error.toString()}`}</div>
}
if (me) {
return <div>{`Me: ${me.toString()}`}</div>
}
return <div>Loading</div>
}
// Helper to render a userContext, and all the scaffolding needed
// (an SWRConfig as well as a UserPRovider)
export const renderUserContext = (
simulatedRequest: () => Promise<User>,
redirectOnFailure: boolean,
): React.ReactElement => {
return (
// Set up an SWRConfig that works for testing - we'll simulate a request,
// and set up the cache to reset every test.
<SWRConfig
value={{
fetcher: simulatedRequest,
// Reset cache for every test. Without this, requests will be cached between test cases.
provider: () => new Map(),
}}
>
<UserProvider>
<TestComponent redirectOnFailure={redirectOnFailure} />
</UserProvider>
</SWRConfig>
)
}
export const mockUser: User = {
id: "test-user-id",
username: "TestUser",
email: "test@coder.com",
created_at: "",
}
}
describe("UserContext", () => {
const failingRequest = () => Promise.reject("Failed to load user")
const successfulRequest = () => Promise.resolve(Helpers.mockUser)
// Reset the router to '/' before every test
beforeEach(() => {
mockRouter.setCurrentUrl("/")
})
it("shouldn't redirect if user fails to load and redirectOnFailure is false", async () => {
// When
render(Helpers.renderUserContext(failingRequest, false))
// Then
// Verify we get an error message
await waitFor(() => {
expect(screen.queryByText("Error:", { exact: false })).toBeDefined()
})
// ...and the route should be unchanged
expect(singletonRouter).toMatchObject({ asPath: "/" })
})
it("should redirect if user fails to load and redirectOnFailure is true", async () => {
// When
render(Helpers.renderUserContext(failingRequest, true))
// Then
// Verify we route to the login page
await waitFor(() => expect(singletonRouter).toMatchObject({ asPath: "/login?redirect=%2F" }))
})
it("should not redirect if user loads and redirectOnFailure is true", async () => {
// When
render(Helpers.renderUserContext(successfulRequest, true))
// Then
// Verify the user is rendered
await waitFor(() => {
expect(screen.queryByText("Me:", { exact: false })).toBeDefined()
})
// ...and the route should be unchanged
expect(singletonRouter).toMatchObject({ asPath: "/" })
})
})