implemented jest tests
This commit is contained in:
parent
acca5c387f
commit
f1b3d9e5be
30
README.md
30
README.md
|
@ -5,11 +5,18 @@ It contains:
|
|||
- Navbar
|
||||
|
||||
- A page to search for movies by title:
|
||||
- searchParams to string
|
||||
- Object.entries(searchParams)
|
||||
.map(
|
||||
([key, value], i, arr) =>
|
||||
`${key}=${value}${i < arr.length - 1 ? "&" : ""}`
|
||||
)
|
||||
.toString();
|
||||
|
||||
- SearchBar component:
|
||||
- Input for Title (Year & Plot too?)
|
||||
- Input for Title
|
||||
- Submit button
|
||||
- Cear button
|
||||
- Clear button
|
||||
- List of results - paginated so we might need a pagination component:
|
||||
- Title
|
||||
- Year
|
||||
|
@ -50,7 +57,7 @@ External API Docs: https://www.omdbapi.com/
|
|||
|
||||
Built on:
|
||||
Next.js
|
||||
Server side rendering for list & movie details to hide api token - Could possibly use Route Handler
|
||||
Server side rendering for list & movie details to hide api token/network requests and eliminate the need for state-management on data returned from the external API.
|
||||
|
||||
Switched to Tailwindcss for styling. Was using chakra ui components but it isn't server-side render friendly
|
||||
|
||||
|
@ -60,18 +67,13 @@ Since we're using server side rendering for pages that fetch data, we don't need
|
|||
We can implement Context in a client component for managing "Favorites" for a user if we'd like
|
||||
this might look like:
|
||||
|
||||
favorites/page.tsx
|
||||
- FavoriteContext - favorites, setFavorites
|
||||
|
||||
cosnt FavoriteContext = createContext({
|
||||
favorites,
|
||||
addFavorite
|
||||
})
|
||||
- FavoriteProvider - A wrapper for FavoriteContext.Provider with local state that we can render client-side and pass children through to make use of server-side rendering for child components (interleaving)
|
||||
|
||||
const FavoriteProvider = ()=>{
|
||||
// local state management
|
||||
return (
|
||||
- FavoriteBtn - a client-side component rendering a button and using useContext(FormContext) to consume favorites and setFavorites - filter favorites by id to prevent duplicats/allow removing from list.
|
||||
|
||||
)
|
||||
}
|
||||
Known issues:
|
||||
* https://github.com/vercel/next.js/issues/65161
|
||||
* https://github.com/vercel/next.js/issues/54757
|
||||
|
||||
const { searchResults } = useContext(FavoriteContext);
|
||||
|
|
2
movie-search/.jest/setEnvVars.js
Normal file
2
movie-search/.jest/setEnvVars.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
process.env.API_KEY='6200aa0'
|
||||
process.env.OMDB_URL='http://www.omdbapi.com/'
|
16
movie-search/__tests__/MovieCard.test.jsx
Normal file
16
movie-search/__tests__/MovieCard.test.jsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
import "@testing-library/jest-dom";
|
||||
import {render, screen} from '@testing-library/react'
|
||||
import MovieCard from '../src/app/Search/MovieCard.tsx'
|
||||
const movie = {
|
||||
Title: "Dune",
|
||||
Year: "2000",
|
||||
imdbID: "tt0142032",
|
||||
Type: "series",
|
||||
Poster: "https://m.media-amazon.com/images/M/MV5BMTU4MjMyMTkxN15BMl5BanBnXkFtZTYwODA5OTU5._V1_SX300.jpg"
|
||||
}
|
||||
|
||||
test('MovieCard Renders',()=>{
|
||||
render(<MovieCard movie={movie} />)
|
||||
const movieTitle = screen.getByRole('heading')
|
||||
expect(movieTitle).toHaveTextContent('Dune')
|
||||
})
|
39
movie-search/__tests__/SearchBar.test.jsx
Normal file
39
movie-search/__tests__/SearchBar.test.jsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import SearchBar from "@/app/Search/SearchBar.tsx";
|
||||
import { queryOMDb } from "@/api/omdb";
|
||||
|
||||
test("SearchBar Allows user input", () => {
|
||||
render(<SearchBar />);
|
||||
const input = screen.getByPlaceholderText("Search by Title");
|
||||
|
||||
fireEvent.change(input, { target: { value: "some value" } });
|
||||
|
||||
expect(input.value).toBe("some value");
|
||||
});
|
||||
|
||||
test("SearchBar Allows user input and Clear button clears", () => {
|
||||
render(<SearchBar />);
|
||||
const input = screen.getByPlaceholderText("Search by Title");
|
||||
const clear = screen.getByText("Clear");
|
||||
|
||||
fireEvent.change(input, { target: { value: "some value" } });
|
||||
expect(input.value).toBe("some value");
|
||||
|
||||
fireEvent.click(clear);
|
||||
|
||||
expect(input.value).toBe('');
|
||||
});
|
||||
|
||||
// test("SearchBar Allows user submit", () => {
|
||||
// render(<SearchBar />);
|
||||
// const input = screen.getByPlaceholderText("Search by Title");
|
||||
// const submit = screen.getByText("Search");
|
||||
// const spy = jest.spyOn({ queryOMDb }, "queryOMDb");
|
||||
|
||||
// fireEvent.change(input, { target: { value: "back to the" } });
|
||||
// fireEvent.click(submit);
|
||||
// // Somehow test for form submission - currently facing this issue
|
||||
// // https://github.com/vercel/next.js/issues/54757
|
||||
// // expect(spy).toHaveBeenCalled();
|
||||
// });
|
8
movie-search/__tests__/omdb.test.jsx
Normal file
8
movie-search/__tests__/omdb.test.jsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import "@testing-library/jest-dom";
|
||||
import { queryOMDb } from "../src/api/omdb.ts";
|
||||
|
||||
test("queryOMDb returns movie data", async () => {
|
||||
const data = await queryOMDb("s=back to");
|
||||
|
||||
expect(data).toHaveProperty("Response");
|
||||
});
|
19
movie-search/jest.config.ts
Normal file
19
movie-search/jest.config.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import type { Config } from 'jest'
|
||||
import nextJest from 'next/jest.js'
|
||||
|
||||
const createJestConfig = nextJest({
|
||||
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
|
||||
dir: './',
|
||||
})
|
||||
|
||||
// Add any custom config to be passed to Jest
|
||||
const config: Config = {
|
||||
coverageProvider: 'v8',
|
||||
testEnvironment: 'jsdom',
|
||||
setupFilesAfterEnv: ["<rootDir>/.jest/setEnvVars.js", "jest-fetch-mock"]
|
||||
// Add more setup options before each test is run
|
||||
// setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
||||
}
|
||||
|
||||
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
|
||||
export default createJestConfig(config)
|
7406
movie-search/package-lock.json
generated
7406
movie-search/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,9 @@
|
|||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.4",
|
||||
|
@ -14,15 +16,21 @@
|
|||
"framer-motion": "^11.2.6",
|
||||
"next": "14.2.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
"react-dom": "^18",
|
||||
"ts-node-dev": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^6.4.5",
|
||||
"@testing-library/react": "^15.0.7",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.3",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"postcss": "^8.4.38",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^5"
|
||||
|
|
|
@ -2,12 +2,16 @@ const url = `${process.env.OMDB_URL}?apikey=${process.env.API_KEY}`;
|
|||
|
||||
export const queryOMDb = async (queryParamString: string) => {
|
||||
"use server";
|
||||
try {
|
||||
const queryUrl = `${url}&${queryParamString}`;
|
||||
const response = await fetch(queryUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch movie data");
|
||||
}
|
||||
const result = await response.json();
|
||||
console.log(queryUrl, result);
|
||||
// console.log(queryUrl, result);
|
||||
return result;
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error("Something went wrong searching OMDb");
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import FavoriteBtn from "@/components/FavoriteBtn";
|
||||
import ImgCard from "@/components/ImgCard";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export interface IMovieCardItem {
|
||||
|
@ -14,20 +13,6 @@ interface IMovieCardProps {
|
|||
movie: IMovieCardItem;
|
||||
}
|
||||
|
||||
const testclass = {
|
||||
boxShadow: "md",
|
||||
_hover: {
|
||||
cursor: "pointer",
|
||||
border: "1px solid blue",
|
||||
borderRadius: 4,
|
||||
// boxShadow:'border'
|
||||
},
|
||||
maxW: "sm",
|
||||
borderWidth: "1px",
|
||||
borderRadius: "lg",
|
||||
overflow: "hidden",
|
||||
}.toString();
|
||||
|
||||
export default ({ movie }: IMovieCardProps) => {
|
||||
return (
|
||||
<ImgCard
|
||||
|
|
|
@ -16,7 +16,7 @@ export const stringifyQueryParams = (searchParams: object) =>
|
|||
|
||||
export default async ({ searchParams }: INextJsProps) => {
|
||||
const queryParamString = stringifyQueryParams(searchParams!);
|
||||
console.log(queryParamString)
|
||||
// console.log(queryParamString)
|
||||
const { Search } = await queryOMDb(queryParamString);
|
||||
const movies = Search || [];
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ export default ({ movie }: any) => {
|
|||
if (isFavorite) {
|
||||
setFavorites([...filteredFavorites])
|
||||
} else {
|
||||
|
||||
setFavorites([...favorites, movie]);
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -3,15 +3,11 @@ import Link from "next/link";
|
|||
export default () => {
|
||||
return (
|
||||
<nav className="px-2 flex gap-4">
|
||||
|
||||
<Link href="/">
|
||||
<strong>Movie Search</strong>
|
||||
<strong>Home</strong>
|
||||
</Link>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<Link href="/Search">Search</Link>
|
||||
<Link href="/Favorites">Favorites</Link>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "__tests__/*.jsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user