diff --git a/site/src/components/RequireAuth/RequireAuth.test.tsx b/site/src/components/RequireAuth/RequireAuth.test.tsx
new file mode 100644
index 0000000000..a71dd7aedc
--- /dev/null
+++ b/site/src/components/RequireAuth/RequireAuth.test.tsx
@@ -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(
Test
, {
+ routes: Setup} />,
+ })
+
+ await screen.findByText("Setup")
+ })
+})
diff --git a/site/src/components/RequireAuth/RequireAuth.tsx b/site/src/components/RequireAuth/RequireAuth.tsx
index 1ceb4ceef2..162280e1c3 100644
--- a/site/src/components/RequireAuth/RequireAuth.tsx
+++ b/site/src/components/RequireAuth/RequireAuth.tsx
@@ -15,8 +15,11 @@ export const RequireAuth: React.FC> =
const location = useLocation()
const isHomePage = location.pathname === "/"
const navigateTo = isHomePage ? "/login" : embedRedirect(location.pathname)
+
if (authState.matches("signedOut")) {
return
+ } else if (authState.matches("waitingForTheFirstUser")) {
+ return
} else if (authState.hasTag("loading")) {
return
} else {
diff --git a/site/src/pages/LoginPage/LoginPage.test.tsx b/site/src/pages/LoginPage/LoginPage.test.tsx
index a491b0c077..0cdf0ca991 100644
--- a/site/src/pages/LoginPage/LoginPage.test.tsx
+++ b/site/src/pages/LoginPage/LoginPage.test.tsx
@@ -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()
+ 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()
+ render(
+
+ }>
+ Setup}>
+ ,
+ )
// Then
- await waitFor(() => expect(history.location.pathname).toEqual("/setup"))
+ await screen.findByText("Setup")
})
})
diff --git a/site/src/pages/LoginPage/LoginPage.tsx b/site/src/pages/LoginPage/LoginPage.tsx
index 9074acec07..ecf32eab09 100644
--- a/site/src/pages/LoginPage/LoginPage.tsx
+++ b/site/src/pages/LoginPage/LoginPage.tsx
@@ -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
+ } else if (authState.matches("waitingForTheFirstUser")) {
+ return
} else {
return (
<>
{pageTitle("Login")}
-
-
-
+ {authState.hasTag("loading") ? (
+
+ ) : (
+
+
+
+ )}
>
)
}
diff --git a/site/src/testHelpers/renderHelpers.tsx b/site/src/testHelpers/renderHelpers.tsx
index 4f7bd34028..928ef526b9 100644
--- a/site/src/testHelpers/renderHelpers.tsx
+++ b/site/src/testHelpers/renderHelpers.tsx
@@ -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(
@@ -59,6 +59,7 @@ export function renderWithAuth(
{ui}} />
+ {routes}
diff --git a/site/src/xServices/StateContext.tsx b/site/src/xServices/StateContext.tsx
index a795690e35..78ac6fe452 100644
--- a/site/src/xServices/StateContext.tsx
+++ b/site/src/xServices/StateContext.tsx
@@ -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 (
- authMachine.withConfig({ actions: { redirectToSetupPage } }),
- ),
+ authXService: useInterpret(authMachine),
buildInfoXService: useInterpret(buildInfoMachine),
entitlementsXService: useInterpret(entitlementsMachine),
siteRolesXService: useInterpret(siteRolesMachine),
diff --git a/site/src/xServices/auth/authXService.ts b/site/src/xServices/auth/authXService.ts
index b90d0d7321..1fa3040e9f 100644
--- a/site/src/xServices/auth/authXService.ts
+++ b/site/src/xServices/auth/authXService.ts
@@ -408,7 +408,6 @@ export const authMachine =
tags: "loading",
},
waitingForTheFirstUser: {
- entry: "redirectToSetupPage",
on: {
SIGN_IN: {
target: "signingIn",