Skip to content
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

Load the data #7

Merged
merged 50 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
444acc7
header task: first commit
bahobab Sep 25, 2020
d7e6cf6
header task: fixed missing default 'javascript'
bahobab Sep 25, 2020
34c1fd3
header task: fixed default link: '/search/javascript'
bahobab Sep 25, 2020
c6faa67
header after first review
bahobab Sep 27, 2020
f46dc2d
header fixing test
bahobab Sep 27, 2020
ae0229e
implemented unit test
bahobab Sep 27, 2020
84feae2
header: before rebase after app-skeleton-review
bahobab Sep 27, 2020
e74b390
resolved conflicts. Fixed unit tests
bahobab Sep 28, 2020
60db4f7
footer: initial commit
bahobab Sep 28, 2020
a462336
implemented Footer.js and Footer.style.js
bahobab Sep 28, 2020
b7c4094
footer: completed unit tests
bahobab Sep 28, 2020
0b12d62
hero-section: initial commit with with fixes from previous PR
bahobab Sep 28, 2020
0817a00
Merge branch 'master' into hero-section
bahobab Sep 28, 2020
e99e5dc
hero-section: completed unit tests
bahobab Sep 29, 2020
2c55849
Merge branch 'hero-section' of https://github.com/ooloo-io/reddit-tim…
bahobab Sep 29, 2020
88238ac
hero-section: fixed linting issues in unit tests
bahobab Sep 29, 2020
0e72262
hero-section: fixed Apps to have all unit tests pass
bahobab Sep 29, 2020
035041f
hero-section: added missing test descriptions in footer.js
bahobab Sep 29, 2020
880d020
hero-section: refactor components and file structure after review
bahobab Sep 29, 2020
2c629e2
info-section: initial commit
bahobab Sep 29, 2020
97ed18d
Merge branch 'master' into info-section
bahobab Sep 30, 2020
3c568ed
info-section: implemented About and How it works sections
bahobab Sep 30, 2020
c4f0d4d
Merge branch 'info-section' of https://github.com/ooloo-io/reddit-tim…
bahobab Sep 30, 2020
bb4486d
info-section: fix link to https://ooloo.io/employers
bahobab Sep 30, 2020
13bdf67
info-section: implemented react-router-hash-link
bahobab Sep 30, 2020
b4a1e4e
info-section: fixed ooloo.io link
bahobab Sep 30, 2020
ee27a75
info-section: implemented unit tests
bahobab Sep 30, 2020
bf59a70
info-section: fixed linting errors
bahobab Sep 30, 2020
d71c19d
info-section: fixed linting errors
bahobab Sep 30, 2020
3ec116c
info-section: fix unit test using this: https://github.com/testing-li…
bahobab Sep 30, 2020
242aefa
info-section: commit after review
bahobab Oct 1, 2020
2780c04
subreddit-form: initial commit. Setup folder structure
bahobab Oct 1, 2020
5b11f42
Merge branch 'master' into subreddit-form
bahobab Oct 1, 2020
f2c2e2d
subreddit-form: implement tests
bahobab Oct 1, 2020
4bb12dc
Merge branch 'subreddit-form' of https://github.com/ooloo-io/reddit-t…
bahobab Oct 1, 2020
c112f47
subreddit-form: fix lint error in Header.js
bahobab Oct 1, 2020
04cf9d2
subreddit-form: completed unit and e2e tests
bahobab Oct 2, 2020
0de4627
subreddit-form: fixes and cleanup after review
bahobab Oct 2, 2020
56554d7
load-the-data: initial commit: added LoadTheData.js
bahobab Oct 2, 2020
56d31c6
load-the-data: fetching data implemented. But unit test and e2e test …
bahobab Oct 3, 2020
7326c4f
Merge branch 'master' into load-the-data
bahobab Oct 3, 2020
1af6086
load-the-data: troubleshooting tests
bahobab Oct 3, 2020
5a60619
Merge branch 'load-the-data' of https://github.com/ooloo-io/reddit-ti…
bahobab Oct 3, 2020
7f50064
load-the-data: continue troubleshooting tests
bahobab Oct 3, 2020
9179df7
load-the-data: fix linting error
bahobab Oct 3, 2020
02223cf
load-the-data: fix the code to fetch top 500 posts
bahobab Oct 3, 2020
1bd7a8e
load-the-data: troubleshooting unit test - 'invalid json response bod…
bahobab Oct 4, 2020
4361e96
load-the-data: integration test passing
bahobab Oct 4, 2020
e061c4a
load-the-data: refactor code after review. still 1 test to fix in Sea…
bahobab Oct 4, 2020
baaccb4
laod-the-data: all tests pass
bahobab Oct 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
"dependencies": {
"@testing-library/jest-dom": "^5.11.0",
"@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",
"history": "^5.0.0",
"jest-fetch-mock": "^3.0.3",
"msw": "^0.21.2",
"prop-types": "^15.7.2",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react-router-dom": "^5.2.0",
"react-router-hash-link": "^2.1.0",
"react-scripts": "3.4.1",
"react-test-renderer": "^16.13.1",
"styled-components": "^5.2.0"
},
"scripts": {
Expand Down Expand Up @@ -44,7 +48,7 @@
]
},
"devDependencies": {
"cypress": "^4.10.0",
"cypress": "5.3.0",
"eslint": "^6.8.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-plugin-cypress": "^2.11.1",
Expand Down
Binary file added public/images/loading-spinner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/images/loading-spinner.svg
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-spinner@2x.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-spinner@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions src/__mocks__/handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { rest } from 'msw';
import response1 from './response-1.json'; // /r/javascript/top.json?t=year&limit=100
import response2 from './response-2.json'; // /r/javascript/top.json?t=year&limit=100&after=t3_f807cu
import response3 from './response-3.json'; // /r/javascript/top.json?t=year&limit=100&after=t3_gwddb5
import response4 from './response-4.json'; // /r/javascript/top.json?t=year&limit=100&after=t3_czqd6o
import response5 from './response-5.json'; // /r/javascript/top.json?t=year&limit=100&after=t3_e5dnm2

const cursorResponseMap = {
initial: response1,
t3_j0oewq: response2,
t3_i7s9wh: response3,
t3_ex7ieb: response4,
t3_g5a7o5: response5,
};

function getJSONResponseForRequest(req) {
const after = req.url.searchParams.get('after');
return cursorResponseMap[after || 'initial'];
}

const handlers = [
rest.get('https://www.reddit.com/r/less-than-500-posts/top.json', (req, res, ctx) => {
const after = req.url.searchParams.get('after');
const json = getJSONResponseForRequest(req);
if (after === 't3_i7s9wh') {
json.data.dist = 70;
json.data.after = null;
json.data.children = json.data.children.slice(0, 70);
}
return res(
ctx.status(200),
ctx.json(json),
);
}),

rest.get('https://www.reddit.com/r/failing-request/top.json', (req, res, ctx) => {
const after = req.url.searchParams.get('after');
if (after === 't3_i7s9wh') {
return res(
ctx.status(500),
ctx.json({ errorMessage: 'Internal server error' }),
);
}
return res(
ctx.status(200),
ctx.json(getJSONResponseForRequest(req)),
);
}),

rest.get('https://www.reddit.com/*', (req, res, ctx) => res(
ctx.status(200),
ctx.json(getJSONResponseForRequest(req)),
)),
];

export default handlers;
1 change: 1 addition & 0 deletions src/__mocks__/response-1.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/__mocks__/response-2.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/__mocks__/response-3.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/__mocks__/response-4.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/__mocks__/response-5.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/__mocks__/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { setupServer } from 'msw/node';

import handlers from './handlers';

const server = setupServer(...handlers);

export default server;
19 changes: 19 additions & 0 deletions src/__tests__/SearchPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ const setup = (initialPath = '/') => {
return { history };
};

describe('search page', () => {
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();
});

test('renders error message', async () => {
setup('/search/failing-request');

expect(await screen.findByText(/something went wrong/i)).toBeInTheDocument();
});
});

describe('subreddit form', () => {
it('updates the URL when submitting the form', () => {
const { history } = setup('/search/python');
Expand Down
71 changes: 71 additions & 0 deletions src/__tests__/_LoadTheData.js_
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
// import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect';
import fetchMock from 'jest-fetch-mock';

// import { defaultSubReddit } from '../config';
import App from '../app';
import mockResponse1 from './__mocks__/subreddit-reactjs-response1.json';
import mockResponse2 from './__mocks__/subreddit-reactjs-response2.json';
import mockResponse3 from './__mocks__/subreddit-reactjs-response3.json';
import mockResponse4 from './__mocks__/subreddit-reactjs-response4.json';
import mockResponse5 from './__mocks__/subreddit-reactjs-response5.json';

fetchMock.enableMocks();

const setup = (initialPath = '/') => {
let history;
// let subredditName;
// const redditUrl = `https://www.reddit.com/r/${subredditName}/top.json?t=year&limit=100`;

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

describe('load the data', () => {
it('fetch the top 500 posts of the last year for the specified subreddit on form submit', async () => {
fetch
.once(JSON.stringify(mockResponse1))
.once(JSON.stringify(mockResponse2))
.once(JSON.stringify(mockResponse3))
.once(JSON.stringify(mockResponse4))
.once(JSON.stringify(mockResponse5));

setup('/search/reactjs');

// const searchLink = within(screen.getByRole('banner')).getByRole('link', { name: /search/i });
// userEvent.click(searchLink);

// const subredditInput = screen.getByLabelText('r /');
// const submitButton = screen.getByRole('button', { name: /search/i });

// userEvent.clear(subredditInput);
// userEvent.type(subredditInput, 'reactjs');
// expect(subredditInput.value).toBe('reactjs');

// await userEvent.click(submitButton);

// expect(history.location.pathname).toEqual('/search/reactjs');

const loadingImage = screen.getByAltText(/is loading/i);
expect(loadingImage).toBeInTheDocument();

expect(await screen.findByText(/500/i)).toBeInTheDocument();
expect(fetch).toHaveBeenCalledTimes(5);
// expect(fetch).toHaveBeenCalledWith('https://www.reddit.com/r/javascript/top.json?t=year&limit=100');
// screen.debug(searchResults);
});
});
32 changes: 32 additions & 0 deletions src/page-search/Heatmap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { useParams } from 'react-router-dom';

import useFetchPosts from './useFetchPosts';
import { ErrorContainer, LoadingContainer, LoadingSpinner } from './Heatmap.style';

function Heatmap() {
const { subreddit } = useParams(); // route param set in App
const { isLoading, hasError, posts } = useFetchPosts(subreddit);

if (isLoading) {
return (
<LoadingContainer>
<LoadingSpinner />
</LoadingContainer>
);
}

if (hasError) {
return (
<ErrorContainer>
Something went wrong. Please check the subreddit you entered then try again.
</ErrorContainer>
);
}

return (
<div>{posts.length}</div>
);
}

export default Heatmap;
29 changes: 29 additions & 0 deletions src/page-search/Heatmap.style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import styled, { keyframes } from 'styled-components';
import { ReactComponent as UnstyledSpinner } from './loading-spinner.svg';

export const LoadingContainer = styled.div`
width: 100%;
display: flex;
justify-content: center;
margin-top: 56px;
`;

export const ErrorContainer = styled.div`
padding: 30px;
color: red;
font-size: ${(props) => props.theme.font.size.small};
`;

const rotate = keyframes`
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
`;

export const LoadingSpinner = styled(UnstyledSpinner)`
animation: ${rotate} 1.5s linear infinite;
`;
3 changes: 3 additions & 0 deletions src/page-search/SearchPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import React from 'react';

import { Container, Headline } from './SearchPage.style';
import SubredditForm from './SubredditForm';
import Heatmap from './Heatmap';

function SearchPage() {
return (
<Container>
<Headline>Find the best time for a subreddit</Headline>
<SubredditForm />

<Heatmap />
</Container>
);
}
Expand Down
75 changes: 63 additions & 12 deletions src/page-search/SubredditForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,92 @@ import {
Form, Input, Label,
} from './SubredditForm.style';
import Button from '../common/button';
import Container from '../common/container';

function SubredditForm() {
const { subreddit: initialSubreddit } = useParams();
const [subreddit, setSubreddit] = useState(initialSubreddit);
// const [posts, setPosts] = useState([]);
// const [isLoading, setLoading] = useState(false);

function handleChange(event) {
setSubreddit(event.target.value);
}

// async function fetch100SubReddit(url) {
// let response;
// try {
// response = await fetch(url);
// const redditData = await response.json();
// return redditData.data;
// } catch (error) {
// return null;
// }
// }

// async function fetchSubReddit(subredditName) {
// setLoading(true);
// let allSubreddit = [];
// let subRedditData;

// try {
// subRedditData = await fetch100SubReddit(`https://www.reddit.com/r/${subredditName}/top.json?t=year&limit=100`);
// allSubreddit = [...allSubreddit, ...subRedditData.children];

// subRedditData = await fetch100SubReddit(`https://www.reddit.com/r/${subredditName}/top.json?t=year&limit=100&after=${subRedditData.after}`);
// allSubreddit = [...allSubreddit, ...subRedditData.children];

// subRedditData = await fetch100SubReddit(`https://www.reddit.com/r/${subredditName}/top.json?t=year&limit=100&after=${subRedditData.after}`);
// allSubreddit = [...allSubreddit, ...subRedditData.children];

// subRedditData = await fetch100SubReddit(`https://www.reddit.com/r/${subredditName}/top.json?t=year&limit=100&after=${subRedditData.after}`);
// allSubreddit = [...allSubreddit, ...subRedditData.children];

// subRedditData = await fetch100SubReddit(`https://www.reddit.com/r/${subredditName}/top.json?t=year&limit=100&after=${subRedditData.after}`);
// allSubreddit = [...allSubreddit, ...subRedditData.children];
// } catch (error) {
// // console.log('ERROR in fetchSubreddit', error);
// }

// setPosts(allSubreddit);

// setLoading(false);
// }

const history = useHistory();

function handleSubmit(evt) {
evt.preventDefault();
// const subRedditUrl = `/search/${subreddit}`;
history.push(`/search/${subreddit}`);

// fetchSubReddit(`${subreddit}`);
}

// update input value when URL is updated externally
// (e.g. when user clicks on search link in header)
useEffect(() => {
setSubreddit(initialSubreddit);
// fetchSubReddit(initialSubreddit);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialSubreddit]);

return (
<Form onSubmit={handleSubmit}>
<Label>
r /
<Input
type="text"
value={subreddit}
name="subreddit"
onChange={handleChange}
/>
</Label>
<Button>Search</Button>
</Form>
<Container>
<Form onSubmit={handleSubmit}>
<Label>
r /
<Input
type="text"
value={subreddit}
name="subreddit"
onChange={handleChange}
/>
</Label>
<Button>Search</Button>
</Form>
</Container>

);
}

Expand Down
Loading