archive-from-any-folder.test.ts2.2 KBView on GitHub
/**
 * Archive must remove INBOX from every inbox-ish view, not just `/mail/inbox`.
 *
 * `moveThreadsTo`'s 'archive' case used to gate the INBOX removal on
 * `currentFolder === 'inbox'`. Every other view — the Important and Other tabs, a
 * custom inbox slug (`/mail/active-pipeline`), a label folder, All Mail — fell
 * through to `removeLabel = ''`, and with no labels on either side the function hit
 * its `console.warn('No labels to modify')` guard and returned WITHOUT calling the
 * API. Archiving from the thread view on those tabs did nothing at all.
 */

interface ModifyLabelsInput {
  threadId: string[];
  addLabels: string[];
  removeLabels: string[];
}

const mockMutate = jest.fn(async (_input: ModifyLabelsInput) => ({ ok: true }));

// Wrapped rather than passed directly: babel hoists the `import` below above the `const`,
// so the factory would read `mockMutate` in its temporal dead zone.
jest.mock('@/providers/query-provider', () => ({
  trpcClient: {
    mail: {
      modifyLabels: { mutate: (input: ModifyLabelsInput) => mockMutate(input) },
    },
  },
}));

import { moveThreadsTo } from '@/modules/threads/thread/utils/thread-actions';

beforeEach(() => mockMutate.mockClear());

describe('moveThreadsTo — archive', () => {
  it.each(['inbox', 'important', 'other', 'active-pipeline', 'all', ''])(
    'removes INBOX from /mail/%s',
    async (folder) => {
      await moveThreadsTo({ threadIds: ['t1'], currentFolder: folder, destination: 'archive' });

      expect(mockMutate).toHaveBeenCalledTimes(1);
      expect(mockMutate).toHaveBeenCalledWith({
        threadId: ['t1'],
        addLabels: [],
        removeLabels: ['INBOX'],
      });
    },
  );

  it('removes SPAM when archiving out of spam', async () => {
    await moveThreadsTo({ threadIds: ['t1'], currentFolder: 'spam', destination: 'archive' });

    expect(mockMutate).toHaveBeenCalledWith({
      threadId: ['t1'],
      addLabels: [],
      removeLabels: ['SPAM'],
    });
  });

  it('removes TRASH when archiving out of the bin', async () => {
    await moveThreadsTo({ threadIds: ['t1'], currentFolder: 'bin', destination: 'archive' });

    expect(mockMutate).toHaveBeenCalledWith({
      threadId: ['t1'],
      addLabels: [],
      removeLabels: ['TRASH'],
    });
  });
});