diff --git a/jest.config.ts b/jest.config.ts
index a68f0ee..1eb1cbf 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -5,6 +5,7 @@
import type { Config } from "jest"
import nextJest from "next/jest.js"
+// import "@testing-library/jest-dom"
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
diff --git a/package-lock.json b/package-lock.json
index 550f923..10516a2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11405,9 +11405,9 @@
}
},
"node_modules/ws": {
- "version": "8.18.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
- "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+ "version": "8.20.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
+ "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
"dev": true,
"license": "MIT",
"engines": {
diff --git a/package.json b/package.json
index ac303b4..6264a93 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"start": "next start",
"lint": "next lint",
"test": "jest test",
+ "test:watch": "jest --watch",
"e2e_test": "npx playwright test",
"e2e_report": "npx playwright show-report",
"e2e_ui": "npx playwright test --ui"
diff --git a/src/__tests__/component/books/library/BookLibrary.test.tsx b/src/__tests__/component/books/library/BookLibrary.test.tsx
new file mode 100644
index 0000000..06b779d
--- /dev/null
+++ b/src/__tests__/component/books/library/BookLibrary.test.tsx
@@ -0,0 +1,50 @@
+import BookLibrary from "@/components/books/library/BookLibrary"
+import { useGetQuery } from "@/hooks/fetch-hooks/useGetQuery"
+import { Genre } from "@/types/Genre"
+import { render } from "@testing-library/react"
+import "@testing-library/jest-dom"
+
+jest.mock("@/hooks/fetch-hooks/useGetQuery")
+
+const mockUseGetQuery = jest.mocked(useGetQuery)
+
+describe("tests the book library page", () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+
+ test("renders book data successfully", () => {
+ const mockBookData = [
+ {
+ author: "testAuthor",
+ genre: [Genre.ACTION],
+ pages: 500,
+ title: "test",
+ yearPublished: 1900,
+ _id: "dfgdfgfd",
+ read: true,
+ },
+ {
+ author: "testAuthor2",
+ genre: [Genre.ACTION],
+ pages: 500,
+ title: "test2",
+ yearPublished: 1900,
+ _id: "dfgdfgfd222",
+ read: true,
+ },
+ ]
+
+ mockUseGetQuery.mockReturnValue({
+ data: mockBookData,
+ isLoading: false,
+ isError: false,
+ error: null,
+ })
+
+ const { getByRole } = render()
+
+ expect(getByRole("heading", { name: /^test$/i })).toBeInTheDocument()
+ expect(getByRole("heading", { name: /^test2$/i })).toBeInTheDocument()
+ })
+})
diff --git a/src/__tests__/component/books/library/single-book/AdminViewLeftSide.test.tsx b/src/__tests__/component/books/library/single-book/AdminViewLeftSide.test.tsx
new file mode 100644
index 0000000..faeae68
--- /dev/null
+++ b/src/__tests__/component/books/library/single-book/AdminViewLeftSide.test.tsx
@@ -0,0 +1,116 @@
+import AdminViewLeftSide from "@/components/books/library/single-book/AdminViewLeftSide"
+import { Genre } from "@/types/Genre"
+import { render, fireEvent } from "@testing-library/react"
+import StoreProvider from "@/store/StoreProvider"
+import { NotificationProvider } from "@/context/NotificationProvider"
+import QueryProvider from "@/query/QueryProvider"
+import "@testing-library/jest-dom"
+
+beforeAll(() => {
+ Object.defineProperty(window, "matchMedia", {
+ writable: true,
+ value: jest.fn().mockImplementation((query) => ({
+ matches: false, // Default to desktop/mobile layout state
+ media: query,
+ onchange: null,
+ })),
+ })
+})
+
+describe("Left side of Admin view of Single book component", () => {
+ test("all book edit and delete buttons render for admin user", () => {
+ const props = {
+ bookData: {
+ author: "testAuthor",
+ genre: [Genre.ACTION],
+ pages: 500,
+ title: "test",
+ yearPublished: 1900,
+ _id: "dfgdfgfd",
+ },
+ bookId: "dfgdfgfd",
+ }
+ const { getByRole } = render(
+
+
+
+
+
+
+ ,
+ )
+ const deleteBookButton = getByRole("button", { name: /delete book/i })
+ const editTitleButton = getByRole("button", { name: /edit title/i })
+ const editImageButton = getByRole("button", { name: /change image/i })
+
+ expect(deleteBookButton).toBeDefined()
+ expect(editTitleButton).toBeDefined()
+ expect(editImageButton).toBeDefined()
+ })
+ test("book card renders correct information", () => {
+ const props = {
+ bookData: {
+ author: "testAuthor",
+ genre: [Genre.ACTION],
+ pages: 500,
+ title: "test",
+ yearPublished: 1900,
+ dateOfMeeting: "2026-04-11T22:00:00.000Z",
+ actualDateOfMeeting: "2026-04-11T22:00:00.000Z",
+ reviewImageURL: "https://res.cloudinary.com",
+ totalScore: 9.5,
+ _id: "dfgdfgfd",
+ },
+ bookId: "dfgdfgfd",
+ }
+ const { getByText, getByRole } = render(
+
+
+
+
+
+
+ ,
+ )
+
+ const cardImg = getByRole("img", { name: /test book cover/i })
+ const cardCertImg = getByRole("img", { name: /worm badge certification/i })
+
+ const cardScore = getByText("9.5/10")
+
+ expect(cardImg).toBeDefined()
+ expect(cardCertImg).toBeDefined()
+ expect(cardImg).toHaveAttribute(
+ "src",
+ "/_next/image?url=https%3A%2F%2Fres.cloudinary.com&w=1080&q=75",
+ )
+ expect(cardScore).toBeDefined()
+ })
+ test("edit title button when click show book edit input", () => {
+ const props = {
+ bookData: {
+ author: "testAuthor",
+ genre: [Genre.ACTION],
+ pages: 500,
+ title: "test",
+ yearPublished: 1900,
+ _id: "dfgdfgfd",
+ },
+ bookId: "dfgdfgfd",
+ }
+ const { getByRole } = render(
+
+
+
+
+
+
+ ,
+ )
+ const editTitleButton = getByRole("button", { name: /edit title/i })
+
+ fireEvent.click(editTitleButton)
+ expect(getByRole("textbox")).toBeInTheDocument()
+ expect(getByRole("textbox")).toHaveValue("test")
+ })
+})
diff --git a/src/__tests__/component/books/library/single-book/AdminViewRightSide.test.tsx b/src/__tests__/component/books/library/single-book/AdminViewRightSide.test.tsx
new file mode 100644
index 0000000..2d1b034
--- /dev/null
+++ b/src/__tests__/component/books/library/single-book/AdminViewRightSide.test.tsx
@@ -0,0 +1,47 @@
+import { Genre } from "@/types/Genre"
+import { render } from "@testing-library/react"
+import StoreProvider from "@/store/StoreProvider"
+import { NotificationProvider } from "@/context/NotificationProvider"
+import QueryProvider from "@/query/QueryProvider"
+import AdminViewRightSide from "@/components/books/library/single-book/AdminViewRightSide"
+
+describe("Right side of Admin view of Single book component", () => {
+ test("all book edit and delete buttons render for admin user", () => {
+ const props = {
+ bookData: {
+ author: "testAuthor",
+ genre: [Genre.ACTION],
+ pages: 500,
+ title: "test",
+ yearPublished: 1900,
+ _id: "dfgdfgfd",
+ },
+ bookId: "dfgdfgfd",
+ }
+ const { getByRole } = render(
+
+
+
+
+
+
+ ,
+ )
+
+ const editBookButton = getByRole("button", { name: /edit author/i })
+ const editBookYear = getByRole("button", { name: /edit year/i })
+ const editBookPages = getByRole("button", { name: /edit genre/i })
+ const editBookGenre = getByRole("button", { name: /edit genre/i })
+ const editBookDate = getByRole("button", { name: /edit date/i })
+ const editActualBookDate = getByRole("button", {
+ name: /edit actual date/i,
+ })
+
+ expect(editBookButton).toBeDefined()
+ expect(editBookYear).toBeDefined()
+ expect(editBookPages).toBeDefined()
+ expect(editBookGenre).toBeDefined()
+ expect(editBookDate).toBeDefined()
+ expect(editActualBookDate).toBeDefined()
+ })
+})
diff --git a/src/__tests__/component/brothers/library/BrothersLibrary.test.tsx b/src/__tests__/component/brothers/library/BrothersLibrary.test.tsx
new file mode 100644
index 0000000..7b6bdb7
--- /dev/null
+++ b/src/__tests__/component/brothers/library/BrothersLibrary.test.tsx
@@ -0,0 +1,79 @@
+import BrotherLibrary from "@/components/brothers/library/BrothersLibrary"
+import { useGetQuery } from "@/hooks/fetch-hooks/useGetQuery"
+import { Genre } from "@/types/Genre"
+import { render } from "@testing-library/react"
+import "@testing-library/jest-dom"
+import QueryProvider from "@/query/QueryProvider"
+import StoreProvider from "@/store/StoreProvider"
+import { NotificationProvider } from "@/context/NotificationProvider"
+
+jest.mock("@/hooks/fetch-hooks/useGetQuery")
+
+const mockGetQuery = jest.mocked(useGetQuery)
+
+describe("mocks the brother library component", () => {
+ beforeEach(() => jest.clearAllMocks())
+
+ test("component loads brothers data", () => {
+ const mockBrotherData = [
+ {
+ userInfo: {
+ books: {
+ booksCommented: [""],
+ booksScored: [""],
+ comments: [""],
+ score: [0],
+ },
+ favGenre: [Genre.ACTION],
+ profileURL: "",
+ residence: {
+ country: "",
+ city: "",
+ },
+ },
+ username: "test",
+ _id: "testid",
+ lastLoggedIn: "",
+ },
+ {
+ userInfo: {
+ books: {
+ booksCommented: [""],
+ booksScored: [""],
+ comments: [""],
+ score: [0],
+ },
+ favGenre: [Genre.ACTION],
+ profileURL: "",
+ residence: {
+ country: "",
+ city: "",
+ },
+ },
+ username: "test2",
+ _id: "testid2",
+ lastLoggedIn: "",
+ },
+ ]
+
+ mockGetQuery.mockReturnValue({
+ data: mockBrotherData,
+ isLoading: false,
+ isError: false,
+ error: null,
+ })
+
+ const { getByRole } = render(
+
+
+
+
+
+
+ ,
+ )
+
+ expect(getByRole("heading", { name: /^test$/i })).toBeInTheDocument()
+ expect(getByRole("heading", { name: /^test2$/i })).toBeInTheDocument()
+ })
+})
diff --git a/src/__tests__/unit/find-functions/findBook.test.tsx b/src/__tests__/unit/find-functions/findBook.test.tsx
index 248a22f..383c580 100644
--- a/src/__tests__/unit/find-functions/findBook.test.tsx
+++ b/src/__tests__/unit/find-functions/findBook.test.tsx
@@ -39,7 +39,7 @@ describe("book functions that return a key value given its parameters", () => {
const expectedDateOfMeeting =
"Thu Nov 17 2025 15:56:20 GMT+0100 (Mitteleuropäische Normalzeit)"
expect(findDateOfMeeting(bookTitle, mockBookArray)).toBe(
- expectedDateOfMeeting
+ expectedDateOfMeeting,
)
})
})