feat: Update AI service to use new Google Generative AI SDK
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running
Some checks are pending
Deploy to Test Environment / deploy-to-test (push) Has started running
- Refactored AIService to integrate with the latest GoogleGenAI SDK, updating the generateContent method signature and response handling. - Adjusted error handling and logging for improved clarity and consistency. - Enhanced mock implementations in tests to align with the new SDK structure. refactor: Modify Admin DB service to use Profile type - Updated AdminRepository to replace User type with Profile in relevant methods. - Enhanced test cases to utilize mock factories for creating Profile and AdminUserView objects. fix: Improve error handling in BudgetRepository - Implemented type-safe checks for PostgreSQL error codes to enhance error handling in createBudget method. test: Refactor Deals DB tests for type safety - Updated DealsRepository tests to use Pool type for mock instances, ensuring type safety. chore: Add new mock factories for testing - Introduced mock factories for UserWithPasswordHash, Profile, WatchedItemDeal, LeaderboardUser, and UnmatchedFlyerItem to streamline test data creation. style: Clean up queue service tests - Refactored queue service tests to improve readability and maintainability, including better handling of mock worker instances. docs: Update types to include UserWithPasswordHash - Added UserWithPasswordHash interface to types for better clarity on user authentication data structure. chore: Remove deprecated Google AI SDK references - Updated code and documentation to reflect the migration to the new Google Generative AI SDK, removing references to the deprecated SDK.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
// src/routes/user.routes.test.ts
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import supertest from 'supertest';
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import express from 'express';
|
||||
// Use * as bcrypt to match the implementation's import style and ensure mocks align.
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import userRouter from './user.routes';
|
||||
import { createMockUserProfile, createMockMasterGroceryItem, createMockShoppingList, createMockShoppingListItem, createMockRecipe } from '../tests/utils/mockFactories';
|
||||
import { Appliance, Notification } from '../types';
|
||||
import { createMockUserProfile, createMockMasterGroceryItem, createMockShoppingList, createMockShoppingListItem, createMockRecipe, createMockNotification, createMockDietaryRestriction, createMockAppliance, createMockUserWithPasswordHash } from '../tests/utils/mockFactories';
|
||||
import { Appliance, Notification, DietaryRestriction } from '../types';
|
||||
import { ForeignKeyConstraintError, NotFoundError } from '../services/db/errors.db';
|
||||
import { createTestApp } from '../tests/utils/createTestApp';
|
||||
|
||||
@@ -351,12 +351,7 @@ describe('User Routes (/api/users)', () => {
|
||||
|
||||
describe('DELETE /account', () => {
|
||||
it('should delete the account with the correct password', async () => {
|
||||
const userWithHash = {
|
||||
...mockUserProfile.user,
|
||||
password_hash: 'hashed-password',
|
||||
failed_login_attempts: 0, // Add missing properties
|
||||
last_failed_login: null
|
||||
};
|
||||
const userWithHash = createMockUserWithPasswordHash({ ...mockUserProfile.user, password_hash: 'hashed-password' });
|
||||
vi.mocked(db.userRepo.findUserWithPasswordHashById).mockResolvedValue(userWithHash);
|
||||
vi.mocked(db.userRepo.deleteUserById).mockResolvedValue(undefined);
|
||||
vi.mocked(bcrypt.compare).mockResolvedValue(true as never);
|
||||
@@ -368,12 +363,7 @@ describe('User Routes (/api/users)', () => {
|
||||
});
|
||||
|
||||
it('should return 403 for an incorrect password', async () => {
|
||||
const userWithHash = {
|
||||
...mockUserProfile.user,
|
||||
password_hash: 'hashed-password',
|
||||
failed_login_attempts: 0,
|
||||
last_failed_login: null
|
||||
};
|
||||
const userWithHash = createMockUserWithPasswordHash({ ...mockUserProfile.user, password_hash: 'hashed-password' });
|
||||
vi.mocked(db.userRepo.findUserWithPasswordHashById).mockResolvedValue(userWithHash);
|
||||
vi.mocked(bcrypt.compare).mockResolvedValue(false as never);
|
||||
const response = await supertest(app)
|
||||
@@ -422,8 +412,8 @@ describe('User Routes (/api/users)', () => {
|
||||
|
||||
describe('GET and PUT /users/me/dietary-restrictions', () => {
|
||||
it('GET should return a list of restriction IDs', async () => {
|
||||
const mockRestrictions = [{ dietary_restriction_id: 1, name: 'Gluten-Free', type: 'diet' as const }];
|
||||
vi.mocked(db.personalizationRepo.getUserDietaryRestrictions).mockResolvedValue(mockRestrictions);
|
||||
const mockRestrictions: DietaryRestriction[] = [createMockDietaryRestriction({ name: 'Gluten-Free' })];
|
||||
vi.mocked(db.personalizationRepo.getUserDietaryRestrictions).mockResolvedValue(mockRestrictions);
|
||||
const response = await supertest(app).get('/api/users/me/dietary-restrictions');
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockRestrictions);
|
||||
@@ -455,8 +445,8 @@ describe('User Routes (/api/users)', () => {
|
||||
|
||||
describe('GET and PUT /users/me/appliances', () => {
|
||||
it('GET should return a list of appliance IDs', async () => {
|
||||
const mockAppliances: Appliance[] = [{ appliance_id: 2, name: 'Air Fryer' }];
|
||||
vi.mocked(db.personalizationRepo.getUserAppliances).mockResolvedValue(mockAppliances);
|
||||
const mockAppliances: Appliance[] = [createMockAppliance({ name: 'Air Fryer' })];
|
||||
vi.mocked(db.personalizationRepo.getUserAppliances).mockResolvedValue(mockAppliances);
|
||||
const response = await supertest(app).get('/api/users/me/appliances');
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual(mockAppliances);
|
||||
@@ -482,7 +472,7 @@ describe('User Routes (/api/users)', () => {
|
||||
|
||||
describe('Notification Routes', () => {
|
||||
it('GET /notifications should return notifications for the user', async () => {
|
||||
const mockNotifications: Notification[] = [{ notification_id: 1, user_id: 'user-123', content: 'Test', is_read: false, created_at: '', link_url: null }];
|
||||
const mockNotifications: Notification[] = [createMockNotification({ user_id: 'user-123', content: 'Test' })];
|
||||
vi.mocked(db.notificationRepo.getNotificationsForUser).mockResolvedValue(mockNotifications);
|
||||
|
||||
const response = await supertest(app).get('/api/users/notifications?limit=10&offset=0');
|
||||
@@ -500,16 +490,17 @@ describe('User Routes (/api/users)', () => {
|
||||
});
|
||||
|
||||
it('POST /notifications/:notificationId/mark-read should return 204', async () => {
|
||||
vi.mocked(db.notificationRepo.markNotificationAsRead).mockResolvedValue({} as any);
|
||||
// Fix: Return a mock notification object to match the function's signature.
|
||||
vi.mocked(db.notificationRepo.markNotificationAsRead).mockResolvedValue(createMockNotification({ notification_id: 1, user_id: 'user-123' }));
|
||||
const response = await supertest(app).post('/api/users/notifications/1/mark-read');
|
||||
expect(response.status).toBe(204);
|
||||
expect(db.notificationRepo.markNotificationAsRead).toHaveBeenCalledWith(1, 'user-123');
|
||||
});
|
||||
|
||||
it('should return 400 for an invalid notificationId', async () => {
|
||||
const response = await supertest(app).post('/api/users/notifications/abc/mark-read');
|
||||
const response = await supertest(app).post('/api/users/notifications/abc/mark-read').send({});
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid notification ID.');
|
||||
expect(response.body.errors[0].message).toBe("Invalid ID for parameter 'notificationId'. Must be a number.");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -539,7 +530,7 @@ describe('User Routes (/api/users)', () => {
|
||||
const appWithUser = createTestApp({ router: userRouter, basePath, authenticatedUser: { ...mockUserProfile, address_id: null } }); // User has no address yet
|
||||
const addressData = { address_line_1: '123 New St' };
|
||||
vi.mocked(db.addressRepo.upsertAddress).mockResolvedValue(5); // New address ID is 5
|
||||
vi.mocked(db.userRepo.updateUserProfile).mockResolvedValue({} as any);
|
||||
vi.mocked(db.userRepo.updateUserProfile).mockResolvedValue({ ...mockUserProfile, address_id: 5 });
|
||||
|
||||
const response = await supertest(appWithUser)
|
||||
.put('/api/users/profile/address')
|
||||
|
||||
Reference in New Issue
Block a user