Files
adopt-a-street/backend/__tests__/models/Comment.test.js
William Valentin 32bddbd1d1 fix: update Comment and Reward tests to use local mocks and proper validation
- Fixed Comment.test.js to use local mocks instead of global mocks
- Updated Comment tests to match new model structure (user.userId, post.postId)
- Fixed Reward.test.js to use local mocks instead of global mocks
- Updated Reward validation tests to expect ValidationError exceptions
- All Phase 2 models now have 100% passing tests:
  - Event.js: 19/19 tests passing
  - Reward.js: 22/22 tests passing
  - Comment.js: 16/16 tests passing

🤖 Generated with [AI Assistant]

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
2025-11-03 10:07:33 -08:00

449 lines
15 KiB
JavaScript

// Mock CouchDB service for testing
const mockCouchdbService = {
findUserById: jest.fn(),
getById: jest.fn(),
createDocument: jest.fn(),
updateDocument: jest.fn(),
findByType: jest.fn(),
find: jest.fn(),
deleteDocument: jest.fn(),
updatePost: jest.fn(),
initialize: jest.fn(),
isReady: jest.fn().mockReturnValue(true),
shutdown: jest.fn()
};
// Mock the service module
jest.mock('../../services/couchdbService', () => mockCouchdbService);
const Comment = require('../../models/Comment');
describe('Comment Model', () => {
beforeEach(() => {
jest.clearAllMocks();
// Reset all mocks to ensure clean state
mockCouchdbService.findUserById.mockReset();
mockCouchdbService.getById.mockReset();
mockCouchdbService.createDocument.mockReset();
mockCouchdbService.updateDocument.mockReset();
mockCouchdbService.findByType.mockReset();
mockCouchdbService.find.mockReset();
mockCouchdbService.deleteDocument.mockReset();
mockCouchdbService.updatePost.mockReset();
});
describe('Schema Validation', () => {
it('should create a valid comment', async () => {
const commentData = {
user: 'user_123',
post: 'post_123',
content: 'This is a great post!',
};
const mockUser = {
_id: 'user_123',
name: 'Test User',
profilePicture: ''
};
const mockPost = {
_id: 'post_123',
content: 'Test post content',
user: { userId: 'user_123' },
commentsCount: 0
};
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: {
userId: 'user_123',
name: 'Test User',
profilePicture: ''
},
post: {
postId: 'post_123',
content: 'Test post content',
userId: 'user_123'
},
content: 'This is a great post!',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment._id).toBeDefined();
expect(comment.user.userId).toBe('user_123');
expect(comment.post.postId).toBe('post_123');
expect(comment.content).toBe('This is a great post!');
});
it('should require post field', async () => {
const commentData = {
user: { userId: 'user_123' },
content: 'Comment without post',
};
expect(() => new Comment(commentData)).toThrow();
});
it('should require user field', async () => {
const commentData = {
post: { postId: 'post_123' },
content: 'Comment without user',
};
expect(() => new Comment(commentData)).toThrow();
});
it('should require content field', async () => {
const commentData = {
post: { postId: 'post_123' },
user: { userId: 'user_123' },
};
expect(() => new Comment(commentData)).toThrow();
});
});
describe('Content Validation', () => {
it('should trim content', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: ' This comment has spaces ',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'This comment has spaces',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.content).toBe('This comment has spaces');
});
it('should allow long comments', async () => {
const longContent = 'a'.repeat(400); // Within 500 character limit
const commentData = {
post: 'post_123',
user: 'user_123',
content: longContent,
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: longContent,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.content).toBe(longContent);
});
it('should reject empty content after trimming', async () => {
const commentData = {
post: { postId: 'post_123' },
user: { userId: 'user_123' },
content: ' ', // Only spaces
};
expect(() => new Comment(commentData)).toThrow();
});
});
describe('Basic Properties', () => {
it('should create comment with basic properties', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: 'Basic comment',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'Basic comment',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment._id).toBeDefined();
expect(comment.type).toBe('comment');
expect(comment.content).toBe('Basic comment');
});
});
describe('Relationships', () => {
it('should reference post ID', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: 'Comment on specific post',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'Comment on specific post',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.post.postId).toBe('post_123');
});
it('should reference user ID', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: 'Comment by specific user',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'Comment by specific user',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.user.userId).toBe('user_123');
});
});
describe('Timestamps', () => {
it('should automatically set createdAt and updatedAt', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: 'Timestamp test comment',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'Timestamp test comment',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.createdAt).toBeDefined();
expect(comment.updatedAt).toBeDefined();
expect(typeof comment.createdAt).toBe('string');
expect(typeof comment.updatedAt).toBe('string');
});
it('should update updatedAt on modification', async () => {
const mockComment = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'Update test comment',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.getById.mockResolvedValue(mockComment);
mockCouchdbService.updateDocument.mockResolvedValue({
...mockComment,
content: 'Updated comment content',
_rev: '2-def',
updatedAt: '2023-01-01T00:00:01.000Z'
});
const comment = await Comment.findById('comment_123');
const originalUpdatedAt = comment.updatedAt;
comment.content = 'Updated comment content';
await comment.save();
expect(comment.updatedAt).not.toBe(originalUpdatedAt);
});
});
describe('Content Edge Cases', () => {
it('should handle special characters in content', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: 'This comment has émojis 🎉 and spëcial charactërs!',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'This comment has émojis 🎉 and spëcial charactërs!',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.content).toBe('This comment has émojis 🎉 and spëcial charactërs!');
});
it('should handle newlines in content', async () => {
const commentData = {
post: 'post_123',
user: 'user_123',
content: 'This comment\nhas\nmultiple\nlines',
};
const mockUser = { _id: 'user_123', name: 'Test User' };
const mockPost = { _id: 'post_123', content: 'Test post', user: { userId: 'user_123' } };
const mockCreated = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'This comment\nhas\nmultiple\nlines',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.findUserById.mockResolvedValue(mockUser);
mockCouchdbService.getById.mockResolvedValue(mockPost);
mockCouchdbService.createDocument.mockResolvedValue(mockCreated);
mockCouchdbService.updatePost.mockResolvedValue(mockPost);
const comment = await Comment.create(commentData);
expect(comment.content).toBe('This comment\nhas\nmultiple\nlines');
});
});
describe('Static Methods', () => {
it('should find comment by ID', async () => {
const mockComment = {
_id: 'comment_123',
_rev: '1-abc',
type: 'comment',
user: { userId: 'user_123', name: 'Test User' },
post: { postId: 'post_123', content: 'Test post', userId: 'user_123' },
content: 'Test comment',
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z'
};
mockCouchdbService.getById.mockResolvedValue(mockComment);
const comment = await Comment.findById('comment_123');
expect(comment).toBeDefined();
expect(comment._id).toBe('comment_123');
expect(comment.content).toBe('Test comment');
});
it('should return null when comment not found', async () => {
mockCouchdbService.getById.mockResolvedValue(null);
const comment = await Comment.findById('nonexistent');
expect(comment).toBeNull();
});
});
});