Skip to content

Commit 37fad32

Browse files
complete tests for the homepage
1 parent 2476625 commit 37fad32

File tree

9 files changed

+204
-47
lines changed

9 files changed

+204
-47
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@types/react": "^17.0.0",
5353
"@types/react-dom": "^17.0.0",
5454
"@types/react-redux": "^7.1.16",
55-
"@types/react-router-dom": "^5.1.7"
55+
"@types/react-router-dom": "^5.1.7",
56+
"axios-mock-adapter": "^1.19.0"
5657
}
5758
}

src/App.test.tsx

+120-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,125 @@
11
import React from 'react';
2-
import { render, screen } from '@testing-library/react';
2+
import { render } from '@testing-library/react';
3+
import { Router } from 'react-router-dom';
4+
import { createMemoryHistory } from 'history';
5+
import { Provider } from 'react-redux';
6+
import { createStore } from 'redux';
7+
import MockAdapter from 'axios-mock-adapter';
8+
9+
import AxiosInstance from './services/generalAxiosInstance';
310

411
import App from './App';
512

6-
test('renders learn react link', () => {
7-
render(<App />);
8-
const linkElement = screen.getByText(/learn react/i);
9-
expect(linkElement).toBeInTheDocument();
13+
import reducer, { initialState } from './store/reducer';
14+
15+
import * as Actions from './store/actions';
16+
17+
import { transformSearchResult } from './utils';
18+
19+
import NewReleases from './tests/NewReleases.json';
20+
import SearchResults from './tests/SearchResults.json';
21+
22+
jest.mock('./services');
23+
24+
const spotifyUrl = process.env.REACT_APP_SPOTIFY_API_URL;
25+
26+
describe('All tests', () => {
27+
const store = createStore(reducer, initialState);
28+
const mock = new MockAdapter(AxiosInstance);
29+
30+
const appWrapper = () => {
31+
const history = createMemoryHistory();
32+
33+
return render(
34+
<Provider store={store}>
35+
<Router history={history}>
36+
<App />
37+
</Router>
38+
</Provider>
39+
);
40+
};
41+
42+
test('renders the App component without crashing', () => {
43+
const wrapper = appWrapper();
44+
45+
expect(wrapper).toBeDefined();
46+
});
47+
48+
test('renders the login page on initial render', async () => {
49+
const wrapper = appWrapper();
50+
51+
const loginButton = await wrapper.findByTestId('login-button');
52+
53+
expect(loginButton).toBeDefined();
54+
});
55+
56+
describe('Authenticated User tests', () => {
57+
beforeEach(() => {
58+
window.localStorage.setItem('token', '9090hjut-0-40-jhh');
59+
window.localStorage.setItem(
60+
'auth-user',
61+
JSON.stringify({
62+
country: 'NG',
63+
display_name: 'John Doe',
64+
email: 'john.doe@example.com',
65+
explicit_content: { filter_enabled: false, filter_locked: false },
66+
external_urls: {
67+
spotify: 'lll',
68+
},
69+
followers: { href: null, total: 0 },
70+
href: 'jkjjkf',
71+
id: 'jjkfkjfi904h',
72+
images: [],
73+
product: 'open',
74+
type: 'user',
75+
uri: 'spotify:user:jjkfkjfi904h',
76+
})
77+
);
78+
79+
mock
80+
.onGet(`${spotifyUrl}/browse/new-releases?limit=5`)
81+
.reply(200, { response: { data: NewReleases } });
82+
});
83+
84+
test('renders the home page when user token is set', async () => {
85+
const wrapper = appWrapper();
86+
87+
const newReleasesHeading = await wrapper.findByTestId(
88+
'new-release-heading'
89+
);
90+
const searchResultsHeading = await wrapper.findByTestId(
91+
'search-results-heading'
92+
);
93+
94+
expect(newReleasesHeading).toHaveTextContent('New Releases');
95+
expect(searchResultsHeading).toHaveTextContent('Search Results');
96+
});
97+
98+
test('renders the homepage with new released albums when album items are in the store', async () => {
99+
store.dispatch(Actions.getNewReleasesSuccess(NewReleases.albums.items));
100+
101+
const wrapper = appWrapper();
102+
103+
const allNewlyReleasedAlbums = await wrapper.findAllByTestId(
104+
'song-portrait'
105+
);
106+
107+
expect(allNewlyReleasedAlbums.length).toEqual(10);
108+
});
109+
110+
test(`renders all the search items from the user's previous searches`, async () => {
111+
store.dispatch(
112+
Actions.getUserLastSearchResultSuccess({
113+
searchQuery: 'ojuelegba',
114+
searchResult: transformSearchResult(SearchResults.tracks.items),
115+
})
116+
);
117+
118+
const wrapper = appWrapper();
119+
120+
const searchResults = await wrapper.findAllByTestId('song-landscape');
121+
122+
expect(searchResults.length).toEqual(10);
123+
});
124+
});
10125
});

src/components/NavBar/NavBar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ const NavBar = () => {
130130
};
131131

132132
return (
133-
<nav>
133+
<nav data-testid="navbar">
134134
<ul className="nav-bar">
135135
<li className="nav-bar__user-profile pointer" role="link">
136136
<div className="nav-bar__user-profile pointer" onClick={goToHomePage}>

src/components/Song/Song.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ const Song: React.FunctionComponent<SongProps> = ({
9898
);
9999

100100
return layout === SongLayout.PORTRAIT ? (
101-
<div className="song-portrait">
101+
<div className="song-portrait" data-testid="song-portrait">
102102
<div className="song-portrait__thumbnail">
103103
<img src={song.thumbnail} alt={`${song.title}`} loading="lazy" />
104104
</div>
@@ -121,7 +121,7 @@ const Song: React.FunctionComponent<SongProps> = ({
121121
)}
122122
</div>
123123
) : (
124-
<div className="song-landscape">
124+
<div className="song-landscape" data-testid="song-landscape">
125125
<div className="song-landscape__art-and-title">
126126
<div className="song-landscape__thumbnail">
127127
<img src={song.thumbnail} alt={`${song.title}`} loading="lazy" />

src/pages/Home/Home.tsx

+45-37
Original file line numberDiff line numberDiff line change
@@ -68,52 +68,55 @@ const Home: FunctionComponent = () => {
6868
}
6969
}, [dispatch]);
7070

71-
useEffect(() => {
72-
const getUserLibrary = async () => {
73-
try {
74-
dispatch(getUserLibraryRequestLoading());
75-
const response = await Services.getUserLibrary();
76-
77-
dispatch(getUserLibrarySuccess(response));
78-
} catch (error) {
79-
toast.error(errorHandler(error.message));
80-
dispatch(getUserLibraryError(error.message));
81-
}
82-
};
83-
84-
const getUserLastSearchResult = async () => {
85-
try {
86-
dispatch(getUserLastSearchResultRequestLoading());
87-
const response = await Services.getUserLastSearchResult();
88-
89-
dispatch(
90-
getUserLastSearchResultSuccess({
91-
searchQuery: response.searchQuery,
92-
searchResult: response.searchResult,
93-
})
94-
);
95-
} catch (error) {
96-
toast.error(errorHandler(error.message));
97-
dispatch(getUserLastSearchResultError(error.message));
98-
}
99-
};
71+
const getUserLibrary = useCallback(async () => {
72+
try {
73+
dispatch(getUserLibraryRequestLoading());
74+
const response = await Services.getUserLibrary();
75+
76+
dispatch(getUserLibrarySuccess(response));
77+
} catch (error) {
78+
toast.error(errorHandler(error.message));
79+
dispatch(getUserLibraryError(error.message));
80+
}
81+
}, [dispatch]);
82+
83+
const getUserLastSearchResult = useCallback(async () => {
84+
try {
85+
dispatch(getUserLastSearchResultRequestLoading());
86+
const response = await Services.getUserLastSearchResult();
87+
88+
dispatch(
89+
getUserLastSearchResultSuccess({
90+
searchQuery: response.searchQuery,
91+
searchResult: response.searchResult,
92+
})
93+
);
94+
} catch (error) {
95+
toast.error(errorHandler(error.message));
96+
dispatch(getUserLastSearchResultError(error.message));
97+
}
98+
}, [dispatch]);
10099

100+
useEffect(() => {
101101
getUserLibrary();
102102
getNewReleases();
103103
getUserLastSearchResult();
104-
105-
return () => {};
106-
}, [getNewReleases, dispatch]);
104+
}, [getNewReleases, dispatch, getUserLastSearchResult, getUserLibrary]);
107105

108106
return (
109107
<div className="home page">
110108
<section className="new-release">
111-
<div className="page-title">New Releases</div>
109+
<div className="page-title" data-testid="new-release-heading">
110+
New Releases
111+
</div>
112112

113113
{newReleasesAreBeingLoaded ? (
114114
<Loader width={8} />
115115
) : (
116-
<div className={`songs-${SongLayout.PORTRAIT.toLowerCase()}`}>
116+
<div
117+
className={`songs-${SongLayout.PORTRAIT.toLowerCase()}`}
118+
data-testid="new-releases"
119+
>
117120
{newReleases.map((album: Album) => (
118121
<Song
119122
key={album.id}
@@ -170,16 +173,21 @@ const Home: FunctionComponent = () => {
170173
)}
171174
</section>
172175

173-
<section className="search-results">
174-
<div className="page-title">Search Results</div>
176+
<section
177+
className="search-results"
178+
data-testid="search-results-container"
179+
>
180+
<div className="page-title" data-testid="search-results-heading">
181+
Search Results
182+
</div>
175183

176184
<div className={`songs-${SongLayout.LANDSCAPE.toLowerCase()}`}>
177185
<div className="search-results__headings">
178186
<div className="search-results__headings--title">Title</div>
179187
<div className="search-results__headings--album">Album</div>
180188
<div className="search-results__headings--duration">Duration</div>
181189
</div>
182-
{/* {searchIsBeingProcessed && <p>Loading...</p>} */}
190+
183191
{searchCameBackEmpty ? (
184192
<p>No Match Found</p>
185193
) : (

src/pages/Login/Login.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const Login: FunctionComponent = () => {
1313
redirecUri
1414
)}&response_type=token&scope=playlist-modify-private,user-read-private,user-read-email,playlist-modify-public`}
1515
className="login-button"
16+
data-testid="login-button"
1617
>
1718
Login
1819
</a>

src/setupTests.ts

+19
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,22 @@
33
// expect(element).toHaveTextContent(/react/i)
44
// learn more: https://github.com/testing-library/jest-dom
55
import '@testing-library/jest-dom';
6+
7+
Object.defineProperty(window, 'localStorage', {
8+
value: {
9+
data: {},
10+
length: 0,
11+
setItem(name: string, value: string) {
12+
this.data[name] = value.toString();
13+
this.length = Object.keys(this.data).length;
14+
},
15+
getItem(name: string) {
16+
return this.data[name];
17+
},
18+
removeItem(name: string) {
19+
delete this.data[name];
20+
this.length = Object.keys(this.data).length;
21+
},
22+
},
23+
writable: true,
24+
});
File renamed without changes.

yarn.lock

+14-1
Original file line numberDiff line numberDiff line change
@@ -2601,6 +2601,14 @@ axe-core@^4.0.2:
26012601
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224"
26022602
integrity sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==
26032603

2604+
axios-mock-adapter@^1.19.0:
2605+
version "1.19.0"
2606+
resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz#9d72e321a6c5418e1eff067aa99761a86c5188a4"
2607+
integrity sha512-D+0U4LNPr7WroiBDvWilzTMYPYTuZlbo6BI8YHZtj7wYQS8NkARlP9KBt8IWWHTQJ0q/8oZ0ClPBtKCCkx8cQg==
2608+
dependencies:
2609+
fast-deep-equal "^3.1.3"
2610+
is-buffer "^2.0.3"
2611+
26042612
axios@^0.21.1:
26052613
version "0.21.1"
26062614
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
@@ -4987,7 +4995,7 @@ extsprintf@^1.2.0:
49874995
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
49884996
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
49894997

4990-
fast-deep-equal@^3.1.1:
4998+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
49914999
version "3.1.3"
49925000
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
49935001
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
@@ -6056,6 +6064,11 @@ is-buffer@^1.1.5:
60566064
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
60576065
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
60586066

6067+
is-buffer@^2.0.3:
6068+
version "2.0.5"
6069+
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
6070+
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
6071+
60596072
is-callable@^1.1.4, is-callable@^1.2.2:
60606073
version "1.2.3"
60616074
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"

0 commit comments

Comments
 (0)