Skip to content

Commit e980d97

Browse files
AbhineetJainkylecarbs
authored andcommitted
feat: add a divider after Account menu item (#1927)
* add a divider after Account menu item * test: improve Storybook tests * add closed and open userdropdown tests * add default isOpen * extract UserDropdownContent into a single component * remove the isOpen prop * address nit comments * update test name
1 parent ecda971 commit e980d97

File tree

7 files changed

+223
-203
lines changed

7 files changed

+223
-203
lines changed

site/src/components/UserDropdown/UserDropdown.stories.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ const Template: Story<UserDropdownProps> = (args: UserDropdownProps) => (
1717
</Box>
1818
)
1919

20-
export const ExampleNoRoles = Template.bind({})
21-
ExampleNoRoles.args = {
20+
export const Example = Template.bind({})
21+
Example.args = {
2222
user: MockUser,
2323
onSignOut: () => {
2424
return Promise.resolve()
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { screen } from "@testing-library/react"
2-
import { MockAdminRole, MockUser } from "../../testHelpers/entities"
2+
import { MockUser } from "../../testHelpers/entities"
33
import { render } from "../../testHelpers/renderHelpers"
4-
import { Language, UserDropdown, UserDropdownProps } from "./UsersDropdown"
4+
import { Language } from "../UserDropdownContent/UserDropdownContent"
5+
import { UserDropdown, UserDropdownProps } from "./UsersDropdown"
56

67
const renderAndClick = async (props: Partial<UserDropdownProps> = {}) => {
78
render(<UserDropdown user={props.user ?? MockUser} onSignOut={props.onSignOut ?? jest.fn()} />)
@@ -10,18 +11,6 @@ const renderAndClick = async (props: Partial<UserDropdownProps> = {}) => {
1011
}
1112

1213
describe("UserDropdown", () => {
13-
const env = process.env
14-
15-
// REMARK: copying process.env so we don't mutate that object or encounter conflicts between tests
16-
beforeEach(() => {
17-
process.env = { ...env }
18-
})
19-
20-
// REMARK: restoring process.env
21-
afterEach(() => {
22-
process.env = env
23-
})
24-
2514
describe("when the trigger is clicked", () => {
2615
it("opens the menu", async () => {
2716
await renderAndClick()
@@ -30,44 +19,4 @@ describe("UserDropdown", () => {
3019
expect(screen.getByText(Language.signOutLabel)).toBeDefined()
3120
})
3221
})
33-
34-
describe("when the menu is open", () => {
35-
it("displays the user's roles", async () => {
36-
await renderAndClick()
37-
38-
expect(screen.getByText(MockAdminRole.display_name)).toBeDefined()
39-
})
40-
41-
it("has the correct link for the documentation item", async () => {
42-
process.env.CODER_VERSION = "v0.5.4"
43-
await renderAndClick()
44-
45-
const link = screen.getByText(Language.docsLabel).closest("a")
46-
if (!link) {
47-
throw new Error("Anchor tag not found for the documentation menu item")
48-
}
49-
50-
expect(link.getAttribute("href")).toBe(`https://github.com/coder/coder/tree/${process.env.CODER_VERSION}/docs`)
51-
})
52-
53-
it("has the correct link for the account item", async () => {
54-
await renderAndClick()
55-
56-
const link = screen.getByText(Language.accountLabel).closest("a")
57-
if (!link) {
58-
throw new Error("Anchor tag not found for the account menu item")
59-
}
60-
61-
expect(link.getAttribute("href")).toBe("/settings/account")
62-
})
63-
64-
describe("and sign out is clicked", () => {
65-
it("calls the onSignOut function", async () => {
66-
const onSignOut = jest.fn()
67-
await renderAndClick({ onSignOut })
68-
screen.getByText(Language.signOutLabel).click()
69-
expect(onSignOut).toBeCalledTimes(1)
70-
})
71-
})
72-
})
7322
})
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
import Badge from "@material-ui/core/Badge"
2-
import Divider from "@material-ui/core/Divider"
3-
import ListItemIcon from "@material-ui/core/ListItemIcon"
4-
import ListItemText from "@material-ui/core/ListItemText"
52
import MenuItem from "@material-ui/core/MenuItem"
63
import { fade, makeStyles } from "@material-ui/core/styles"
7-
import AccountIcon from "@material-ui/icons/AccountCircleOutlined"
84
import React, { useState } from "react"
9-
import { Link } from "react-router-dom"
105
import * as TypesGen from "../../api/typesGenerated"
116
import { navHeight } from "../../theme/constants"
127
import { BorderedMenu } from "../BorderedMenu/BorderedMenu"
138
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
14-
import { DocsIcon } from "../Icons/DocsIcon"
15-
import { LogoutIcon } from "../Icons/LogoutIcon"
169
import { UserAvatar } from "../UserAvatar/UserAvatar"
17-
import { UserProfileCard } from "../UserProfileCard/UserProfileCard"
10+
import { UserDropdownContent } from "../UserDropdownContent/UserDropdownContent"
1811

19-
export const Language = {
20-
accountLabel: "Account",
21-
docsLabel: "Documentation",
22-
signOutLabel: "Sign Out",
23-
}
2412
export interface UserDropdownProps {
2513
user: TypesGen.User
2614
onSignOut: () => void
@@ -64,41 +52,7 @@ export const UserDropdown: React.FC<UserDropdownProps> = ({ user, onSignOut }: U
6452
variant="user-dropdown"
6553
onClose={onPopoverClose}
6654
>
67-
<div className={styles.userInfo}>
68-
<UserProfileCard user={user} />
69-
70-
<Divider />
71-
72-
<Link to="/settings/account" className={styles.link}>
73-
<MenuItem className={styles.menuItem} onClick={onPopoverClose}>
74-
<ListItemIcon className={styles.icon}>
75-
<AccountIcon />
76-
</ListItemIcon>
77-
<ListItemText primary={Language.accountLabel} />
78-
</MenuItem>
79-
</Link>
80-
81-
<a
82-
href={`https://github.com/coder/coder/tree/${process.env.CODER_VERSION}/docs`}
83-
target="_blank"
84-
rel="noreferrer"
85-
className={styles.link}
86-
>
87-
<MenuItem className={styles.menuItem} onClick={onPopoverClose}>
88-
<ListItemIcon className={styles.icon}>
89-
<DocsIcon />
90-
</ListItemIcon>
91-
<ListItemText primary={Language.docsLabel} />
92-
</MenuItem>
93-
</a>
94-
95-
<MenuItem className={styles.menuItem} onClick={onSignOut}>
96-
<ListItemIcon className={styles.icon}>
97-
<LogoutIcon />
98-
</ListItemIcon>
99-
<ListItemText primary={Language.signOutLabel} />
100-
</MenuItem>
101-
</div>
55+
<UserDropdownContent user={user} onPopoverClose={onPopoverClose} onSignOut={onSignOut} />
10256
</BorderedMenu>
10357
</>
10458
)
@@ -117,10 +71,6 @@ export const useStyles = makeStyles((theme) => ({
11771
maxWidth: 300,
11872
},
11973

120-
userInfo: {
121-
marginBottom: theme.spacing(1),
122-
},
123-
12474
menuItem: {
12575
height: navHeight,
12676
padding: `${theme.spacing(1.5)}px ${theme.spacing(2.75)}px`,
@@ -130,13 +80,4 @@ export const useStyles = makeStyles((theme) => ({
13080
transition: "background-color 0.3s ease",
13181
},
13282
},
133-
134-
link: {
135-
textDecoration: "none",
136-
color: "inherit",
137-
},
138-
139-
icon: {
140-
color: theme.palette.text.secondary,
141-
},
14283
}))

site/src/components/UserProfileCard/UserProfileCard.stories.tsx renamed to site/src/components/UserDropdownContent/UserDropdownContent.stories.tsx

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import { Story } from "@storybook/react"
22
import React from "react"
33
import { MockUser } from "../../testHelpers/entities"
4-
import { UserProfileCard, UserProfileCardProps } from "./UserProfileCard"
4+
import { UserDropdownContent, UserDropdownContentProps } from "./UserDropdownContent"
55

66
export default {
7-
title: "components/UserDropdown",
8-
component: UserProfileCard,
9-
argTypes: {
10-
onSignOut: { action: "Sign Out" },
11-
},
7+
title: "components/UserDropdownContent",
8+
component: UserDropdownContent,
129
}
1310

14-
const Template: Story<UserProfileCardProps> = (args: UserProfileCardProps) => <UserProfileCard {...args} />
11+
const Template: Story<UserDropdownContentProps> = (args) => <UserDropdownContent {...args} />
1512

1613
export const ExampleNoRoles = Template.bind({})
1714
ExampleNoRoles.args = {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { screen } from "@testing-library/react"
2+
import { MockAdminRole, MockUser } from "../../testHelpers/entities"
3+
import { render } from "../../testHelpers/renderHelpers"
4+
import { Language, UserDropdownContent } from "./UserDropdownContent"
5+
6+
describe("UserDropdownContent", () => {
7+
const env = process.env
8+
9+
// REMARK: copying process.env so we don't mutate that object or encounter conflicts between tests
10+
beforeEach(() => {
11+
process.env = { ...env }
12+
})
13+
14+
// REMARK: restoring process.env
15+
afterEach(() => {
16+
process.env = env
17+
})
18+
19+
it("displays the menu items", () => {
20+
render(<UserDropdownContent user={MockUser} onSignOut={jest.fn()} onPopoverClose={jest.fn()} />)
21+
expect(screen.getByText(Language.accountLabel)).toBeDefined()
22+
expect(screen.getByText(Language.docsLabel)).toBeDefined()
23+
expect(screen.getByText(Language.signOutLabel)).toBeDefined()
24+
})
25+
26+
it("displays the user's roles", () => {
27+
render(<UserDropdownContent user={MockUser} onSignOut={jest.fn()} onPopoverClose={jest.fn()} />)
28+
29+
expect(screen.getByText(MockAdminRole.display_name)).toBeDefined()
30+
})
31+
32+
it("has the correct link for the documentation item", () => {
33+
process.env.CODER_VERSION = "v0.5.4"
34+
render(<UserDropdownContent user={MockUser} onSignOut={jest.fn()} onPopoverClose={jest.fn()} />)
35+
36+
const link = screen.getByText(Language.docsLabel).closest("a")
37+
if (!link) {
38+
throw new Error("Anchor tag not found for the documentation menu item")
39+
}
40+
41+
expect(link.getAttribute("href")).toBe(`https://github.com/coder/coder/tree/${process.env.CODER_VERSION}/docs`)
42+
})
43+
44+
it("has the correct link for the account item", () => {
45+
render(<UserDropdownContent user={MockUser} onSignOut={jest.fn()} onPopoverClose={jest.fn()} />)
46+
47+
const link = screen.getByText(Language.accountLabel).closest("a")
48+
if (!link) {
49+
throw new Error("Anchor tag not found for the account menu item")
50+
}
51+
52+
expect(link.getAttribute("href")).toBe("/settings/account")
53+
})
54+
55+
it("calls the onSignOut function", () => {
56+
const onSignOut = jest.fn()
57+
render(<UserDropdownContent user={MockUser} onSignOut={onSignOut} onPopoverClose={jest.fn()} />)
58+
screen.getByText(Language.signOutLabel).click()
59+
expect(onSignOut).toBeCalledTimes(1)
60+
})
61+
})

0 commit comments

Comments
 (0)