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

Enhancement #10

Open
wants to merge 11 commits into
base: development
Choose a base branch
from
3 changes: 2 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Header from './components/header/Header';
import VideoPage from './components/content/VideoPage/VideoPage';
import SearchResult from './components/content/SearchResult';
import NotFound from './components/content/NotFound';
import InitialPage from './components/content/InitialPage';
import Profile from './components/Profile';

class App extends Component {
render() {
Expand All @@ -28,6 +28,7 @@ class App extends Component {
path="/results/:searchParam"
render={(props) => <SearchResult {...props} />}
/>
<Route to="/profile" component={Profile} />
<Route path="*" component={NotFound} />
</Switch>
</div>
Expand Down
50 changes: 50 additions & 0 deletions src/__tests__/AltHeader.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import App from '../App';
import mockSearchVideo from '../__mocks__/mockSearchVideo';
import * as api from '../api/service';

jest.mock('react-router-dom', () => {
const moduloOriginal = jest.requireActual('react-router-dom');
return {
...moduloOriginal,
BrowserRouter: ({ children }) => <div>{children}</div>,
};
});

jest.mock('../api/service');
api.searchVideos.mockImplementation(() => Promise.resolve(mockSearchVideo));

function renderWithRouter(ui, routeConfigs = {}) {
const route = routeConfigs.route || '/';
const history = routeConfigs.history || createMemoryHistory({ initialEntries: [route] });
return {
...render(<Router history={history}>{ui}</Router>),
history,
};
}

describe('Funcionalidades Componente Header', () => {
it('Renderiza dois links na tela', () => {
const { container } = renderWithRouter(<App />);
const links = container.querySelectorAll('a');
expect(links.length).toBe(3);
expect(links[1].href).toMatch('/results');
});

it('Ao fazer uma busca redireciona a página de resultados', async () => {
const { getAllByRole, getByPlaceholderText, history } = renderWithRouter(
<App />,
);
expect(history.location.pathname).toBe('/');

const searchText = 'bugs';
fireEvent.change(getByPlaceholderText(/search/i), { target: { value: searchText } });
fireEvent.click(getAllByRole('link')[1]);

await waitFor(() => expect(api.searchVideos).toHaveBeenCalled());
expect(history.location.pathname).toBe(`/results/${searchText}`);
});
});
65 changes: 65 additions & 0 deletions src/__tests__/AltSearchResults.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import {
render,
screen,
fireEvent,
getByRole,
waitFor,
} from '@testing-library/react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import SearchResult from '../components/content/SearchResult/index';
import App from '../App';
import mockSearchVideo from '../__mocks__/mockSearchVideo';
import mockGetVideoInfo from '../__mocks__/mockGetVideoInfo';
import mockGetVideoComments from '../__mocks__/mockGetVideoComments';
import * as api from '../api/service';

jest.mock('react-router-dom', () => {
const moduloOriginal = jest.requireActual('react-router-dom');
return {
...moduloOriginal,
BrowserRouter: ({ children }) => <div>{children}</div>,
};
});

jest.mock('../api/service');
api.searchVideos.mockImplementation(() => Promise.resolve(mockSearchVideo));
api.getVideoInfo.mockImplementation(() => Promise.resolve(mockGetVideoInfo));
api.getVideoComments.mockImplementation(() => Promise.resolve(mockGetVideoComments));
api.getRelatedVideos.mockImplementation(() => Promise.resolve(mockSearchVideo));

function renderWithRouter(ui, routeConfigs = {}) {
const route = routeConfigs.route || '/';
const history = routeConfigs.history || createMemoryHistory({ initialEntries: [route] });
return {
...render(<Router history={history}>{ui}</Router>),
history,
};
}

describe('Funcionalidades Componente Search Result', () => {
it('Renderiza uma lista de videos em cima da busca', async () => {
renderWithRouter(
<SearchResult match={{ params: { searchParam: 'bugs' } }} />,
);
await waitFor(() => expect(api.searchVideos).toHaveBeenCalled());
expect(screen.getAllByRole('link').length).toBeLessThan(
mockSearchVideo.items.length,
);
});

it('Ao clicar em um video redireciona a pagina de display', async () => {
const { history } = renderWithRouter(<App />, { route: '/results/bugs' });
await waitFor(() => expect(api.searchVideos).toHaveBeenCalled());

const videoLink = screen.getAllByRole('link')[3];
fireEvent.click(videoLink);
expect(history.location.pathname).toMatch(/watch/i);

await waitFor(() => expect(api.getVideoInfo).toHaveBeenCalled());
await waitFor(() => expect(api.getVideoComments).toHaveBeenCalled());

expect(screen.getByTestId('videoplayer')).toBeInTheDocument();
});
});
76 changes: 76 additions & 0 deletions src/__tests__/AltVideoPage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import VideoPage from '../components/content/VideoPage/VideoPage';
import mockSearchVideo from '../__mocks__/mockSearchVideo';
import mockGetVideoInfo from '../__mocks__/mockGetVideoInfo';
import mockGetVideoComments from '../__mocks__/mockGetVideoComments';
import * as api from '../api/service';

jest.mock('react-router-dom', () => {
const moduloOriginal = jest.requireActual('react-router-dom');
return {
...moduloOriginal,
BrowserRouter: ({ children }) => <div>{children}</div>,
useHistory: () => ({ push: jest.fn() }),
};
});

jest.mock('../api/service');
api.getVideoInfo.mockImplementation(() => Promise.resolve(mockGetVideoInfo));
api.getVideoComments.mockImplementation(() => Promise.resolve(mockGetVideoComments));
api.getRelatedVideos.mockImplementation(() => Promise.resolve(mockSearchVideo));

function renderWithRouter(ui, routeConfigs = {}) {
const route = routeConfigs.route || '/';
const history = routeConfigs.history || createMemoryHistory({ initialEntries: [route] });
return {
...render(<Router history={history}>{ui}</Router>),
history,
};
}

describe('Funcionalidades Componente Video Page', () => {
it('Renderiza dados no vídeo na página', async () => {
const randomVideoID = mockSearchVideo.items[1].id.videoId;

renderWithRouter(
<VideoPage
match={{ params: { videoId: randomVideoID } }}
location={{ state: { data: mockSearchVideo.items } }}
/>,
);

await waitFor(() => expect(api.getVideoInfo).toHaveBeenCalled());
await waitFor(() => expect(api.getVideoComments).toHaveBeenCalled());

expect(screen.getByTestId('videoplayer')).toBeInTheDocument();
expect(screen.getByTestId('videoinfo')).toBeInTheDocument();
expect(screen.getByTestId('channelinfo')).toBeInTheDocument();
expect(screen.getByTestId('comments')).toBeInTheDocument();
});

it('Vídeo selecionado atualiza os dados do vídeo atual na página', async () => {
const randomVideoID = mockSearchVideo.items[1].id.videoId;
const { history } = renderWithRouter(
<VideoPage
match={{ params: { videoId: randomVideoID } }}
location={{ state: { data: mockSearchVideo.items } }}
/>,
{ route: `/watch/${randomVideoID}` },
);

await waitFor(() => expect(api.getVideoInfo).toHaveBeenCalled());
await waitFor(() => expect(api.getVideoComments).toHaveBeenCalled());
await waitFor(() => expect(api.getRelatedVideos).toHaveBeenCalled());
expect(history.location.pathname).toBe(`/watch/${randomVideoID}`);

fireEvent.click(screen.getAllByTestId('selectedVideo')[2]);
await waitFor(() => expect(api.getVideoInfo).toHaveBeenCalled());
await waitFor(() => expect(api.getVideoComments).toHaveBeenCalled());
await waitFor(() => expect(api.getRelatedVideos).toHaveBeenCalled());

expect(history.location.pathname).not.toEqual(`/watch/${randomVideoID}`);
});
});
18 changes: 9 additions & 9 deletions src/__tests__/SearchResult.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ import App from '../App';
import mockSearchVideo from '../__mocks__/mockSearchVideo';
import mockGetVideoInfo from '../__mocks__/mockGetVideoInfo';
import mockGetVideoComments from '../__mocks__/mockGetVideoComments';
import * as api from '../api/service'
import * as api from '../api/service';

jest.mock('react-router-dom', () => {
const moduloOriginal = jest.requireActual('react-router-dom');
return {
...moduloOriginal,
BrowserRouter: ({ children }) => (<div>{children}</div>),
};
})
});

jest.mock('../api/service');
api.searchVideos.mockImplementation(
() => Promise.resolve(mockSearchVideo)
() => Promise.resolve(mockSearchVideo),
);
api.getVideoInfo.mockImplementation(
() => Promise.resolve(mockGetVideoInfo)
() => Promise.resolve(mockGetVideoInfo),
);
api.getVideoComments.mockImplementation(
() => Promise.resolve(mockGetVideoComments)
() => Promise.resolve(mockGetVideoComments),
);

function renderWithRouter(ui, routeConfigs = {}) {
Expand All @@ -42,7 +42,7 @@ describe('Funcionalidades Componente Search Result', () => {
renderWithRouter(<SearchResult match={{ params: { searchParam: 'bugs' } }} />);
await waitFor(() => expect(api.searchVideos).toHaveBeenCalled());
expect(screen.getAllByRole('link').length).toBeLessThan(mockSearchVideo.items.length);
})
});

it('Ao clicar em um video redireciona a pagina de display', async () => {
const { history } = renderWithRouter(<App />, { route: '/results/bugs' });
Expand All @@ -54,7 +54,7 @@ describe('Funcionalidades Componente Search Result', () => {

await waitFor(() => expect(api.getVideoInfo).toHaveBeenCalled());
await waitFor(() => expect(api.getVideoComments).toHaveBeenCalled());

expect(screen.getByTestId('videoplayer')).toBeInTheDocument();
})
})
});
});
11 changes: 6 additions & 5 deletions src/api/localStorage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export default function addToLocalStorage(key, value) {
const jsonKey = JSON.stringify(key);
if (!localStorage[jsonKey]) localStorage[jsonKey] = JSON.stringify([]);
const searchHistory = JSON.parse(localStorage[jsonKey]);
const updatedSearchHistory = [...searchHistory, value];
localStorage[jsonKey] = JSON.stringify(updatedSearchHistory);
// const jsonKey = JSON.stringify(key);
if (!localStorage[key]) localStorage[key] = JSON.stringify([]);
const searchHistory = JSON.parse(localStorage[key]);
const historyArray = searchHistory.filter((element) => element !== value);
const updatedSearchHistory = [...historyArray, value];
localStorage[key] = JSON.stringify(updatedSearchHistory);
}
13 changes: 13 additions & 0 deletions src/api/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,16 @@ export const getVideoComments = async (videoId) => {
return error;
}
};

export const getRelatedVideos = async (videoId) => {
const urlParams = `part=snippet&relatedToVideoId=${videoId}&type=video&key=${YOUTUBE_AUTH_KEY()}`;
const URL = `${YOUTUBE_API_URL}/search?${urlParams}`;

try {
const response = await fetch(URL);
const data = await response.json();
return data;
} catch (error) {
return error;
}
};
41 changes: 41 additions & 0 deletions src/components/Profile/ViewedVideos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import VideoCard from '../content/SearchResult/VideoCard/VideoCard';
import '../../css/sideBar.css';

class ViewedVideos extends Component {
constructor(props) {
super(props);

this.state = { data: [] };
}

componentDidMount() {
this.mountViewedComponent();
}

mountViewedComponent() {
const data = new Set(JSON.parse(localStorage.getItem('viewedVideos') || '[]'));
return this.setState({ data: [...data] });
}

render() {
const { data } = this.state;
if (!data) return <h4>Sem vídeos favoritos</h4>;
return (
<div>
{data.map((item) => (
<Link
className="thumbnail-card"
key={item.etag}
to={{ pathname: `/watch/${item.id.videoId}`, state: { item } }}
>
<VideoCard video={item} />
</Link>
))}
</div>
);
}
}

export default ViewedVideos;
23 changes: 23 additions & 0 deletions src/components/Profile/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { Component } from 'react';
import ViewedVideos from './ViewedVideos';

class Profile extends Component {
render() {
return <section>
<div>
<h3>Vídeos Pesquisados</h3>
</div>
<div>
<ViewedVideos/>
</div>
<div>
<h3>Vídeos Favoritos</h3>
</div>
<div>
<h3>Assistir mais tarde</h3>
</div>
</section>;
}
}

export default Profile;
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ class VideoCard extends Component {
return !!(props === param1 || props === param2);
}

render() {
constructor(props) {
super(props);
const { video } = this.props;

this.state = { video };
}

render() {
const { video } = this.state;
const { id: { kind }, snippet } = video;
const { thumbnails: { medium: { url } }, channelTitle, description, title } = snippet;
return (
Expand Down
5 changes: 1 addition & 4 deletions src/components/content/SearchResult/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ class SearchResult extends Component {
<Link
className="thumbnail-card"
key={item.etag}
to={{
pathname: `/watch/${item.id.videoId}`,
state: { data },
}}
to={{ pathname: `/watch/${item.id.videoId}`, state: { item } }}
>
<VideoCard video={item} />
</Link>
Expand Down
Loading