Skip to content

Commit

Permalink
test: chat module tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pauljaijai committed Oct 10, 2024
1 parent 3a2ab39 commit 396cbd6
Show file tree
Hide file tree
Showing 8 changed files with 506 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* ConversationCard component test
*
* @group unit
*/

import React from "react"
import { useRouter, useSearchParams } from "next/navigation"
import ConversationCard from "@/modules/chat/components/cards/conversation/conversation"
import { useI18n } from "@/utils/services/internationalization/client"
import { useQueryClient } from "@tanstack/react-query"
import { fireEvent, render, screen } from "@testing-library/react"

import useUpdateConversation from "@/hooks/api/message/update-conversation"
import useCreatedAt from "@/hooks/common/created-at"
import useUserStore from "@/hooks/state/user/store"

// Mock the hooks
jest.mock("next/navigation", () => ({
useRouter: jest.fn(),
useSearchParams: jest.fn(),
}))
jest.mock("@/utils/services/internationalization/client", () => ({
useI18n: jest.fn(),
}))
jest.mock("@tanstack/react-query", () => ({
useQueryClient: jest.fn(),
}))
jest.mock("@/hooks/api/message/update-conversation", () => ({
__esModule: true,
default: jest.fn(),
}))
jest.mock("@/hooks/common/created-at", () => ({
__esModule: true,
default: jest.fn(),
}))
jest.mock("@/hooks/state/user/store", () => ({
__esModule: true,
default: jest.fn(),
}))

describe("ConversationCard", () => {
const mockProps = {
username: "Test User",
text: "Hello, this is a test message",
isSeen: false,
avatarUrl: "https://example.com/avatar.jpg",
updatedAt: "2023-01-01T00:00:00Z",
uuid: "123",
type: "sender" as const,
acceptRequest: true,
}

beforeEach(() => {
jest.clearAllMocks()
;(useRouter as jest.Mock).mockReturnValue({ push: jest.fn() })
;(useSearchParams as jest.Mock).mockReturnValue({ get: jest.fn() })
;(useI18n as jest.Mock).mockReturnValue((key: string) => key)
;(useQueryClient as jest.Mock).mockReturnValue({
invalidateQueries: jest.fn(),
})
;(useUpdateConversation as jest.Mock).mockReturnValue({ mutate: jest.fn() })
;(useCreatedAt as jest.Mock).mockReturnValue({ data: "1 hour ago" })
// @ts-ignore
;(useUserStore as jest.Mock).mockImplementation(() => ({
uuid: "user123",
}))
})

it("renders correctly", () => {
render(<ConversationCard {...mockProps} />)
expect(screen.getByText("Test User")).toBeInTheDocument()
expect(screen.getByText("Hello, this is a test mes")).toBeInTheDocument()
expect(screen.getByText("1 hour ago")).toBeInTheDocument()
})

it("truncates long messages", () => {
const longMessage = "This is a very long message that should be truncated"
render(<ConversationCard {...mockProps} text={longMessage} />)
expect(screen.getByText("This is a very long messa")).toBeInTheDocument()
})

it("shows conversation request message when not accepted", () => {
render(<ConversationCard {...mockProps} acceptRequest={false} />)
expect(screen.getByText("chat.conversation_request")).toBeInTheDocument()
})

it("shows unread indicator when message is not seen", () => {
render(<ConversationCard {...mockProps} />)
expect(screen.getByTestId("unread-big-dot")).toBeInTheDocument()
})

it("updates conversation and navigates when clicked", () => {
const mockUpdate = jest.fn()
;(useUpdateConversation as jest.Mock).mockReturnValue({
mutate: mockUpdate,
})
const mockPush = jest.fn()
;(useRouter as jest.Mock).mockReturnValue({ push: mockPush })

render(<ConversationCard {...mockProps} />)
fireEvent.click(screen.getByText("Test User"))

expect(mockUpdate).toHaveBeenCalled()
expect(mockPush).toHaveBeenCalled()
})

it("handles document name when text is null", () => {
render(
<ConversationCard
{...mockProps}
text={null}
documentName="document.pdf"
/>
)
expect(screen.getByText("document.pdf")).toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ const ConversationCard: React.FunctionComponent<IConversationProps> = ({
)}

{!isSeen && (
<Icons.bigDot className="absolute right-0 text-green-700 dark:text-yellow-300" />
<Icons.bigDot
className="absolute right-0 text-green-700 dark:text-yellow-300"
data-testid="unread-big-dot"
/>
)}
</div>
</div>
Expand Down
68 changes: 68 additions & 0 deletions client/modules/chat/components/cards/document/document.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* DocumentCard component test
*
* @group unit
*/

import React from "react"
import DocumentCard from "@/modules/chat/components/cards/document/document"
import { render, screen } from "@testing-library/react"

// Mock the internationalization hook
jest.mock("@/utils/services/internationalization/client", () => ({
useI18n: () => (key: string) => key,
}))

describe("DocumentCard", () => {
const mockProps = {
url: "https://example.com/document.pdf",
documentName: "Test Document.pdf",
documentSize: 1024000, // 1024 KB
sentByUser: false,
isDocumentExpired: false,
}

it("renders correctly for a non-expired document", () => {
render(<DocumentCard {...mockProps} />)

expect(screen.getByText("Test Document.pdf")).toBeInTheDocument()
expect(screen.getByText("1024.0 kb")).toBeInTheDocument()
expect(screen.getByRole("link")).toHaveAttribute(
"href",
"https://example.com/document.pdf"
)
})

it("renders correctly for an expired document", () => {
render(<DocumentCard {...mockProps} isDocumentExpired={true} />)

expect(screen.getByText("Test Document.pdf")).toBeInTheDocument()
expect(screen.getByText("1024.0 kb")).toBeInTheDocument()
expect(screen.getByText("(general.expired)")).toBeInTheDocument()
expect(screen.queryByRole("link")).not.toBeInTheDocument()
})

it("applies correct styles for user-sent documents", () => {
const { container } = render(
<DocumentCard {...mockProps} sentByUser={true} />
)
expect(container.firstChild).toHaveClass("bg-teal-100")
})

it("applies correct styles for received documents", () => {
const { container } = render(
<DocumentCard {...mockProps} sentByUser={false} />
)
expect(container.firstChild).toHaveClass("bg-slate-200")
})

it("formats file size correctly", () => {
render(<DocumentCard {...mockProps} documentSize={2048} />)
expect(screen.getByText("2.0 kb")).toBeInTheDocument()
})

it("renders file icon", () => {
render(<DocumentCard {...mockProps} />)
expect(screen.getByTestId("file-icon")).toBeInTheDocument()
})
})
2 changes: 1 addition & 1 deletion client/modules/chat/components/cards/document/document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const DocumentCard: React.FunctionComponent<IDocumentCardProp> = ({
rel="noopener noreferrer nofollow"
>
<div className="flex flex-row gap-2">
<Icons.file />
<Icons.file data-testid="file-icon" />
<p className="break-all">{documentName}</p>
</div>
<p className="text-end text-xs">
Expand Down
90 changes: 90 additions & 0 deletions client/modules/chat/components/cards/message/message.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* MessageCard component test
*
* @group unit
*/

import React from "react"
import MessageCard from "@/modules/chat/components/cards/message/message"
import { render, screen } from "@testing-library/react"

// Mock the hooks and components
jest.mock("@/hooks/common/created-at", () => ({
__esModule: true,
default: () => ({ data: "2023-01-01 12:00" }),
}))

jest.mock("@/modules/chat/components/cards/document/document", () => ({
__esModule: true,
default: ({ documentName }: { documentName: string }) => (
<div data-testid="document-card">{documentName}</div>
),
}))

describe("MessageCard", () => {
const mockProps = {
text: "Hello, this is a test message",
sentByUser: false,
createdAt: "2023-01-01T12:00:00Z",
isDocumentExpired: false,
}

it("renders correctly for received message", () => {
render(<MessageCard {...mockProps} />)

expect(screen.getByTestId("message-card")).toHaveClass("bg-slate-50")
expect(
screen.getByText("Hello, this is a test message")
).toBeInTheDocument()
expect(screen.getByText("2023-01-01 12:00")).toBeInTheDocument()
})

it("renders correctly for sent message", () => {
render(<MessageCard {...mockProps} sentByUser={true} />)

expect(screen.getByTestId("message-card")).toHaveClass("bg-green-300")
expect(
screen.getByText("Hello, this is a test message")
).toBeInTheDocument()
expect(screen.getByText("2023-01-01 12:00")).toBeInTheDocument()
})

it("renders links correctly", () => {
const propsWithLink = {
...mockProps,
text: "Check out this link: https://example.com",
}
render(<MessageCard {...propsWithLink} />)

const link = screen.getByRole("link")
expect(link).toHaveAttribute("href", "https://example.com")
expect(link).toHaveAttribute("target", "_blank")
})

it("renders DocumentCard when document is provided", () => {
const propsWithDocument = {
...mockProps,
document: {
name: "test.pdf",
size: 1024,
path: "https://example.com/test.pdf",
},
}
render(<MessageCard {...propsWithDocument} />)

expect(screen.getByTestId("document-card")).toBeInTheDocument()
expect(screen.getByText("test.pdf")).toBeInTheDocument()
})

it("does not render DocumentCard when document is not provided", () => {
render(<MessageCard {...mockProps} />)

expect(screen.queryByTestId("document-card")).not.toBeInTheDocument()
})

it("handles null text correctly", () => {
render(<MessageCard {...mockProps} text={null} />)

expect(screen.queryByText("null")).not.toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* ConversationHeader component test
*
* @group unit
*/

import React from "react"
import { useRouter } from "next/navigation"
import ConversationHeader from "@/modules/chat/components/header/conversation/conversation"
import { fireEvent, render, screen } from "@testing-library/react"

// Mock the next/navigation hook
jest.mock("next/navigation", () => ({
useRouter: jest.fn(),
}))

// Mock the BaseAvatar component
jest.mock("@/components/customized-ui/avatars/base", () => ({
__esModule: true,
default: ({ fallBack, alt }: any) => (
<div data-testid="base-avatar">
{fallBack}-{alt}
</div>
),
}))

describe("ConversationHeader", () => {
const mockProps = {
username: "John Doe",
jobTitle: "Software Engineer",
companyName: "Tech Corp",
avatarUrl: "https://example.com/avatar.jpg",
uuid: "123-456",
}

const mockPush = jest.fn()

beforeEach(() => {
jest.clearAllMocks()
;(useRouter as jest.Mock).mockReturnValue({ push: mockPush })
})

it("renders correctly with all props", () => {
render(<ConversationHeader {...mockProps} />)

expect(screen.getByText("John Doe")).toBeInTheDocument()
expect(screen.getByText("Software Engineer")).toBeInTheDocument()
expect(screen.getByText("@Tech Corp")).toBeInTheDocument()
expect(screen.getByTestId("base-avatar")).toHaveTextContent("J-John Doe")
})

it("renders correctly without optional props", () => {
render(
<ConversationHeader
{...mockProps}
jobTitle={null}
companyName={null}
avatarUrl={null}
/>
)

expect(screen.getByText("John Doe")).toBeInTheDocument()
expect(screen.queryByText("Software Engineer")).not.toBeInTheDocument()
expect(screen.queryByText("@Tech Corp")).not.toBeInTheDocument()
})

it("navigates back when back button is clicked", () => {
render(<ConversationHeader {...mockProps} />)

fireEvent.click(screen.getByTestId("chevron-left"))
expect(mockPush).toHaveBeenCalledWith("/chat")
})

it("navigates to profile when avatar is clicked", () => {
render(<ConversationHeader {...mockProps} />)

fireEvent.click(screen.getByTestId("base-avatar"))
expect(mockPush).toHaveBeenCalledWith("/profile/123-456")
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const ConversationHeader: React.FunctionComponent<IConversationHeaderProps> = ({
<Icons.chevronLeft
className="block hover:cursor-pointer md:hidden"
onClick={handleBackClick}
data-testid="chevron-left"
/>
<div className="hover:cursor-pointer" onClick={handleAvatarClick}>
<BaseAvatar
Expand Down
Loading

0 comments on commit 396cbd6

Please sign in to comment.