Skip to content

Commit

Permalink
Добавит тесты для роутинга
Browse files Browse the repository at this point in the history
  • Loading branch information
strawberrycheeks committed Jan 12, 2025
1 parent a6c56d0 commit 13c1477
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 36 deletions.
178 changes: 178 additions & 0 deletions src/app/app.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { render, screen } from '@testing-library/react';
import { createMemoryHistory, MemoryHistory } from 'history';
import { Provider } from 'react-redux';

import { cities } from '@/entities/city';
import { makeOfferMaximum, makeOffers } from '@/entities/offer-card/lib/mocks';
import { makeReviews } from '@/entities/review/lib/mocks';
import { makeUser } from '@/entities/user/lib/mocks';
import { AppRoutes } from '@/shared/model/app-routes';
import {
AuthorizationStatus,
FetchStatus,
NameSpace,
} from '@/shared/model/enums';

import { App } from './app';
import { HistoryRouter } from './history-router';
import { initAsyncActionsStore } from './lib/mocks';

describe('<App />', () => {
const { mockStoreCreator } = initAsyncActionsStore();
let store: ReturnType<typeof mockStoreCreator>;

let mockHistory: MemoryHistory;

beforeEach(() => {
store = mockStoreCreator({
[NameSpace.USER]: {
authorizationStatus: AuthorizationStatus.AUTH,
user: makeUser(),
},
[NameSpace.CITY]: {
city: cities.Paris,
},
[NameSpace.OFFER]: {
offers: makeOffers(),
offersFetchStatus: FetchStatus.SUCCESS,
offer: makeOfferMaximum(),
offerFetchStatus: FetchStatus.SUCCESS,
},
[NameSpace.REVIEW]: {
reviews: makeReviews(),
reviewsFetchStatus: FetchStatus.SUCCESS,
},
});

mockHistory = createMemoryHistory();
});

it('should render MainPage correctly', () => {
const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push(AppRoutes.HOME);

const { container } = render(component);

expect(container.querySelector('.header')).toBeInTheDocument();
expect(container.querySelector('.locations__list')).toBeInTheDocument();
expect(container.querySelector('.cities')).toBeInTheDocument();
});

it('should render LoginPage correctly', () => {
store = mockStoreCreator({
[NameSpace.USER]: {
authorizationStatus: AuthorizationStatus.NO_AUTH,
},
});

const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push(AppRoutes.LOGIN);

const { container } = render(component);

expect(container.querySelector('form.login__form')).toBeInTheDocument();
expect(container.querySelectorAll('input').length).toBe(2);
});

it('should render LoginPage instead of FavoritesPage due to user is not authenticated', () => {
store = mockStoreCreator({
[NameSpace.USER]: {
authorizationStatus: AuthorizationStatus.NO_AUTH,
},
});

const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push(AppRoutes.FAVORITES);

const { container } = render(component);

expect(container.querySelector('form.login__form')).toBeInTheDocument();
expect(container.querySelectorAll('input').length).toBe(2);
});

it('should render FavoritesPage correctly', () => {
const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push(AppRoutes.FAVORITES);

const { container } = render(component);

expect(screen.getByText('Saved listing')).toBeInTheDocument();
expect(container.querySelector('.favorites__list')).toBeInTheDocument();
});

it('should render OfferPage correctly', () => {
const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push(`${AppRoutes.OFFER}/1`);

const { container } = render(component);

expect(container.querySelector('.page__main--offer')).toBeInTheDocument();
});

it('should render Error404Page if offer was not provided', () => {
const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push(AppRoutes.OFFER);

render(component);

expect(screen.getByText('404 — Page not found')).toBeInTheDocument();
});

it('should render Error404Page route does not exist', () => {
const component = (
<Provider store={store}>
<HistoryRouter history={mockHistory}>
<App />
</HistoryRouter>
</Provider>
);

mockHistory.push('/123');

render(component);

expect(screen.getByText('404 — Page not found')).toBeInTheDocument();
});
});
39 changes: 18 additions & 21 deletions src/app/router/index.tsx → src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useEffect } from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Route, Routes } from 'react-router-dom';

import { PrivateRoute } from '@/app/router/private-route';
import { checkLogin, getAuthorizationStatus } from '@/entities/user';
import { Error404Page } from '@/pages/error';
import { FavoritesPage } from '@/pages/favorites';
Expand All @@ -12,11 +11,11 @@ import { AppRoutes } from '@/shared/model/app-routes';
import { AuthorizationStatus } from '@/shared/model/enums';
import { Spinner } from '@/shared/ui/spinner';

import { useAppDispatch, useAppSelector } from '../store/model/hooks';
import { PrivateRoute } from './private-route';
import { useAppDispatch, useAppSelector } from './store/model/hooks';

export const AppRouter = () => {
export const App = () => {
const dispatch = useAppDispatch();

const authorizationStatus = useAppSelector(getAuthorizationStatus);

useEffect(() => {
Expand All @@ -26,21 +25,19 @@ export const AppRouter = () => {
return authorizationStatus === AuthorizationStatus.UNKNOWN ? (
<Spinner />
) : (
<BrowserRouter>
<Routes>
<Route path={AppRoutes.HOME} element={<MainPage />} />
<Route path={AppRoutes.LOGIN} element={<LoginPage />} />
<Route
path={AppRoutes.FAVORITES}
element={
<PrivateRoute>
<FavoritesPage />
</PrivateRoute>
}
/>
<Route path={`${AppRoutes.OFFER}/:id`} element={<OfferPage />} />
<Route path={AppRoutes.NOT_FOUND} element={<Error404Page />} />
</Routes>
</BrowserRouter>
<Routes>
<Route path={AppRoutes.HOME} element={<MainPage />} />
<Route path={AppRoutes.LOGIN} element={<LoginPage />} />
<Route
path={AppRoutes.FAVORITES}
element={
<PrivateRoute>
<FavoritesPage />
</PrivateRoute>
}
/>
<Route path={`${AppRoutes.OFFER}/:id`} element={<OfferPage />} />
<Route path={AppRoutes.NOT_FOUND} element={<Error404Page />} />
</Routes>
);
};
31 changes: 31 additions & 0 deletions src/app/history-router/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { BrowserHistory } from 'history';
import { useLayoutEffect, useState } from 'react';
import { Router } from 'react-router-dom';

type HistoryRouterProps = {
history: BrowserHistory;
basename?: string;
children?: React.ReactNode;
};

export const HistoryRouter = (props: HistoryRouterProps) => {
const { basename, children, history } = props;

const [state, setState] = useState({
action: history.action,
location: history.location,
});

useLayoutEffect(() => history.listen(setState), [history]);

return (
<Router
basename={basename}
location={state.location}
navigationType={state.action}
navigator={history}
>
{children}
</Router>
);
};
1 change: 1 addition & 0 deletions src/app/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { App } from './app';
12 changes: 0 additions & 12 deletions src/app/index.tsx

This file was deleted.

File renamed without changes.
1 change: 1 addition & 0 deletions src/entities/user/api/api-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const checkLogin = createAsyncThunk<void, undefined, DispatchStateExtra>(
} else {
// TODO: показывать сообщение об ошибке пользователю (бэк сообщает, что именно не так)
dispatch(setAuthorizationStatus(AuthorizationStatus.NO_AUTH));
removeToken();
}
},
);
Expand Down
11 changes: 9 additions & 2 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';

import { App } from './app';
import { App } from './app/app';
import { store } from './app/store';

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);

root.render(
<React.StrictMode>
<App />
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>,
);
2 changes: 1 addition & 1 deletion src/shared/ui/rating/ui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type RatingProps = {
};

export const Rating = (props: RatingProps) => {
const { rating, mode, containerStyles, starsStyles } = props;
const { rating, mode = 'full', containerStyles, starsStyles } = props;

const isFullMode = mode === 'full';

Expand Down

0 comments on commit 13c1477

Please sign in to comment.