Ctrl K
ComunidadGuías…

frontend/test/api-library.test.ts

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { apiGet, apiSend } from '../src/api';
import { api } from '../src/core';

describe('媒体库查询范围', () => {
  const fetchMock = vi.fn(async (_url: string, _options?: RequestInit) => new Response('{}', { headers: { 'Content-Type': 'application/json' } }));
  beforeEach(() => {
    sessionStorage.clear();
    fetchMock.mockClear();
    vi.stubGlobal('fetch', fetchMock);
  });
  afterEach(() => { sessionStorage.clear(); vi.unstubAllGlobals() });

  for (const [name, get] of [['React', apiGet], ['应用', api]] as const) {
    it(`${name}:目录、搜索和筛选逐次读取当前媒体库`, async () => {
      sessionStorage.setItem('peach.library', '本地 & A');
      await get('/api/items?q=影片&offset=48#results');
      expect(fetchMock.mock.calls.at(-1)?.[0]).toBe('/api/items?q=影片&offset=48&library=%E6%9C%AC%E5%9C%B0%20%26%20A#results');
      sessionStorage.setItem('peach.library', 'cloud');
      await get('/api/facets?');
      expect(fetchMock.mock.calls.at(-1)?.[0]).toBe('/api/facets?library=cloud');
      sessionStorage.removeItem('peach.library');
      await get('/api/items?limit=1');
      expect(fetchMock.mock.calls.at(-1)?.[0]).toBe('/api/items?limit=1');
    });

    it(`${name}:显式范围和其他端点保留调用方参数`, async () => {
      sessionStorage.setItem('peach.library', 'selected');
      for (const path of ['/api/items?library=other', '/api/items?library=', '/api/facets?%6cibrary=other',
        '/api/item?id=1', '/api/items-extra', '/api/libraries', 'https://example.test/api/items']) {
        await get(path);
        expect(fetchMock.mock.calls.at(-1)?.[0]).toBe(path);
      }
    });
  }

  it('写操作保留调用方范围与请求体', async () => {
    sessionStorage.setItem('peach.library', 'selected');
    await api('/api/items', { method: 'POST', body: '{}' });
    await apiSend('/api/items', { id: 1 });
    expect(fetchMock.mock.calls.map(call => call[0])).toEqual(['/api/items', '/api/items']);
    expect(fetchMock.mock.calls.map(call => [call[1]?.method, call[1]?.body])).toEqual([
      ['POST', '{}'], ['POST', '{"id":1}'],
    ]);
  });
});

describe('响应体读取期间取消请求', () => {
  afterEach(() => { vi.unstubAllGlobals() });

  for (const method of ['GET', 'POST'] as const) {
    it(`${method} 保留取消原因`, async () => {
      const controller = new AbortController();
      const cancelled = new DOMException('已中止', 'AbortError');
      let rejectBody!: (reason: unknown) => void;
      const body = new Promise<never>((_resolve, reject) => { rejectBody = reject });
      vi.stubGlobal('fetch', vi.fn(async () => ({ ok: true, json: () => body })));
      const pending = method === 'GET'
        ? apiGet('/api/duplicates', controller.signal)
        : apiSend('/api/batch', { ids: [1] }, 'POST', controller.signal);
      const rejected = expect(pending).rejects.toBe(cancelled);
      controller.abort(cancelled);
      rejectBody(cancelled);
      await rejected;
    });
  }
});