-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from ktvtk/module9-task2
- Loading branch information
Showing
16 changed files
with
558 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import {BRUSSELS, CITIES, PARIS} from '../../const.ts'; | ||
import {configureMockStore} from '@jedmao/redux-mock-store'; | ||
import {State} from '../../types/state.ts'; | ||
import {render, screen} from '@testing-library/react'; | ||
import {Provider} from 'react-redux'; | ||
import {MemoryRouter} from 'react-router-dom'; | ||
import MemoizedCitiesList from './cities-list.tsx'; | ||
import userEvent from '@testing-library/user-event'; | ||
|
||
const mockStore = configureMockStore<State>(); | ||
|
||
describe('Component: CitiesList', () => { | ||
const initialState = { | ||
APP: { | ||
city: PARIS, | ||
}, | ||
}; | ||
|
||
const store = mockStore(initialState); | ||
|
||
it('should render all cities correctly', () => { | ||
render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<MemoizedCitiesList activeCity={PARIS.name} /> | ||
</MemoryRouter> | ||
</Provider> | ||
); | ||
|
||
CITIES.forEach((city) => { | ||
expect(screen.getByText(city.name)).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('should have active state for the currently selected city', () => { | ||
render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<MemoizedCitiesList activeCity={PARIS.name} /> | ||
</MemoryRouter> | ||
</Provider> | ||
); | ||
|
||
const parisLink = screen.getByText('Paris'); | ||
expect(parisLink.closest('div')).toHaveClass('tabs__item--active'); | ||
}); | ||
|
||
it('should dispatch active city change on city click', async () => { | ||
const user = userEvent.setup(); | ||
|
||
render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<MemoizedCitiesList activeCity={PARIS.name} /> | ||
</MemoryRouter> | ||
</Provider> | ||
); | ||
|
||
const brusselsLink = screen.getByText('Brussels'); | ||
await user.click(brusselsLink); | ||
|
||
const actions = store.getActions(); | ||
expect(actions).toHaveLength(1); | ||
expect(actions[0].type).toBe('APP/changeActiveCity'); | ||
expect(actions[0].payload).toBe(BRUSSELS); | ||
}); | ||
|
||
it('should have correct number of city items', () => { | ||
render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<MemoizedCitiesList activeCity={PARIS.name} /> | ||
</MemoryRouter> | ||
</Provider> | ||
); | ||
|
||
const cityItems = screen.getAllByRole('listitem'); | ||
expect(cityItems).toHaveLength(CITIES.length); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import MemoizedHeader from './header.tsx'; | |
import userEvent from '@testing-library/user-event'; | ||
import {logout} from '../../store/api-actions.ts'; | ||
import {MemoryRouter} from 'react-router-dom'; | ||
import {internet} from 'faker'; | ||
|
||
describe('Component: Header', () => { | ||
const middlewares = [thunk]; | ||
|
@@ -22,10 +23,11 @@ describe('Component: Header', () => { | |
}, | ||
}; | ||
|
||
const testUserEmail = internet.email() | ||
const initialStateAuth = { | ||
USER: { | ||
authorizationStatus: AuthorizationStatus.Authorized, | ||
userEmail: '[email protected]', | ||
userEmail: testUserEmail, | ||
}, | ||
OFFERS: { | ||
favoritesCount: 2, | ||
|
@@ -59,7 +61,7 @@ describe('Component: Header', () => { | |
</Provider> | ||
); | ||
|
||
const userEmail = screen.getByText('[email protected]'); | ||
const userEmail = screen.getByText(testUserEmail); | ||
expect(userEmail).toBeInTheDocument(); | ||
|
||
const favoritesCount = screen.getByText('2'); | ||
|
@@ -99,7 +101,7 @@ describe('Component: Header', () => { | |
</Provider> | ||
); | ||
|
||
const favoritesLink = screen.getByText('[email protected]').closest('a'); | ||
const favoritesLink = screen.getByText(testUserEmail).closest('a'); | ||
expect(favoritesLink).toHaveAttribute('href', AppRoute.Favorites); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import {Offer} from '../../types/offer.ts'; | ||
import {makeFakeOffer} from '../../utils/mocks.ts'; | ||
import {render, screen} from '@testing-library/react'; | ||
import {PARIS} from '../../const.ts'; | ||
import {Map} from './map.tsx'; | ||
|
||
vi.mock('../../hooks/useMap', () => ({ | ||
__esModule: true, | ||
default: vi.fn(), | ||
})); | ||
|
||
|
||
describe('Component: Map', () => { | ||
let mockOffers: Offer[]; | ||
let mockActiveOffer: Offer; | ||
|
||
beforeEach(() => { | ||
mockOffers = [makeFakeOffer(), makeFakeOffer()]; | ||
mockActiveOffer = mockOffers[0]; | ||
}); | ||
|
||
it('should render map correctly', () => { | ||
render( | ||
<Map | ||
city={PARIS} | ||
offers={mockOffers} | ||
selectedOffer= {mockActiveOffer} | ||
/> | ||
); | ||
|
||
const mapContainer = screen.getByTestId('map'); | ||
expect(mapContainer).toBeInTheDocument(); | ||
expect(mapContainer).toHaveClass('cities__map map') | ||
}); | ||
|
||
it('should highlight active marker when activeOffer is provided', () => { | ||
render( | ||
<Map | ||
city={PARIS} | ||
offers={mockOffers} | ||
selectedOffer= {mockActiveOffer} | ||
/> | ||
); | ||
const activeMarkerIconUrl = 'img/pin-active.svg'; | ||
expect(mockActiveOffer.id).toBe(mockOffers[0].id); | ||
expect(activeMarkerIconUrl).toBe('img/pin-active.svg'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import {render, screen} from '@testing-library/react'; | ||
import {Provider} from 'react-redux'; | ||
import {store} from '../../store'; | ||
import {MemoryRouter} from 'react-router-dom'; | ||
import {makeFakeOffer} from '../../utils/mocks.ts'; | ||
import {OffersList} from './offers-list.tsx'; | ||
import userEvent from '@testing-library/user-event'; | ||
|
||
describe('Component: OffersList', () => { | ||
const renderWithProvider = (elem: React.ReactElement) => | ||
render( | ||
<Provider store={store}> | ||
<MemoryRouter>{elem}</MemoryRouter> | ||
</Provider> | ||
); | ||
|
||
it('should render offers correctly', () => { | ||
const mockOffers = [makeFakeOffer(), makeFakeOffer(), makeFakeOffer()]; | ||
|
||
renderWithProvider(<OffersList offers={mockOffers} onChange={() => {}} />); | ||
|
||
mockOffers.forEach((offer) => { | ||
expect(screen.getByText(offer.title)).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('should call onOfferHover when an offer is hovered', async () => { | ||
const mockOffers = [makeFakeOffer(), makeFakeOffer()]; | ||
const handleOfferHover = vi.fn(); | ||
const user = userEvent.setup(); | ||
|
||
renderWithProvider(<OffersList offers={mockOffers} onChange={handleOfferHover} />); | ||
|
||
const firstOffer = screen.getByText(mockOffers[0].title); | ||
await user.hover(firstOffer); | ||
|
||
expect(handleOfferHover).toHaveBeenCalledWith(mockOffers[0].id); | ||
|
||
await user.unhover(firstOffer); | ||
|
||
expect(handleOfferHover).toHaveBeenCalledWith(null); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import {FavoriteScreen} from './favorite-screen.tsx'; | ||
import {withStore} from '../../utils/mocks-components.tsx'; | ||
import {makeFakeOffer, makeFakeStore} from '../../utils/mocks.ts'; | ||
import {AuthorizationStatus} from '../../const.ts'; | ||
import {render, screen} from '@testing-library/react'; | ||
import {HelmetProvider} from 'react-helmet-async'; | ||
import {MemoryRouter} from 'react-router-dom'; | ||
import {internet} from 'faker'; | ||
|
||
describe('Component: FavoriteScreen', () => { | ||
const component = | ||
<MemoryRouter> | ||
<HelmetProvider> | ||
<FavoriteScreen /> | ||
</HelmetProvider> | ||
</MemoryRouter> | ||
it('should render "Nothing yet saved" when there are no favorite offers', () => { | ||
const { withStoreComponent } = withStore( | ||
component, | ||
makeFakeStore({ | ||
USER: { | ||
authorizationStatus: AuthorizationStatus.Authorized, | ||
userEmail: internet.email(), | ||
}, | ||
OFFERS: { | ||
offers: [], | ||
favoritesOffers: [], | ||
favoritesCount: 0, | ||
}, | ||
}) | ||
); | ||
|
||
render(withStoreComponent); | ||
|
||
expect(screen.getByText(/Nothing yet saved/i)).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render favorite offers when there are favorite offers', () => { | ||
const favoriteOffer = makeFakeOffer(); | ||
|
||
const { withStoreComponent } = withStore( | ||
component, | ||
makeFakeStore({ | ||
USER: { | ||
authorizationStatus: AuthorizationStatus.Authorized, | ||
userEmail: internet.email(), | ||
}, | ||
OFFERS: { | ||
offers: [], | ||
favoritesOffers: [favoriteOffer], | ||
favoritesCount: 0, | ||
}, | ||
}) | ||
); | ||
|
||
render(withStoreComponent); | ||
|
||
expect(screen.getByText(/Saved listing/i)).toBeInTheDocument(); | ||
expect(screen.getByText(favoriteOffer.title)).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import {withStore} from '../../utils/mocks-components.tsx'; | ||
import {makeFakeStore} from '../../utils/mocks.ts'; | ||
import {AuthorizationStatus, LoadingStatus, PARIS} from '../../const.ts'; | ||
import {MemoryRouter} from 'react-router-dom'; | ||
import {HelmetProvider} from 'react-helmet-async'; | ||
import {LoginScreen} from './login-screen.tsx'; | ||
import {fireEvent, render, screen} from '@testing-library/react'; | ||
import {internet} from 'faker'; | ||
|
||
describe('Component: LoginScreen', () => { | ||
const component = | ||
<MemoryRouter> | ||
<HelmetProvider> | ||
<LoginScreen /> | ||
</HelmetProvider> | ||
</MemoryRouter> | ||
it('should render correctly', () => { | ||
const { withStoreComponent } = withStore( | ||
component, | ||
makeFakeStore({ | ||
USER: { | ||
authorizationStatus: AuthorizationStatus.Unauthorized, | ||
userEmail: null, | ||
}, | ||
APP: { | ||
city: PARIS, | ||
loadingStatus: LoadingStatus.Succeed | ||
}, | ||
}) | ||
); | ||
|
||
render(withStoreComponent); | ||
|
||
expect(screen.getByRole('heading', { name: /Sign in/i })).toBeInTheDocument(); | ||
expect(screen.getByRole('button', { name: /Sign in/i })).toBeInTheDocument(); | ||
expect(screen.getByPlaceholderText(/Email/i)).toBeInTheDocument(); | ||
expect(screen.getByPlaceholderText(/Password/i)).toBeInTheDocument(); | ||
}); | ||
|
||
|
||
it('should handle form submission', () => { | ||
const { withStoreComponent, mockStore } = withStore( | ||
component, | ||
makeFakeStore({ | ||
USER: { | ||
authorizationStatus: AuthorizationStatus.Unauthorized, | ||
userEmail: null, | ||
}, | ||
APP: { | ||
city: PARIS, | ||
loadingStatus: LoadingStatus.Succeed | ||
}, | ||
}) | ||
); | ||
|
||
render(withStoreComponent); | ||
|
||
fireEvent.change(screen.getByPlaceholderText(/Email/i), { target: { value: internet.email() } }); | ||
fireEvent.change(screen.getByPlaceholderText(/Password/i), { target: { value: 'password123' } }); | ||
fireEvent.click(screen.getByRole('button', { name: /Sign in/i })); | ||
|
||
const actions = mockStore.getActions(); | ||
expect(actions[0].type).toBe('auth/login/pending'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import {MemoryRouter} from 'react-router-dom'; | ||
import {HelmetProvider} from 'react-helmet-async'; | ||
import {MainEmptyScreen} from './main-empty-screen.tsx'; | ||
import {withStore} from '../../utils/mocks-components.tsx'; | ||
import {makeFakeStore} from '../../utils/mocks.ts'; | ||
import {AuthorizationStatus, LoadingStatus, PARIS} from '../../const.ts'; | ||
import {internet} from 'faker'; | ||
import {render, screen} from '@testing-library/react'; | ||
|
||
describe('Component: MainEmptyScreen', () => { | ||
const component = | ||
<MemoryRouter> | ||
<HelmetProvider> | ||
<MainEmptyScreen /> | ||
</HelmetProvider> | ||
</MemoryRouter> | ||
it('should render "No places to stay available" when there are no offers', () => { | ||
const { withStoreComponent } = withStore( | ||
component, | ||
makeFakeStore({ | ||
USER: { | ||
authorizationStatus: AuthorizationStatus.Authorized, | ||
userEmail: internet.email(), | ||
}, | ||
OFFERS: { | ||
offers: [], | ||
favoritesOffers: [], | ||
favoritesCount: 0, | ||
}, | ||
APP: { | ||
city: PARIS, | ||
loadingStatus: LoadingStatus.Succeed | ||
}, | ||
}) | ||
); | ||
|
||
render(withStoreComponent); | ||
|
||
expect(screen.getByText(/No places to stay available/i)).toBeInTheDocument(); | ||
expect(screen.getByText(/We could not find any property available at the moment in Paris/i)).toBeInTheDocument(); | ||
}); | ||
}) | ||
Oops, something went wrong.