const Street = require('../../models/Street'); const User = require('../../models/User'); const mongoose = require('mongoose'); describe('Street Model', () => { describe('Schema Validation', () => { it('should create a valid street', async () => { const user = await User.create({ name: 'Test User', email: 'test@example.com', password: 'password123', }); const streetData = { name: 'Main Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, }; const street = new Street(streetData); const savedStreet = await street.save(); expect(savedStreet._id).toBeDefined(); expect(savedStreet.name).toBe(streetData.name); expect(savedStreet.city).toBe(streetData.city); expect(savedStreet.state).toBe(streetData.state); expect(savedStreet.adoptedBy.toString()).toBe(user._id.toString()); expect(savedStreet.location.type).toBe('Point'); expect(savedStreet.location.coordinates).toEqual(streetData.location.coordinates); }); it('should require name field', async () => { const user = await User.create({ name: 'Test User', email: 'test@example.com', password: 'password123', }); const street = new Street({ location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, }); let error; try { await street.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.name).toBeDefined(); }); it('should require location field', async () => { const user = await User.create({ name: 'Test User', email: 'test@example.com', password: 'password123', }); const street = new Street({ name: 'Main Street', city: 'New York', state: 'NY', adoptedBy: user._id, }); let error; try { await street.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.location).toBeDefined(); }); it('should require adoptedBy field', async () => { const street = new Street({ name: 'Main Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', }); let error; try { await street.save(); } catch (err) { error = err; } expect(error).toBeDefined(); expect(error.errors.adoptedBy).toBeDefined(); }); }); describe('GeoJSON Location', () => { it('should store Point type correctly', async () => { const user = await User.create({ name: 'Test User', email: 'geo@example.com', password: 'password123', }); const street = await Street.create({ name: 'Geo Street', location: { type: 'Point', coordinates: [-122.4194, 37.7749], // San Francisco }, city: 'San Francisco', state: 'CA', adoptedBy: user._id, }); expect(street.location.type).toBe('Point'); expect(street.location.coordinates).toEqual([-122.4194, 37.7749]); expect(street.location.coordinates[0]).toBe(-122.4194); // longitude expect(street.location.coordinates[1]).toBe(37.7749); // latitude }); it('should create 2dsphere index on location', async () => { const indexes = await Street.collection.getIndexes(); const locationIndex = Object.keys(indexes).find(key => indexes[key].some(field => field[0] === 'location') ); expect(locationIndex).toBeDefined(); }); }); describe('Status Field', () => { it('should default status to active', async () => { const user = await User.create({ name: 'Test User', email: 'status@example.com', password: 'password123', }); const street = await Street.create({ name: 'Status Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, }); expect(street.status).toBe('active'); }); it('should allow setting custom status', async () => { const user = await User.create({ name: 'Test User', email: 'custom@example.com', password: 'password123', }); const street = await Street.create({ name: 'Custom Status Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, status: 'inactive', }); expect(street.status).toBe('inactive'); }); }); describe('Timestamps', () => { it('should automatically set createdAt and updatedAt', async () => { const user = await User.create({ name: 'Test User', email: 'timestamp@example.com', password: 'password123', }); const street = await Street.create({ name: 'Timestamp Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, }); expect(street.createdAt).toBeDefined(); expect(street.updatedAt).toBeDefined(); expect(street.createdAt).toBeInstanceOf(Date); expect(street.updatedAt).toBeInstanceOf(Date); }); }); describe('Adoption Date', () => { it('should default adoptionDate to current time', async () => { const user = await User.create({ name: 'Test User', email: 'adoption@example.com', password: 'password123', }); const beforeCreate = new Date(); const street = await Street.create({ name: 'Adoption Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, }); const afterCreate = new Date(); expect(street.adoptionDate).toBeDefined(); expect(street.adoptionDate.getTime()).toBeGreaterThanOrEqual(beforeCreate.getTime()); expect(street.adoptionDate.getTime()).toBeLessThanOrEqual(afterCreate.getTime()); }); it('should allow custom adoption date', async () => { const user = await User.create({ name: 'Test User', email: 'customdate@example.com', password: 'password123', }); const customDate = new Date('2023-01-15'); const street = await Street.create({ name: 'Custom Date Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, adoptionDate: customDate, }); expect(street.adoptionDate.getTime()).toBe(customDate.getTime()); }); }); describe('Relationships', () => { it('should reference User model through adoptedBy', async () => { const user = await User.create({ name: 'Adopter User', email: 'adopter@example.com', password: 'password123', }); const street = await Street.create({ name: 'Relationship Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: user._id, }); const populatedStreet = await Street.findById(street._id).populate('adoptedBy'); expect(populatedStreet.adoptedBy).toBeDefined(); expect(populatedStreet.adoptedBy.name).toBe('Adopter User'); expect(populatedStreet.adoptedBy.email).toBe('adopter@example.com'); }); }); describe('Virtual Properties', () => { it('should support tasks virtual', () => { const street = new Street({ name: 'Test Street', location: { type: 'Point', coordinates: [-73.935242, 40.730610], }, city: 'New York', state: 'NY', adoptedBy: new mongoose.Types.ObjectId(), }); expect(street.schema.virtuals.tasks).toBeDefined(); }); }); describe('Coordinates Format', () => { it('should accept valid longitude and latitude', async () => { const user = await User.create({ name: 'Test User', email: 'coords@example.com', password: 'password123', }); const validCoordinates = [ [-180, -90], // min values [180, 90], // max values [0, 0], // origin [-74.006, 40.7128], // NYC ]; for (const coords of validCoordinates) { const street = await Street.create({ name: `Street at ${coords.join(',')}`, location: { type: 'Point', coordinates: coords, }, city: 'Test City', state: 'TS', adoptedBy: user._id, }); expect(street.location.coordinates).toEqual(coords); } }); }); });