-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PORTALS-3308 - What's in Portals Component (GoalsV2) #1399
base: main
Are you sure you want to change the base?
Changes from all commits
6d2ccdb
6714f25
3ba91fc
50668f9
ca758c0
513fd94
0c25ce9
f2b888c
643f34b
f292993
c68fb26
c845ed6
dfc72d9
5eed0da
a089d30
75c5cd0
001f516
7073b49
3cc4331
d795916
33e2dea
f68b999
20c7954
39b26c8
a2e5844
71c3d30
430e34a
bef55b6
abd1401
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React from 'react' | ||
import { render, screen, fireEvent } from '@testing-library/react' | ||
import '@testing-library/jest-dom' | ||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query' | ||
import GoalsV2Desktop from './GoalsV2.Desktop' | ||
|
||
const mockProps = { | ||
asset: 'https://example.com/asset.jpg', | ||
link: 'https://example.com', | ||
countSql: 'SELECT COUNT(*) FROM syn12345', | ||
title: 'Test Title', | ||
summary: 'Test Summary', | ||
} | ||
|
||
const queryClient = new QueryClient() | ||
|
||
describe('GoalsV2Desktop', () => { | ||
test('renders the component with the correct props', () => { | ||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<GoalsV2Desktop {...mockProps} /> | ||
</QueryClientProvider>, | ||
) | ||
|
||
const image = screen.getByRole('img') | ||
expect(image).toHaveAttribute('src', mockProps.asset) | ||
expect(image).toHaveAttribute('alt', mockProps.title) | ||
|
||
const title = screen.getByText(mockProps.title) | ||
expect(title).toBeInTheDocument() | ||
}) | ||
|
||
test('opens the link when the card is clicked', () => { | ||
window.open = jest.fn() | ||
|
||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<GoalsV2Desktop {...mockProps} /> | ||
</QueryClientProvider>, | ||
) | ||
|
||
const card = screen.getByRole('button', { name: /Test Title/i }) | ||
fireEvent.click(card) | ||
|
||
expect(window.open).toHaveBeenCalledWith(mockProps.link) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import React from 'react' | ||
import { GoalsV2DataProps } from './GoalsV2' | ||
import QueryCount from '../QueryCount/QueryCount' | ||
import IconButton from '@mui/material/IconButton' | ||
import NavigateNextIcon from '@mui/icons-material/NavigateNext' | ||
import { Typography } from '@mui/material' | ||
import { Card, CardActionArea, CardContent, CardMedia } from '@mui/material' | ||
|
||
export default function GoalsV2Desktop({ | ||
asset, | ||
link, | ||
countSql, | ||
title, | ||
}: GoalsV2DataProps) { | ||
return ( | ||
<Card | ||
sx={{ | ||
width: 200, | ||
height: 'auto', | ||
backgroundColor: 'transparent', | ||
borderColor: 'transparent', | ||
boxShadow: 'none', | ||
}} | ||
> | ||
<CardActionArea onClick={() => window.open(link)}> | ||
<CardMedia | ||
component="img" | ||
sx={{ height: 150, width: '100%', paddingX: 2, overflow: 'visible' }} | ||
image={asset} | ||
alt={title} | ||
/> | ||
<CardContent | ||
sx={{ | ||
display: 'flex', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
}} | ||
> | ||
<Typography variant="h6" component="strong" sx={{ marginRight: 1 }}> | ||
{countSql && ( | ||
<QueryCount parens={false} query={{ sql: countSql }} /> | ||
)} | ||
</Typography> | ||
<Typography variant="body1">{title}</Typography> | ||
<IconButton sx={{ color: '#5BA998' }}> | ||
<NavigateNextIcon /> | ||
</IconButton> | ||
</CardContent> | ||
</CardActionArea> | ||
</Card> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react' | ||
import { GoalsV2DataProps } from './GoalsV2' | ||
import ExpandableContent from '../home_page/ExpandableContent' | ||
import QueryCount from '../QueryCount/QueryCount' | ||
import { Button } from '@mui/material' | ||
|
||
export default function GoalsV2Mobile({ | ||
link, | ||
summary, | ||
countSql, | ||
title, | ||
}: GoalsV2DataProps) { | ||
const titleElement = ( | ||
<div className="GoalsV2__Mobile__Header"> | ||
{countSql && ( | ||
<span className="GoalsV2__Mobile__Header__Count"> | ||
<QueryCount parens={false} query={{ sql: countSql }} /> | ||
</span> | ||
)} | ||
<span className="GoalsV2__Mobile__Header__Title"> {title} </span> | ||
</div> | ||
) | ||
const content = ( | ||
<div className="GoalsV2__Mobile__Content"> | ||
<p>{summary}</p> | ||
<Button | ||
variant="contained" | ||
color="secondary" | ||
className="GoalsV2__Mobile__Content__Link" | ||
href={link} | ||
> | ||
Explore | ||
</Button> | ||
</div> | ||
) | ||
return <ExpandableContent title={titleElement} content={content} /> | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import Goals from './GoalsV2' | ||
|
||
const meta = { | ||
title: 'Home Page/GoalsV2', | ||
component: Goals, | ||
parameters: { | ||
chromatic: { viewports: [600, 1200] }, | ||
}, | ||
} satisfies Meta | ||
export default meta | ||
type Story = StoryObj<typeof meta> | ||
|
||
export const Demo: Story = { | ||
args: { | ||
entityId: 'syn22315959', | ||
dataLink: 'https://eliteportal.synapse.org/Explore/Data', | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import React from 'react' | ||
import { render, screen, waitFor } from '@testing-library/react' | ||
import '@testing-library/jest-dom' | ||
import { rest } from 'msw' | ||
import { setupServer } from 'msw/node' | ||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query' | ||
import GoalsV2 from './GoalsV2' | ||
import { | ||
SynapseContextProvider, | ||
SynapseContextType, | ||
} from '../../utils/context/SynapseContext' | ||
|
||
const mockSynapseContext: Partial<SynapseContextType> = { | ||
isInExperimentalMode: false, | ||
utcTime: false, | ||
withErrorBoundary: false, | ||
downloadCartPageUrl: '/DownloadCart', | ||
appId: undefined, | ||
} | ||
|
||
const queryClient = new QueryClient() | ||
|
||
const server = setupServer( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to call |
||
rest.post( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your handlers look good, but we have a utility |
||
'https://repo-prod.prod.sagebase.org/repo/v1/entity/:entityId/table/query/async/start', | ||
(req, res, ctx) => { | ||
return res( | ||
ctx.json<{ token: string }>({ | ||
token: 'mockToken', | ||
}), | ||
) | ||
}, | ||
), | ||
rest.get( | ||
'https://repo-prod.prod.sagebase.org/repo/v1/entity/:entityId/table/query/async/get/:token', | ||
(req, res, ctx) => { | ||
return res( | ||
ctx.json({ | ||
queryResult: { | ||
queryResults: { | ||
rows: [ | ||
{ | ||
values: [ | ||
'syn22315959', | ||
'SELECT COUNT(*) FROM syn22315959', | ||
'Sample Title', | ||
'Sample Summary', | ||
'https://example.com', | ||
'12345', | ||
], | ||
}, | ||
], | ||
}, | ||
}, | ||
}), | ||
) | ||
}, | ||
), | ||
) | ||
|
||
beforeAll(() => server.listen()) | ||
afterEach(() => server.resetHandlers()) | ||
afterAll(() => server.close()) | ||
|
||
describe('GoalsV2', () => { | ||
test('renders the component with provided props', async () => { | ||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<SynapseContextProvider synapseContext={mockSynapseContext}> | ||
<GoalsV2 | ||
entityId="syn22315959" | ||
dataLink="https://eliteportal.synapse.org/Explore/Data" | ||
/> | ||
</SynapseContextProvider> | ||
</QueryClientProvider>, | ||
) | ||
|
||
await waitFor(() => { | ||
expect(screen.getByText("What's in the Portal?")).toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
test('images do not display on fetch failure', async () => { | ||
server.use( | ||
rest.get( | ||
'https://repo-prod.prod.sagebase.org/repo/v1/entity/:entityId/table/query/async/get/:token', | ||
(req, res, ctx) => { | ||
return res( | ||
ctx.status(500), | ||
ctx.json({ message: 'Internal Server Error' }), | ||
) | ||
}, | ||
), | ||
) | ||
|
||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<SynapseContextProvider synapseContext={mockSynapseContext}> | ||
<GoalsV2 | ||
entityId="synxyz" | ||
dataLink="https://eliteportal.synapse.org/Explore/Data" | ||
/> | ||
</SynapseContextProvider> | ||
</QueryClientProvider>, | ||
) | ||
|
||
await waitFor(() => { | ||
expect(screen.queryByRole('img')).not.toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
test('displays assets when fetch is successful', async () => { | ||
render( | ||
<QueryClientProvider client={queryClient}> | ||
<SynapseContextProvider synapseContext={mockSynapseContext}> | ||
<GoalsV2 | ||
entityId="syn22315959" | ||
dataLink="https://eliteportal.synapse.org/Explore/Data" | ||
/> | ||
</SynapseContextProvider> | ||
</QueryClientProvider>, | ||
) | ||
|
||
await waitFor(() => { | ||
expect(screen.getByText("What's in the Portal?")).toBeInTheDocument() | ||
}) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go ahead and remove all classNames that are not being used for styling