172 lines
6.5 KiB
JavaScript
172 lines
6.5 KiB
JavaScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import * as AuthController from '../../src/controllers/auth.controller.js';
|
|
import * as ReviewController from '../../src/controllers/review.controller.js';
|
|
import * as SyncController from '../../src/controllers/sync.controller.js';
|
|
import * as CollectionController from '../../src/controllers/collection.controller.js';
|
|
|
|
import * as AuthService from '../../src/services/auth.service.js';
|
|
import * as ReviewService from '../../src/services/review.service.js';
|
|
import * as SyncService from '../../src/services/sync.service.js';
|
|
import * as StatsService from '../../src/services/stats.service.js';
|
|
import { StudyItem } from '../../src/models/StudyItem.js';
|
|
|
|
vi.mock('../../src/services/auth.service.js');
|
|
vi.mock('../../src/services/review.service.js');
|
|
vi.mock('../../src/services/sync.service.js');
|
|
vi.mock('../../src/services/stats.service.js');
|
|
vi.mock('../../src/models/StudyItem.js');
|
|
|
|
const mockReq = (body = {}, user = {}, query = {}) => ({ body, user, query });
|
|
const mockReply = () => {
|
|
const res = {};
|
|
res.code = vi.fn().mockReturnValue(res);
|
|
res.send = vi.fn().mockReturnValue(res);
|
|
res.jwtSign = vi.fn().mockResolvedValue('token');
|
|
return res;
|
|
};
|
|
|
|
describe('Controllers', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('Auth Controller', () => {
|
|
it('login should fail without apiKey', async () => {
|
|
const reply = mockReply();
|
|
await AuthController.login(mockReq({}), reply);
|
|
expect(reply.code).toHaveBeenCalledWith(400);
|
|
});
|
|
|
|
it('login should succeed', async () => {
|
|
const reply = mockReply();
|
|
AuthService.loginUser.mockResolvedValue({ _id: 1, tokenVersion: 1 });
|
|
await AuthController.login(mockReq({ apiKey: 'key' }), reply);
|
|
expect(reply.jwtSign).toHaveBeenCalled();
|
|
expect(reply.code).not.toHaveBeenCalledWith(401);
|
|
});
|
|
|
|
it('login should catch errors', async () => {
|
|
const reply = mockReply();
|
|
AuthService.loginUser.mockRejectedValue(new Error('fail'));
|
|
await AuthController.login(mockReq({ apiKey: 'k' }), reply);
|
|
expect(reply.code).toHaveBeenCalledWith(401);
|
|
});
|
|
|
|
it('logout should succeed', async () => {
|
|
const reply = mockReply();
|
|
await AuthController.logout(mockReq({}, { _id: 1 }), reply);
|
|
expect(AuthService.logoutUser).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Review Controller', () => {
|
|
it('submitReview should succeed', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.processReview.mockResolvedValue({});
|
|
await ReviewController.submitReview(mockReq({}), reply);
|
|
expect(reply.send).toHaveBeenCalled();
|
|
});
|
|
|
|
it('submitReview should handle error', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.processReview.mockRejectedValue(new Error('err'));
|
|
await ReviewController.submitReview(mockReq({}), reply);
|
|
expect(reply.code).toHaveBeenCalledWith(404);
|
|
});
|
|
|
|
it('submitLesson should succeed', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.processLesson.mockResolvedValue({ success: true });
|
|
await ReviewController.submitLesson(mockReq({ subjectId: 100 }), reply);
|
|
expect(reply.send).toHaveBeenCalledWith({ success: true });
|
|
});
|
|
|
|
it('submitLesson should handle error', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.processLesson.mockRejectedValue(new Error('Lesson error'));
|
|
await ReviewController.submitLesson(mockReq({ subjectId: 100 }), reply);
|
|
expect(reply.code).toHaveBeenCalledWith(404);
|
|
expect(reply.send).toHaveBeenCalledWith({ error: 'Lesson error' });
|
|
});
|
|
});
|
|
|
|
describe('Sync Controller', () => {
|
|
it('sync should succeed', async () => {
|
|
const reply = mockReply();
|
|
SyncService.syncWithWaniKani.mockResolvedValue({});
|
|
await SyncController.sync(mockReq({}, {}), reply);
|
|
expect(reply.send).toHaveBeenCalled();
|
|
});
|
|
|
|
it('sync should handle error', async () => {
|
|
const reply = mockReply();
|
|
SyncService.syncWithWaniKani.mockRejectedValue(new Error('err'));
|
|
await SyncController.sync(mockReq({}, {}), reply);
|
|
expect(reply.code).toHaveBeenCalledWith(500);
|
|
});
|
|
});
|
|
|
|
describe('Collection Controller', () => {
|
|
it('getCollection should return items', async () => {
|
|
const reply = mockReply();
|
|
StudyItem.find.mockResolvedValue([]);
|
|
await CollectionController.getCollection(mockReq({}, { _id: 1 }), reply);
|
|
expect(reply.send).toHaveBeenCalledWith([]);
|
|
});
|
|
|
|
it('getQueue should call service with default limit', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.getQueue.mockResolvedValue([]);
|
|
await CollectionController.getQueue(mockReq({}, {}, {}), reply);
|
|
expect(ReviewService.getQueue).toHaveBeenCalledWith(expect.anything(), 20, undefined);
|
|
});
|
|
|
|
it('getQueue should call service with provided limit', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.getQueue.mockResolvedValue([]);
|
|
await CollectionController.getQueue(mockReq({}, {}, { limit: '50' }), reply);
|
|
expect(ReviewService.getQueue).toHaveBeenCalledWith(expect.anything(), 50, undefined);
|
|
});
|
|
|
|
it('getLessonQueue should call service with explicit limit', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.getLessonQueue.mockResolvedValue([]);
|
|
await CollectionController.getLessonQueue(mockReq({}, {}, { limit: '10' }), reply);
|
|
expect(ReviewService.getLessonQueue).toHaveBeenCalledWith(expect.anything(), 10);
|
|
});
|
|
|
|
it('getLessonQueue should use default limit when none provided', async () => {
|
|
const reply = mockReply();
|
|
ReviewService.getLessonQueue.mockResolvedValue([]);
|
|
await CollectionController.getLessonQueue(mockReq({}, {}, {}), reply);
|
|
expect(ReviewService.getLessonQueue).toHaveBeenCalledWith(expect.anything(), 10);
|
|
});
|
|
|
|
it('getStats should call service', async () => {
|
|
const reply = mockReply();
|
|
StatsService.getUserStats.mockResolvedValue({});
|
|
await CollectionController.getStats(mockReq({}, {}), reply);
|
|
expect(StatsService.getUserStats).toHaveBeenCalled();
|
|
});
|
|
|
|
it('updateSettings should initialize settings if missing', async () => {
|
|
const reply = mockReply();
|
|
const save = vi.fn();
|
|
const user = { save };
|
|
await CollectionController.updateSettings(mockReq({ batchSize: 50 }, user), reply);
|
|
expect(user.settings).toBeDefined();
|
|
expect(user.settings.batchSize).toBe(50);
|
|
expect(save).toHaveBeenCalled();
|
|
});
|
|
|
|
it('updateSettings should update drawingAccuracy', async () => {
|
|
const reply = mockReply();
|
|
const save = vi.fn();
|
|
const user = { settings: {}, save };
|
|
await CollectionController.updateSettings(mockReq({ drawingAccuracy: 5 }, user), reply);
|
|
expect(user.settings.drawingAccuracy).toBe(5);
|
|
expect(save).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|