const Task = require('../../models/Task'); const User = require('../../models/User'); const Street = require('../../models/Street'); const mongoose = require('mongoose'); describe('Task Model', () => { let user; let street; beforeEach(async () => { user = await User.create({ name: 'Test User', email: 'test@example.com', password: 'password123', }); street = await Street.create({ name: 'Test Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'Test City', state: 'TS', adoptedBy: user._id, }); }); describe('Schema Validation', () => { it('should create a valid task', async () => { const taskData = { street: street._id, description: 'Clean up litter on the street', type: 'cleaning', createdBy: user._id, status: 'pending', }; const task = new Task(taskData); const savedTask = await task.save(); expect(savedTask._id).toBeDefined(); expect(savedTask.description).toBe(taskData.description); expect(savedTask.type).toBe(taskData.type); expect(savedTask.status).toBe(taskData.status); expect(savedTask.street.toString()).toBe(street._id.toString()); expect(savedTask.createdBy.toString()).toBe(user._id.toString()); }); it('should require street field', async () => { const task = new Task({ description: 'Task without street', type: 'cleaning', createdBy: user._id, }); let error; try { await task.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.street).toBeDefined(); }); it('should require description field', async () => { const task = new Task({ street: street._id, type: 'cleaning', createdBy: user._id, }); let error; try { await task.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.description).toBeDefined(); }); it('should require type field', async () => { const task = new Task({ street: street._id, description: 'Task without type', createdBy: user._id, }); let error; try { await task.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.type).toBeDefined(); }); it('should require createdBy field', async () => { const task = new Task({ street: street._id, description: 'Task without creator', type: 'cleaning', }); let error; try { await task.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.createdBy).toBeDefined(); }); }); describe('Task Types', () => { const validTypes = ['cleaning', 'repair', 'maintenance', 'planting', 'other']; validTypes.forEach(type => { it(`should accept "${type}" as valid type`, async () => { const task = await Task.create({ street: street._id, description: `${type} task`, type, createdBy: user._id, }); expect(task.type).toBe(type); }); }); it('should reject invalid task type', async () => { const task = new Task({ street: street._id, description: 'Invalid type task', type: 'invalid_type', createdBy: user._id, }); let error; try { await task.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.type).toBeDefined(); }); }); describe('Task Status', () => { it('should default status to pending', async () => { const task = await Task.create({ street: street._id, description: 'Default status task', type: 'cleaning', createdBy: user._id, }); expect(task.status).toBe('pending'); }); const validStatuses = ['pending', 'in-progress', 'completed', 'cancelled']; validStatuses.forEach(status => { it(`should accept "${status}" as valid status`, async () => { const task = await Task.create({ street: street._id, description: `Task with ${status} status`, type: 'cleaning', createdBy: user._id, status, }); expect(task.status).toBe(status); }); }); it('should reject invalid status', async () => { const task = new Task({ street: street._id, description: 'Invalid status task', type: 'cleaning', createdBy: user._id, status: 'invalid_status', }); let error; try { await task.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.status).toBeDefined(); }); }); describe('Task Assignment', () => { it('should allow assigning task to a user', async () => { const assignee = await User.create({ name: 'Assignee', email: 'assignee@example.com', password: 'password123', }); const task = await Task.create({ street: street._id, description: 'Assigned task', type: 'cleaning', createdBy: user._id, assignedTo: assignee._id, }); expect(task.assignedTo.toString()).toBe(assignee._id.toString()); }); it('should allow task without assignment', async () => { const task = await Task.create({ street: street._id, description: 'Unassigned task', type: 'cleaning', createdBy: user._id, }); expect(task.assignedTo).toBeUndefined(); }); }); describe('Due Date', () => { it('should allow setting due date', async () => { const dueDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days from now const task = await Task.create({ street: street._id, description: 'Task with due date', type: 'cleaning', createdBy: user._id, dueDate, }); expect(task.dueDate).toBeDefined(); expect(task.dueDate.getTime()).toBe(dueDate.getTime()); }); it('should allow task without due date', async () => { const task = await Task.create({ street: street._id, description: 'Task without due date', type: 'cleaning', createdBy: user._id, }); expect(task.dueDate).toBeUndefined(); }); }); describe('Completion Date', () => { it('should allow setting completion date', async () => { const completionDate = new Date(); const task = await Task.create({ street: street._id, description: 'Completed task', type: 'cleaning', createdBy: user._id, status: 'completed', completionDate, }); expect(task.completionDate).toBeDefined(); expect(task.completionDate.getTime()).toBe(completionDate.getTime()); }); it('should allow pending task without completion date', async () => { const task = await Task.create({ street: street._id, description: 'Pending task', type: 'cleaning', createdBy: user._id, status: 'pending', }); expect(task.completionDate).toBeUndefined(); }); }); describe('Priority', () => { it('should allow setting task priority', async () => { const task = await Task.create({ street: street._id, description: 'High priority task', type: 'repair', createdBy: user._id, priority: 'high', }); expect(task.priority).toBe('high'); }); }); describe('Timestamps', () => { it('should automatically set createdAt and updatedAt', async () => { const task = await Task.create({ street: street._id, description: 'Timestamp task', type: 'cleaning', createdBy: user._id, }); expect(task.createdAt).toBeDefined(); expect(task.updatedAt).toBeDefined(); expect(task.createdAt).toBeInstanceOf(Date); expect(task.updatedAt).toBeInstanceOf(Date); }); it('should update updatedAt on modification', async () => { const task = await Task.create({ street: street._id, description: 'Update test task', type: 'cleaning', createdBy: user._id, }); const originalUpdatedAt = task.updatedAt; // Wait a bit to ensure timestamp difference await new Promise(resolve => setTimeout(resolve, 10)); task.status = 'completed'; await task.save(); expect(task.updatedAt.getTime()).toBeGreaterThan(originalUpdatedAt.getTime()); }); }); describe('Relationships', () => { it('should reference Street model', async () => { const task = await Task.create({ street: street._id, description: 'Street relationship task', type: 'cleaning', createdBy: user._id, }); const populatedTask = await Task.findById(task._id).populate('street'); expect(populatedTask.street).toBeDefined(); expect(populatedTask.street.name).toBe('Test Street'); }); it('should reference User model for createdBy', async () => { const task = await Task.create({ street: street._id, description: 'Creator relationship task', type: 'cleaning', createdBy: user._id, }); const populatedTask = await Task.findById(task._id).populate('createdBy'); expect(populatedTask.createdBy).toBeDefined(); expect(populatedTask.createdBy.name).toBe('Test User'); }); it('should reference User model for assignedTo', async () => { const assignee = await User.create({ name: 'Assignee', email: 'assignee@example.com', password: 'password123', }); const task = await Task.create({ street: street._id, description: 'Assignment relationship task', type: 'cleaning', createdBy: user._id, assignedTo: assignee._id, }); const populatedTask = await Task.findById(task._id).populate('assignedTo'); expect(populatedTask.assignedTo).toBeDefined(); expect(populatedTask.assignedTo.name).toBe('Assignee'); }); }); describe('Description Length', () => { it('should enforce maximum description length', async () => { const longDescription = 'a'.repeat(1001); // Assuming 1000 char limit const task = new Task({ street: street._id, description: longDescription, type: 'cleaning', createdBy: user._id, }); let error; try { await task.save(); } catch (err) { error = err; } // This test will pass if there's a maxlength validation, otherwise it will create the task if (error) { expect(error.errors.description).toBeDefined(); } else { // If no max length is enforced, the task should still save expect(task.description).toBe(longDescription); } }); }); });