taskThreadPreload.test.ts2.8 KBView on GitHub
/**
 * A task is a link to a thread, and until now it was the only such link in the product that
 * fetched nothing until the click — the thread list beside it has preloaded its bodies on hover
 * and after load for as long as it has existed.
 *
 * These pin the derivation that decides WHAT gets preloaded, because every way it can be wrong
 * is silent: name too few threads and the task opens on a spinner exactly as before, name a
 * thread that isn't real and every hover spends a request on a 400.
 */
import { taskThreadIds } from '@/modules/userTasks/utils/task-threads';

describe('taskThreadIds', () => {
  it('takes the draft thread off the authoritative output axis', () => {
    expect(taskThreadIds({ taskOutput: { kind: 'email', threadId: 'thread-1' } })).toEqual([
      'thread-1',
    ]);
  });

  it('still finds the thread on a task that only carries the legacy pair', () => {
    // ~12k rows never got a `task_output`, and `openTask` routes on `taskActionData` regardless —
    // so reading only the new axis would leave exactly the tasks that open a thread unpreloaded.
    expect(
      taskThreadIds({ taskActionData: { channel: 'email', threadId: 'thread-legacy' } }),
    ).toEqual(['thread-legacy']);
  });

  it('preloads the thread the task is ABOUT — the ticket renders it inline', () => {
    expect(taskThreadIds({ sourceThreadId: 'thread-source' })).toEqual(['thread-source']);
  });

  it('puts the output thread ahead of the source thread — the output is what a click opens', () => {
    expect(
      taskThreadIds({
        taskOutput: { kind: 'email', threadId: 'thread-draft' },
        sourceThreadId: 'thread-source',
      }),
    ).toEqual(['thread-draft', 'thread-source']);
  });

  it('names a thread once when both axes point at it', () => {
    expect(
      taskThreadIds({
        taskOutput: { kind: 'email', threadId: 'thread-1' },
        taskActionData: { channel: 'email', threadId: 'thread-1' },
      }),
    ).toEqual(['thread-1']);
  });

  it('ignores a client-only compose id — there is no provider thread behind it', () => {
    // `mail.get` 400s on these; ThreadDataSync refuses them for the same reason.
    expect(
      taskThreadIds({ taskOutput: { kind: 'email', threadId: 'draftSessionId-abc' } }),
    ).toEqual([]);
  });

  it('finds nothing on a non-email output', () => {
    // A Slack output's `threadTs` is a Slack timestamp, not a mail thread.
    expect(taskThreadIds({ taskOutput: { kind: 'slack' } })).toEqual([]);
    expect(taskThreadIds({ taskActionData: { channel: 'slack' } })).toEqual([]);
  });

  it('finds nothing on a reminder that produced nothing and names no thread', () => {
    expect(taskThreadIds({ taskOutput: { kind: 'none' } })).toEqual([]);
    expect(taskThreadIds(null)).toEqual([]);
    expect(taskThreadIds(undefined)).toEqual([]);
  });
});