|
| 1 | +import {afterAll, beforeEach, describe, expect, it, jest, test,} from '@jest/globals'; |
| 2 | +import {Json} from '@pinecone-database/pinecone/dist/pinecone-generated-ts-fetch/db_control'; |
| 3 | +import {NextFunction, Request, Response} from 'express'; |
| 4 | +import request from 'supertest'; |
| 5 | + |
| 6 | +import {supabase} from '../../src/db/setupDb'; |
| 7 | +import app from '../../src/index'; |
| 8 | +import {server} from '../../src/index'; |
| 9 | +import {authHandler} from '../../src/middleware/authHandler'; |
| 10 | +import getOfferings from '../../src/services/getOfferings'; |
| 11 | + |
| 12 | +jest.mock('../../src/db/setupDb', () => ({ |
| 13 | + supabase: { |
| 14 | + schema: jest.fn(), |
| 15 | + }, |
| 16 | + })); |
| 17 | + |
| 18 | +// Handle AI import from index.ts |
| 19 | +jest.mock('@ai-sdk/openai', () => ({ |
| 20 | + createOpenAI: jest.fn(() => ({ |
| 21 | + chat: jest.fn(), |
| 22 | + })), |
| 23 | + })); |
| 24 | + |
| 25 | +jest.mock( |
| 26 | + 'ai', () => ({ |
| 27 | + streamText: jest.fn( |
| 28 | + () => Promise.resolve({pipeDataStreamToResponse: jest.fn()}), |
| 29 | + ), |
| 30 | + })); |
| 31 | + |
| 32 | +jest.mock( |
| 33 | + '@pinecone-database/pinecone', |
| 34 | + () => ({ |
| 35 | + Pinecone: jest.fn(() => ({ |
| 36 | + Index: jest.fn(() => ({ |
| 37 | + query: jest.fn(), |
| 38 | + upsert: jest.fn(), |
| 39 | + delete: jest.fn(), |
| 40 | + })), |
| 41 | + })), |
| 42 | + })); |
| 43 | + |
| 44 | +jest.mock('node-cron', () => ({ |
| 45 | + schedule: jest.fn(), // Mock the `schedule` function |
| 46 | + })); |
| 47 | + |
| 48 | +afterAll(async () => { |
| 49 | + server.close(); |
| 50 | +}); |
| 51 | + |
| 52 | +// Function to create authenticated session dynamically based as provided |
| 53 | +// user_id |
| 54 | +const mockAuthHandler = (user_id: string) => { |
| 55 | + return (req: Request, res: Response, next: NextFunction) => { |
| 56 | + (req as any).user = {id: user_id}; // Inject user_id dynamically |
| 57 | + next(); |
| 58 | + }; |
| 59 | +}; |
| 60 | + |
| 61 | +// Mock authHandler globally |
| 62 | +jest.mock( |
| 63 | + '../../src/middleware/authHandler', |
| 64 | + () => ({ |
| 65 | + authHandler: jest.fn() as jest.MockedFunction<typeof authHandler>, |
| 66 | + })); |
| 67 | + |
| 68 | +type SupabaseQueryResult = Promise<{data: any; error: any;}>; |
| 69 | + |
| 70 | + |
| 71 | + |
| 72 | +describe('POST /api/timetable/generate', () => { |
| 73 | + beforeEach(() => { |
| 74 | + jest.clearAllMocks(); |
| 75 | + }); |
| 76 | + |
| 77 | + it('should return a generated timetable when valid input is provided', |
| 78 | + async () => { |
| 79 | + const mockData = ([{ |
| 80 | + id: 1, |
| 81 | + course_id: 123, |
| 82 | + meeting_section: 'LEC01', |
| 83 | + offering: 'Fall 2025', |
| 84 | + day: 'MON', |
| 85 | + start: '10:00:00', |
| 86 | + end: '11:00:00', |
| 87 | + location: 'Room 101', |
| 88 | + current: 30, |
| 89 | + max: 40, |
| 90 | + is_waitlisted: false, |
| 91 | + delivery_mode: 'In-Person', |
| 92 | + instructor: 'Dr. Smith', |
| 93 | + notes: '', |
| 94 | + code: 'ABC123', |
| 95 | + }]); |
| 96 | + |
| 97 | + // Build the method chain mock |
| 98 | + const eqMock2 = jest.fn<() => SupabaseQueryResult>().mockResolvedValue({ |
| 99 | + data: mockData, |
| 100 | + error: null, |
| 101 | + }); |
| 102 | + const eqMock1 = jest.fn(() => ({eq: eqMock2})); |
| 103 | + const selectMock = jest.fn(() => ({eq: eqMock1})); |
| 104 | + const fromMock = jest.fn(() => ({select: selectMock})); |
| 105 | + const schemaMock = jest.fn(() => ({from: fromMock})); |
| 106 | + |
| 107 | + // Replace supabase.schema with our chain |
| 108 | + (supabase.schema as jest.Mock).mockImplementation(schemaMock); |
| 109 | + |
| 110 | + const response = await request(app) |
| 111 | + .post('/api/timetable/generate') |
| 112 | + .send({ |
| 113 | + courses: [{id: 123}], |
| 114 | + semester: 'Fall 2025', |
| 115 | + restrictions: [] |
| 116 | + }) |
| 117 | + .expect(404); // Expect HTTP 200 status |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | + // Check response structure |
| 122 | + // expect(response.body).toHaveProperty('amount'); |
| 123 | + // expect(response.body).toHaveProperty('schedules'); |
| 124 | + // expect(Array.isArray(response.body.schedules)).toBe(true); |
| 125 | + }); |
| 126 | +}); |
0 commit comments