Ctrl K
ComunidadGuías…

frontend/e2e/taste-browsers.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('口味浏览器来源', () => {
  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, '/taste', viewport);
    const { page } = opened;
    const browsers = [{ id: 'aside', name: 'Aside', path: 'C:/Demo/Aside/User Data', enabled: true, available: true, profiles: 1,
      source_keys: ['d'.repeat(64), 'e'.repeat(64)] }];
    const data = () => ({ summary: { history_visits: 25 }, rankings: {},
      sources: [{ source_key: 'c'.repeat(64), browser: 'bookmarks', profile: '导入书签示例.html', host: 'demo', bookmarks: 3 },
        ...browsers.some(row => row.id === 'aside') ? [
          { source_key: 'd'.repeat(64), browser: 'aside', profile: 'Default', host: 'demo', visits: 25 },
          { source_key: 'e'.repeat(64), browser: 'aside', profile: 'Default · 书签', host: 'demo', bookmarks: 7 }] : []],
      browsers: [...browsers] });
    const requests: string[] = [];
    try {
      await page.route('**/api/taste?*', route => route.fulfill({ json: data() }));
      await page.route('**/api/taste/refresh', route => route.fulfill({ json: { status: 'idle' } }));
      await page.route('**/api/taste/source', async route => {
        const body = route.request().postDataJSON(); requests.push(body.operation);
        if (body.operation === 'add') browsers.push({ ...browsers[0], id: 'custom', name: body.name, path: body.path, source_keys: [] });
        else if (body.operation === 'delete_browser') browsers.splice(browsers.findIndex(row => row.id === body.id), 1);
        else browsers.find(row => row.id === body.id)!.enabled = body.operation === 'enable';
        await route.fulfill({ json: { dashboard: data() } });
      });
      await page.reload(); await settle(page);
      const sources = page.getByRole('region', { name: '数据源', exact: true });
      assert.equal(await sources.count(), 1);
      assert.equal(await sources.locator('[data-taste-source]').count(), 2);
      await sources.getByText('导入书签示例.html', { exact: true }).waitFor();
      await sources.getByText('25 条历史 · 7 枚书签', { exact: true }).waitFor();
      assert.equal(await sources.getByText('Default · 书签', { exact: true }).count(), 0);
      const cards = await sources.locator('[data-taste-source]').evaluateAll(elements => elements.map(element => {
        const style = getComputedStyle(element);
        return { background: style.backgroundColor, radius: style.borderRadius, parent: element.parentElement?.className };
      }));
      assert.deepEqual(cards[0], cards[1]);
      await sources.getByRole('button', { name: '添加浏览器', exact: true }).click();
      await sources.getByRole('textbox', { name: '浏览器名称', exact: true }).fill('演示浏览器');
      await sources.getByRole('textbox', { name: '资料目录或历史文件', exact: true }).fill('C:/Demo/Custom/User Data');
      await sources.getByRole('button', { name: '添加', exact: true }).click();
      await sources.getByText('演示浏览器', { exact: true }).waitFor();
      await sources.getByRole('button', { name: '停止读取 Aside', exact: true }).click();
      const dialog = page.getByRole('dialog', { name: '停止读取 Aside', exact: true });
      await dialog.getByRole('button', { name: '停止读取', exact: true }).click();
      await sources.getByText('已停止读取', { exact: true }).waitFor();
      await sources.getByRole('button', { name: '启用 Aside', exact: true }).click();
      await sources.getByRole('button', { name: '停止读取 Aside', exact: true }).waitFor();
      await sources.getByRole('button', { name: '删除 Aside', exact: true }).click();
      await page.getByRole('alertdialog', { name: '删除 Aside', exact: true }).getByRole('button', { name: '删除浏览器来源', exact: true }).click();
      await sources.getByRole('button', { name: '停止读取 Aside', exact: true }).waitFor({ state: 'hidden' });
      assert.equal(await sources.getByRole('button', { name: '停止读取 Aside', exact: true }).count(), 0);
      assert.deepEqual(requests, ['add', 'disable', 'enable', 'delete_browser']);
      const geometry = await layout(page);
      assert.ok(geometry.scrollWidth <= geometry.viewportWidth, JSON.stringify(geometry));
      await page.screenshot({ path: `../build/taste-browsers-${viewport.name}.png` });
      assert.deepEqual(opened.problems, []);
    } finally { await opened.page.context().close(); }
  });
  for (const viewport of VIEWPORTS) it(`${viewport.name}:书签导入入口、独立读数和来源删除`, { timeout: 60_000 }, async () => {
    const { page, problems } = await visit(browser, '/taste', viewport);
    let imported = false;
    const data = () => ({ summary: { history_visits: 0, bookmarks: imported ? 1284 : 0, history_sources: 2,
      range_start: '2026-10-12', range_end: '2026-10-17' }, rankings: {}, browsers: [],
      sources: imported ? [{ source_key: 'b'.repeat(64), browser: 'bookmarks', host: 'desktop',
        profile: 'Chrome 与 Firefox 收藏的创作者与作品书签.html', bookmarks: 1284 }] : [] });
    try {
      await page.route('**/api/taste?*', route => route.fulfill({ json: data() }));
      await page.route('**/api/taste/refresh', route => route.fulfill({ json: { status: 'idle' } }));
      await page.route('**/api/taste/import', async route => {
        assert.equal(decodeURIComponent(route.request().headers()['x-peach-filename']), '书签.html');
        assert.match(route.request().postData() || '', /NETSCAPE-Bookmark-file-1/);
        imported = true;
        await route.fulfill({ json: { dashboard: data() } });
      });
      await page.route('**/api/taste/source', async route => {
        assert.equal(route.request().postDataJSON().operation, 'remove');
        imported = false;
        await route.fulfill({ json: { removed: 1284, dashboard: data() } });
      });
      await page.reload(); await settle(page);
      await page.getByRole('button', { name: '更多取得浏览记录的方式', exact: true }).click();
      const chooser = page.waitForEvent('filechooser');
      await page.getByRole('button', { name: '导入书签文件', exact: true }).click();
      await (await chooser).setFiles({ name: '书签.html', mimeType: 'text/html',
        buffer: Buffer.from('<!DOCTYPE NETSCAPE-Bookmark-file-1><DL></DL>') });
      await page.getByText('导入文件 · desktop · 1,284 枚书签', { exact: true }).waitFor();
      const footer = page.getByText('2 个数据源 · 10/12–10/17', { exact: true });
      const footerStyle = await footer.evaluate(element => ({ height: element.getBoundingClientRect().height,
        line: parseFloat(getComputedStyle(element).lineHeight), whitespace: getComputedStyle(element).whiteSpace }));
      assert.equal(footerStyle.whitespace, 'nowrap');
      assert.ok(footerStyle.height <= footerStyle.line + 1);
      const geometry = await layout(page);
      assert.ok(geometry.scrollWidth <= geometry.viewportWidth, JSON.stringify(geometry));
      await page.screenshot({ path: `../build/taste-bookmarks-${viewport.name}.png` });
      await page.getByRole('button', { name: '移除 Chrome 与 Firefox 收藏的创作者与作品书签.html', exact: true }).click();
      await page.getByRole('dialog', { name: '移除口味数据源', exact: true })
        .getByRole('button', { name: '移除口味数据源', exact: true }).click();
      await page.getByText('还没有数据源', { exact: true }).waitFor();
      assert.deepEqual(problems, []);
    } finally { await page.context().close(); }
  });
});