import { jest } from '@jest/globals'; import { testDb } from '../../db/__tests__/setup'; import { resolvers } from '../resolvers'; import { GroupRepository, TaskRepository, StepRepository, UserRepository, NoteRepository, PrintHistoryRepository, ImageRepository } from '../../db/repositories'; import type { Printer, Group, Task, Step, Note, PrintHistory, User, Image } from '@shared/index'; describe('GraphQL Resolvers', () => { const context = { db: testDb, printer: { printTask: jest.fn(), printStep: jest.fn(), } as unknown as Printer, }; const groupRepo = new GroupRepository(testDb); const taskRepo = new TaskRepository(testDb); const stepRepo = new StepRepository(testDb); const userRepo = new UserRepository(testDb); const noteRepo = new NoteRepository(testDb); const printHistoryRepo = new PrintHistoryRepository(testDb); const imageRepo = new ImageRepository(testDb); beforeEach(async () => { await testDb('print_history').del(); await testDb('notes').del(); await testDb('images').del(); await testDb('steps').del(); await testDb('tasks').del(); await testDb('groups').del(); await testDb('users').del(); }); describe('Queries', () => { describe('groups', () => { it('should return all groups', async () => { await groupRepo.create({ name: 'Group 1' }); await groupRepo.create({ name: 'Group 2' }); const result = await resolvers.Query.groups(null, {}, context) as Group[]; expect(result).toHaveLength(2); expect(result[0].name).toBe('Group 1'); expect(result[1].name).toBe('Group 2'); }); }); describe('group', () => { it('should return a group by id', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const result = await resolvers.Query.group(null, { id: group.id.toString() }, context) as Group; expect(result.name).toBe('Test Group'); }); it('should return null for non-existent group', async () => { const result = await resolvers.Query.group(null, { id: '999' }, context); expect(result).toBeNull(); }); }); describe('tasks', () => { it('should return tasks for a group', async () => { const group = await groupRepo.create({ name: 'Test Group' }); await taskRepo.create({ name: 'Task 1', group_id: group.id, print_count: 0 }); await taskRepo.create({ name: 'Task 2', group_id: group.id, print_count: 0 }); const result = await resolvers.Query.tasks(null, { groupId: group.id.toString() }, context) as Task[]; expect(result).toHaveLength(2); expect(result[0].name).toBe('Task 1'); expect(result[1].name).toBe('Task 2'); }); }); describe('task', () => { it('should return a task by id', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const result = await resolvers.Query.task(null, { id: task.id.toString() }, context) as Task; expect(result.name).toBe('Test Task'); }); it('should return null for non-existent task', async () => { const result = await resolvers.Query.task(null, { id: '999' }, context); expect(result).toBeNull(); }); }); describe('steps', () => { it('should return steps for a task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); await stepRepo.create({ name: 'Step 1', instructions: 'Instructions 1', task_id: task.id, order: 1, print_count: 0 }); await stepRepo.create({ name: 'Step 2', instructions: 'Instructions 2', task_id: task.id, order: 2, print_count: 0 }); const result = await resolvers.Query.steps(null, { taskId: task.id.toString() }, context) as Step[]; expect(result).toHaveLength(2); expect(result[0].name).toBe('Step 1'); expect(result[1].name).toBe('Step 2'); }); }); describe('step', () => { it('should return a step by id', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const result = await resolvers.Query.step(null, { id: step.id.toString() }, context) as Step; expect(result.name).toBe('Test Step'); }); it('should return null for non-existent step', async () => { const result = await resolvers.Query.step(null, { id: '999' }, context); expect(result).toBeNull(); }); }); describe('notes', () => { it('should return notes for a task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); await noteRepo.create({ content: 'Note 1', task_id: task.id, created_by: user.id }); await noteRepo.create({ content: 'Note 2', task_id: task.id, created_by: user.id }); const result = await resolvers.Query.notes(null, { taskId: task.id.toString() }, context) as Note[]; expect(result).toHaveLength(2); expect(result[0].content).toBe('Note 1'); expect(result[1].content).toBe('Note 2'); }); it('should return notes for a step', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); await noteRepo.create({ content: 'Note 1', step_id: step.id, created_by: user.id }); await noteRepo.create({ content: 'Note 2', step_id: step.id, created_by: user.id }); const result = await resolvers.Query.notes(null, { stepId: step.id.toString() }, context) as Note[]; expect(result).toHaveLength(2); expect(result[0].content).toBe('Note 1'); expect(result[1].content).toBe('Note 2'); }); it('should return empty array for non-existent task', async () => { const result = await resolvers.Query.notes(null, { taskId: '999' }, context) as Note[]; expect(result).toHaveLength(0); }); it('should return empty array for non-existent step', async () => { const result = await resolvers.Query.notes(null, { stepId: '999' }, context) as Note[]; expect(result).toHaveLength(0); }); }); describe('printHistory', () => { it('should return print history for a task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); await printHistoryRepo.create({ user_id: user.id, task_id: task.id, printed_at: new Date(), }); await printHistoryRepo.create({ user_id: user.id, task_id: task.id, printed_at: new Date(), }); const result = await resolvers.Query.printHistory(null, { taskId: task.id.toString() }, context) as PrintHistory[]; expect(result).toHaveLength(2); }); it('should return print history for a step', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); await printHistoryRepo.create({ user_id: user.id, step_id: step.id, printed_at: new Date(), }); await printHistoryRepo.create({ user_id: user.id, step_id: step.id, printed_at: new Date(), }); const result = await resolvers.Query.printHistory(null, { stepId: step.id.toString() }, context) as PrintHistory[]; expect(result).toHaveLength(2); }); it('should return empty array for non-existent task', async () => { const result = await resolvers.Query.printHistory(null, { taskId: '999' }, context) as PrintHistory[]; expect(result).toHaveLength(0); }); it('should return empty array for non-existent step', async () => { const result = await resolvers.Query.printHistory(null, { stepId: '999' }, context) as PrintHistory[]; expect(result).toHaveLength(0); }); }); describe('recentTasks', () => { it('should return recent tasks', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const oldTimestamp = new Date('2020-01-01T00:00:00.000Z'); const newTimestamp = new Date('2021-01-01T00:00:00.000Z'); await taskRepo.create({ name: 'Old Task', group_id: group.id, print_count: 0, created_at: oldTimestamp, updated_at: oldTimestamp }); await taskRepo.create({ name: 'New Task', group_id: group.id, print_count: 0, created_at: newTimestamp, updated_at: newTimestamp }); const result = await resolvers.Query.recentTasks(null, {}, context) as Task[]; expect(result.length).toBeGreaterThanOrEqual(2); expect(result[0].name).toBe('New Task'); expect(result[1].name).toBe('Old Task'); }); }); describe('frequentTasks', () => { it('should return frequent tasks', async () => { const group = await groupRepo.create({ name: 'Test Group' }); await taskRepo.create({ name: 'Less Frequent', group_id: group.id, print_count: 1 }); await taskRepo.create({ name: 'More Frequent', group_id: group.id, print_count: 10 }); const result = await resolvers.Query.frequentTasks(null, {}, context) as Task[]; expect(result.length).toBeGreaterThanOrEqual(2); expect(result[0].name).toBe('More Frequent'); }); }); }); describe('Mutations', () => { describe('createGroup', () => { it('should create a group', async () => { const result = await resolvers.Mutation.createGroup(null, { name: 'Test Group' }, context) as Group; expect(result.name).toBe('Test Group'); }); it('should create a child group', async () => { const parent = await groupRepo.create({ name: 'Parent Group' }); const result = await resolvers.Mutation.createGroup(null, { name: 'Child Group', parentId: parent.id.toString() }, context) as Group; expect(result.name).toBe('Child Group'); expect(result.parent_id).toBe(parent.id); }); }); describe('createTask', () => { it('should create a task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const result = await resolvers.Mutation.createTask(null, { name: 'Test Task', groupId: group.id.toString() }, context) as Task; expect(result.name).toBe('Test Task'); expect(result.group_id).toBe(group.id); }); }); describe('createStep', () => { it('should create a step', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const result = await resolvers.Mutation.createStep( null, { name: 'Test Step', instructions: 'Test Instructions', taskId: task.id.toString(), order: 1 }, context ) as Step; expect(result.name).toBe('Test Step'); expect(result.task_id).toBe(task.id); }); }); describe('createImage', () => { it('should create an image', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const result = await resolvers.Mutation.createImage( null, { stepId: step.id.toString(), originalPath: '/path/to/image.jpg', bwPath: '/path/to/image.bw.jpg', order: 1 }, context ) as Image; expect(result.original_path).toBe('/path/to/image.jpg'); expect(result.bw_path).toBe('/path/to/image.bw.jpg'); expect(result.step_id).toBe(step.id); }); }); describe('createUser', () => { it('should create a user', async () => { const result = await resolvers.Mutation.createUser(null, { name: 'Test User' }, context) as User; expect(result.name).toBe('Test User'); }); }); describe('createNote', () => { it('should create a note for a task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const result = await resolvers.Mutation.createNote( null, { content: 'Test Note', taskId: task.id.toString(), userId: user.id.toString() }, context ) as Note; expect(result.content).toBe('Test Note'); expect(result.task_id).toBe(task.id); expect(result.created_by).toBe(user.id); }); it('should create a note for a step', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const result = await resolvers.Mutation.createNote( null, { content: 'Test Note', stepId: step.id.toString(), userId: user.id.toString() }, context ) as Note; expect(result.content).toBe('Test Note'); expect(result.step_id).toBe(step.id); expect(result.created_by).toBe(user.id); }); }); describe('printTask', () => { it('should print a task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const result = await resolvers.Mutation.printTask(null, { id: task.id.toString(), userId: user.id.toString() }, context) as Task; expect(result && result.print_count).toBe(1); expect(result && result.last_printed_at).toBeDefined(); }); }); describe('printStep', () => { it('should print a step', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const result = await resolvers.Mutation.printStep(null, { id: step.id.toString(), userId: user.id.toString() }, context) as Step; expect(result && result.print_count).toBe(1); expect(result && result.last_printed_at).toBeDefined(); }); }); }); describe('Field Resolvers', () => { describe('Group', () => { it('should resolve tasks', async () => { const group = await groupRepo.create({ name: 'Test Group' }); await taskRepo.create({ name: 'Task 1', group_id: group.id, print_count: 0 }); await taskRepo.create({ name: 'Task 2', group_id: group.id, print_count: 0 }); const result = await resolvers.Group.tasks(group, {}, context) as Task[]; expect(result).toHaveLength(2); expect(result[0].name).toBe('Task 1'); expect(result[1].name).toBe('Task 2'); }); }); describe('Task', () => { it('should resolve group', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const result = await resolvers.Task.group(task, {}, context) as Group; expect(result.name).toBe('Test Group'); }); it('should resolve steps', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); await stepRepo.create({ name: 'Step 1', instructions: 'Test', task_id: task.id, order: 1, print_count: 0 }); await stepRepo.create({ name: 'Step 2', instructions: 'Test', task_id: task.id, order: 2, print_count: 0 }); const result = await resolvers.Task.steps(task, {}, context) as Step[]; expect(result).toHaveLength(2); expect(result[0].name).toBe('Step 1'); expect(result[1].name).toBe('Step 2'); }); it('should resolve notes', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); await noteRepo.create({ content: 'Note 1', task_id: task.id, created_by: user.id }); await noteRepo.create({ content: 'Note 2', task_id: task.id, created_by: user.id }); const result = await resolvers.Task.notes(task, {}, context) as Note[]; expect(result).toHaveLength(2); expect(result[0].content).toBe('Note 1'); expect(result[1].content).toBe('Note 2'); }); }); describe('Step', () => { it('should resolve task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const result = await resolvers.Step.task(step, {}, context) as Task; expect(result.name).toBe('Test Task'); }); it('should resolve images', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); await imageRepo.create({ step_id: step.id, original_path: '/path/to/original1.jpg', bw_path: '/path/to/bw1.jpg', order: 1 }); await imageRepo.create({ step_id: step.id, original_path: '/path/to/original2.jpg', bw_path: '/path/to/bw2.jpg', order: 2 }); const result = await resolvers.Step.images(step, {}, context) as Image[]; expect(result).toHaveLength(2); expect(result[0].original_path).toBe('/path/to/original1.jpg'); expect(result[1].original_path).toBe('/path/to/original2.jpg'); }); it('should resolve notes', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); await noteRepo.create({ content: 'Note 1', step_id: step.id, created_by: user.id }); await noteRepo.create({ content: 'Note 2', step_id: step.id, created_by: user.id }); const result = await resolvers.Step.notes(step, {}, context) as Note[]; expect(result).toHaveLength(2); expect(result[0].content).toBe('Note 1'); expect(result[1].content).toBe('Note 2'); }); }); describe('Note', () => { it('should resolve createdBy', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const note = await noteRepo.create({ content: 'Test Note', task_id: task.id, created_by: user.id }); const result = await resolvers.Note.createdBy(note, {}, context) as User; expect(result.name).toBe('Test User'); }); }); describe('PrintHistory', () => { it('should resolve user', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const history = await printHistoryRepo.create({ user_id: user.id, task_id: task.id, printed_at: new Date(), }); const result = await resolvers.PrintHistory.user(history, {}, context) as User; expect(result.name).toBe('Test User'); }); it('should resolve task', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const history = await printHistoryRepo.create({ user_id: user.id, task_id: task.id, printed_at: new Date(), }); const result = await resolvers.PrintHistory.task(history, {}, context) as Task; expect(result.name).toBe('Test Task'); }); it('should resolve step', async () => { const group = await groupRepo.create({ name: 'Test Group' }); const task = await taskRepo.create({ name: 'Test Task', group_id: group.id, print_count: 0 }); const step = await stepRepo.create({ name: 'Test Step', instructions: 'Test Instructions', task_id: task.id, order: 1, print_count: 0 }); const user = await userRepo.create({ name: 'Test User' }); const history = await printHistoryRepo.create({ user_id: user.id, step_id: step.id, printed_at: new Date(), }); const result = await resolvers.PrintHistory.step(history, {}, context) as Step; expect(result.name).toBe('Test Step'); }); }); }); });