Skip to main content
Glama
intersect.test.ts8.16 kB
import { describe, it, expect, vi } from 'vitest'; import { IntersectionService } from '../src/scheduling/intersect.js'; import { ProposeMeetingTimesInput } from '../src/types.js'; // Mock the config module vi.mock('../src/config.js', () => ({ default: { graph: { tenantId: 'test-tenant-id', clientId: 'test-client-id', authMode: 'delegated' }, organizer: { email: 'test@example.com' }, server: { defaultTimezone: 'UTC' }, logging: { level: 'info' } }, logger: { info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn(), trace: vi.fn(), fatal: vi.fn() } })); describe('IntersectionService', () => { const service = new IntersectionService(); describe('findIntersectingSlots', () => { it('should find intersecting slots for simple case', () => { const input: ProposeMeetingTimesInput = { participants: ['user1@example.com', 'user2@example.com'], durationMinutes: 30, windowStart: '2025-01-15T09:00:00Z', windowEnd: '2025-01-15T17:00:00Z', maxCandidates: 5, bufferBeforeMinutes: 0, bufferAfterMinutes: 0, workHoursOnly: false }; const userAvailabilities = [ { email: 'user1@example.com', free: [ { start: '2025-01-15T09:00:00Z', end: '2025-01-15T12:00:00Z' }, { start: '2025-01-15T14:00:00Z', end: '2025-01-15T17:00:00Z' } ], busy: [ { start: '2025-01-15T12:00:00Z', end: '2025-01-15T14:00:00Z', subject: 'Lunch' } ] }, { email: 'user2@example.com', free: [ { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z' }, { start: '2025-01-15T15:00:00Z', end: '2025-01-15T16:00:00Z' } ], busy: [ { start: '2025-01-15T11:00:00Z', end: '2025-01-15T15:00:00Z', subject: 'Meeting' } ] } ]; const result = service.findIntersectingSlots(input, userAvailabilities); expect(result).toHaveLength(2); expect(result[0].start).toBe('2025-01-15T10:00:00Z'); expect(result[0].end).toBe('2025-01-15T11:00:00Z'); expect(result[1].start).toBe('2025-01-15T15:00:00Z'); expect(result[1].end).toBe('2025-01-15T16:00:00Z'); }); it('should respect meeting duration constraints', () => { const input: ProposeMeetingTimesInput = { participants: ['user1@example.com', 'user2@example.com'], durationMinutes: 60, windowStart: '2025-01-15T09:00:00Z', windowEnd: '2025-01-15T17:00:00Z', maxCandidates: 5, bufferBeforeMinutes: 0, bufferAfterMinutes: 0, workHoursOnly: false }; const userAvailabilities = [ { email: 'user1@example.com', free: [ { start: '2025-01-15T09:00:00Z', end: '2025-01-15T12:00:00Z' } ], busy: [] }, { email: 'user2@example.com', free: [ { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z' } ], busy: [] } ]; const result = service.findIntersectingSlots(input, userAvailabilities); // Should not return slots shorter than 60 minutes expect(result).toHaveLength(0); }); it('should apply buffers correctly', () => { const input: ProposeMeetingTimesInput = { participants: ['user1@example.com', 'user2@example.com'], durationMinutes: 30, windowStart: '2025-01-15T09:00:00Z', windowEnd: '2025-01-15T17:00:00Z', maxCandidates: 5, bufferBeforeMinutes: 15, bufferAfterMinutes: 15, workHoursOnly: false }; const userAvailabilities = [ { email: 'user1@example.com', free: [ { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z' } ], busy: [] }, { email: 'user2@example.com', free: [ { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z' } ], busy: [] } ]; const result = service.findIntersectingSlots(input, userAvailabilities); // With 15 min buffers, the effective slot is 30 minutes (60 - 15 - 15) expect(result).toHaveLength(1); expect(result[0].start).toBe('2025-01-15T10:15:00Z'); expect(result[0].end).toBe('2025-01-15T10:45:00Z'); }); it('should handle no intersections gracefully', () => { const input: ProposeMeetingTimesInput = { participants: ['user1@example.com', 'user2@example.com'], durationMinutes: 30, windowStart: '2025-01-15T09:00:00Z', windowEnd: '2025-01-15T17:00:00Z', maxCandidates: 5, bufferBeforeMinutes: 0, bufferAfterMinutes: 0, workHoursOnly: false }; const userAvailabilities = [ { email: 'user1@example.com', free: [ { start: '2025-01-15T09:00:00Z', end: '2025-01-15T12:00:00Z' } ], busy: [] }, { email: 'user2@example.com', free: [ { start: '2025-01-15T14:00:00Z', end: '2025-01-15T17:00:00Z' } ], busy: [] } ]; const result = service.findIntersectingSlots(input, userAvailabilities); expect(result).toHaveLength(0); }); it('should respect maxCandidates limit', () => { const input: ProposeMeetingTimesInput = { participants: ['user1@example.com', 'user2@example.com'], durationMinutes: 30, windowStart: '2025-01-15T09:00:00Z', windowEnd: '2025-01-15T17:00:00Z', maxCandidates: 2, bufferBeforeMinutes: 0, bufferAfterMinutes: 0, workHoursOnly: false }; const userAvailabilities = [ { email: 'user1@example.com', free: [ { start: '2025-01-15T09:00:00Z', end: '2025-01-15T10:00:00Z' }, { start: '2025-01-15T11:00:00Z', end: '2025-01-15T12:00:00Z' }, { start: '2025-01-15T13:00:00Z', end: '2025-01-15T14:00:00Z' } ], busy: [] }, { email: 'user2@example.com', free: [ { start: '2025-01-15T09:00:00Z', end: '2025-01-15T10:00:00Z' }, { start: '2025-01-15T11:00:00Z', end: '2025-01-15T12:00:00Z' }, { start: '2025-01-15T13:00:00Z', end: '2025-01-15T14:00:00Z' } ], busy: [] } ]; const result = service.findIntersectingSlots(input, userAvailabilities); expect(result).toHaveLength(2); }); }); describe('checkMinimumAttendance', () => { it('should pass when minimum attendance is met', () => { const slot = { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z', attendeeAvailability: { 'user1@example.com': 'free' as const, 'user2@example.com': 'free' as const, 'user3@example.com': 'tentative' as const }, confidence: 0.8 }; const result = service.checkMinimumAttendance(slot, 2); expect(result).toBe(true); }); it('should fail when minimum attendance is not met', () => { const slot = { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z', attendeeAvailability: { 'user1@example.com': 'free' as const, 'user2@example.com': 'busy' as const, 'user3@example.com': 'busy' as const }, confidence: 0.3 }; const result = service.checkMinimumAttendance(slot, 2); expect(result).toBe(false); }); it('should pass when no minimum is specified', () => { const slot = { start: '2025-01-15T10:00:00Z', end: '2025-01-15T11:00:00Z', attendeeAvailability: { 'user1@example.com': 'busy' as const }, confidence: 0.0 }; const result = service.checkMinimumAttendance(slot, undefined); expect(result).toBe(true); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ChitSingh/mcp-outlook'

If you have feedback or need assistance with the MCP directory API, please join our Discord server