import { describe, it, expect, vi } from 'vitest';
import { retryOnTransportError } from '@/lib/retryAction';

describe('retryOnTransportError', () => {
  it('returns the result without retrying when the call succeeds', async () => {
    const fn = vi.fn().mockResolvedValue({ success: true });
    const result = await retryOnTransportError(fn);
    expect(result).toEqual({ success: true });
    expect(fn).toHaveBeenCalledTimes(1);
  });

  it('passes through an application-level { error } without retrying', async () => {
    // A returned error (bad password, rate limit) is a real result, not a
    // transport failure — it must not trigger a retry.
    const fn = vi.fn().mockResolvedValue({ error: 'Invalid email or password' });
    const result = await retryOnTransportError(fn);
    expect(result).toEqual({ error: 'Invalid email or password' });
    expect(fn).toHaveBeenCalledTimes(1);
  });

  it('retries once on a thrown transport error and returns the second result', async () => {
    const fn = vi
      .fn()
      .mockRejectedValueOnce(new TypeError('The network connection was lost'))
      .mockResolvedValueOnce({ success: true });
    const result = await retryOnTransportError(fn);
    expect(result).toEqual({ success: true });
    expect(fn).toHaveBeenCalledTimes(2);
  });

  it('rejects after a single retry when both attempts throw', async () => {
    const fn = vi.fn().mockRejectedValue(new TypeError('Failed to fetch'));
    await expect(retryOnTransportError(fn)).rejects.toThrow('Failed to fetch');
    expect(fn).toHaveBeenCalledTimes(2);
  });
});
