Ctrl K
ComunidadGuías…

frontend/e2e/want-resources.test.ts

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

Archivo original ↗Preguntar a KiBot
import assert from 'node:assert/strict';
import { after, before, describe, it } from 'node:test';
import type { Browser } from 'playwright-core';
import { launch, layout, settle, visit, VIEWPORTS } from './harness.ts';

describe('JAV 入库作品卡', () => {
  let browser: Browser;
  before(async () => { browser = await launch(); });
  after(async () => { await browser?.close(); });
  for (const viewport of VIEWPORTS) {
    it(`资源链接与操作完整可见(${viewport.name})`, { timeout: 60_000 }, async () => {
      const opened = await visit(browser, '/jav', viewport);
      const page = opened.page;
      try {
        await settle(page);
        await page.route('**/api/wants', route => route.fulfill({ json: { items: [{
          id: 9001, code: 'DEMO-001', title: '演示作品'.repeat(30), origin: 'code', phase: 'searching',
          link: null, release_date: '2025-01-01', studio: '演示厂牌', performers: '演示人物',
          fresh: false, search_count: 0, cover: null, scrape_error: null,
        }], counts: { searching: 1 }, scraping: false } }));
        let resourceRequests = 0;
        await page.route('**/api/wants/magnets?*', route => {
          resourceRequests += 1;
          return route.fulfill({ json: {
          state: 'ready', error: '', checked_at: null, warnings: [], source_url: 'https://example.test/work', items: [{
            id: 'magnet:abc', protocol: 'magnet', info_hash: 'abc', uri: 'magnet:?xt=urn:btih:abc',
            name: 'DEMO-001'.repeat(24), size: '4 GB', files: '2 個文件', date: '2026-10-01',
            attributes: ['字幕', '高清'], source: 'JavDB', source_url: 'https://example.test/resources',
            origins: ['https://example.test/resources'],
          }, {
            id: 'ed2k:abc', protocol: 'ed2k', info_hash: '', uri: 'ed2k://|file|demo|1|abc|/', name: '评论补充文件',
            size: '27,311,519,717 B', files: '', date: '2026-10-02', attributes: [], source: 'JavDB 评论',
            source_url: 'https://example.test/comment', origins: ['https://example.test/comment'],
          }, ...Array.from({ length: 6 }, (_, index) => ({
            id: `magnet:extra-${index}`, protocol: 'magnet', info_hash: `extra-${index}`, uri: `magnet:?xt=urn:btih:extra-${index}`,
            name: `DEMO-001 资源 ${index}`, size: '2 GB', files: '1 個文件', date: '2025-01-01',
            attributes: [], source: 'JavDB', source_url: 'https://example.test/resources', origins: [],
          }))],
        } }); });
        await page.route('**/api/downloads?*', route => route.fulfill({ json: { available: true,
          providers: [{ key: '115', label: '115', configured: true, target: '/下载' }], tasks: [] } }));
        await page.getByRole('tab', { name: '想要', exact: true }).click();
        await page.locator('[data-want-magnets]').scrollIntoViewIfNeeded();
        await page.getByRole('heading', { name: '资源链接 · 8' }).waitFor();
        await settle(page);
        const card = page.locator('[data-want-id="9001"]');
        assert.equal(await page.locator('#stats').getByRole('button', { name: '查找资源', exact: true }).count(), 2, '通用入口与作品入口分别保留一处');
        assert.equal(await page.getByRole('combobox', { name: '下载到', exact: true }).count(), 0, '下载目标在资源下载面板中选择');
        const source = card.getByRole('link', { name: '来源页', exact: true });
        assert.deepEqual(await source.evaluate(node => [...node.parentElement!.querySelectorAll('button, a')].map(action => action.textContent)), ['来源页', '移除', '查找资源']);
        const style = await card.evaluate(el => ({ radius: getComputedStyle(el).borderRadius,
          border: getComputedStyle(el).borderTopWidth }));
        assert.notEqual(style.radius, '0px');
        assert.equal(style.border, '0px', '想要卡还带着外框,页面上的卡只靠填充底');
        assert.equal(await source.evaluate(el => el.getBoundingClientRect().height), 32);
        assert.equal(await source.evaluate(el => getComputedStyle(el).borderTopWidth), '1px');
        assert.equal(await source.getAttribute('href'), 'https://example.test/work');
        assert.equal(await card.locator('[data-resource-protocol]:visible').count(), 3);
        assert.equal((await card.textContent())!.includes('個'), false);
        const ed2k = card.locator('[data-resource-protocol="ed2k"]');
        assert.ok((await ed2k.textContent())!.includes('ED2K'));
        assert.ok((await ed2k.textContent())!.includes('25.4 GB'));
        assert.equal(await ed2k.locator('span').first().locator('svg').count(), 0);
        const magnetStyle = await card.locator('[data-resource-protocol="magnet"]').first().locator('span').first().evaluate(el => getComputedStyle(el).backgroundColor);
        const ed2kStyle = await card.locator('[data-resource-protocol="ed2k"] span').first().evaluate(el => getComputedStyle(el).backgroundColor);
        assert.notEqual(magnetStyle, ed2kStyle);
        const add = card.getByRole('button', { name: '添加下载', exact: true }).first();
        const copy = card.getByRole('button', { name: '复制链接', exact: true }).first();
        assert.notEqual(await add.evaluate(el => getComputedStyle(el).backgroundColor), await copy.evaluate(el => getComputedStyle(el).backgroundColor));
        assert.equal(await add.locator('img').count(), 1, '下载渠道使用对应的网盘图标');
        if (viewport.name === 'desktop') {
          const centers = await add.evaluate(el => {
            const row = el.closest('[data-resource-protocol]')!.getBoundingClientRect();
            const button = el.getBoundingClientRect();
            return { row: row.top + row.height / 2, button: button.top + button.height / 2 };
          });
          assert.ok(Math.abs(centers.row - centers.button) <= 1, JSON.stringify(centers));
        }
        const geometry = await layout(page);
        assert.ok(geometry.scrollWidth <= geometry.viewportWidth + 1, JSON.stringify(geometry));
        assert.deepEqual(geometry.offenders, []);
        await card.screenshot({ path: `../build/want-resources-${viewport.name}.png` });
        await card.locator('summary').click();
        await page.waitForFunction(() => document.querySelectorAll('[data-resource-protocol]').length === 8 &&
          !document.querySelector('details [inert=""]'));
        assert.equal(await card.locator('[data-resource-protocol]:visible').count(), 8);
        const phase = page.locator('[data-want-phase="searching"]');
        await phase.locator('label:has(input[value="available"])').click();
        assert.equal(await phase.locator('[data-want-id]').count(), 1);
        await phase.locator('label:has(input[value="missing"])').click();
        assert.equal(await phase.locator('[data-want-id]').count(), 0);
        await phase.locator('label:has(input[value="available"])').click();
        await phase.getByRole('heading', { name: '资源链接 · 8' }).waitFor();
        assert.equal(resourceRequests, 1, '切换磁链筛选重复查询已有资源');
        await phase.screenshot({ path: `../build/want-filter-${viewport.name}.png` });
        await page.getByRole('tab', { name: '馆藏', exact: true }).click();
        await page.getByRole('tab', { name: '想要', exact: true }).click();
        await page.getByRole('heading', { name: '资源链接 · 8' }).waitFor();
        assert.equal(resourceRequests, 1, '返回页面重复查询资源');
        await page.reload();
        await page.getByRole('tab', { name: '想要', exact: true }).click();
        await page.getByRole('heading', { name: '资源链接 · 8' }).waitFor();
        assert.equal(resourceRequests, 1, '刷新页面未复用持久缓存');
        assert.deepEqual(opened.problems, []);
      } finally { await opened.close(); }
    });
  }
});