-
Notifications
You must be signed in to change notification settings - Fork 0
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
Heatmap #9
Conversation
src/tests/Heatmap.test.js
Outdated
const { waitForNextUpdate } = renderHook(() => useFetchPosts('kittens')); | ||
|
||
await waitForNextUpdate(); | ||
await act(async () => { |
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.
I guess there are a couple of smaller problems.
- For the test of the search page these three lines are not necessary. They are only required for testing a custom hook, but not when you want to test a component or page
- Maybe you did that already: You can use the debug function that is returned from
render
to see the DOM. So when you have a test like this you will see no heatmap table as you mentioned.
fetch.once...
const { getByRole, debug } = renderSearchPage('/search/kittens');
debug()
That's because the (mock) fetching is not done yet. During the initial render the heatmap is not visible.
3. Instead of the getByRole
query you can use findByRole
. This one is async, so you have to await
it. When you run the test now you should see the act
warnings plus a different error: MutationObserver is not a constructor
4. This leads us to this comment where you can find the solution. When you add debug()
now after findByRole
you should see the table in the output
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.
That worked! Thanks
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.
Oddly, the tests are passing locally, but not remotely even though they should be using the same data, right? Am I missing something?
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.
Perfect, glad that it worked 👍
The problem with the failing tests in the CI is probably that the GitHub pipelines have a different timezone than your local machine. You need to set a fixed timezone. You can check the cypress scripts inside package.json. There's an environment variable TZ that you can use
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.
Looks very nice 👍 Of course, I left some comments 😄
src/components/HeatmapCell.js
Outdated
const [clicked, setClicked] = useState(false); | ||
|
||
const handleClick = () => { | ||
setClicked(true); | ||
handleCellClick(id); | ||
}; | ||
|
||
useEffect(() => { | ||
if (clickedCellId === id) { | ||
setClicked(true); | ||
} else { | ||
setClicked(false); | ||
} | ||
}, [clickedCellId, id]); |
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.
This is a very common mistake and you might be surprised how much simpler it can be 😄
clicked
is just derived from the clickedCellId
and id
props. So you can simply replace the state variable by
const clicked = clickedCellId === id;as you did in the
useEffect`. Try it out, your component will look much simpler
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.
woah! So much better. Thanks! I was overthinking it, it seems
src/styles/themes.js
Outdated
@@ -39,12 +39,30 @@ const mainTheme = { | |||
externalLink: '#0087ff', | |||
searchBoxBorder: '#e6e6e6', | |||
spinner: '#fdb755', | |||
tablecolumnheader: '#787878', |
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.
I'd probably use camelCase here 😉
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.
oops... my python is showing 😅
count: { | ||
0: '#e0e592', | ||
1: '#aed396', | ||
2: '#a9d194', | ||
3: '#a0ce93', | ||
4: '#99cd94', | ||
5: '#8cc894', | ||
6: '#5eb391', | ||
7: '#5db492', | ||
8: '#5cb391', | ||
9: '#5aad8c', | ||
10: '#3984a3', | ||
}, |
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.
Perfect 🚀
const originalStyle = window.getComputedStyle(tableCells[1]); | ||
const originalBorder = originalStyle.getPropertyValue('border'); | ||
expect(originalBorder).toEqual('1px solid #a0ce93'); | ||
|
||
fireEvent.click(tableCells[1]); | ||
|
||
const updatedStyle = window.getComputedStyle(tableCells[1]); | ||
const updatedBorder = updatedStyle.getPropertyValue('border'); | ||
expect(updatedBorder).toEqual('1px solid #1e2537'); |
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.
Haven't seen anyone testing the borders yet! 🎉
src/tests/Heatmap.test.js
Outdated
|
||
it('cell highlights on click', async () => { | ||
let tableCells; | ||
await act(async () => { |
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.
This is not required. You can remove the act
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.
Almost good to go. I just left a few more comments for smaller optimizations
src/components/Heatmap.js
Outdated
'12:00pm', '2:00pm', '4:00pm', '6:00pm', '8:00pm', '10:00pm', | ||
]; | ||
|
||
const getCounts = (posts) => { |
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.
This name is very generic. Can you find a more descriptive name? Remember the email lesson about variable/function naming and the 5 Whats.
This also goes for the counts
array below
src/components/Heatmap.js
Outdated
`; | ||
|
||
const Timezone = styled.span` | ||
font-weight: bold; |
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.
indentation
src/components/Heatmap.js
Outdated
return ( | ||
<tr key={dayOfWeek}> | ||
<RowHeader key={dayOfWeek}>{dayOfWeek}</RowHeader> | ||
{days.map((hourCount, hour) => { |
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.
indentation
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.
I think this is okay? Since days.map... isn't part of RowHeader? I separated out RowHeader into three lines to make it clearer.
src/components/Heatmap.js
Outdated
@@ -1,5 +1,129 @@ | |||
import React from 'react'; | |||
import React, { useState } from 'react'; |
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.
This file looks very simple compared to other solutions I've seen. Good job 👍
src/components/Heatmap.js
Outdated
{counts.map((days, day) => { | ||
const dayOfWeek = daysOfWeek[day]; | ||
return ( | ||
<tr key={dayOfWeek}> |
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.
You could extract this into its own component. This would potentially allow you to apply performance optimizations with React.memo.
That's a bit premature optimization though. So no problem if you keep it like it is. I just wanted you to know about React.memo
😄
src/components/Heatmap.js
Outdated
`; | ||
|
||
const Heatmap = ({ posts }) => { | ||
const counts = getCounts(posts); |
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.
This is run whenever the Heatmap is re-rendered (e.g. when a cell is clicked). Since the function iterates over 500 elements you might want to optimize it performance-wise.
By using useMemo you can call this function only when posts
changes.
font-size: ${({ theme }) => theme.font.size.small}; | ||
background-color: ${({ theme, colorValue }) => theme.color.count[colorValue]}; | ||
border: 1px solid ${({ theme, colorValue, clicked }) => ( | ||
clicked ? theme.color.tableRowHeader : theme.color.count[colorValue] |
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.
Nice usage of styled-components props 👍
} | ||
`; | ||
|
||
const HeatmapCell = ({ |
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.
Just a small suggestion 😄 You could make this component shorter by removing the const
.
const HeatmapCell = ({
children, colorValue, handleCellClick, id, clickedCellId,
}) => (
<TableCell
colorValue={colorValue}
clicked={clickedCellId === id}
onClick={() => handleCellClick(id)}
>
{children}
</TableCell>
);
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.
I love these kinds of suggestions. I think I get caught up in the tiny details sometimes and I forget to step back and see where I can make things more efficient.
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.
Looks great! 😄
Btw change the title 😉 I recently discovered that you can actually create a draft PR instead of WIP prefix. |
Got all the code in place and working but having problems implementing the tests. I keep getting:
I've tried wrapping everything from just the render to both the render and fetch mocks. Nothing works. However, I did stop getting the message if I only called the render method without
const { getByRole }
. When I did some console prints, I noticed that the heatmap isn't getting written into the test. I am guessing that's why the tests are throwing that warning message. But I am not sure how to fix it.