Skip to content

Commit

Permalink
Readme (#11)
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

* posts-table: e2e tests passing

* posts-table: 2 integration tests remaining

* posts-table: resolved conflicts

* posts-table: fix lint issue

* posts-table: fix lint issue

* posts-table: implemented posts sorted by time created

* post-table: refactor after review

* Final refactor: cleaned up tests and set background color to white

* readme: add project readme

* readme: made header menu responsive on mobile device

* readme: made header menu responsive on mobile device: fixe error

* readme: implemented cell with deleted author and cell background colr scheme selection

* readme: implemented postsTable display in modal window

* pre-deployment: clean up styling - added tootips

* readme: Completed features integration tests

* readme: Completed Cypress e2e tests

* readme: refactor for responsive form and footer. Added to readme

* readme: added to readme

* readme: 2nd push after rebase. clean up and fixes
  • Loading branch information
bahobab authored Oct 28, 2020
1 parent 11c47b8 commit cc50da2
Show file tree
Hide file tree
Showing 38 changed files with 3,067 additions and 522 deletions.
126 changes: 68 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,76 @@
<!-- I use this template: https://github.com/dbader/readme-template/blob/master/README.md -->
# Reddit Timer
### or How to find the best time to post your subreddit
(or How to find the best time to post your subreddit)

Use historical posts data to determine the best time to post a subreddit.

This project is the result of a course by ooloo.io.
The project goal is to build a professional web app with professional tools and methods.
This project is the result of a course by [ooloo.io](https://ooloo.io/).
The project aims to build a professional web app with professional tools and methods.

The lead developer at ooloo.io provided the project designs in Zeplin and tasks managed in Clickup management tool.
The lead developer [Johannes](https://jkettmann.com/author/johannes/) at ooloo.io provided the project designs in [Zeplin](https://zeplin.io/) with tasks managed in [ClickUp](https://clickup.com/) management tool.
One of the requirements is that each taks be implemented within its own pull request(PR). And the PR is reviewed by the lead developer before it's merged.

Beside the project being implemented with the React library, additional tools and packages nesesary to deliver the project to plan were free to choose.
And on on occasion, I used TDD methodology to implement some tasks, such as header, footer, form tasks.
During the development process, I occasionally used TDD methodology to implement some tasks, such as header, footer, form tasks.

To ensure code quality and conformity an end to end (e2e) Cypress test suite was provided.
To ensure code quality and conformity an end to end (e2e) Cypress test suite was also provided.
I implemented the integragration tests using React Testing-Library to meet the project's acceptance criteria (AC).

## Tech Stack used:
1. React/React Hooks
2. Styled-components
3. Cypress
4. React Testing-Library

## Tools
1. ClickUp
2. Zeplin
3. Perfect Pixel
4. GitHub
5. Slack

## I Proposed Added Features
In addition to the original AC, I proposed and implemented these features:

1. highlights for cells containing posts with deleted author
2. display the posts table in modal mode
3. choose the heatmap color theme

[![NPM Version][npm-image]][npm-url]
[![Build Status][travis-image]][travis-url]
[![Downloads Stats][npm-downloads]][npm-url]

One to two paragraph statement about your product and what it does.

![](header.png)
The folowing are the screenshots of the different stages of the project:

## Highlights
Use of styled-components makes it easy to solve css issues for the heatmap color scheme.
Tags are components that offer flexibility and ease of stiling
![Home page](https://res.cloudinary.com/krikitue/image/upload/v1603729023/reddit-timer/homePage_rpbxun.png)
![Search page](https://res.cloudinary.com/krikitue/image/upload/v1603729024/reddit-timer/searchPage_lchzu0.png)
![Loading the data](https://res.cloudinary.com/krikitue/image/upload/v1603729496/reddit-timer/loading_ncgf0d.png)
![Display the posts](https://res.cloudinary.com/krikitue/image/upload/v1603729024/reddit-timer/posts_sgabn4.png)

Efficient multiple fetch call using recursion
Effective use of function compositing to simplify code readability

Testing using snapshot for the table that has 168 cells.
Avoid data mutation on a parameter passed by reference
## Tech Stack used:
1. **React/React Hooks**
2. **Styled-components**
3. **Cypress**
4. **React Testing-Library**

## Tools
1. [ClickUp](https://clickup.com/)
2. [Zeplin](https://zeplin.io/)
3. [Perfect Pixel](https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi?hl=en)
4. **GitHub** version control repository
5. **Slack** Team communication tool

## I Proposed these Added Features
For me this is the most important part of the project where I was able to apply the knowledge learnt to propose features and deliver solutions to improve on the app.
So in addition to the original AC (acceptance criteria), I proposed and implemented the folowing features:

1. **highlights for cells** containing posts with deleted author
2. display the posts table in **modal mode to avoid the table to show below the fold**.
we could implement auto-scoll but the user would have to scroll up back to the heatmap grid again. I think offering an modal display option was practical.
3. **choose the heatmap color theme** to provide the user with another viewing comfort.
4. **make the app responsive** on all devices.
5. provide **integration and end to end tests for these features** without breaking the original AC.

## Features Solutions screenshots

1. Cell highlight to indicate it contains deleted author
![Feature #1](https://res.cloudinary.com/krikitue/image/upload/v1603729023/reddit-timer/feature_1_wnshm8.png)
2. choose the heatmap color scheme
![Feature #2](https://res.cloudinary.com/krikitue/image/upload/v1603729023/reddit-timer/feature_2_ygcnrv.png)
3. display the posts table in a modal window
![Feature #3](https://res.cloudinary.com/krikitue/image/upload/v1603729023/reddit-timer/postsModal_wy5ai7.png)
4. responsive on small screens
![Feature #4](https://res.cloudinary.com/krikitue/image/upload/v1603729023/reddit-timer/responsive_fgefov.png)
5. tests
![Feature tests](https://res.cloudinary.com/krikitue/image/upload/v1603729024/reddit-timer/tests_g26rwl.png)

## Project Highlights

- The use of [styled-components]() makes it easy to solve css issues for the heatmap color scheme.
- Tags are components offering flexibility and ease of styling
- Practical components design structure and **'DRY' coding technique** with global variables and styles used throughout the app
- Efficient successive **fetch calls using recursion**
- Effective use of **reduce functions composition** to yield complex data

- **Testing using snapshot** for the table that has 168 cells.
- **Mocks to avoid puting strain on memory**
- **Avoid data mutation on a parameter passed by reference**

## Take Away from this Project:

Expand All @@ -66,16 +84,17 @@ Avoid data mutation on a parameter passed by reference
- pull requests (PR)
- code review
- branch merge
- branch conflicts resolution
3. Production Deployment
- Live app deployed to Netlify with CC/CI webhook
4. Apply techniques learnt to extend/improve the app UI/UX as detailed in [Features section](#I Proposed these Added Features)

## Installation

OS X & Linux:
```sh
yarn install
```

## Usage

After all the packages have been successfully installed, you can run:
Expand All @@ -91,26 +110,17 @@ Run the tests with:
yarn test
```

```sh
yarn cypress:open
```
## Meta
Konan Houphoue – [@linkedIn](https://linkedIn.com/bahobab)khoophdev@gmail.com
[https://github.com/bahobab](https://github.com/bahobab/)

Your Name – [@YourTwitter](https://twitter.com/dbader_org)YourEmail@example.com

Distributed under the XYZ license. See ``LICENSE`` for more information.

[https://github.com/yourname/github-link](https://github.com/dbader/)

## Contributing
<!-- ## Contributing
1. Fork it (<https://github.com/yourname/yourproject/fork>)
2. Create your feature branch (`git checkout -b feature/fooBar`)
3. Commit your changes (`git commit -am 'Add some fooBar'`)
4. Push to the branch (`git push origin feature/fooBar`)
5. Create a new Pull Request

<!-- Markdown link & img dfn's -->
[npm-image]: https://img.shields.io/npm/v/datadog-metrics.svg?style=flat-square
[npm-url]: https://npmjs.org/package/datadog-metrics
[npm-downloads]: https://img.shields.io/npm/dm/datadog-metrics.svg?style=flat-square
[travis-image]: https://img.shields.io/travis/dbader/node-datadog-metrics/master.svg?style=flat-square
[travis-url]: https://travis-ci.org/dbader/node-datadog-metrics
[wiki]: https://github.com/yourname/yourproject/wiki
5. Create a new Pull Request -->
30 changes: 30 additions & 0 deletions cypress/integration/10-Readme.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import describeOnBranches from '../utils/describeOnBranches';

describeOnBranches('readme')('Readme', () => {
before(() => {
cy.stubFetch();
});

beforeEach(() => {
cy.initMockRedditAPI();
cy.visitWithStubbedFetch('/search/javascript');
cy.waitForRedditRequests();
});

it('Has h2 headline "Color Scheme" and two radio buttons', () => {
cy.contains('Color Scheme');

cy.get('[type="radio"]').check('hourBackgroundDefault');
cy.get('[type="radio"]').check('hourBackground1');
});

it('Has h2 headline "Show Posts in Modal Window" and one checkbox to choose how to display posts table', () => {
// click Sunday 6 am, the "5" in the heatmap
cy.contains(/^5$/)
.click();

cy.get('#viewInModal').check();
cy.get('[data-testid="postsModal"]').get('[data-cy="closeModal"]').click();
cy.get('#viewInModal').uncheck();
});
});
Binary file modified public/favicon.ico
Binary file not shown.
Binary file added public/images/heatmap (copy).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/homePage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/loading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/posts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/postsModal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/responsive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/tests.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "Reddit Timer",
"name": "Find the best times to post a reddit",
"icons": [
{
"src": "favicon.ico",
Expand Down
128 changes: 128 additions & 0 deletions src/__tests__/Features.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import {
render, screen, waitFor, within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect';

import App from '../app';

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

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

return { ...view, history };
};

describe('feature #1: choose heatmap color scheme', () => {
it('heatmap shows color scheme choices', async () => {
setup('/search/javascript');

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

expect(await screen.findByRole('heading', { name: 'Color Scheme' })).toBeInTheDocument();

// default color schelme
const defaultColorScheme = screen.getByLabelText('default');
// choco color scheme
const chocoColorScheme = screen.getByLabelText('choco');

// select choco color scheme
userEvent.click(chocoColorScheme);
expect(chocoColorScheme.checked).toBe(true);
expect(defaultColorScheme.checked).toBe(false);

const chocoHeatmap = await screen.findByTestId('heatmap');
expect(chocoHeatmap).toMatchSnapshot();

// switch back to default color scheme
userEvent.click(defaultColorScheme);
expect(defaultColorScheme.checked).toBe(true);
expect(chocoColorScheme.checked).toBe(false);

const defaultHeatmap = await screen.findByTestId('heatmap');
expect(defaultHeatmap).toMatchSnapshot();
});
});

describe('feature #2: optionally display posts table in modal', () => {
it('shows posts table on the page when a cell is clicked and modal option is not checked', async () => {
setup('/search/javascript');

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

const heatmap = screen.getByTestId('heatmap');
const cells = await within(heatmap).findAllByRole('button');
const cellToClick = cells[1];

const selectDisplayInModal = screen.getByLabelText('Show Posts in Modal Window');
expect(selectDisplayInModal.checked).toBe(false);

expect(screen.queryByRole('table')).not.toBeInTheDocument();

userEvent.click(cellToClick);
expect(screen.getByRole('table')).toBeInTheDocument();
expect(screen.queryByTestId('postsModal')).toBeNull();
});

it('shows posts table in a modal window when a cell is clicked and modal option checked', async () => {
setup('/search/javascript');

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

const heatmap = screen.getByTestId('heatmap');
const cells = await within(heatmap).findAllByRole('button');
const cellToClick = cells[1];

const selectDisplayInModal = screen.getByLabelText('Show Posts in Modal Window');
expect(selectDisplayInModal.checked).toBe(false);

userEvent.click(selectDisplayInModal);
expect(selectDisplayInModal.checked).toBe(true);
userEvent.click(cellToClick);

const modalWindow = screen.getByTestId('postsModal');
expect(modalWindow).toBeInTheDocument();
expect(within(modalWindow).getByRole('table')).toBeInTheDocument();

const closeModalButton = within(modalWindow).getByRole('button');
userEvent.click(closeModalButton);
expect(screen.queryByTestId('postsModal')).toBeNull();
expect(screen.queryByRole('table')).not.toBeInTheDocument();
});
});

describe('feature #3', () => {
it('shows a cell has a red dotted border if cell contains deleted author', async () => {
setup('/search/javascript');

const heatmap = await screen.findByTestId('heatmap');
const cells = await within(heatmap).findAllByText('3');
const cellWithDeletdAuthor = cells[4];

userEvent.click(cellWithDeletdAuthor);
const table = screen.getByRole('table');

const rowWithDeletedUser = within(table).getAllByRole('row')[2];
const authorCell = within(rowWithDeletedUser).getAllByRole('cell')[4];

expect(authorCell.innerHTML).toBe('[deleted]');
// screen.debug(cellWithDeletdAuthor);
expect(cellWithDeletdAuthor.getAttribute('style')).toEqual('border: 1px dotted red;');
});
});
Loading

0 comments on commit cc50da2

Please sign in to comment.