diff --git a/backend/test/message.js b/backend/test/message.js index 1ac80f48b..3f62f7da1 100644 --- a/backend/test/message.js +++ b/backend/test/message.js @@ -1,6 +1,7 @@ -let chai = require('chai'); -let chaiHttp = require('chai-http'); -let server = require('../index'); +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const app = require('../index'); // Assuming your Express app is in app.js +const Message = require("../models/message"); chai.should(); @@ -12,9 +13,9 @@ describe('Messages Controller', () => { it('should create a new message', (done) => { const messageData = { message: 'Test message', - fromUser: 'p123jr', - toUser: 'sdijgpo213k', - applicationId: "1231241" + fromUser: '6722e4be0f205dc7a0c0b2ea', + toUser: '6722e4be0f205dc7a0c0b2ec', + applicationId: "6722e4be0f205dc7a0c0b2eb" }; chai.request("http://localhost:8000") @@ -44,6 +45,47 @@ describe('Messages Controller', () => { }); }); describe('GET /fetchMessages', () => { + beforeEach(async () => { + // Create some test messages + await Message.insertMany([ + { applicantId: '6722e4be0f205dc7a0c0b2ea', message: 'Message 1', timestamp: new Date('2023-01-01'), fromUser: "6722e4be0f205dc7a0c0b2ev", toUser:"6722e4be0f205dc7a0c0b2eb" }, + { applicantId: '6722e4be0f205dc7a0c0b2ea', message: 'Message 2', timestamp: new Date('2023-01-02'), fromUser: "6722e4be0f205dc7a0c0b2e1", toUser:"6722e4be0f205dc7a0c0b243" }, + { applicantId: '6722e4be0f205dc7a0c0b2ev', message: 'Other Message', timestamp: new Date('2023-01-03'), fromUser: "6722e4be0f205dc7a0c0b444", toUser:"6722e4be0f205dc7a0c0b34h" } + ]); + }); + + afterEach(async () => { + // Clean up test messages + await Message.deleteMany({}); + }); + + it('should fetch messages for a specific applicant', (done) => { + chai.request(app) + .get('/messsage/fetchMessages') + .query({ applicationId: '6722e4be0f205dc7a0c0b2eb' }) + .end((err, res) => { + res.should.have.status(200); + res.body.should.be.an('object'); + res.body.data.should.be.an('array').with.lengthOf(2); + res.body.data[0].content.should.equal('Message 1'); + res.body.data[1].content.should.equal('Message 2'); + done(); + }); + }); + + it('should sort messages by date', (done) => { + chai.request(app) + .get('/messsage/fetchMessages') + .query({ applicationId: '6722e4be0f205dc7a0c0b2eb' }) + .end((err, res) => { + res.should.have.status(200); + res.body.should.be.an('object'); + res.body.data.should.be.an('array').with.lengthOf(2); + res.body.data[0].date.should.be.below(res.body.data[1].date); + done(); + }); + }); + it('should return 400 when applicationId is missing', (done) => { chai.request("http://localhost:8000") .get('/messsage/fetchMessages') @@ -54,4 +96,95 @@ describe('GET /fetchMessages', () => { done(); }); }); + + it('should handle errors during message fetching', async () => { + // Mock an error in the Message model + sinon.stub(Message, 'find').rejects(new Error('Mocked error')); + + try { + await chai.request(app) + .get('/messsage/fetchMessages') + .query({ applicationId: '6722e4be0f205dc7a0c0b2eb' }); + } catch (error) { + error.response.should.have.status(500); + error.response.body.should.be.an('object'); + error.response.body.message.should.equal('Something went wrong'); + } + + // Restore the original function + Message.find.restore(); + }); }); + +describe('GET /messsage/fetchMessages', () => { + beforeEach(async () => { + // Create some test messages + await Message.insertMany([ + { applicantId: '6722e4be0f205dc7a0c0b2eb', content: 'Message 1', date: new Date('2023-01-01') }, + { applicantId: '6722e4be0f205dc7a0c0b2eb', content: 'Message 2', date: new Date('2023-01-02') }, + { applicantId: '6722e4be0f205dc7a0c0b2eb', content: 'Other Message', date: new Date('2023-01-03') } + ]); + }); + + afterEach(async () => { + // Clean up test messages + await Message.deleteMany({}); + }); + + it('should fetch messages for a specific applicant', (done) => { + chai.request(app) + .get('/messsage/fetchMessages') + .query({ applicationId: '6722e4be0f205dc7a0c0b2eb' }) + .end((err, res) => { + res.should.have.status(200); + res.body.should.be.an('object'); + res.body.data.should.be.an('array').with.lengthOf(2); + res.body.data[0].content.should.equal('Message 1'); + res.body.data[1].content.should.equal('Message 2'); + done(); + }); + }); + + it('should sort messages by date', (done) => { + chai.request(app) + .get('/messsage/fetchMessages') + .query({ applicationId: '6722e4be0f205dc7a0c0b2eb' }) + .end((err, res) => { + res.should.have.status(200); + res.body.should.be.an('object'); + res.body.data.should.be.an('array').with.lengthOf(2); + res.body.data[0].date.should.be.below(res.body.data[1].date); + done(); + }); + }); + + it('should return 400 when applicationId is missing', (done) => { + chai.request(app) + .get('/messsage/fetchMessages') + .end((err, res) => { + res.should.have.status(400); + res.body.should.be.an('object'); + res.body.message.should.equal('applicationId missing'); + done(); + }); + }); + + it('should handle errors during message fetching', async () => { + // Mock an error in the Message model + sinon.stub(Message, 'find').rejects(new Error('Mocked error')); + + try { + await chai.request(app) + .get('/messsage/fetchMessages') + .query({ applicationId: 'testApplicant' }); + } catch (error) { + error.response.should.have.status(500); + error.response.body.should.be.an('object'); + error.response.body.message.should.equal('Something went wrong'); + } + + // Restore the original function + Message.find.restore(); + }); + }); + diff --git a/frontend/src/components/Chat/ChatView.tsx b/frontend/src/components/Chat/ChatView.tsx index cd1b6c8ed..6747e6553 100644 --- a/frontend/src/components/Chat/ChatView.tsx +++ b/frontend/src/components/Chat/ChatView.tsx @@ -95,7 +95,7 @@ const ChatView = ({ selectedChat, refreshChats }: any) => { onChange={(e) => setMessage(e.target.value)} sx={{ mr: 1 }} /> - + diff --git a/frontend/src/components/Chat/ChatWindow.tsx b/frontend/src/components/Chat/ChatWindow.tsx index 2e580edf7..644dafa88 100644 --- a/frontend/src/components/Chat/ChatWindow.tsx +++ b/frontend/src/components/Chat/ChatWindow.tsx @@ -107,7 +107,7 @@ const ChatWindow: React.FC = ({ value={message} onChange={(e) => setMessage(e.target.value)} /> - + diff --git a/frontend/tests/components/Chat/ChatList.test.tsx b/frontend/tests/components/Chat/ChatList.test.tsx new file mode 100644 index 000000000..2b2ce9795 --- /dev/null +++ b/frontend/tests/components/Chat/ChatList.test.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import ChatList from '../../../src/components/Chat/ChatList'; // Adjust the path according to your project structure + +describe('ChatList component', () => { + const mockChats = [ + { + applicationId: '123', + applicantName: 'John Doe', + lastMessage: { + message: 'Hello!', + createdAt: new Date('2023-01-01T12:00:00Z'), + }, + }, + { + applicationId: '456', + applicantName: 'Jane Smith', + lastMessage: { + message: 'Hi there!', + createdAt: new Date('2023-01-01T13:30:00Z'), + }, + }, + ]; + + const mockOnSelectChat = () => {}; + + it('renders the correct number of chat items', () => { + render(); + + const listItems = screen.getAllByRole('listitem'); + expect(listItems.length).toBe(mockChats.length); + }); + + it('displays the applicant name for each chat', () => { + render(); + + mockChats.forEach((chat) => { + const applicantName = screen.getByText(chat.applicantName); + expect(applicantName).toBeInTheDocument(); + }); + }); + + it('renders a Divider at the end of the list', () => { + render(); + + const divider = screen.getByRole('separator'); + expect(divider).toBeInTheDocument(); + }); +}); diff --git a/frontend/tests/components/Chat/ChatView.test.tsx b/frontend/tests/components/Chat/ChatView.test.tsx new file mode 100644 index 000000000..490492f9f --- /dev/null +++ b/frontend/tests/components/Chat/ChatView.test.tsx @@ -0,0 +1,40 @@ +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import ChatView from '../../../src/components/Chat/ChatView'; + +describe("ChatView Component", () => { + const selectedChatMock = { + applicantId: "applicant123", + applicationId: "application456", + applicantName: "John Doe", + messages: [ + { + _id: "message1", + message: "Hello", + fromUser: "applicant123", + createdAt: new Date().toISOString(), + }, + ], + }; + + const refreshChatsMock = vi.fn(); + + it("renders component with messages and allows sending new messages", async () => { + render(); + + // Check if message list renders + expect(screen.getByText("Hello")).toBeInTheDocument(); + expect(screen.getByText("John Doe")).toBeInTheDocument(); + + // Find and interact with input field + const inputField = screen.getByLabelText("Type a message...") as HTMLInputElement; + fireEvent.change(inputField, { target: { value: "Hi there!" } }); + expect(inputField.value).toBe("Hi there!"); + + // Submit the form + const submitButton = screen.getByRole("button", { name: /send/i }); + fireEvent.click(submitButton); + + // Ensure input clears after sending + await waitFor(() => expect(inputField.value).toBe("")); + }); + }); \ No newline at end of file diff --git a/frontend/tests/components/Chat/ChatWindow.test.tsx b/frontend/tests/components/Chat/ChatWindow.test.tsx new file mode 100644 index 000000000..9594ba5e8 --- /dev/null +++ b/frontend/tests/components/Chat/ChatWindow.test.tsx @@ -0,0 +1,63 @@ +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import ChatWindow from "../../../src/components/Chat/ChatWindow"; + +describe("ChatWindow Component", () => { + const onCloseMock = vi.fn(); + const sendMessageMock = vi.fn(); + const refreshChatsMock = vi.fn(); + + const chatsMock = [ + { fromUser: "user123", message: "Hello", createdAt: new Date().toISOString() }, + { fromUser: "applicant123", message: "Hi", createdAt: new Date().toISOString() }, + ]; + + const applicationMock = { _id: "app123", applicantid: "applicant123" }; + + beforeEach(() => { + localStorage.setItem("userId", "user123"); + }); + + it("renders chat messages correctly", () => { + render( + + ); + + expect(screen.getByText("Hello")).toBeInTheDocument(); + expect(screen.getByText("Hi")).toBeInTheDocument(); + expect(screen.getByText("You")).toBeInTheDocument(); + expect(screen.getByText("Applicant")).toBeInTheDocument(); + }); + + it("sends a message and clears the input field on submit", async () => { + render( + + ); + + const inputField = screen.getByLabelText("Send a message...") as HTMLInputElement; + fireEvent.change(inputField, { target: { value: "New message" } }); + expect(inputField.value).toBe("New message"); + + const sendButton = screen.getByRole("button", { name: /send/i }); + fireEvent.click(sendButton); + + await waitFor(() => { + expect(sendMessageMock).toHaveBeenCalledWith("New message"); + expect(inputField.value).toBe(""); + }); + }); +});