Spaces:
Runtime error
Runtime error
File size: 3,956 Bytes
ceb943f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 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();
});
});
|