Skip to content

Commit

Permalink
Test SearchBar unit test and integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
Alambea committed Jan 28, 2024
1 parent 1b0e641 commit 744f557
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 38 deletions.
69 changes: 65 additions & 4 deletions src/components/App/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { BrowserRouter, MemoryRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event";
Expand All @@ -19,7 +18,10 @@ import App from "./App";
import { paths } from "../../routers/paths";
import { setupStore } from "../../store";
import {
oceanRecordMock,
portisheadRecordMock,
radioheadRecordApiMock,
radioheadRecordMock,
recordMock,
recordsMock,
} from "../../mocks/recordsMock";
Expand Down Expand Up @@ -191,6 +193,67 @@ describe("Given an App component", () => {
});
});

describe("And the path is '/records/search?query=head", () => {
test("Then it should show two headings 'Radiohead' and 'Portishead' and not show 'The Ocean'", async () => {
const textToSearch = "head";
const searchButtonAlt = "Magnifying glass icon";

// const initialPath = `${paths.records}/search?query=${textToSearch}`;
const initialPath = `${paths.records}`;
const recordsToShow = [radioheadRecordMock, portisheadRecordMock];
const recordsToNotShow = oceanRecordMock;

const user: Partial<User> = {
getIdToken: vi.fn().mockResolvedValue("token"),
};

const idTokenHookMock: Partial<IdTokenHook> = [user as User];
const authStateHookMock: Partial<AuthStateHook> = [user as User];

authHook.useIdToken = vi.fn().mockReturnValue(idTokenHookMock);
authHook.useAuthState = vi.fn().mockReturnValue(authStateHookMock);

const store = setupStore({
recordsState: {
records: recordsMock,
recordCount: recordsMock.length,
},
});

render(
<Provider store={store}>
<MemoryRouter initialEntries={[initialPath]}>
<App />
</MemoryRouter>
</Provider>,
);

const searchInput = await screen.findByLabelText("Search");

await userEvent.type(searchInput, textToSearch);

const searchButton = screen.getByRole("button", {
name: searchButtonAlt,
});

await userEvent.click(searchButton);

const heading = await screen.queryByRole("heading", {
name: recordsToNotShow.artist,
});

recordsToShow.forEach((recodToShow) => {
const heading = screen.getByRole("heading", {
name: recodToShow.artist,
});

expect(heading).toBeInTheDocument();
});

expect(heading).not.toBeInTheDocument();
});
});

describe("And the path is '/add-new-record' and the user types 'FKA Twigs', 'LP1', 2014, 4, 'LP1 is the debut studio...', '40:46', 'Young Turks', 'Avant-pop, electronic, art pop R&B, trip hop' and 'http://example.com/image.png' on each input and clicks on the 'Add' button it should be enabled", () => {
test("Then it should show a heading 'Records'", async () => {
const initialPath = paths.addRecord;
Expand Down Expand Up @@ -236,9 +299,7 @@ describe("Given an App component", () => {
render(
<Provider store={store}>
<MemoryRouter initialEntries={[initialPath]}>
<React.Suspense>
<App />
</React.Suspense>
<App />
</MemoryRouter>
</Provider>,
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const App = (): React.ReactElement => {
</ProtectedRoute>
}
/>
{[paths.records, paths.records + paths.search].map((path, index) => (
{[paths.records, paths.records + paths.search].map((path) => (
<Route
path={path}
element={
Expand All @@ -44,7 +44,7 @@ const App = (): React.ReactElement => {
</Suspense>
</ProtectedRoute>
}
key={index + path}
key={path}
/>
))}
<Route
Expand Down
23 changes: 21 additions & 2 deletions src/components/Pagination/Pagination.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@ import Pagination from "./Pagination";
import { Provider } from "react-redux";
import { recordsMock } from "../../mocks/recordsMock";
import { setupStore } from "../../store";
import { BrowserRouter } from "react-router-dom";
import reactRouterDom, { BrowserRouter } from "react-router-dom";

const useSearchParamsMockWithQuery: Partial<URLSearchParams> = {
has: vi.fn().mockReturnValue(true),
delete: vi.fn(),
toString: vi.fn().mockReturnValue("query=head"),
};
const useSearchParamsMockWithoutQuery: Partial<URLSearchParams> = {
has: vi.fn().mockReturnValue(true),
delete: vi.fn(),
toString: vi.fn().mockReturnValue(""),
};

describe("Given a Pagination component", () => {
describe("When it is rendered receives an empty string as a currentPage and a limitPerPage 4 and there're 4 records in the store", () => {
Expand All @@ -17,6 +28,10 @@ describe("Given a Pagination component", () => {
recordsState: { records: recordsMock, recordCount: recordsMock.length },
});

reactRouterDom.useSearchParams = vi
.fn()
.mockReturnValue([{ ...useSearchParamsMockWithQuery }]);

render(
<BrowserRouter>
<Provider store={store}>
Expand All @@ -29,7 +44,7 @@ describe("Given a Pagination component", () => {
const previousLink = screen.getByRole("link", {
name: expectedPreviousLink,
});

screen.debug();
expect(nextLink).toBeInTheDocument();
expect(previousLink).toBeInTheDocument();
});
Expand All @@ -46,6 +61,10 @@ describe("Given a Pagination component", () => {
recordsState: { records: recordsMock, recordCount: recordsMock.length },
});

reactRouterDom.useSearchParams = vi
.fn()
.mockReturnValue([{ ...useSearchParamsMockWithoutQuery }]);

render(
<BrowserRouter>
<Provider store={store}>
Expand Down
9 changes: 3 additions & 6 deletions src/components/SearchBar/SearchBar.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
@use "../../styles/variables/colors";

.search-bar {
display: flex;
flex-direction: row;
align-items: flex-end;
height: 44px;
margin-bottom: 30px;

&__form {
display: flex;
flex-direction: row;
align-items: flex-end;
}

&__label {
font-weight: 600;
padding: 5px 10px;
Expand Down
49 changes: 49 additions & 0 deletions src/components/SearchBar/SearchBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { render, screen } from "@testing-library/react";
import SearchBar from "./SearchBar";

beforeEach(() => {
vi.clearAllMocks();
});

describe("Given a SearchBar component", () => {
const expectedLabelText = /search/i;
const expectedInputContent = "head";
const actionOnSubmit = vi.fn();

describe("When it is rendered", () => {
test("Then it should show a 'Search' input", () => {
render(<SearchBar actionOnSubmit={actionOnSubmit} />);

const searchInput = screen.getByLabelText(expectedLabelText);

expect(searchInput).toBeInTheDocument();
});

test("Then it should show a button with an alt text 'Magnifying glass icon'", () => {
const expectedSearchButtonAlt = "Magnifying glass icon";

render(<SearchBar actionOnSubmit={actionOnSubmit} />);

const button = screen.getByRole("button", {
name: expectedSearchButtonAlt,
});

expect(button).toBeInTheDocument();
});
});

describe("When it is rendered with a current query 'head'", () => {
test("Then the input should have the received value 'head'", () => {
render(
<SearchBar
actionOnSubmit={actionOnSubmit}
currentQuery={expectedInputContent}
/>,
);

const searchInput = screen.getByLabelText(expectedLabelText);

expect(searchInput).toHaveValue(expectedInputContent);
});
});
});
40 changes: 19 additions & 21 deletions src/components/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,26 @@ const SearchBar = ({
};

return (
<search className="search-bar">
<form className="search-bar__form" onSubmit={submit}>
<label htmlFor="query" className="search-bar__label">
Search
</label>
<input
type="search"
id="query"
className="search-bar__input"
value={updatedSearch}
onChange={updateSearch}
<form className="search-bar" onSubmit={submit}>
<label htmlFor="query" className="search-bar__label">
Search
</label>
<input
type="search"
id="query"
className="search-bar__input"
value={updatedSearch}
onChange={updateSearch}
/>
<Button className="icon search-bar__button" type="submit">
<img
src="/images/search_icon.svg"
alt="Magnifying glass icon"
width="20"
height="20"
/>
<Button className="icon search-bar__button" type="submit">
<img
src="/images/search_icon.svg"
alt="Magnifying glass icon"
width="20"
height="20"
/>
</Button>
</form>
</search>
</Button>
</form>
);
};

Expand Down
16 changes: 13 additions & 3 deletions src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { rest } from "msw";
import {
filteredRecordsApiMock,
fkaRatedRecordApiMock,
fkaRecordApiMock,
modifiedRecordsApiMock,
Expand All @@ -10,9 +11,18 @@ import {
const urlApi = import.meta.env.VITE_API_URL;

export const handlers = [
rest.get(`${urlApi}/records`, (_req, res, ctx) =>
res(ctx.status(200), ctx.json(recordsApiMock)),
),
rest.get(`${urlApi}/records`, (req, res, ctx) => {
let recordsToRespond = recordsApiMock;

const url = new URL(req.url);
const queryParam = url.searchParams.get("query");

if (queryParam) {
recordsToRespond = filteredRecordsApiMock;
}

return res(ctx.status(200), ctx.json(recordsToRespond));
}),

rest.delete(`${urlApi}/records/:id`, (_req, res, ctx) =>
res(ctx.status(200), ctx.json({ message: "Record deleted successfully" })),
Expand Down
11 changes: 11 additions & 0 deletions src/mocks/recordsMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ export const recordsApiMock: RecordsApi = {
count: "4",
};

export const filteredRecordsApiMock: RecordsApi = {
records: [
{ ...radioheadRecordMock, _id: recordIdMock },
{
...portisheadRecordMock,
_id: "1o8c9c6a5c621a08508d598y",
},
],
count: "2",
};

export const modifiedRecordsApiMock: RecordsApi = {
records: [
{ ...radioheadRecordMock, _id: recordIdMock, artist: "Another Artist" },
Expand Down

0 comments on commit 744f557

Please sign in to comment.