vault-video-processor / src /inngest /functions /__tests__ /detect-objects.test.ts
dvijaykrishnan's picture
Deployment fix for HF
ceb943f
Raw
History Blame Contribute Delete
3.96 kB
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { detectObjects } from '../detect-objects';
import { extractFramesAtIntervals } from '@/features/discovery/services/frame-extraction.service';
import { detectObjectsInFrame } from '@/features/discovery/services/ai-vision.service';
import { db } from '@/lib/db';
import { uploadThumbnail } from '@/features/discovery/services/storage.service';
// Mock dependencies
vi.mock('@/features/discovery/services/storage.service', () => ({
uploadThumbnail: vi.fn().mockResolvedValue('https://supa-storage.com/thumb.jpg')
}));
vi.mock('sharp', () => {
return {
default: vi.fn(() => ({
metadata: vi.fn().mockResolvedValue({ width: 1920, height: 1080 }),
extract: vi.fn().mockReturnThis(),
resize: vi.fn().mockReturnThis(),
toFormat: vi.fn().mockReturnThis(),
toBuffer: vi.fn().mockResolvedValue(Buffer.from('thumb')),
}))
};
});
vi.mock('@/features/discovery/services/frame-extraction.service', () => ({
extractFramesAtIntervals: vi.fn(),
VideoUnavailableError: class VideoUnavailableError extends Error {
constructor(message: string) {
super(message);
this.name = 'VideoUnavailableError';
}
}
}));
vi.mock('@/features/discovery/services/ai-vision.service', () => ({
detectObjectsInFrame: vi.fn(),
VisionRateLimitError: class VisionRateLimitError extends Error { },
}));
vi.mock('@/lib/db', () => ({
db: {
insert: vi.fn(() => ({
values: vi.fn(() => ({
returning: vi.fn().mockResolvedValue([{ id: 'det-1' }, { id: 'det-2' }]),
})),
})),
update: vi.fn(() => ({
set: vi.fn(() => ({
where: vi.fn().mockResolvedValue(undefined),
})),
})),
query: {
youtubeVideos: {
findFirst: vi.fn().mockResolvedValue({ id: 'v123', duration: 33 }),
},
},
},
}));
vi.mock('@/lib/db/schema', () => ({
detectedObjects: {},
youtubeVideos: {},
}));
// Mock Inngest client to expose handler
vi.mock('../../client', () => ({
inngest: {
createFunction: vi.fn((config, trigger, handler) => ({ config, trigger, handler, fn: handler })),
send: vi.fn().mockResolvedValue(undefined),
}
}));
vi.mock('@sentry/nextjs', () => ({
captureException: vi.fn(),
}));
describe('Detect Objects Inngest Function', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should be defined', () => {
expect(detectObjects).toBeDefined();
});
it('should execute analysis and save results', async () => {
// Setup mocks
vi.mocked(extractFramesAtIntervals).mockResolvedValue([
{ timestamp: 0, frameBuffer: Buffer.from('f1') },
{ timestamp: 10, frameBuffer: Buffer.from('f2') }
]);
vi.mocked(detectObjectsInFrame).mockResolvedValue([
{ name: 'Obj1', category: 'Tech', confidence: 0.9, boundingBox: { x: 10, y: 10, width: 100, height: 100 } }
]);
const stepMock = {
run: vi.fn(async (_name: string, fn: () => Promise<any>) => {
return await fn();
})
};
const event = {
data: {
videoId: 'v123',
videoUrl: 'http://video.com'
}
};
// Execute handler
const result = await detectObjects.fn({ event, step: stepMock });
expect(result.success).toBe(true);
expect(result.count).toBe(2); // 2 frames × 1 detection each
expect(extractFramesAtIntervals).toHaveBeenCalledWith('http://video.com', 5); // Adaptive: 5s for 33s video
expect(detectObjectsInFrame).toHaveBeenCalledTimes(2);
expect(uploadThumbnail).toHaveBeenCalledTimes(2);
expect(db.insert).toHaveBeenCalled();
});
});