fix: Setup redirect (#4064)

This commit is contained in:
Bruno Quaresma
2022-09-15 13:26:24 +00:00
committed by GitHub
parent 40c0fc285c
commit 9e9a9e0cd2
7 changed files with 66 additions and 29 deletions
@@ -0,0 +1,28 @@
import { screen } from "@testing-library/react"
import { rest } from "msw"
import { Route } from "react-router-dom"
import { renderWithAuth } from "testHelpers/renderHelpers"
import { server } from "testHelpers/server"
describe("RequireAuth", () => {
it("redirects to /setup if there is no first user", async () => {
// appear logged out
server.use(
rest.get("/api/v2/users/me", (req, res, ctx) => {
return res(ctx.status(401), ctx.json({ message: "no user here" }))
}),
)
// No first user
server.use(
rest.get("/api/v2/users/first", async (req, res, ctx) => {
return res(ctx.status(404))
}),
)
renderWithAuth(<h1>Test</h1>, {
routes: <Route path="setup" element={<h1>Setup</h1>} />,
})
await screen.findByText("Setup")
})
})
@@ -15,8 +15,11 @@ export const RequireAuth: React.FC<React.PropsWithChildren<RequireAuthProps>> =
const location = useLocation()
const isHomePage = location.pathname === "/"
const navigateTo = isHomePage ? "/login" : embedRedirect(location.pathname)
if (authState.matches("signedOut")) {
return <Navigate to={navigateTo} state={{ isRedirect: !isHomePage }} />
} else if (authState.matches("waitingForTheFirstUser")) {
return <Navigate to="/setup" />
} else if (authState.hasTag("loading")) {
return <FullScreenLoader />
} else {
+11 -4
View File
@@ -1,8 +1,9 @@
import { fireEvent, screen, waitFor } from "@testing-library/react"
import { fireEvent, screen } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import { rest } from "msw"
import { Route, Routes } from "react-router-dom"
import { Language } from "../../components/SignInForm/SignInForm"
import { history, render } from "../../testHelpers/renderHelpers"
import { history, render, waitForLoaderToBeRemoved } from "../../testHelpers/renderHelpers"
import { server } from "../../testHelpers/server"
import { LoginPage } from "./LoginPage"
@@ -36,6 +37,7 @@ describe("LoginPage", () => {
// When
render(<LoginPage />)
await waitForLoaderToBeRemoved()
const email = screen.getByLabelText(Language.emailLabel)
const password = screen.getByLabelText(Language.passwordLabel)
await userEvent.type(email, "test@coder.com")
@@ -99,9 +101,14 @@ describe("LoginPage", () => {
)
// When
render(<LoginPage />)
render(
<Routes>
<Route path="/login" element={<LoginPage />}></Route>
<Route path="/setup" element={<h1>Setup</h1>}></Route>
</Routes>,
)
// Then
await waitFor(() => expect(history.location.pathname).toEqual("/setup"))
await screen.findByText("Setup")
})
})
+21 -14
View File
@@ -1,4 +1,5 @@
import { useActor } from "@xstate/react"
import { FullScreenLoader } from "components/Loader/FullScreenLoader"
import { SignInLayout } from "components/SignInLayout/SignInLayout"
import React, { useContext } from "react"
import { Helmet } from "react-helmet-async"
@@ -28,26 +29,32 @@ export const LoginPage: React.FC = () => {
if (authState.matches("signedIn")) {
return <Navigate to={redirectTo} replace />
} else if (authState.matches("waitingForTheFirstUser")) {
return <Navigate to="/setup" />
} else {
return (
<>
<Helmet>
<title>{pageTitle("Login")}</title>
</Helmet>
<SignInLayout>
<SignInForm
authMethods={authState.context.methods}
redirectTo={redirectTo}
isLoading={isLoading}
loginErrors={{
[LoginErrors.AUTH_ERROR]: authError,
[LoginErrors.GET_USER_ERROR]: isRedirected ? getUserError : null,
[LoginErrors.CHECK_PERMISSIONS_ERROR]: checkPermissionsError,
[LoginErrors.GET_METHODS_ERROR]: getMethodsError,
}}
onSubmit={onSubmit}
/>
</SignInLayout>
{authState.hasTag("loading") ? (
<FullScreenLoader />
) : (
<SignInLayout>
<SignInForm
authMethods={authState.context.methods}
redirectTo={redirectTo}
isLoading={isLoading}
loginErrors={{
[LoginErrors.AUTH_ERROR]: authError,
[LoginErrors.GET_USER_ERROR]: isRedirected ? getUserError : null,
[LoginErrors.CHECK_PERMISSIONS_ERROR]: checkPermissionsError,
[LoginErrors.GET_METHODS_ERROR]: getMethodsError,
}}
onSubmit={onSubmit}
/>
</SignInLayout>
)}
</>
)
}
+2 -1
View File
@@ -49,7 +49,7 @@ type RenderWithAuthResult = RenderResult & { user: typeof MockUser }
*/
export function renderWithAuth(
ui: JSX.Element,
{ route = "/", path }: { route?: string; path?: string } = {},
{ route = "/", path, routes }: { route?: string; path?: string; routes?: JSX.Element } = {},
): RenderWithAuthResult {
const renderResult = wrappedRender(
<HelmetProvider>
@@ -59,6 +59,7 @@ export function renderWithAuth(
<ThemeProvider theme={dark}>
<Routes>
<Route path={path ?? route} element={<RequireAuth>{ui}</RequireAuth>} />
{routes}
</Routes>
</ThemeProvider>
</I18nextProvider>
+1 -9
View File
@@ -1,6 +1,5 @@
import { useInterpret } from "@xstate/react"
import { createContext, FC, ReactNode } from "react"
import { useNavigate } from "react-router"
import { ActorRefFrom } from "xstate"
import { authMachine } from "./auth/authXService"
import { buildInfoMachine } from "./buildInfo/buildInfoXService"
@@ -25,17 +24,10 @@ interface XServiceContextType {
export const XServiceContext = createContext({} as XServiceContextType)
export const XServiceProvider: FC<{ children: ReactNode }> = ({ children }) => {
const navigate = useNavigate()
const redirectToSetupPage = () => {
navigate("setup")
}
return (
<XServiceContext.Provider
value={{
authXService: useInterpret(() =>
authMachine.withConfig({ actions: { redirectToSetupPage } }),
),
authXService: useInterpret(authMachine),
buildInfoXService: useInterpret(buildInfoMachine),
entitlementsXService: useInterpret(entitlementsMachine),
siteRolesXService: useInterpret(siteRolesMachine),
-1
View File
@@ -408,7 +408,6 @@ export const authMachine =
tags: "loading",
},
waitingForTheFirstUser: {
entry: "redirectToSetupPage",
on: {
SIGN_IN: {
target: "signingIn",