Skip to content

Commit

Permalink
Heatmap (#8)
Browse files Browse the repository at this point in the history
* header task: first commit

* header task: fixed missing default 'javascript'

* header task: fixed default link: '/search/javascript'

* header after first review

* header fixing test

* implemented unit test

* header: before rebase after app-skeleton-review

* resolved conflicts. Fixed unit tests

* footer: initial commit

* implemented Footer.js and Footer.style.js

* footer: completed unit tests

* hero-section: initial commit with with fixes from previous PR

* hero-section: completed unit tests

* hero-section: fixed linting issues in unit tests

* hero-section: fixed Apps to have all unit tests pass

* hero-section: added missing test descriptions in footer.js

* hero-section: refactor components and file structure after review

* info-section: initial commit

* info-section: implemented About and How it works sections

* info-section: fix link to https://ooloo.io/employers

* info-section: implemented react-router-hash-link

* info-section: fixed ooloo.io link

* info-section: implemented unit tests

* info-section: fixed linting errors

* info-section: fixed linting errors

* info-section: fix unit test using this: testing-library/dom-testing-library#477 (comment)

* info-section: commit after review

* subreddit-form: initial commit. Setup folder structure

* subreddit-form: implement tests

* subreddit-form: fix lint error in Header.js

* subreddit-form: completed unit and e2e tests

* subreddit-form: fixes and cleanup after review

* load-the-data: initial commit: added LoadTheData.js

* load-the-data: fetching data implemented. But unit test and e2e test filing

* load-the-data: troubleshooting tests

* load-the-data: continue troubleshooting tests

* load-the-data: fix linting error

* load-the-data: fix the code to fetch top 500 posts

* load-the-data: troubleshooting unit test - 'invalid json response body at  reason: Unexpected end of JSON input'

* load-the-data: integration test passing

* load-the-data: refactor code after review. still 1 test to fix in SearchPage.js

* laod-the-data: all tests pass

* heatmap: first commit: setup heatmap table

* heatmap: implemented heatmap architecture

* heatmap: implemented user timezone

* heatmap: implemented hover, highlit and timezone

* heatmap: completed implementation - start testing

* heatmap: refactor component structure - set test skeleton

* heatmap: complete integration tests

* heatmap: complete. fix user timezone in tests

* heatmap: refactor code after review

* heatmap: fix all test errors. ready to merge pr

* heatmap: fix last test errors. ready to merge pr
  • Loading branch information
bahobab authored Oct 10, 2020
1 parent b5167cf commit 377d3d7
Show file tree
Hide file tree
Showing 30 changed files with 1,443 additions and 1,934 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
"@testing-library/react": "^10.4.5",
"@testing-library/react-hooks": "^3.4.2",
"@testing-library/user-event": "^12.0.11",
"eslint-plugin-styled-components-a11y": "^0.0.16",
"eslint-plugin-styled-components-a11y": "^0.0.17",
"history": "^5.0.0",
"jest-axe": "^4.0.0",
"jest-fetch-mock": "^3.0.3",
"jest-styled-components": "^7.0.3",
"msw": "^0.21.2",
"prop-types": "^15.7.2",
"react": "^16.13.0",
Expand All @@ -23,7 +25,7 @@
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jest-environment-jsdom-sixteen",
"test": "TZ=Europe/Berlin react-scripts test --env=jest-environment-jsdom-sixteen",
"eject": "react-scripts eject",
"lint": "eslint .",
"format": "eslint --fix .",
Expand Down
55 changes: 47 additions & 8 deletions src/__tests__/SearchPage.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import React from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import { render, screen, within } from '@testing-library/react';
import {
render, screen, within, waitFor,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect';
import { axe } from 'jest-axe';
import 'jest-styled-components';

import App from '../app';
import { defaultSubReddit } from '../config';

const setup = (initialPath = '/') => {
let history;

render(
const view = render(
<MemoryRouter initialEntries={[initialPath]}>
<App />
<Route
Expand All @@ -22,19 +26,46 @@ const setup = (initialPath = '/') => {
/>
</MemoryRouter>,
);
return { history };
return { ...view, history };
};

describe('search page', () => {
describe('heatmap', () => {
it('loads top post for subreddit in URL', async () => {
setup('/search/reactjs');

screen.getByText('loading-spinner.svg');

// this is just a placeholder assertion that tests if the result
// was rendered correctly
expect(await screen.findByText('500')).toBeInTheDocument();
expect(screen.queryByText('loading-spinner.svg')).not.toBeInTheDocument();
// expect(await screen.findByText('500')).toBeInTheDocument();

expect(await screen.findByTestId('heatmap')).toBeInTheDocument();
await waitFor(() => expect(screen.queryByText('loading-spinner.svg')).not.toBeInTheDocument());

const heatmap = screen.getByTestId('heatmap');
const cells = await within(heatmap).findAllByRole('button');
expect(cells.length).toEqual(7 * 24);

const numberOfPostsPerCell = cells.map((cell) => cell.innerHTML);
expect(numberOfPostsPerCell).toMatchSnapshot();

const timezone = screen.getByText('All times are shown in your timezone:');
expect(within(timezone).getByText('Europe/Berlin')).toBeInTheDocument();
});

it('highlights cell on click', async () => {
setup('/search/reactjs');

const heatmap = await screen.findByTestId('heatmap');
const cells = await within(heatmap).findAllByRole('button');

const cellToClick = cells[1];
// expect(cellToClick).toHaveStyle('border: none');
expect(cellToClick).toHaveStyleRule('border: none');

userEvent.click(cellToClick);
// expect(cellToClick).toHaveStyle('border: 1px solid #1e2537');
expect(cellToClick).toHaveStyleRule('border: 1px solid #1e2537');
});

test('renders error message', async () => {
Expand All @@ -45,7 +76,7 @@ describe('search page', () => {
});

describe('subreddit form', () => {
it('updates the URL when submitting the form', () => {
it('updates the URL when submitting the form', async () => {
const { history } = setup('/search/python');
const searchInput = screen.getByLabelText('r /');

Expand All @@ -62,7 +93,7 @@ describe('subreddit form', () => {
expect(history.location.pathname).toEqual('/search/Gatsbyjs');
});

it('input value changes to default subredit when seach link in header is clicked', () => {
it('input value changes to default subredit when seach link in header is clicked', async () => {
setup('/search/reactjs');
const searchInput = screen.getByRole('textbox');
const header = screen.getByRole('banner');
Expand All @@ -71,5 +102,13 @@ describe('subreddit form', () => {
userEvent.click(searchLink);

expect(searchInput.value).toBe(defaultSubReddit);
await waitFor(() => expect(screen.queryByText('loading-spinner.svg')).not.toBeInTheDocument());
});

it('no accessibility violation', async () => {
const { container } = setup('/search/reactjs');

expect(await screen.findByTestId('heatmap')).toBeInTheDocument();
expect(await axe(container)).toHaveNoViolations();
});
});
115 changes: 115 additions & 0 deletions src/__tests__/_Heatmap.js_
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import {
render, screen, waitForElementToBeRemoved, within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect';
import 'jest-styled-components';

import {
cellBackgroundColorMap, mapWeekday, postsTimeSlots, getUserTimeZone,
} from '../config';

import App from '../app';

const weekdays = Object.values(mapWeekday);
const cellBackgroundColor = Object.values(cellBackgroundColorMap);

const setup = (initialPath = '/') => {
let history;

render(
<MemoryRouter initialEntries={[initialPath]}>
<App />
<Route
path="*"
render={(props) => {
history = props.history;
return null;
}}
/>
</MemoryRouter>,
);
return { history };
};

describe('heatmap', () => {
it.each(weekdays)(
'weekdays are shown from Sunday to Saturday', async (weekday) => {
setup('/search/less-than-500-posts');
// find weekday container element tr.weekday
// assert that it contains Sunday, Monday, Tuesday, Wednesday
// Thursday, Friday, Saturday
const spinner = screen.getByText('loading-spinner.svg');

await waitForElementToBeRemoved(spinner);

screen.getByRole('table');
// weekday
screen.getByRole('cell', { name: weekday });
},
);

it.each(postsTimeSlots)(
'hours are shown from 12:00am to 10:00pm', async (postsTimeSlot) => {
setup('/search/reactjs');
// find hours container element th.timeline
// assert that it contains 12:00am, 2:00am..
const spinner = screen.getByText('loading-spinner.svg');

await waitForElementToBeRemoved(spinner);

screen.getByRole('table');

const timeSlots = screen.getAllByRole('columnheader');
// screen.debug(timeSlot);
within(timeSlots[1]).getByText(postsTimeSlot);
},
);

it('each combination of weekday and hour is represented by a square box', async () => {
setup('/search/less-than-500-posts');

const spinner = screen.getByText('loading-spinner.svg');
await waitForElementToBeRemoved(spinner);
screen.getByRole('table');

const cells = await document.querySelector('td.cell');
// select cells td.cell
const el = within(cells).getByText(cells.textContent);
const numPosts = Number(el.textContent);

expect(el).toHaveStyle({ border: 'unset', backgroundColor: '#a0ce93' });
// assert that background-color correspond to numeric innerText value
expect(el).toHaveStyle({ backgroundColor: `${cellBackgroundColor[numPosts]}` });

// assert that each has width === height
expect(el).toHaveStyleRule('width', '40px');
expect(el).toHaveStyleRule('height', '40px');

// assert that innerText.value is a number
// expect(el).toHaveValue(numPosts);

// assert that element is highlighted when hovered
userEvent.hover(el);
expect(el).toHaveStyle({ border: '1px solid red' });
userEvent.unhover(el);
expect(el).toHaveStyle({ border: 'unset' });

// assert that element is highlighted when clicked
userEvent.click(el);
expect(el).toHaveStyle({ border: '1px solid red' });
});

it("the user' timezone is shown below the heatmap", async () => {
setup('/search/less-than-500-posts');
// select div.timezone
// assert that the element contains "America/Chicago - Central Saving Time"
const spinner = screen.getByText('loading-spinner.svg');

await waitForElementToBeRemoved(spinner);
screen.getByRole('table');
screen.getByText(getUserTimeZone());
});
});
Loading

0 comments on commit 377d3d7

Please sign in to comment.