Skip to content

Commit d81cb4c

Browse files
committed
added testcases for codespace services
1 parent d867bde commit d81cb4c

File tree

9 files changed

+491
-9
lines changed

9 files changed

+491
-9
lines changed
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// CodespaceController.test.js
2+
import { CodespaceController } from "../controllers/codespaceController";
3+
import { CodespaceService } from "../services/codespaceService";
4+
5+
jest.mock("../services/codespaceService.js", () => ({
6+
CodespaceService: {
7+
getUserCodespaces: jest.fn(),
8+
createCodespace: jest.fn(),
9+
updateCodespace: jest.fn(),
10+
deleteCodespace: jest.fn(),
11+
shareCodespaceByEmail: jest.fn(),
12+
getUserCodespaceMembership: jest.fn(),
13+
shareCodespace: jest.fn(),
14+
acceptInvitation: jest.fn(),
15+
},
16+
}));
17+
18+
// Mock Express req, res, next
19+
const mockResponse = () => {
20+
const res = {};
21+
res.status = jest.fn().mockReturnValue(res);
22+
res.json = jest.fn().mockReturnValue(res);
23+
return res;
24+
};
25+
26+
const mockNext = jest.fn();
27+
28+
describe("CodespaceController", () => {
29+
beforeEach(() => {
30+
jest.clearAllMocks();
31+
});
32+
33+
describe("getCodespaces", () => {
34+
it("should return codespaces and count", async () => {
35+
const req = { user: { id: "user1" } };
36+
const res = mockResponse();
37+
38+
CodespaceService.getUserCodespaces.mockResolvedValue([
39+
{ id: "cs1", name: "CS 1" },
40+
]);
41+
42+
await CodespaceController.getCodespaces(req, res, mockNext);
43+
44+
expect(res.json).toHaveBeenCalledWith({
45+
codespaces: [{ id: "cs1", name: "CS 1" }],
46+
count: 1,
47+
});
48+
});
49+
50+
it("should call next on error", async () => {
51+
const req = { user: { id: "user1" } };
52+
const res = mockResponse();
53+
const error = new Error("DB error");
54+
55+
CodespaceService.getUserCodespaces.mockRejectedValue(error);
56+
57+
await CodespaceController.getCodespaces(req, res, mockNext);
58+
59+
expect(mockNext).toHaveBeenCalledWith(error);
60+
});
61+
});
62+
63+
describe("createCodespace", () => {
64+
it("should create a codespace and return 201", async () => {
65+
const req = { user: { id: "user1" }, body: { name: "New CS" } };
66+
const res = mockResponse();
67+
68+
CodespaceService.createCodespace.mockResolvedValue({ id: "cs1", name: "New CS" });
69+
70+
await CodespaceController.createCodespace(req, res, mockNext);
71+
72+
expect(res.status).toHaveBeenCalledWith(201);
73+
expect(res.json).toHaveBeenCalledWith({
74+
codespace: { id: "cs1", name: "New CS" },
75+
message: "Codespace created successfully",
76+
});
77+
});
78+
});
79+
80+
describe("updateCodespace", () => {
81+
it("should update codespace successfully", async () => {
82+
const req = { user: { id: "user1" }, params: { id: "cs1" }, body: { name: "Updated CS" } };
83+
const res = mockResponse();
84+
85+
CodespaceService.updateCodespace.mockResolvedValue({ id: "cs1", name: "Updated CS" });
86+
87+
await CodespaceController.updateCodespace(req, res, mockNext);
88+
89+
expect(res.json).toHaveBeenCalledWith({
90+
codespace: { id: "cs1", name: "Updated CS" },
91+
message: "Codespace updated successfully",
92+
});
93+
});
94+
95+
it("should return error status if error has statusCode", async () => {
96+
const req = { user: { id: "user1" }, params: { id: "cs1" }, body: { name: "Updated CS" } };
97+
const res = mockResponse();
98+
const error = new Error("Forbidden");
99+
error.statusCode = 403;
100+
error.code = "INSUFFICIENT_PERMISSIONS";
101+
102+
CodespaceService.updateCodespace.mockRejectedValue(error);
103+
104+
await CodespaceController.updateCodespace(req, res, mockNext);
105+
106+
expect(res.status).toHaveBeenCalledWith(403);
107+
expect(res.json).toHaveBeenCalledWith({
108+
error: "Forbidden",
109+
code: "INSUFFICIENT_PERMISSIONS",
110+
});
111+
});
112+
});
113+
114+
describe("deleteCodespace", () => {
115+
it("should delete codespace successfully", async () => {
116+
const req = { user: { id: "user1" }, params: { id: "cs1" } };
117+
const res = mockResponse();
118+
119+
CodespaceService.deleteCodespace.mockResolvedValue();
120+
121+
await CodespaceController.deleteCodespace(req, res, mockNext);
122+
123+
expect(res.json).toHaveBeenCalledWith({ message: "Codespace deleted successfully" });
124+
});
125+
});
126+
127+
describe("shareCodespaceByEmail", () => {
128+
it("should return 400 if email is invalid", async () => {
129+
const req = { user: { id: "user1" }, params: { id: "cs1" }, body: { email: "invalid" } };
130+
const res = mockResponse();
131+
132+
await CodespaceController.shareCodespaceByEmail(req, res, mockNext);
133+
134+
expect(res.status).toHaveBeenCalledWith(400);
135+
expect(res.json).toHaveBeenCalledWith({
136+
error: "Invalid email format",
137+
code: "INVALID_EMAIL",
138+
});
139+
});
140+
141+
it("should share codespace successfully", async () => {
142+
const req = { user: { id: "user1" }, params: { id: "cs1" }, body: { email: "test@example.com", role: "member" } };
143+
const res = mockResponse();
144+
145+
CodespaceService.shareCodespaceByEmail.mockResolvedValue({ invitation: { id: "inv1" } });
146+
147+
await CodespaceController.shareCodespaceByEmail(req, res, mockNext);
148+
149+
expect(res.json).toHaveBeenCalledWith({
150+
message: "Invitation sent successfully",
151+
invitation: { id: "inv1" },
152+
});
153+
});
154+
});
155+
156+
describe("getCodespaceById", () => {
157+
it("should return codespace if found", async () => {
158+
const req = { user: { id: "user1" }, params: { id: "cs1" } };
159+
const res = mockResponse();
160+
161+
CodespaceService.getUserCodespaceMembership.mockResolvedValue({});
162+
CodespaceService.getUserCodespaces.mockResolvedValue([{ id: "cs1", name: "CS 1" }]);
163+
164+
await CodespaceController.getCodespaceById(req, res, mockNext);
165+
166+
expect(res.json).toHaveBeenCalledWith({ codespace: { id: "cs1", name: "CS 1" } });
167+
});
168+
169+
it("should return 404 if codespace not found", async () => {
170+
const req = { user: { id: "user1" }, params: { id: "cs2" } };
171+
const res = mockResponse();
172+
173+
CodespaceService.getUserCodespaceMembership.mockResolvedValue({});
174+
CodespaceService.getUserCodespaces.mockResolvedValue([{ id: "cs1", name: "CS 1" }]);
175+
176+
await CodespaceController.getCodespaceById(req, res, mockNext);
177+
178+
expect(res.status).toHaveBeenCalledWith(404);
179+
expect(res.json).toHaveBeenCalledWith({
180+
error: "Codespace not found",
181+
code: "CODESPACE_NOT_FOUND",
182+
});
183+
});
184+
});
185+
186+
describe("acceptInvitation", () => {
187+
it("should accept invitation successfully", async () => {
188+
const req = { params: { invitationId: "inv1" } };
189+
const res = mockResponse();
190+
191+
CodespaceService.acceptInvitation.mockResolvedValue({ invitation: { id: "inv1" }, member: { id: "user1" } });
192+
193+
await CodespaceController.acceptInvitation(req, res, mockNext);
194+
195+
expect(res.json).toHaveBeenCalledWith({
196+
message: "Invitation accepted successfully",
197+
invitation: { id: "inv1" },
198+
member: { id: "user1" },
199+
});
200+
});
201+
});
202+
});

Codespace_Service/src/services/CodespaceService.test.js renamed to Codespace_Service/src/Test/CodespaceService.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { CodespaceService } from "./codespaceService.js";
2-
import { supabase } from "./supabaseClient.js";
1+
import { CodespaceService } from "../services/codespaceService.js";
2+
import { supabase } from "../services/supabaseClient.js";
33
import nodemailer from "nodemailer";
44

5-
jest.mock("./supabaseClient.js", () => ({
5+
jest.mock("../services/supabaseClient.js", () => ({
66
supabase: {
77
from: jest.fn(() => ({
88
select: jest.fn(),
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { AIChatResponse } from "../services/aiService";
2+
import { streamText, convertToModelMessages } from "ai";
3+
import { google } from "@ai-sdk/google";
4+
5+
jest.mock("ai", () => ({
6+
streamText: jest.fn(),
7+
convertToModelMessages: jest.fn(),
8+
}));
9+
10+
jest.mock("@ai-sdk/google", () => ({
11+
google: jest.fn(),
12+
}));
13+
14+
describe("AIChatResponse", () => {
15+
beforeEach(() => {
16+
jest.clearAllMocks();
17+
process.env.GEMINI_API_KEY = "fake-key";
18+
});
19+
20+
it("should throw error if GEMINI_API_KEY is not set", async () => {
21+
delete process.env.GEMINI_API_KEY;
22+
await expect(AIChatResponse([{ role: "user", content: "Hello" }]))
23+
.rejects.toThrow("GEMINI_API_KEY environment variable is not set.");
24+
});
25+
26+
it("should call streamText with correct parameters", async () => {
27+
const mockMessages = [{ role: "user", content: "Hello" }];
28+
const convertedMessages = [{ role: "user", content: "Hello (converted)" }];
29+
30+
convertToModelMessages.mockReturnValue(convertedMessages);
31+
google.mockReturnValue("gemini-model");
32+
streamText.mockResolvedValue("mock-stream-response");
33+
34+
const result = await AIChatResponse(mockMessages);
35+
36+
expect(convertToModelMessages).toHaveBeenCalledWith(mockMessages);
37+
expect(google).toHaveBeenCalledWith("gemini-1.5-pro");
38+
expect(streamText).toHaveBeenCalledWith({
39+
model: "gemini-model",
40+
messages: convertedMessages,
41+
system: expect.stringContaining("You are an expert AI coding assistant"),
42+
});
43+
expect(result).toBe("mock-stream-response");
44+
});
45+
46+
it("should propagate error from streamText", async () => {
47+
convertToModelMessages.mockReturnValue([]);
48+
google.mockReturnValue("gemini-model");
49+
streamText.mockRejectedValue(new Error("API failed"));
50+
51+
await expect(AIChatResponse([{ role: "user", content: "test" }]))
52+
.rejects.toThrow("API failed");
53+
});
54+
});

0 commit comments

Comments
 (0)