diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 00000000..c2864883 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,24 @@ +name: Build +run-name: ${{ github.actor }} is testing out Next building 🚀 +on: + push: + branches: [main] + pull_request: + branches: [main] +jobs: + building: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [22.x] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Starting Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Install dependencies + run: npm install --force + - name: Build + run: npm run build \ No newline at end of file diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml deleted file mode 100644 index 9a24689e..00000000 --- a/.github/workflows/check.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: Actions -run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 -on: - push: - branches: [main] - pull_request: - branches: [main] -jobs: - building: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Starting Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - name: Install dependencies - run: npm install --force - - name: Lint - run: npm run lint - linting: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Starting Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - name: Install dependencies - run: npm install --force - - name: Lint - run: npm run lint \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..e5e441ab --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,24 @@ +name: Lint +run-name: ${{ github.actor }} is testing out Eslint ⚡ +on: + push: + branches: [main] + pull_request: + branches: [main] +jobs: + linting: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [22.x] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Starting Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Install dependencies + run: npm install --force + - name: Lint + run: npm run lint \ No newline at end of file diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml deleted file mode 100644 index 81162484..00000000 --- a/.github/workflows/playwright.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Playwright Tests -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] -jobs: - test: - timeout-minutes: 60 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - name: Install dependencies - run: npm install -g pnpm && pnpm install - - name: Install Playwright Browsers - run: pnpm exec playwright install --with-deps - - name: Run Playwright tests - run: pnpm exec playwright test - - uses: actions/upload-artifact@v4 - if: ${{ !cancelled() }} - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 diff --git a/.husky/pre-commit b/.husky/pre-commit index 098a3bea..a75a5a9d 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,3 @@ -git add . -pnpm test +pnpm unit pnpm fix pnpm build \ No newline at end of file diff --git "a/app/(main)/components/found-\321\201ards.tsx" "b/app/(main)/components/found-\321\201ards.tsx" index 788e2d3e..a8297458 100644 --- "a/app/(main)/components/found-\321\201ards.tsx" +++ "b/app/(main)/components/found-\321\201ards.tsx" @@ -26,9 +26,10 @@ export default function FoundCards({ query }: { query: string | null }) { return (
Результаты поиска diff --git a/app/(main)/components/header.module.scss b/app/(main)/components/header.module.scss index 9d474f60..c1e3cca2 100644 --- a/app/(main)/components/header.module.scss +++ b/app/(main)/components/header.module.scss @@ -53,9 +53,20 @@ .found-container { @apply w-full flex flex-col gap-2.5 box-border overflow-hidden text-2xl; - transition-duration: 500ms; + transition-duration: 300ms; } .found-anime { @apply flex justify-between gap-5 flex-nowrap; -} \ No newline at end of file +} + +.found-open { + @apply full:h-[446px] mt-2.5; + @media (width >= 1000px) { + height: calc(20vw * 1.388888888 + 10px + 20px + 29px); + } +} + +.found-close { + @apply h-0 mt-0; +} diff --git a/app/(main)/components/header.tsx b/app/(main)/components/header.tsx index 9a0ce157..ebcbd8ec 100644 --- a/app/(main)/components/header.tsx +++ b/app/(main)/components/header.tsx @@ -38,6 +38,7 @@ export default function Header() { )} /> {/* Потом сделаем проверку на авторизацию */} @@ -17,7 +19,7 @@ export default async function Page() { Сейчас в тренде
- +
Новинки diff --git a/app/libs/anime/getAnimeData.ts b/app/libs/anime/getAnimeData.ts index 040b0c0e..476dfa80 100644 --- a/app/libs/anime/getAnimeData.ts +++ b/app/libs/anime/getAnimeData.ts @@ -10,9 +10,9 @@ export default async function getAnimeData(id: number): Promise { finishedOn: new Date("2023-09-23T00:00:00.000"), genre: "DRAMA", image_url: - "https://i.ibb.co/BHRrPJ8Y/bb3588279b31a01820543e196cbcf950e65e257d.jpg", + "https://i.ibb.co/7wQnztK/bb3588279b31a01820543e196cbcf950e65e257d-1.jpg", banner_url: - "https://i.ibb.co/YB47m8kb/2d66f78024e5da9e3dcfa55134644bdd90576ca4.png", + "https://i.ibb.co/KzWcM8Dv/2d66f78024e5da9e3dcfa55134644bdd90576ca4-1.png", average_rating: 7.53, type: "ТВ сериал", total_episodes: 24, diff --git a/app/libs/anime/getRelated.ts b/app/libs/anime/getRelated.ts index 2b03bcdd..f7f698f0 100644 --- a/app/libs/anime/getRelated.ts +++ b/app/libs/anime/getRelated.ts @@ -5,7 +5,7 @@ export default async function getSimilar(id: number) { console.log(id); try { const res = await axios.get( - "http://localhost:3000/animeDetailsItems", + "http://localhost:3000/animeListItems", ); return res.data; } catch (error) { diff --git a/app/libs/anime/getSimilar.ts b/app/libs/anime/getSimilar.ts index 2b03bcdd..f7f698f0 100644 --- a/app/libs/anime/getSimilar.ts +++ b/app/libs/anime/getSimilar.ts @@ -5,7 +5,7 @@ export default async function getSimilar(id: number) { console.log(id); try { const res = await axios.get( - "http://localhost:3000/animeDetailsItems", + "http://localhost:3000/animeListItems", ); return res.data; } catch (error) { diff --git a/app/libs/types/anime.ts b/app/libs/types/anime.ts index 61c239b5..66e15529 100644 --- a/app/libs/types/anime.ts +++ b/app/libs/types/anime.ts @@ -3,7 +3,7 @@ export type AnimeCardData = { genre: string; name: string; released_at: string; - id: number; + id: string; }; export type AnimeData = { diff --git a/app/ui/anime-card/__tests__/anime-card.test.tsx b/app/ui/anime-card/__tests__/anime-card.test.tsx new file mode 100644 index 00000000..ad1b660a --- /dev/null +++ b/app/ui/anime-card/__tests__/anime-card.test.tsx @@ -0,0 +1,67 @@ +import userEvent from "@testing-library/user-event"; +import { render, screen } from "@testing-library/react"; +import AnimeCard from "../anime-card"; +import CardSkeleton from "../card-skeleton"; + +test("Проверка карточки аниме", () => { + render( + , + ); + + const card = screen.getByTestId("AnimeCard: anime-card"); + + // Тест градиента + const darkness = screen.getByTestId("AnimeCard: darkness"); + expect(darkness).toHaveStyle("opacity: 30%;"); + userEvent.hover(card); + expect(darkness).toHaveStyle("opacity: 100%;"); + + // Тест названия + const title = screen.getByTestId("AnimeCard: title"); + expect(title).toBeVisible(); + + // Тест описания + const description = screen.getByTestId("AnimeCard: year&genre"); + expect(description.textContent).toBe("2022Драма"); +}); + +test("Проверка кнопки в карточки аниме", () => { + render( + {}} + />, + ); + + const card = screen.getByTestId("AnimeCard: anime-card"); + + // Проверяю появляется ли кнопка при ховере + const button = screen.getByTestId("AnimeCard: favourite"); + expect(button).toHaveStyle("opacity: 0%;"); + userEvent.hover(card); + expect(button).toHaveStyle("opacity: 100%;"); +}); + +test("Проверка скелетона карточки", () => { + render(); + + const card = screen.getByTestId("AnimeSkeleton: container"); + const bg = screen.getByTestId("AnimeSkeleton: bg"); + const text = screen.getAllByTestId("AnimeSkeleton: text"); + + expect(card).toHaveClass("shimmer", "pulsing"); + expect(bg).toHaveClass("shimmer"); + text.forEach((el) => { + expect(el).toHaveClass("shimmer"); + }); +}); diff --git a/app/ui/anime-card/anime-card.tsx b/app/ui/anime-card/anime-card.tsx index b3384f9e..af26f08d 100644 --- a/app/ui/anime-card/anime-card.tsx +++ b/app/ui/anime-card/anime-card.tsx @@ -21,7 +21,7 @@ export default function AnimeCard({ genre: string; name: string; released_at: string; - id: number; + id: string; classes?: string; style?: CSSProperties; addToFavourite?: () => void; @@ -31,6 +31,7 @@ export default function AnimeCard({ className={clsx(classes, styles.container)} style={style} href={`/anime/${id}`} + data-testid="AnimeCard: anime-card" > anime image -
+
-

{name}

-
+

+ {name} +

+
{new Date(released_at).getFullYear()}
{AnimeGenre[genre as keyof typeof AnimeGenre]}
{addToFavourite && ( - )} diff --git a/app/ui/anime-card/card-skeleton.tsx b/app/ui/anime-card/card-skeleton.tsx index 4d4b7fd4..7ed7da94 100644 --- a/app/ui/anime-card/card-skeleton.tsx +++ b/app/ui/anime-card/card-skeleton.tsx @@ -4,12 +4,19 @@ import styles from "./card-skeleton.module.scss"; export default function CardSkeleton({ style }: { style?: CSSProperties }) { return ( -
+
- +
- - + +
diff --git a/app/ui/anime-card/favourite-button.tsx b/app/ui/anime-card/favourite-button.tsx index d1ccf6bf..a7e05f12 100644 --- a/app/ui/anime-card/favourite-button.tsx +++ b/app/ui/anime-card/favourite-button.tsx @@ -12,16 +12,19 @@ export default function FavouriteButton() { ); diff --git a/app/ui/banners/__tests__/banners-showing.test.tsx b/app/ui/banners/__tests__/banners-showing.test.tsx new file mode 100644 index 00000000..6099929e --- /dev/null +++ b/app/ui/banners/__tests__/banners-showing.test.tsx @@ -0,0 +1,29 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import BannerShowing from "../banners-showing"; + +test("Проверка баннеров", async () => { + render( + , + ); + const banner = screen.getAllByTestId("Banners: banner"); + waitFor(() => { + expect(banner[0]).toHaveStyle( + "transform: translateX(calc(-100% - 20px`}))", + ); + }); +}); diff --git a/app/ui/banners/banners-showing.tsx b/app/ui/banners/banners-showing.tsx index 9db10ad9..a063ef73 100644 --- a/app/ui/banners/banners-showing.tsx +++ b/app/ui/banners/banners-showing.tsx @@ -20,6 +20,7 @@ export default function BannerShowing({ data }: { data: BannerData[] }) {
{data.map((el) => ( ; -} diff --git a/app/ui/carousel/__tests__/carousel.test.tsx b/app/ui/carousel/__tests__/carousel.test.tsx new file mode 100644 index 00000000..d2a29239 --- /dev/null +++ b/app/ui/carousel/__tests__/carousel.test.tsx @@ -0,0 +1,52 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import { AnimeCardData } from "@/app/libs/types/anime"; +import userEvent from "@testing-library/user-event"; +import Carousel from "../carousel"; + +const testData: AnimeCardData[] = [ + { + id: "1", + genre: "DRAMA", + image_url: "/empty_card.png", + name: "Anime test", + released_at: "2022-01-01T00:00:00.000", + }, + { + id: "2", + genre: "DRAMA", + image_url: "/empty_card.png", + name: "Anime test", + released_at: "2022-01-01T00:00:00.000", + }, + { + id: "3", + genre: "DRAMA", + image_url: "/empty_card.png", + name: "Anime test", + released_at: "2022-01-01T00:00:00.000", + }, + { + id: "4", + genre: "DRAMA", + image_url: "/empty_card.png", + name: "Anime test", + released_at: "2022-01-01T00:00:00.000", + }, + { + id: "5", + genre: "DRAMA", + image_url: "/empty_card.png", + name: "Anime test", + released_at: "2022-01-01T00:00:00.000", + }, +]; + +test("Тест карусели", () => { + render(); + const next = screen.getByTestId("Carousel: next"); + const firstCard = screen.getAllByTestId("Carousel: card")[0]; + userEvent.click(next); + waitFor(() => { + expect(firstCard).toHaveStyle("transform: translateX(calc(-300% - 60px));"); + }); +}); diff --git a/app/ui/carousel/carousel.tsx b/app/ui/carousel/carousel.tsx index fa929421..46dc46d7 100644 --- a/app/ui/carousel/carousel.tsx +++ b/app/ui/carousel/carousel.tsx @@ -59,6 +59,7 @@ export default function Carousel({ {animeData.map((el, i) => (
diff --git a/app/ui/navigation/__tests__/sidebar.test.tsx b/app/ui/navigation/__tests__/sidebar.test.tsx new file mode 100644 index 00000000..d8e63f12 --- /dev/null +++ b/app/ui/navigation/__tests__/sidebar.test.tsx @@ -0,0 +1,29 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import SideBar from "../sidebar"; + +const mock = jest.fn(); + +jest.mock("next/navigation", () => ({ + usePathname() { + return mock(); + }, +})); + +test("Проверка навигации", () => { + mock.mockImplementation(() => "/home"); + render(); + const navLinks = screen.getAllByTestId("Sidebar: navlink"); + const currLink = screen.getByTestId("Sidebar: navlink-curr"); + waitFor(() => { + navLinks.forEach((el) => { + expect(el).toHaveStyle("filter: grayscale();"); + }); + expect(currLink).not.toHaveStyle("filter: grayscale(100%);"); + }); + + navLinks.forEach((el) => { + userEvent.hover(el); + waitFor(() => expect(el).not.toHaveStyle("filter: grayscale(100%);")); + }); +}); diff --git a/app/ui/navigation/nav-link.tsx b/app/ui/navigation/nav-link.tsx index d8730e9a..a07b4015 100644 --- a/app/ui/navigation/nav-link.tsx +++ b/app/ui/navigation/nav-link.tsx @@ -20,6 +20,7 @@ export default function NavLink({ +