attendee-availability.test.ts3.5 KBView on GitHub
import {
  isBusyDuringSlot,
  isInternalAttendee,
} from '@/modules/calendar/hooks/use-attendee-availability';

/**
 * The two decisions behind "is this colleague free?".
 *
 * Both are quiet failures if they get it wrong: a bad domain test asks Google about strangers
 * (and shows every external guest as unreadable), and a bad overlap test paints half the day
 * busy — a signal nobody would trust twice.
 */
describe('isInternalAttendee', () => {
  const owner = '<email>';

  it('counts the same domain as internal', () => {
    expect(isInternalAttendee('<email>', owner)).toBe(true);
  });

  it('ignores case and the local part', () => {
    expect(isInternalAttendee('<email>', owner)).toBe(true);
  });

  it('rejects a different domain', () => {
    expect(isInternalAttendee('<email>', owner)).toBe(false);
  });

  it('rejects a SUBdomain, which is a different Workspace', () => {
    expect(isInternalAttendee('<email>', owner)).toBe(false);
  });

  it('rejects a domain that merely ends with the owner’s — the lookalike case', () => {
    expect(isInternalAttendee('<email>', owner)).toBe(false);
  });

  it('is false when there is no signed-in address to compare against', () => {
    expect(isInternalAttendee('<email>', undefined)).toBe(false);
    expect(isInternalAttendee('<email>', '')).toBe(false);
  });
});

describe('isBusyDuringSlot', () => {
  const slotStart = '2026-08-28T17:00:00.000Z';
  const slotEnd = '2026-08-28T17:30:00.000Z';

  it('is busy when a meeting covers the slot', () => {
    const busy = [{ start: '2026-08-28T16:45:00.000Z', end: '2026-08-28T17:15:00.000Z' }];
    expect(isBusyDuringSlot(busy, slotStart, slotEnd)).toBe(true);
  });

  it('is busy when the slot swallows a shorter meeting', () => {
    const busy = [{ start: '2026-08-28T17:05:00.000Z', end: '2026-08-28T17:10:00.000Z' }];
    expect(isBusyDuringSlot(busy, slotStart, slotEnd)).toBe(true);
  });

  it('is free when a meeting ends exactly as the slot begins', () => {
    // Back-to-back is the normal shape of a working day, not a conflict.
    const busy = [{ start: '2026-08-28T16:30:00.000Z', end: slotStart }];
    expect(isBusyDuringSlot(busy, slotStart, slotEnd)).toBe(false);
  });

  it('is free when a meeting begins exactly as the slot ends', () => {
    const busy = [{ start: slotEnd, end: '2026-08-28T18:00:00.000Z' }];
    expect(isBusyDuringSlot(busy, slotStart, slotEnd)).toBe(false);
  });

  it('is free with nothing booked', () => {
    expect(isBusyDuringSlot([], slotStart, slotEnd)).toBe(false);
    expect(isBusyDuringSlot(null, slotStart, slotEnd)).toBe(false);
    expect(isBusyDuringSlot(undefined, slotStart, slotEnd)).toBe(false);
  });

  it('skips a malformed interval rather than reporting the guest busy', () => {
    const busy = [
      { start: null, end: '2026-08-28T17:15:00.000Z' },
      { start: 'not a date', end: 'also not a date' },
    ];
    expect(isBusyDuringSlot(busy, slotStart, slotEnd)).toBe(false);
  });

  it('finds the conflict even when it is not the first interval of the day', () => {
    const busy = [
      { start: '2026-08-28T14:00:00.000Z', end: '2026-08-28T15:00:00.000Z' },
      { start: '2026-08-28T15:30:00.000Z', end: '2026-08-28T16:00:00.000Z' },
      { start: '2026-08-28T17:15:00.000Z', end: '2026-08-28T18:00:00.000Z' },
    ];
    expect(isBusyDuringSlot(busy, slotStart, slotEnd)).toBe(true);
  });
});