Files
rentall-app/backend/tests/unit/services/s3OwnershipService.test.js
jackiettran 3f319bfdd0 unit tests
2025-12-12 16:27:56 -05:00

255 lines
7.9 KiB
JavaScript

const S3OwnershipService = require('../../../services/s3OwnershipService');
const { Message, ConditionCheck, Rental } = require('../../../models');
jest.mock('../../../models');
describe('S3OwnershipService', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('getFileTypeFromKey', () => {
it('should return "profile" for profiles folder', () => {
expect(S3OwnershipService.getFileTypeFromKey('profiles/uuid.jpg')).toBe('profile');
});
it('should return "item" for items folder', () => {
expect(S3OwnershipService.getFileTypeFromKey('items/uuid.jpg')).toBe('item');
});
it('should return "message" for messages folder', () => {
expect(S3OwnershipService.getFileTypeFromKey('messages/uuid.jpg')).toBe('message');
});
it('should return "forum" for forum folder', () => {
expect(S3OwnershipService.getFileTypeFromKey('forum/uuid.jpg')).toBe('forum');
});
it('should return "condition-check" for condition-checks folder', () => {
expect(S3OwnershipService.getFileTypeFromKey('condition-checks/uuid.jpg')).toBe('condition-check');
});
it('should return null for unknown folder', () => {
expect(S3OwnershipService.getFileTypeFromKey('unknown/uuid.jpg')).toBeNull();
});
it('should return null for null key', () => {
expect(S3OwnershipService.getFileTypeFromKey(null)).toBeNull();
});
it('should return null for undefined key', () => {
expect(S3OwnershipService.getFileTypeFromKey(undefined)).toBeNull();
});
it('should return null for empty string', () => {
expect(S3OwnershipService.getFileTypeFromKey('')).toBeNull();
});
});
describe('canAccessFile', () => {
describe('public folders', () => {
it('should authorize access to profile images for any user', async () => {
const result = await S3OwnershipService.canAccessFile('profiles/uuid.jpg', 'user-123');
expect(result).toEqual({ authorized: true });
});
it('should authorize access to item images for any user', async () => {
const result = await S3OwnershipService.canAccessFile('items/uuid.jpg', 'user-123');
expect(result).toEqual({ authorized: true });
});
it('should authorize access to forum images for any user', async () => {
const result = await S3OwnershipService.canAccessFile('forum/uuid.jpg', 'user-123');
expect(result).toEqual({ authorized: true });
});
});
describe('private folders', () => {
it('should call verifyMessageAccess for message images', async () => {
Message.findOne.mockResolvedValue({ id: 'msg-123' });
const result = await S3OwnershipService.canAccessFile('messages/uuid.jpg', 'user-123');
expect(Message.findOne).toHaveBeenCalled();
expect(result.authorized).toBe(true);
});
it('should call verifyConditionCheckAccess for condition-check images', async () => {
ConditionCheck.findOne.mockResolvedValue({ id: 'check-123' });
const result = await S3OwnershipService.canAccessFile('condition-checks/uuid.jpg', 'user-123');
expect(ConditionCheck.findOne).toHaveBeenCalled();
expect(result.authorized).toBe(true);
});
});
describe('unknown file types', () => {
it('should deny access for unknown folder', async () => {
const result = await S3OwnershipService.canAccessFile('unknown/uuid.jpg', 'user-123');
expect(result).toEqual({
authorized: false,
reason: 'Unknown file type'
});
});
});
});
describe('verifyMessageAccess', () => {
const testKey = 'messages/550e8400-e29b-41d4-a716-446655440000.jpg';
const senderId = 'sender-123';
const receiverId = 'receiver-456';
it('should authorize sender to access message image', async () => {
Message.findOne.mockResolvedValue({
id: 'msg-123',
senderId,
receiverId,
imageFilename: testKey
});
const result = await S3OwnershipService.verifyMessageAccess(testKey, senderId);
expect(result).toEqual({
authorized: true,
reason: null
});
expect(Message.findOne).toHaveBeenCalledWith({
where: expect.objectContaining({
imageFilename: testKey
})
});
});
it('should authorize receiver to access message image', async () => {
Message.findOne.mockResolvedValue({
id: 'msg-123',
senderId,
receiverId,
imageFilename: testKey
});
const result = await S3OwnershipService.verifyMessageAccess(testKey, receiverId);
expect(result.authorized).toBe(true);
});
it('should deny access to unauthorized user', async () => {
Message.findOne.mockResolvedValue(null);
const result = await S3OwnershipService.verifyMessageAccess(testKey, 'other-user');
expect(result).toEqual({
authorized: false,
reason: 'Not a participant in this message'
});
});
it('should deny access when message does not exist', async () => {
Message.findOne.mockResolvedValue(null);
const result = await S3OwnershipService.verifyMessageAccess('messages/nonexistent.jpg', senderId);
expect(result.authorized).toBe(false);
expect(result.reason).toBe('Not a participant in this message');
});
});
describe('verifyConditionCheckAccess', () => {
const testKey = 'condition-checks/550e8400-e29b-41d4-a716-446655440000.jpg';
const ownerId = 'owner-123';
const renterId = 'renter-456';
it('should authorize owner to access condition check image', async () => {
ConditionCheck.findOne.mockResolvedValue({
id: 'check-123',
imageFilenames: [testKey],
rental: {
id: 'rental-123',
ownerId,
renterId
}
});
const result = await S3OwnershipService.verifyConditionCheckAccess(testKey, ownerId);
expect(result).toEqual({
authorized: true,
reason: null
});
expect(ConditionCheck.findOne).toHaveBeenCalledWith({
where: expect.objectContaining({
imageFilenames: expect.anything()
}),
include: expect.arrayContaining([
expect.objectContaining({
model: Rental,
as: 'rental'
})
])
});
});
it('should authorize renter to access condition check image', async () => {
ConditionCheck.findOne.mockResolvedValue({
id: 'check-123',
imageFilenames: [testKey],
rental: {
id: 'rental-123',
ownerId,
renterId
}
});
const result = await S3OwnershipService.verifyConditionCheckAccess(testKey, renterId);
expect(result.authorized).toBe(true);
});
it('should deny access to unauthorized user', async () => {
ConditionCheck.findOne.mockResolvedValue(null);
const result = await S3OwnershipService.verifyConditionCheckAccess(testKey, 'other-user');
expect(result).toEqual({
authorized: false,
reason: 'Not a participant in this rental'
});
});
it('should deny access when condition check does not exist', async () => {
ConditionCheck.findOne.mockResolvedValue(null);
const result = await S3OwnershipService.verifyConditionCheckAccess(
'condition-checks/nonexistent.jpg',
ownerId
);
expect(result.authorized).toBe(false);
expect(result.reason).toBe('Not a participant in this rental');
});
it('should use Op.contains for imageFilenames array search', async () => {
const { Op } = require('sequelize');
ConditionCheck.findOne.mockResolvedValue(null);
await S3OwnershipService.verifyConditionCheckAccess(testKey, ownerId);
expect(ConditionCheck.findOne).toHaveBeenCalledWith(
expect.objectContaining({
where: {
imageFilenames: expect.anything()
}
})
);
});
});
});