Files
adopt-a-street/backend/__tests__/models/Street.test.js
William Valentin 17e5c90a90 test(backend): add comprehensive testing infrastructure
Implement complete backend testing infrastructure with Jest and Supertest:

Test Setup:
- Configure Jest for Node.js environment
- Add MongoDB Memory Server for isolated testing
- Create test setup with database connection helpers
- Add test scripts: test, test:coverage, test:watch

Test Files (176 total tests, 109 passing):
- Middleware tests: auth.test.js (100% coverage)
- Model tests: User, Street, Task, Post (82.5% coverage)
- Route tests: auth, streets, tasks, posts, events, rewards, reports

Test Coverage:
- Overall: 54.75% (on track for 70% target)
- Models: 82.5%
- Middleware: 100%
- Routes: 45.84%

Test Utilities:
- Helper functions for creating test users, streets, tasks, posts
- Test database setup and teardown
- MongoDB Memory Server configuration
- Coverage reporting with lcov

Testing Features:
- Isolated test environment (no production data pollution)
- Async/await test patterns
- Proper setup/teardown for each test
- Authentication testing with JWT tokens
- Validation testing for all routes
- Error handling verification

Scripts:
- Database seeding scripts for development
- Test data generation utilities

Dependencies:
- jest@29.7.0
- supertest@7.0.0
- mongodb-memory-server@10.1.2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 10:43:20 -07:00

348 lines
9.2 KiB
JavaScript

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);
}
});
});
});