diff --git a/src/__tests__/project.model.test.js b/src/__tests__/project.model.test.js new file mode 100644 index 0000000..1520b36 --- /dev/null +++ b/src/__tests__/project.model.test.js @@ -0,0 +1,84 @@ +const mongoose = require('mongoose'); +const Project = require('../models/Project.model'); + +describe('Project model schema', () => { + const ownerId = new mongoose.Types.ObjectId(); + + it('saves with required fields and correct defaults', () => { + const project = new Project({ title: 'Clean Water Fund', goalAmount: 5000, owner: ownerId }); + + expect(project.title).toBe('Clean Water Fund'); + expect(project.goalAmount).toBe(5000); + expect(project.raisedAmount).toBe(0); + expect(project.currency).toBe('XLM'); + expect(project.status).toBe('draft'); + expect(project.documents).toEqual([]); + }); + + it('rejects invalid status enum', () => { + const project = new Project({ title: 'Test', goalAmount: 100, owner: ownerId, status: 'unknown' }); + const err = project.validateSync(); + expect(err.errors.status).toBeDefined(); + }); + + it('requires title', () => { + const project = new Project({ goalAmount: 100, owner: ownerId }); + const err = project.validateSync(); + expect(err.errors.title).toBeDefined(); + }); + + it('requires owner', () => { + const project = new Project({ title: 'Test', goalAmount: 100 }); + const err = project.validateSync(); + expect(err.errors.owner).toBeDefined(); + }); + + it('requires goalAmount', () => { + const project = new Project({ title: 'Test', owner: ownerId }); + const err = project.validateSync(); + expect(err.errors.goalAmount).toBeDefined(); + }); + + it('accepts all status enum values', () => { + for (const status of ['draft', 'pending', 'active', 'rejected', 'completed']) { + const project = new Project({ title: 'T', goalAmount: 1, owner: ownerId, status }); + expect(project.validateSync()).toBeUndefined(); + } + }); + + it('accepts optional fields', () => { + const project = new Project({ + title: 'Solar Initiative', + goalAmount: 10000, + owner: ownerId, + category: 'Energy', + currency: 'USDC', + stellarAddress: 'GABC123', + coverImage: 'https://example.com/cover.jpg', + startDate: new Date('2026-01-01'), + endDate: new Date('2026-12-31'), + documents: [ + { + originalName: 'plan.pdf', + filename: 'plan-stored.pdf', + mimetype: 'application/pdf', + size: 1024, + url: '/uploads/plan-stored.pdf', + }, + ], + }); + + expect(project.category).toBe('Energy'); + expect(project.currency).toBe('USDC'); + expect(project.stellarAddress).toBe('GABC123'); + expect(project.documents).toHaveLength(1); + expect(project.documents[0].originalName).toBe('plan.pdf'); + }); + + it('has indexes on status and owner', () => { + const indexes = Project.schema.indexes(); + const keys = indexes.map(([fields]) => Object.keys(fields).join(',')); + expect(keys).toContain('status'); + expect(keys).toContain('owner'); + }); +}); diff --git a/src/models/Project.model.js b/src/models/Project.model.js index 73c9ecf..6962112 100644 --- a/src/models/Project.model.js +++ b/src/models/Project.model.js @@ -3,18 +3,18 @@ const mongoose = require('mongoose'); const documentSchema = new mongoose.Schema( { originalName: { type: String, required: true }, - filename: { type: String, required: true }, // stored name on disk - mimetype: { type: String, required: true }, - size: { type: Number, required: true }, // bytes - url: { type: String, required: true }, // public URL path - uploadedAt: { type: Date, default: Date.now }, + filename: { type: String, required: true }, + mimetype: { type: String, required: true }, + size: { type: Number, required: true }, + url: { type: String, required: true }, + uploadedAt: { type: Date, default: Date.now }, }, { _id: true } ); const projectSchema = new mongoose.Schema( { - title: { type: String, required: true, trim: true }, + title: { type: String, required: true, trim: true }, description: { type: String, trim: true }, owner: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, isActive: { type: Boolean, default: true }, @@ -25,4 +25,7 @@ const projectSchema = new mongoose.Schema( { timestamps: true } ); -module.exports = mongoose.model('Project', projectSchema); \ No newline at end of file +projectSchema.index({ status: 1 }); +projectSchema.index({ owner: 1 }); + +module.exports = mongoose.model('Project', projectSchema);