Skip to content

Commit 31ffb56

Browse files
authored
fix: disable setup page once setup has been completed (coder#9198)
1 parent 6e41cd1 commit 31ffb56

File tree

2 files changed

+113
-10
lines changed

2 files changed

+113
-10
lines changed

site/src/pages/SetupPage/SetupPage.test.tsx

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { fireEvent, screen, waitFor } from "@testing-library/react"
22
import userEvent from "@testing-library/user-event"
33
import { rest } from "msw"
4-
import { render } from "testHelpers/renderHelpers"
4+
import { createMemoryRouter } from "react-router-dom"
5+
import { render, renderWithRouter } from "testHelpers/renderHelpers"
56
import { server } from "testHelpers/server"
67
import { SetupPage } from "./SetupPage"
78
import { Language as PageViewLanguage } from "./SetupPageView"
@@ -35,6 +36,12 @@ describe("Setup Page", () => {
3536
rest.get("/api/v2/users/me", (req, res, ctx) => {
3637
return res(ctx.status(401), ctx.json({ message: "no user here" }))
3738
}),
39+
rest.get("/api/v2/users/first", (req, res, ctx) => {
40+
return res(
41+
ctx.status(404),
42+
ctx.json({ message: "no first user has been created" }),
43+
)
44+
}),
3845
)
3946
})
4047

@@ -63,23 +70,109 @@ describe("Setup Page", () => {
6370
)
6471
}),
6572
)
73+
6674
render(<SetupPage />)
6775
await fillForm()
6876
const errorMessage = await screen.findByText(fieldErrorMessage)
6977
expect(errorMessage).toBeDefined()
7078
})
7179

72-
it("redirects to workspaces page when success", async () => {
80+
it("redirects to the app when setup is successful", async () => {
81+
let userHasBeenCreated = false
82+
83+
server.use(
84+
rest.get("/api/v2/users/me", (req, res, ctx) => {
85+
if (!userHasBeenCreated) {
86+
return res(ctx.status(401), ctx.json({ message: "no user here" }))
87+
}
88+
return res(ctx.status(200), ctx.json(MockUser))
89+
}),
90+
rest.get("/api/v2/users/first", (req, res, ctx) => {
91+
if (!userHasBeenCreated) {
92+
return res(
93+
ctx.status(404),
94+
ctx.json({ message: "no first user has been created" }),
95+
)
96+
}
97+
return res(
98+
ctx.status(200),
99+
ctx.json({ message: "hooray, someone exists!" }),
100+
)
101+
}),
102+
rest.post("/api/v2/users/first", (req, res, ctx) => {
103+
userHasBeenCreated = true
104+
return res(
105+
ctx.status(200),
106+
ctx.json({ data: "user setup was successful!" }),
107+
)
108+
}),
109+
)
110+
73111
render(<SetupPage />)
112+
await fillForm()
113+
await waitFor(() => expect(window.location).toBeAt("/"))
114+
})
115+
116+
it("redirects to login if setup has already completed", async () => {
117+
// simulates setup having already been completed
118+
server.use(
119+
rest.get("/api/v2/users/first", (req, res, ctx) => {
120+
return res(
121+
ctx.status(200),
122+
ctx.json({ message: "hooray, someone exists!" }),
123+
)
124+
}),
125+
)
126+
127+
renderWithRouter(
128+
createMemoryRouter(
129+
[
130+
{
131+
path: "/setup",
132+
element: <SetupPage />,
133+
},
134+
{
135+
path: "/login",
136+
element: <h1>Login</h1>,
137+
},
138+
],
139+
{ initialEntries: ["/setup"] },
140+
),
141+
)
74142

143+
await screen.findByText("Login")
144+
})
145+
146+
it("redirects to the app when already logged in", async () => {
75147
// simulates the user will be authenticated
76148
server.use(
77149
rest.get("/api/v2/users/me", (req, res, ctx) => {
78150
return res(ctx.status(200), ctx.json(MockUser))
79151
}),
152+
rest.get("/api/v2/users/first", (req, res, ctx) => {
153+
return res(
154+
ctx.status(200),
155+
ctx.json({ message: "hooray, someone exists!" }),
156+
)
157+
}),
80158
)
81159

82-
await fillForm()
83-
await waitFor(() => expect(window.location).toBeAt("/workspaces"))
160+
renderWithRouter(
161+
createMemoryRouter(
162+
[
163+
{
164+
path: "/setup",
165+
element: <SetupPage />,
166+
},
167+
{
168+
path: "/",
169+
element: <h1>Workspaces</h1>,
170+
},
171+
],
172+
{ initialEntries: ["/setup"] },
173+
),
174+
)
175+
176+
await screen.findByText("Workspaces")
84177
})
85178
})

site/src/pages/SetupPage/SetupPage.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useMachine } from "@xstate/react"
22
import { useAuth } from "components/AuthProvider/AuthProvider"
3-
import { FC, useEffect } from "react"
3+
import { FC } from "react"
44
import { Helmet } from "react-helmet-async"
55
import { pageTitle } from "utils/page"
66
import { setupMachine } from "xServices/setup/setupXService"
77
import { SetupPageView } from "./SetupPageView"
8+
import { Navigate } from "react-router-dom"
89

910
export const SetupPage: FC = () => {
1011
const [authState, authSend] = useAuth()
@@ -24,11 +25,20 @@ export const SetupPage: FC = () => {
2425
})
2526
const { error } = setupState.context
2627

27-
useEffect(() => {
28-
if (authState.matches("signedIn")) {
29-
window.location.assign("/workspaces")
30-
}
31-
}, [authState])
28+
const userIsSignedIn = authState.matches("signedIn")
29+
const setupIsComplete =
30+
!authState.matches("loadingInitialAuthData") &&
31+
!authState.matches("configuringTheFirstUser")
32+
33+
// If the user is logged in, navigate to the app
34+
if (userIsSignedIn) {
35+
return <Navigate to="/" state={{ isRedirect: true }} />
36+
}
37+
38+
// If we've already completed setup, navigate to the login page
39+
if (setupIsComplete) {
40+
return <Navigate to="/login" state={{ isRedirect: true }} />
41+
}
3242

3343
return (
3444
<>

0 commit comments

Comments
 (0)