mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
chore: bump react-router-dom from 6.4.1 to 6.12.1 in /site (#7950)
* chore: bump react-router-dom from 6.4.1 to 6.12.1 in /site Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.4.1 to 6.12.1. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.12.1/packages/react-router-dom) --- updated-dependencies: - dependency-name: react-router-dom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * fix what needs to be fixed * fix storybook --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: BrunoQuaresma <bruno_nonato_quaresma@hotmail.com>
This commit is contained in:
co-authored by
BrunoQuaresma
parent
6e598234b6
commit
33c0674d76
@@ -1,14 +1,12 @@
|
||||
import CssBaseline from "@mui/material/CssBaseline"
|
||||
import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles"
|
||||
import { createMemoryHistory } from "history"
|
||||
import { unstable_HistoryRouter as HistoryRouter } from "react-router-dom"
|
||||
|
||||
import { MemoryRouter } from "react-router-dom"
|
||||
import { HelmetProvider } from "react-helmet-async"
|
||||
import { dark } from "../src/theme"
|
||||
import "../src/theme/globalFonts"
|
||||
import "../src/i18n"
|
||||
|
||||
const history = createMemoryHistory()
|
||||
|
||||
export const decorators = [
|
||||
(Story) => (
|
||||
<StyledEngineProvider injectFirst>
|
||||
@@ -20,9 +18,9 @@ export const decorators = [
|
||||
),
|
||||
(Story) => {
|
||||
return (
|
||||
<HistoryRouter history={history}>
|
||||
<MemoryRouter>
|
||||
<Story />
|
||||
</HistoryRouter>
|
||||
</MemoryRouter>
|
||||
)
|
||||
},
|
||||
(Story) => {
|
||||
|
||||
+1
-2
@@ -64,7 +64,6 @@
|
||||
"eventsourcemock": "2.0.0",
|
||||
"formik": "2.4.1",
|
||||
"front-matter": "4.0.2",
|
||||
"history": "5.3.0",
|
||||
"i18next": "22.5.0",
|
||||
"jest-environment-jsdom": "29.5.0",
|
||||
"jest-location-mock": "1.0.9",
|
||||
@@ -80,7 +79,7 @@
|
||||
"react-helmet-async": "1.3.0",
|
||||
"react-i18next": "12.2.2",
|
||||
"react-markdown": "8.0.3",
|
||||
"react-router-dom": "6.4.1",
|
||||
"react-router-dom": "6.13.0",
|
||||
"react-syntax-highlighter": "15.5.0",
|
||||
"react-use": "17.4.0",
|
||||
"react-virtualized-auto-sizer": "1.0.7",
|
||||
|
||||
@@ -292,7 +292,7 @@ export const AppRouter: FC = () => {
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/@:username">
|
||||
<Route path="/:username">
|
||||
<Route path=":workspace">
|
||||
<Route index element={<WorkspacePage />} />
|
||||
<Route
|
||||
@@ -316,7 +316,7 @@ export const AppRouter: FC = () => {
|
||||
|
||||
{/* Terminal and CLI auth pages don't have the dashboard layout */}
|
||||
<Route
|
||||
path="/@:username/:workspace/terminal"
|
||||
path="/:username/:workspace/terminal"
|
||||
element={<TerminalPage />}
|
||||
/>
|
||||
<Route path="cli-auth" element={<CliAuthenticationPage />} />
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react"
|
||||
import { FC } from "react"
|
||||
import { WrapperComponent } from "../../../testHelpers/renderHelpers"
|
||||
import { fireEvent, screen } from "@testing-library/react"
|
||||
import { ConfirmDialog, ConfirmDialogProps } from "./ConfirmDialog"
|
||||
|
||||
namespace Helpers {
|
||||
export const Component: FC<React.PropsWithChildren<ConfirmDialogProps>> = (
|
||||
props: ConfirmDialogProps,
|
||||
) => {
|
||||
return (
|
||||
<WrapperComponent>
|
||||
<ConfirmDialog {...props} />
|
||||
</WrapperComponent>
|
||||
)
|
||||
}
|
||||
}
|
||||
import { render } from "testHelpers/renderHelpers"
|
||||
|
||||
describe("ConfirmDialog", () => {
|
||||
it("renders", () => {
|
||||
@@ -26,7 +13,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
|
||||
// Then
|
||||
expect(screen.getByRole("dialog")).toBeDefined()
|
||||
@@ -43,7 +30,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
|
||||
// Then
|
||||
expect(screen.queryByText("CANCEL")).toBeNull()
|
||||
@@ -61,7 +48,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
|
||||
// Then
|
||||
expect(screen.getByText("CANCEL")).toBeDefined()
|
||||
@@ -79,7 +66,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
|
||||
// Then
|
||||
expect(screen.getByText("CANCEL")).toBeDefined()
|
||||
@@ -98,7 +85,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
|
||||
// Then
|
||||
expect(screen.queryByText("CANCEL")).toBeNull()
|
||||
@@ -116,7 +103,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
fireEvent.click(screen.getByText("CANCEL"))
|
||||
|
||||
// Then
|
||||
@@ -138,7 +125,7 @@ describe("ConfirmDialog", () => {
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
render(<ConfirmDialog {...props} />)
|
||||
fireEvent.click(screen.getByText("CONFIRM"))
|
||||
|
||||
// Then
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { ComponentMeta, Story } from "@storybook/react"
|
||||
import { MockUser, MockUserAgent } from "testHelpers/entities"
|
||||
import { UserCell, UserCellProps } from "./UserCell"
|
||||
|
||||
export default {
|
||||
title: "components/UserCell",
|
||||
component: UserCell,
|
||||
} as ComponentMeta<typeof UserCell>
|
||||
|
||||
const Template: Story<UserCellProps> = (args) => <UserCell {...args} />
|
||||
|
||||
export const AuditLogExample = Template.bind({})
|
||||
AuditLogExample.args = {
|
||||
Avatar: {
|
||||
username: MockUser.username,
|
||||
avatarURL: "",
|
||||
},
|
||||
caption: MockUserAgent.ip_address,
|
||||
primaryText: MockUser.email,
|
||||
onPrimaryTextSelect: () => {
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
export const AuditLogEmptyUserExample = Template.bind({})
|
||||
AuditLogEmptyUserExample.args = {
|
||||
Avatar: {
|
||||
username: MockUser.username,
|
||||
avatarURL: "",
|
||||
},
|
||||
caption: MockUserAgent.ip_address,
|
||||
primaryText: "Deleted User",
|
||||
onPrimaryTextSelect: undefined,
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react"
|
||||
import { FC } from "react"
|
||||
import { MockUser, MockUserAgent } from "testHelpers/entities"
|
||||
import { WrapperComponent } from "../../testHelpers/renderHelpers"
|
||||
import { UserCell, UserCellProps } from "./UserCell"
|
||||
|
||||
namespace Helpers {
|
||||
export const Props: UserCellProps = {
|
||||
Avatar: {
|
||||
username: MockUser.username,
|
||||
avatarURL: "",
|
||||
},
|
||||
caption: MockUserAgent.ip_address,
|
||||
primaryText: MockUser.username,
|
||||
onPrimaryTextSelect: jest.fn(),
|
||||
}
|
||||
|
||||
export const Component: FC<React.PropsWithChildren<UserCellProps>> = (
|
||||
props,
|
||||
) => (
|
||||
<WrapperComponent>
|
||||
<UserCell {...props} />
|
||||
</WrapperComponent>
|
||||
)
|
||||
}
|
||||
|
||||
describe("UserCell", () => {
|
||||
// callbacks
|
||||
it("calls onPrimaryTextSelect when primaryText is clicked", () => {
|
||||
// Given
|
||||
const onPrimaryTextSelectMock = jest.fn()
|
||||
const props: UserCellProps = {
|
||||
...Helpers.Props,
|
||||
onPrimaryTextSelect: onPrimaryTextSelectMock,
|
||||
}
|
||||
|
||||
// When - click the user's email address
|
||||
render(<Helpers.Component {...props} />)
|
||||
fireEvent.click(screen.getByText(props.primaryText))
|
||||
|
||||
// Then - callback was fired once
|
||||
expect(onPrimaryTextSelectMock).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
// primaryText
|
||||
it("renders primaryText as a link when onPrimaryTextSelect is defined", () => {
|
||||
// Given
|
||||
const props: UserCellProps = Helpers.Props
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
const primaryTextNode = screen.getByText(props.primaryText)
|
||||
|
||||
// Then
|
||||
expect(primaryTextNode.tagName).toBe("A")
|
||||
})
|
||||
it("renders primaryText without a link when onPrimaryTextSelect is undefined", () => {
|
||||
// Given
|
||||
const props: UserCellProps = {
|
||||
...Helpers.Props,
|
||||
onPrimaryTextSelect: undefined,
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
const primaryTextNode = screen.getByText(props.primaryText)
|
||||
|
||||
// Then
|
||||
expect(primaryTextNode.tagName).toBe("P")
|
||||
})
|
||||
|
||||
// caption
|
||||
it("renders caption", () => {
|
||||
// Given
|
||||
const caption = "definitely a caption"
|
||||
const props: UserCellProps = {
|
||||
...Helpers.Props,
|
||||
caption,
|
||||
}
|
||||
|
||||
// When
|
||||
render(<Helpers.Component {...props} />)
|
||||
|
||||
// Then
|
||||
expect(screen.getByText(caption)).toBeDefined()
|
||||
})
|
||||
})
|
||||
@@ -1,69 +0,0 @@
|
||||
import Box from "@mui/material/Box"
|
||||
import Link from "@mui/material/Link"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import Typography from "@mui/material/Typography"
|
||||
import { FC } from "react"
|
||||
import { UserAvatar, UserAvatarProps } from "../UserAvatar/UserAvatar"
|
||||
|
||||
export interface UserCellProps {
|
||||
Avatar: UserAvatarProps
|
||||
/**
|
||||
* primaryText is rendered beside the avatar
|
||||
*/
|
||||
primaryText: string /* | React.ReactNode <-- if needed */
|
||||
/**
|
||||
* caption is rendered beneath the avatar and primaryText
|
||||
*/
|
||||
caption?: string /* | React.ReactNode <-- if needed */
|
||||
/**
|
||||
* onPrimaryTextSelect, if defined, is called when the primaryText is clicked
|
||||
*/
|
||||
onPrimaryTextSelect?: () => void
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
primaryText: {
|
||||
color: theme.palette.text.primary,
|
||||
fontFamily: theme.typography.fontFamily,
|
||||
fontSize: "16px",
|
||||
lineHeight: "15px",
|
||||
marginBottom: "5px",
|
||||
},
|
||||
}))
|
||||
|
||||
/**
|
||||
* UserCell is a single cell in an audit log table row that contains user-level
|
||||
* information
|
||||
*/
|
||||
export const UserCell: FC<React.PropsWithChildren<UserCellProps>> = ({
|
||||
Avatar,
|
||||
caption,
|
||||
primaryText,
|
||||
onPrimaryTextSelect,
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Box alignItems="center" display="flex" flexDirection="row">
|
||||
<Box display="flex" margin="auto 14px auto 0">
|
||||
<UserAvatar {...Avatar} />
|
||||
</Box>
|
||||
|
||||
<Box display="flex" flexDirection="column">
|
||||
{onPrimaryTextSelect ? (
|
||||
<Link className={styles.primaryText} onClick={onPrimaryTextSelect}>
|
||||
{primaryText}
|
||||
</Link>
|
||||
) : (
|
||||
<Typography className={styles.primaryText}>{primaryText}</Typography>
|
||||
)}
|
||||
|
||||
{caption && (
|
||||
<Typography color="textSecondary" variant="caption">
|
||||
{caption}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
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 { createMemoryRouter } from "react-router-dom"
|
||||
import { Language } from "../../components/SignInForm/SignInForm"
|
||||
import {
|
||||
history,
|
||||
render,
|
||||
renderWithRouter,
|
||||
waitForLoaderToBeRemoved,
|
||||
} from "../../testHelpers/renderHelpers"
|
||||
import { server } from "../../testHelpers/server"
|
||||
@@ -17,7 +17,6 @@ const { t } = i18n
|
||||
|
||||
describe("LoginPage", () => {
|
||||
beforeEach(() => {
|
||||
history.replace("/login")
|
||||
// appear logged out
|
||||
server.use(
|
||||
rest.get("/api/v2/users/me", (req, res, ctx) => {
|
||||
@@ -58,7 +57,6 @@ describe("LoginPage", () => {
|
||||
// Then
|
||||
const errorMessage = await screen.findByText(apiErrorMessage)
|
||||
expect(errorMessage).toBeDefined()
|
||||
expect(history.location.pathname).toEqual("/login")
|
||||
})
|
||||
|
||||
it("shows github authentication when enabled", async () => {
|
||||
@@ -92,11 +90,20 @@ describe("LoginPage", () => {
|
||||
)
|
||||
|
||||
// When
|
||||
render(
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />}></Route>
|
||||
<Route path="/setup" element={<h1>Setup</h1>}></Route>
|
||||
</Routes>,
|
||||
renderWithRouter(
|
||||
createMemoryRouter(
|
||||
[
|
||||
{
|
||||
path: "/login",
|
||||
element: <LoginPage />,
|
||||
},
|
||||
{
|
||||
path: "/setup",
|
||||
element: <h1>Setup</h1>,
|
||||
},
|
||||
],
|
||||
{ initialEntries: ["/login"] },
|
||||
),
|
||||
)
|
||||
|
||||
// Then
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { fireEvent, screen, waitFor } from "@testing-library/react"
|
||||
import userEvent from "@testing-library/user-event"
|
||||
import { rest } from "msw"
|
||||
import { history, render } from "testHelpers/renderHelpers"
|
||||
import { render } from "testHelpers/renderHelpers"
|
||||
import { server } from "testHelpers/server"
|
||||
import { SetupPage } from "./SetupPage"
|
||||
import { Language as PageViewLanguage } from "./SetupPageView"
|
||||
@@ -30,7 +30,6 @@ const fillForm = async ({
|
||||
|
||||
describe("Setup Page", () => {
|
||||
beforeEach(() => {
|
||||
history.replace("/setup")
|
||||
// appear logged out
|
||||
server.use(
|
||||
rest.get("/api/v2/users/me", (req, res, ctx) => {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { rest } from "msw"
|
||||
import { Language as FormLanguage } from "../../../components/CreateUserForm/CreateUserForm"
|
||||
import { Language as FooterLanguage } from "../../../components/FormFooter/FormFooter"
|
||||
import {
|
||||
history,
|
||||
renderWithAuth,
|
||||
waitForLoaderToBeRemoved,
|
||||
} from "../../../testHelpers/renderHelpers"
|
||||
@@ -41,10 +40,6 @@ const fillForm = async ({
|
||||
}
|
||||
|
||||
describe("Create User Page", () => {
|
||||
beforeEach(() => {
|
||||
history.replace("/users/create")
|
||||
})
|
||||
|
||||
it("shows validation error message", async () => {
|
||||
await renderCreateUserPage()
|
||||
await fillForm({ email: "test" })
|
||||
|
||||
@@ -25,7 +25,7 @@ describe("WorkspaceBuildPage", () => {
|
||||
client.onmessage = async () => {
|
||||
renderWithAuth(<WorkspaceBuildPage />, {
|
||||
route: `/@${MockWorkspace.owner_name}/${MockWorkspace.name}/builds/${MockWorkspace.latest_build.build_number}`,
|
||||
path: "/@:username/:workspace/builds/:buildNumber",
|
||||
path: "/:username/:workspace/builds/:buildNumber",
|
||||
})
|
||||
|
||||
await screen.findByText(MockWorkspaceBuild.workspace_name)
|
||||
|
||||
@@ -45,7 +45,7 @@ const renderWorkspacePage = async () => {
|
||||
})
|
||||
renderWithAuth(<WorkspacePage />, {
|
||||
route: `/@${MockWorkspace.owner_name}/${MockWorkspace.name}`,
|
||||
path: "/@:username/:workspace",
|
||||
path: "/:username/:workspace",
|
||||
})
|
||||
|
||||
await waitForLoaderToBeRemoved()
|
||||
|
||||
@@ -33,10 +33,12 @@ const useFailedBuildLogs = (workspace: Workspace | undefined) => {
|
||||
}
|
||||
|
||||
export const WorkspacePage: FC = () => {
|
||||
const { username, workspace: workspaceName } = useParams() as {
|
||||
const params = useParams() as {
|
||||
username: string
|
||||
workspace: string
|
||||
}
|
||||
const workspaceName = params.workspace
|
||||
const username = params.username.replace("@", "")
|
||||
const orgId = useOrganizationId()
|
||||
const [workspaceState, workspaceSend] = useMachine(workspaceMachine, {
|
||||
context: {
|
||||
|
||||
+2
-2
@@ -40,9 +40,9 @@ test("Submit the workspace settings page successfully", async () => {
|
||||
const user = userEvent.setup()
|
||||
renderWithWorkspaceSettingsLayout(<WorkspaceParametersPage />, {
|
||||
route: "/@test-user/test-workspace/settings",
|
||||
path: "/@:username/:workspace/settings",
|
||||
path: "/:username/:workspace/settings",
|
||||
// Need this because after submit the user is redirected
|
||||
extraRoutes: [{ path: "/@:username/:workspace", element: <div /> }],
|
||||
extraRoutes: [{ path: "/:username/:workspace", element: <div /> }],
|
||||
})
|
||||
await waitForLoaderToBeRemoved()
|
||||
// Fill the form and submit
|
||||
|
||||
+38
-35
@@ -258,11 +258,44 @@ describe("WorkspaceSchedulePage", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("autostop", () => {
|
||||
it("uses template default ttl when first enabled", async () => {
|
||||
// have autostop disabled
|
||||
server.use(
|
||||
rest.get(
|
||||
"/api/v2/users/:userId/workspace/:workspaceName",
|
||||
(req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({ ...MockWorkspace, ttl_ms: 0 }),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
renderWithWorkspaceSettingsLayout(<WorkspaceSchedulePage />, {
|
||||
route: `/@${MockUser.username}/${MockWorkspace.name}/schedule`,
|
||||
path: "/:username/:workspace/schedule",
|
||||
})
|
||||
const user = userEvent.setup()
|
||||
const autostopToggle = await screen.findByLabelText(
|
||||
FormLanguage.stopSwitch,
|
||||
)
|
||||
// enable autostop
|
||||
await user.click(autostopToggle)
|
||||
// find helper text that describes the mock template's 24 hour default
|
||||
const autostopHelperText = await screen.findByText(
|
||||
"Your workspace will shut down a day after",
|
||||
{ exact: false },
|
||||
)
|
||||
expect(autostopHelperText).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("autostop change dialog", () => {
|
||||
it("shows if autostop is changed", async () => {
|
||||
renderWithWorkspaceSettingsLayout(<WorkspaceSchedulePage />, {
|
||||
route: `/@${MockUser.username}/${MockWorkspace.name}/schedule`,
|
||||
path: "/@:username/:workspace/schedule",
|
||||
path: "/:username/:workspace/schedule",
|
||||
})
|
||||
const user = userEvent.setup()
|
||||
const autostopToggle = await screen.findByLabelText(
|
||||
@@ -281,7 +314,10 @@ describe("WorkspaceSchedulePage", () => {
|
||||
it("doesn't show if autostop is not changed", async () => {
|
||||
renderWithWorkspaceSettingsLayout(<WorkspaceSchedulePage />, {
|
||||
route: `/@${MockUser.username}/${MockWorkspace.name}/schedule`,
|
||||
path: "/@:username/:workspace/schedule",
|
||||
path: "/:username/:workspace/schedule",
|
||||
extraRoutes: [
|
||||
{ path: "/:username/:workspace", element: <div>Workspace</div> },
|
||||
],
|
||||
})
|
||||
const user = userEvent.setup()
|
||||
const autostartToggle = await screen.findByLabelText(
|
||||
@@ -297,37 +333,4 @@ describe("WorkspaceSchedulePage", () => {
|
||||
expect(dialog).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe("autostop", () => {
|
||||
it("uses template default ttl when first enabled", async () => {
|
||||
// have autostop disabled
|
||||
server.use(
|
||||
rest.get(
|
||||
"/api/v2/users/:userId/workspace/:workspaceName",
|
||||
(req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({ ...MockWorkspace, ttl_ms: 0 }),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
renderWithWorkspaceSettingsLayout(<WorkspaceSchedulePage />, {
|
||||
route: `/@${MockUser.username}/${MockWorkspace.name}/schedule`,
|
||||
path: "/@:username/:workspace/schedule",
|
||||
})
|
||||
const user = userEvent.setup()
|
||||
const autostopToggle = await screen.findByLabelText(
|
||||
FormLanguage.stopSwitch,
|
||||
)
|
||||
// enable autostop
|
||||
await user.click(autostopToggle)
|
||||
// find helper text that describes the mock template's 24 hour default
|
||||
const autostopHelperText = await screen.findByText(
|
||||
"Your workspace will shut down a day after",
|
||||
{ exact: false },
|
||||
)
|
||||
expect(autostopHelperText).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+3
-5
@@ -16,7 +16,6 @@ import { pageTitle } from "utils/page"
|
||||
import { scheduleChanged } from "utils/schedule"
|
||||
import * as TypesGen from "../../../api/typesGenerated"
|
||||
import { WorkspaceScheduleForm } from "../../../components/WorkspaceScheduleForm/WorkspaceScheduleForm"
|
||||
import { firstOrItem } from "../../../utils/array"
|
||||
import { workspaceSchedule } from "../../../xServices/workspaceSchedule/workspaceScheduleXService"
|
||||
import {
|
||||
formValuesToAutostartRequest,
|
||||
@@ -41,11 +40,10 @@ const useStyles = makeStyles((theme) => ({
|
||||
export const WorkspaceSchedulePage: FC = () => {
|
||||
const { t } = useTranslation("workspaceSchedulePage")
|
||||
const styles = useStyles()
|
||||
const { username: usernameQueryParam, workspace: workspaceQueryParam } =
|
||||
useParams()
|
||||
const params = useParams() as { username: string; workspace: string }
|
||||
const navigate = useNavigate()
|
||||
const username = firstOrItem(usernameQueryParam, null)
|
||||
const workspaceName = firstOrItem(workspaceQueryParam, null)
|
||||
const username = params.username.replace("@", "")
|
||||
const workspaceName = params.workspace
|
||||
const { workspace } = useWorkspaceSettingsContext()
|
||||
const [scheduleState, scheduleSend] = useMachine(workspaceSchedule, {
|
||||
context: { workspace },
|
||||
|
||||
@@ -43,10 +43,12 @@ export const useWorkspaceSettingsContext = () => {
|
||||
|
||||
export const WorkspaceSettingsLayout: FC = () => {
|
||||
const styles = useStyles()
|
||||
const { workspace: workspaceName, username } = useParams() as {
|
||||
const params = useParams() as {
|
||||
workspace: string
|
||||
username: string
|
||||
}
|
||||
const workspaceName = params.workspace
|
||||
const username = params.username.replace("@", "")
|
||||
const { data: settings } = useWorkspace(username, workspaceName)
|
||||
|
||||
return (
|
||||
|
||||
@@ -21,9 +21,9 @@ test("Submit the workspace settings page successfully", async () => {
|
||||
const user = userEvent.setup()
|
||||
renderWithWorkspaceSettingsLayout(<WorkspaceSettingsPage />, {
|
||||
route: "/@test-user/test-workspace/settings",
|
||||
path: "/@:username/:workspace/settings",
|
||||
path: "/:username/:workspace/settings",
|
||||
// Need this because after submit the user is redirected
|
||||
extraRoutes: [{ path: "/@:username/:workspace", element: <div /> }],
|
||||
extraRoutes: [{ path: "/:username/:workspace", element: <div /> }],
|
||||
})
|
||||
await waitForLoaderToBeRemoved()
|
||||
// Fill the form and submit
|
||||
|
||||
@@ -9,10 +9,12 @@ import { patchWorkspace } from "api/api"
|
||||
import { WorkspaceSettingsFormValues } from "./WorkspaceSettingsForm"
|
||||
|
||||
const WorkspaceSettingsPage = () => {
|
||||
const { username, workspace: workspaceName } = useParams() as {
|
||||
username: string
|
||||
const params = useParams() as {
|
||||
workspace: string
|
||||
username: string
|
||||
}
|
||||
const workspaceName = params.workspace
|
||||
const username = params.username.replace("@", "")
|
||||
const { workspace } = useWorkspaceSettingsContext()
|
||||
const navigate = useNavigate()
|
||||
const mutation = useMutation({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { screen } from "@testing-library/react"
|
||||
import { rest } from "msw"
|
||||
import * as CreateDayString from "utils/createDayString"
|
||||
import { MockWorkspace, MockWorkspacesResponse } from "testHelpers/entities"
|
||||
import { history, renderWithAuth } from "testHelpers/renderHelpers"
|
||||
import { renderWithAuth } from "testHelpers/renderHelpers"
|
||||
import { server } from "testHelpers/server"
|
||||
import WorkspacesPage from "./WorkspacesPage"
|
||||
import { i18n } from "i18n"
|
||||
@@ -11,7 +11,6 @@ const { t } = i18n
|
||||
|
||||
describe("WorkspacesPage", () => {
|
||||
beforeEach(() => {
|
||||
history.replace("/workspaces")
|
||||
// Mocking the dayjs module within the createDayString file
|
||||
const mock = jest.spyOn(CreateDayString, "createDayString")
|
||||
mock.mockImplementation(() => "a minute ago")
|
||||
|
||||
@@ -1,40 +1,52 @@
|
||||
import {
|
||||
render as wrappedRender,
|
||||
RenderResult,
|
||||
render as tlRender,
|
||||
screen,
|
||||
waitForElementToBeRemoved,
|
||||
} from "@testing-library/react"
|
||||
import { AppProviders } from "app"
|
||||
import { DashboardLayout } from "components/Dashboard/DashboardLayout"
|
||||
import { createMemoryHistory } from "history"
|
||||
import { i18n } from "i18n"
|
||||
import { TemplateSettingsLayout } from "pages/TemplateSettingsPage/TemplateSettingsLayout"
|
||||
import { WorkspaceSettingsLayout } from "pages/WorkspaceSettingsPage/WorkspaceSettingsLayout"
|
||||
import { FC, ReactElement } from "react"
|
||||
import { I18nextProvider } from "react-i18next"
|
||||
import {
|
||||
unstable_HistoryRouter as HistoryRouter,
|
||||
RouterProvider,
|
||||
createMemoryRouter,
|
||||
RouteObject,
|
||||
} from "react-router-dom"
|
||||
import { RequireAuth } from "../components/RequireAuth/RequireAuth"
|
||||
import { MockUser } from "./entities"
|
||||
import { ReactNode } from "react"
|
||||
|
||||
export const history = createMemoryHistory()
|
||||
|
||||
export const WrapperComponent: FC<React.PropsWithChildren<unknown>> = ({
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<AppProviders>
|
||||
<HistoryRouter history={history}>{children}</HistoryRouter>
|
||||
</AppProviders>
|
||||
const baseRender = (element: ReactNode) => {
|
||||
return tlRender(
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<AppProviders>{element}</AppProviders>
|
||||
</I18nextProvider>,
|
||||
)
|
||||
}
|
||||
|
||||
export const render = (component: ReactElement): RenderResult => {
|
||||
return wrappedRender(<WrapperComponent>{component}</WrapperComponent>)
|
||||
export const renderWithRouter = (
|
||||
router: ReturnType<typeof createMemoryRouter>,
|
||||
) => {
|
||||
return {
|
||||
...baseRender(<RouterProvider router={router} />),
|
||||
router,
|
||||
}
|
||||
}
|
||||
|
||||
export const render = (element: ReactNode) => {
|
||||
return renderWithRouter(
|
||||
createMemoryRouter(
|
||||
[
|
||||
{
|
||||
path: "/",
|
||||
element,
|
||||
},
|
||||
],
|
||||
{ initialEntries: ["/"] },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
type RenderWithAuthOptions = {
|
||||
@@ -69,19 +81,12 @@ export function renderWithAuth(
|
||||
...nonAuthenticatedRoutes,
|
||||
]
|
||||
|
||||
const router = createMemoryRouter(routes, { initialEntries: [route] })
|
||||
|
||||
const renderResult = wrappedRender(
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<AppProviders>
|
||||
<RouterProvider router={router} />
|
||||
</AppProviders>
|
||||
</I18nextProvider>,
|
||||
const renderResult = renderWithRouter(
|
||||
createMemoryRouter(routes, { initialEntries: [route] }),
|
||||
)
|
||||
|
||||
return {
|
||||
user: MockUser,
|
||||
router,
|
||||
...renderResult,
|
||||
}
|
||||
}
|
||||
@@ -113,19 +118,12 @@ export function renderWithTemplateSettingsLayout(
|
||||
...nonAuthenticatedRoutes,
|
||||
]
|
||||
|
||||
const router = createMemoryRouter(routes, { initialEntries: [route] })
|
||||
|
||||
const renderResult = wrappedRender(
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<AppProviders>
|
||||
<RouterProvider router={router} />
|
||||
</AppProviders>
|
||||
</I18nextProvider>,
|
||||
const renderResult = renderWithRouter(
|
||||
createMemoryRouter(routes, { initialEntries: [route] }),
|
||||
)
|
||||
|
||||
return {
|
||||
user: MockUser,
|
||||
router,
|
||||
...renderResult,
|
||||
}
|
||||
}
|
||||
@@ -148,7 +146,7 @@ export function renderWithWorkspaceSettingsLayout(
|
||||
children: [
|
||||
{
|
||||
element: <WorkspaceSettingsLayout />,
|
||||
children: [{ path, element }, ...extraRoutes],
|
||||
children: [{ element, path }, ...extraRoutes],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -157,19 +155,12 @@ export function renderWithWorkspaceSettingsLayout(
|
||||
...nonAuthenticatedRoutes,
|
||||
]
|
||||
|
||||
const router = createMemoryRouter(routes, { initialEntries: [route] })
|
||||
|
||||
const renderResult = wrappedRender(
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<AppProviders>
|
||||
<RouterProvider router={router} />
|
||||
</AppProviders>
|
||||
</I18nextProvider>,
|
||||
const renderResult = renderWithRouter(
|
||||
createMemoryRouter(routes, { initialEntries: [route] }),
|
||||
)
|
||||
|
||||
return {
|
||||
user: MockUser,
|
||||
router,
|
||||
...renderResult,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { firstOrItem } from "./array"
|
||||
|
||||
describe("array", () => {
|
||||
describe("firstOrItem", () => {
|
||||
it("returns null if empty array", () => {
|
||||
expect(firstOrItem([], null)).toBeNull()
|
||||
})
|
||||
|
||||
it("returns first item if array with more one item", () => {
|
||||
expect(firstOrItem(["a", "b"], "c")).toEqual("a")
|
||||
})
|
||||
|
||||
it("returns item if single item", () => {
|
||||
expect(firstOrItem("c", "d")).toEqual("c")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Helper function that, given an array or a single item:
|
||||
* - If an array with no elements, returns null
|
||||
* - If an array with 1 or more elements, returns the first element
|
||||
* - If a single item, returns that item
|
||||
*/
|
||||
export const firstOrItem = <T>(
|
||||
itemOrItems: undefined | T | T[],
|
||||
defaults: T,
|
||||
): T => {
|
||||
if (Array.isArray(itemOrItems)) {
|
||||
return itemOrItems.length > 0 ? itemOrItems[0] : defaults
|
||||
}
|
||||
|
||||
if (typeof itemOrItems === "undefined") {
|
||||
return defaults
|
||||
}
|
||||
|
||||
return itemOrItems
|
||||
}
|
||||
+16
-23
@@ -1004,7 +1004,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
|
||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
version "7.22.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb"
|
||||
integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==
|
||||
@@ -1932,10 +1932,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7"
|
||||
integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==
|
||||
|
||||
"@remix-run/router@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.0.1.tgz#88d7ac31811ab0cef14aaaeae2a0474923b278bc"
|
||||
integrity sha512-eBV5rvW4dRFOU1eajN7FmYxjAIVz/mRHgUE9En9mBn6m3mulK3WTR5C3iQhL9MZ14rWAq+xOlEaCkDiW0/heOg==
|
||||
"@remix-run/router@1.6.3":
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.6.3.tgz#8205baf6e17ef93be35bf62c37d2d594e9be0dad"
|
||||
integrity sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==
|
||||
|
||||
"@rollup/pluginutils@^4.2.0":
|
||||
version "4.2.1"
|
||||
@@ -6703,13 +6703,6 @@ highlight.js@^10.4.1, highlight.js@~10.7.0:
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
|
||||
integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
|
||||
|
||||
history@5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
|
||||
integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.7.6"
|
||||
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
@@ -10005,20 +9998,20 @@ react-refresh@^0.14.0:
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
||||
|
||||
react-router-dom@6.4.1:
|
||||
version "6.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.4.1.tgz#99c9b7c4967890701c888517475aa5d54d25760e"
|
||||
integrity sha512-MY7NJCrGNVJtGp8ODMOBHu20UaIkmwD2V3YsAOUQoCXFk7Ppdwf55RdcGyrSj+ycSL9Uiwrb3gTLYSnzcRoXww==
|
||||
react-router-dom@6.13.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.13.0.tgz#6651f456bb2af42ef14f6880123b1f575539e81f"
|
||||
integrity sha512-6Nqoqd7fgwxxVGdbiMHTpDHCYPq62d7Wk1Of7B82vH7ZPwwsRaIa22zRZKPPg413R5REVNiyuQPKDG1bubcOFA==
|
||||
dependencies:
|
||||
"@remix-run/router" "1.0.1"
|
||||
react-router "6.4.1"
|
||||
"@remix-run/router" "1.6.3"
|
||||
react-router "6.13.0"
|
||||
|
||||
react-router@6.4.1:
|
||||
version "6.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.4.1.tgz#dd9cc4dfa264751d143a4b6c9d4faa60ab3ce26c"
|
||||
integrity sha512-OJASKp5AykDWFewgWUim1vlLr7yfD4vO/h+bSgcP/ix8Md+LMHuAjovA74MQfsfhQJGGN1nHRhwS5qQQbbBt3A==
|
||||
react-router@6.13.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.13.0.tgz#7e4427a271dae0cafbdb88c56ccbd9b1434ee93f"
|
||||
integrity sha512-Si6KnfEnJw7gUQkNa70dlpI1bul46FuSxX5t5WwlUBxE25DAz2BjVkwaK8Y2s242bQrZPXCpmwLPtIO5pv4tXg==
|
||||
dependencies:
|
||||
"@remix-run/router" "1.0.1"
|
||||
"@remix-run/router" "1.6.3"
|
||||
|
||||
react-syntax-highlighter@15.5.0:
|
||||
version "15.5.0"
|
||||
|
||||
Reference in New Issue
Block a user