Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"permissions": {
"allow": [
"Bash(find:*)",
"Bash(du -sh \"C:\\\\Users\\\\Timothy Lin\\\\Projects\\\\pdr_ai_v2\\\\node_modules\\\\.pnpm\\\\@huggingface+transformers\"*)",
"Bash(cd:*)",
"Bash(npm ls:*)",
"Bash(pnpm build:*)",
"Bash(findstr:*)",
"Bash(pnpm why:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push)",
"Bash(ls:*)",
"Bash(git -C /Users/timothylin/knowledge-base-redesign log --oneline --all)",
"Bash(git -C /Users/timothylin/knowledge-base-redesign branch -a)",
"Bash(npx drizzle-kit:*)",
"Bash(npm install:*)",
"Bash(npx tsc:*)",
"Bash(npm run build:*)",
"Bash(node --check:*)",
"Bash(mkdir:*)"
]
}
}
18 changes: 18 additions & 0 deletions .vercelignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Development files
*.test.ts
*.spec.ts
__tests__
.github
.vscode

# Large static files not needed in serverless
public/vad/*.js.map
public/vad/*.wasm.map

# Documentation
*.md
!README.md

# Build artifacts
.next/cache
.turbo
306 changes: 254 additions & 52 deletions README.md

Large diffs are not rendered by default.

54 changes: 31 additions & 23 deletions __tests__/api/Categories/categories.add.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,29 +186,37 @@ describe("POST /api/Categories/AddCategories", () => {
});

it("should return 500 on database error", async () => {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { CategoryName: "Test Category" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });

const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Database connection failed")),
}),
});
(db.select as jest.Mock) = mockSelect;

const request = new Request("http://localhost/api/Categories/AddCategories", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ CategoryName: "Test Category" }),
});

const response = await POST(request);

expect(response.status).toBe(500);
// Mock console.error to prevent test failure from error logging
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});

try {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { CategoryName: "Test Category" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });

const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Database connection failed")),
}),
});
(db.select as jest.Mock) = mockSelect;

const request = new Request("http://localhost/api/Categories/AddCategories", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ CategoryName: "Test Category" }),
});

const response = await POST(request);

expect(response.status).toBe(500);
} finally {
// Restore console.error even if test fails
consoleErrorSpy.mockRestore();
}
});

it("should return 400 if auth returns null userId", async () => {
Expand Down
126 changes: 71 additions & 55 deletions __tests__/api/Categories/categories.delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,64 +203,80 @@ describe("DELETE /api/Categories/DeleteCategory", () => {
});

it("should return 500 on database error", async () => {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { id: "123" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });

// Mock database error on select
const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Database error")),
}),
});
(db.select as jest.Mock) = mockSelect;

const request = new Request("http://localhost/api/Categories/DeleteCategory", {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: "123" }),
});

const response = await DELETE(request);

expect(response.status).toBe(500);
// Mock console.error to prevent test failure from error logging
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});

try {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { id: "123" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });

// Mock database error on select
const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Database error")),
}),
});
(db.select as jest.Mock) = mockSelect;

const request = new Request("http://localhost/api/Categories/DeleteCategory", {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: "123" }),
});

const response = await DELETE(request);

expect(response.status).toBe(500);
} finally {
// Restore console.error even if test fails
consoleErrorSpy.mockRestore();
}
});

it("should return 500 on delete operation error", async () => {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { id: "123" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "employer-user-123" });

const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockResolvedValue([
{ userId: "employer-user-123", role: "employer", companyId: 1 }
]),
}),
});
(db.select as jest.Mock) = mockSelect;

// Mock delete operation error
const mockDelete = jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Delete failed")),
});
(db.delete as jest.Mock) = mockDelete;

const request = new Request("http://localhost/api/Categories/DeleteCategory", {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: "123" }),
});

const response = await DELETE(request);

expect(response.status).toBe(500);
// Mock console.error to prevent test failure from error logging
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});

try {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { id: "123" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "employer-user-123" });

const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockResolvedValue([
{ userId: "employer-user-123", role: "employer", companyId: 1 }
]),
}),
});
(db.select as jest.Mock) = mockSelect;

// Mock delete operation error
const mockDelete = jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Delete failed")),
});
(db.delete as jest.Mock) = mockDelete;

const request = new Request("http://localhost/api/Categories/DeleteCategory", {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: "123" }),
});

const response = await DELETE(request);

expect(response.status).toBe(500);
} finally {
// Restore console.error even if test fails
consoleErrorSpy.mockRestore();
}
});

it("should return 400 if auth returns null userId", async () => {
Expand Down
118 changes: 67 additions & 51 deletions __tests__/api/fetchDocument/fetchDocument.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,70 +182,86 @@ describe("POST /api/fetchDocument", () => {
});

it("should return 500 on database error during user lookup", async () => {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { userId: "test-user-123" },
});
// Mock console.error to prevent test failure from error logging
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});

(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });
try {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { userId: "test-user-123" },
});

// Mock database error on user lookup
const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Database connection failed")),
}),
});
(db.select as jest.Mock) = mockSelect;
(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });

const request = new Request("http://localhost/api/fetchDocument", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "test-user-123" }),
});
// Mock database error on user lookup
const mockSelect = jest.fn().mockReturnValue({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Database connection failed")),
}),
});
(db.select as jest.Mock) = mockSelect;

const response = await POST(request);
const json = await response.json();
const request = new Request("http://localhost/api/fetchDocument", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "test-user-123" }),
});

expect(response.status).toBe(500);
expect(json.error).toBe("Unable to fetch documents");
const response = await POST(request);
const json = await response.json();

expect(response.status).toBe(500);
expect(json.error).toBe("Unable to fetch documents");
} finally {
// Restore console.error even if test fails
consoleErrorSpy.mockRestore();
}
});

it("should return 500 on database error during documents fetch", async () => {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { userId: "test-user-123" },
});

(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });
// Mock console.error to prevent test failure from error logging
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});

// First call succeeds (user lookup), second call fails (documents fetch)
const mockSelect = jest.fn()
.mockReturnValueOnce({
from: jest.fn().mockReturnValue({
where: jest.fn().mockResolvedValue([
{ userId: "test-user-123", role: "employer", companyId: 1 }
]),
}),
})
.mockReturnValueOnce({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Failed to fetch documents")),
}),
try {
(validateRequestBody as jest.Mock).mockResolvedValue({
success: true,
data: { userId: "test-user-123" },
});

(db.select as jest.Mock) = mockSelect;

const request = new Request("http://localhost/api/fetchDocument", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "test-user-123" }),
});
(auth as jest.Mock).mockResolvedValue({ userId: "test-user-123" });

// First call succeeds (user lookup), second call fails (documents fetch)
const mockSelect = jest.fn()
.mockReturnValueOnce({
from: jest.fn().mockReturnValue({
where: jest.fn().mockResolvedValue([
{ userId: "test-user-123", role: "employer", companyId: 1 }
]),
}),
})
.mockReturnValueOnce({
from: jest.fn().mockReturnValue({
where: jest.fn().mockRejectedValue(new Error("Failed to fetch documents")),
}),
});

(db.select as jest.Mock) = mockSelect;

const request = new Request("http://localhost/api/fetchDocument", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "test-user-123" }),
});

const response = await POST(request);
const json = await response.json();
const response = await POST(request);
const json = await response.json();

expect(response.status).toBe(500);
expect(json.error).toBe("Unable to fetch documents");
expect(response.status).toBe(500);
expect(json.error).toBe("Unable to fetch documents");
} finally {
// Restore console.error even if test fails
consoleErrorSpy.mockRestore();
}
});

it("should return 400 if auth returns null userId", async () => {
Expand Down
Loading
Loading