is-own-event.test.ts6.2 KBView on GitHub
/**
 * The daily agenda's "is this mine?" filter — participation, not access.
 *
 * Two traps, and BOTH of them shipped before being caught here:
 *
 *  1. Google sets `attendees[].self` relative to the calendar the event was read from, so
 *     on a teammate's subscribed calendar the attendee flagged `self` is the TEAMMATE.
 *  2. "A calendar you own" is not "your calendar". Treating `accessRole: 'owner'` as proof
 *     re-admitted every meeting on any SECONDARY calendar the user owns — a team calendar,
 *     a second account — because Google marks those `self: true` too, against the
 *     calendar's own address. Only `primary` counts.
 */

import { makeOwnEventFilter, toAddressSet } from '@/modules/calendar/utils/is-own-event';

const ME = '<email>';
const MINE = { id: ME, primary: true, accessRole: 'owner' };
const THEIRS = { id: '<email>', primary: false, accessRole: 'reader' };
/** A calendar the user genuinely OWNS but is not their own day — the leak that shipped. */
const TEAM = { id: '<email>', primary: false, accessRole: 'owner' };

const filter = (calendars = [MINE, THEIRS, TEAM]) =>
  makeOwnEventFilter(toAddressSet([ME]), calendars);

describe('toAddressSet', () => {
  it('lower-cases, trims, and drops empty entries', () => {
    expect([...toAddressSet(['  <email> ', null, undefined, '', '   '])]).toEqual([
      ME,
    ]);
  });
});

describe('makeOwnEventFilter', () => {
  it('keeps an event I am invited to, wherever it was read from', () => {
    expect(
      filter()({
        calendarId: THEIRS.id,
        attendees: [{ email: '<email>' }, { email: '<email>' }],
      }),
    ).toBe(true);
  });

  it('keeps an event I organized even when I am not on the guest list', () => {
    expect(
      filter()({
        calendarId: THEIRS.id,
        attendees: [{ email: '<email>' }],
        organizer: { email: ME },
      }),
    ).toBe(true);
  });

  it('drops a teammate-only meeting sitting on their subscribed calendar', () => {
    expect(
      filter()({
        calendarId: THEIRS.id,
        attendees: [{ email: '<email>' }, { email: '<email>' }],
      }),
    ).toBe(false);
  });

  it("does NOT trust `self` on somebody else's calendar", () => {
    // Google flagged the TEAMMATE as `self`, because it resolved the flag against the
    // calendar it read the event from.
    expect(
      filter()({
        calendarId: THEIRS.id,
        attendees: [{ email: '<email>', self: true }, { email: '<email>' }],
      }),
    ).toBe(false);
  });

  // ── The leak that shipped ─────────────────────────────────────────────────
  //
  // Access is not participation. A calendar the user OWNS but does not live in — a team
  // calendar, a second account, an events calendar — carries other people's meetings, and
  // Google marks them `self: true` against that calendar's own address.

  it('drops a meeting on a calendar I own but am not on', () => {
    expect(
      filter()({
        calendarId: TEAM.id,
        attendees: [{ email: '<email>', self: true }, { email: '<email>' }],
      }),
    ).toBe(false);
  });

  it('drops a solo block on a calendar I own that is not my primary', () => {
    expect(filter()({ calendarId: TEAM.id })).toBe(false);
  });

  it('still keeps MY meeting even when it is read from a calendar I merely own', () => {
    // The address match runs first and is independent of where the copy came from.
    expect(filter()({ calendarId: TEAM.id, attendees: [{ email: ME }] })).toBe(true);
  });

  // ── The primary calendar ──────────────────────────────────────────────────

  it('DOES trust `self` on my primary calendar, so an alias invite still counts', () => {
    expect(
      filter()({
        calendarId: ME,
        attendees: [{ email: '<email>', self: true }, { email: '<email>' }],
      }),
    ).toBe(true);
  });

  it('keeps a solo block on my primary calendar', () => {
    expect(filter()({ calendarId: ME })).toBe(true);
  });

  it("treats the literal 'primary' as my primary calendar", () => {
    // useAllCalendarEvents stamps events with the id it FETCHED, and that is the alias
    // 'primary' whenever no calendar has been explicitly selected. Without this, the
    // user's own solo blocks vanish from their own agenda.
    expect(filter()({ calendarId: 'primary' })).toBe(true);
    expect(
      filter()({ calendarId: 'primary', attendees: [{ email: '<email>', self: true }] }),
    ).toBe(true);
  });

  it('drops an event with no calendar id and nobody I recognise on it', () => {
    expect(filter()({ attendees: [{ email: '<email>', self: true }] })).toBe(false);
  });

  // ── Cold start ────────────────────────────────────────────────────────────

  it('fails OPEN before the session and calendar list have both loaded', () => {
    // A day that briefly shows too much then settles is a flicker. A day that shows
    // nothing reads as "you have no meetings today", which is a lie the user acts on.
    const cold = makeOwnEventFilter(toAddressSet([]), []);
    expect(cold({ calendarId: THEIRS.id, attendees: [{ email: '<email>' }] })).toBe(true);
  });

  it('filters as soon as the calendar list lands, even with no known address', () => {
    const noAddress = makeOwnEventFilter(toAddressSet([]), [MINE, THEIRS, TEAM]);
    expect(noAddress({ calendarId: ME })).toBe(true);
    expect(noAddress({ calendarId: THEIRS.id, attendees: [{ email: '<email>' }] })).toBe(false);
    expect(noAddress({ calendarId: TEAM.id })).toBe(false);
  });

  it('filters as soon as the address lands, even with no calendar list', () => {
    const noCalendars = makeOwnEventFilter(toAddressSet([ME]), []);
    expect(noCalendars({ calendarId: 'primary' })).toBe(true);
    expect(noCalendars({ calendarId: THEIRS.id, attendees: [{ email: '<email>' }] })).toBe(false);
  });
});