Z ZPI 文档 v0.3.8
介绍页

源码

tests/desktop/thinking-preview.spec.ts

typescript101 行查看原文
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { ElectronApplication } from "@playwright/test";
import { chunk, deferred, done, fakeServer, send } from "../fake-server.ts";
import { runCleanup } from "../helpers/cleanup.ts";
import { launchDesktop } from "../helpers/desktop.ts";
import { expect, test } from "../helpers/test.ts";

test("thinking matches ZCode: latest streaming line, completed duration and history fallback", async () => {
  const dir = await mkdtemp(join(tmpdir(), "zpi-thinking-preview-"));
  const project = join(dir, "project");
  await mkdir(project);
  await writeFile(join(project, "README.md"), "# Test project");
  const preview = `检查项目说明,${"确认配置和实现细节。".repeat(80)}`;
  const thinking = `先读取说明。\r\n${preview}\r\n \r\n`;
  const callTool = deferred();
  const finish = deferred();
  const server = await fakeServer(async (_, response, index) => {
    if (index === 0) {
      send(response, chunk({ reasoning_content: thinking }));
      await callTool.promise;
      send(
        response,
        chunk({
          tool_calls: [
            {
              index: 0,
              id: "readme",
              type: "function",
              function: { name: "read", arguments: JSON.stringify({ path: "README.md" }) },
            },
          ],
        }),
      );
      done(response, "tool_calls");
    } else {
      send(response, chunk({ reasoning_content: "说明已读取。\n现在整理结论。\n\n" }));
      await finish.promise;
      send(response, chunk({ content: "项目说明已验证。" }));
      done(response);
    }
  });
  let app: ElectronApplication | undefined;
  try {
    app = await launchDesktop({ dir, project, url: server.url });
    let page = await app.firstWindow();
    await page.getByRole("button", { name: "添加项目", exact: true }).first().click();
    await page.getByLabel("消息", { exact: true }).fill("检查说明");
    await page.getByLabel("发送", { exact: true }).click();
    let thoughts = page.getByTestId("thinking-block");
    const summary = thoughts.first().locator(".thinking-summary");
    await expect(summary).toHaveText(preview);
    await expect(thoughts.first().getByRole("button")).toContainText("正在思考");
    await expect(thoughts.first().locator(".reasoning-duration")).toHaveCount(0);
    await expect.poll(() => summary.evaluate((node) => node.scrollLeft)).toBeGreaterThan(0);
    await expect(summary).toHaveAttribute("data-overflowing", "true");
    callTool.resolve();
    await expect(thoughts).toHaveCount(2);
    await expect(summary).toHaveCount(0);
    await expect(thoughts.first().getByRole("button")).toHaveText(/^思考·持续了 \d+ 秒$/);
    await expect(thoughts.last().locator(".thinking-summary")).toHaveText("现在整理结论。");
    // 手动展开后,ZCode 用“思考 + 耗时”代替运行态摘要,并保留用户选择。
    await thoughts.last().getByRole("button").click();
    await expect(thoughts.last().locator(".thinking-summary")).toHaveCount(0);
    await expect(thoughts.last().locator(".thinking-body")).toHaveText("说明已读取。\n现在整理结论。\n\n");
    await expect(thoughts.last().getByRole("button")).toHaveText(/^思考·持续了 \d+ 秒$/);
    finish.resolve();
    await expect(page.getByTestId("run")).toHaveAttribute("data-status", "completed");
    await page.getByTestId("progress").click();
    await expect(thoughts.locator(".thinking-summary")).toHaveCount(0);
    await expect(thoughts.last().getByRole("button")).toHaveAttribute("aria-expanded", "true");
    await expect(thoughts.last().getByRole("button")).toHaveText(/^思考·持续了 \d+ 秒$/);
    await thoughts.first().getByRole("button").click();
    await expect(thoughts.first().locator(".thinking-body")).toHaveText(thinking);
    await expect(summary).toHaveCount(0);
    await thoughts.first().getByRole("button").click();
    await expect(thoughts.first().getByRole("button")).toHaveText(/^思考·持续了 \d+ 秒$/);
    await page.screenshot({ path: "test-results/thinking-preview-completed.png" });
    await app.close();
    app = await launchDesktop({ dir, project, url: server.url });
    page = await app.firstWindow();
    await page.getByTestId("progress").click();
    thoughts = page.getByTestId("thinking-block");
    await expect(thoughts.locator(".thinking-summary")).toHaveCount(0);
    await expect(thoughts.getByRole("button")).toHaveText(["思考·持续了几秒", "思考·持续了几秒"]);
    await expect(thoughts.getByRole("button").first()).toHaveAttribute("aria-expanded", "false");
    await thoughts.first().getByRole("button").click();
    await expect(thoughts.first().locator(".thinking-body")).toHaveText(thinking);
    await expect(thoughts.first().getByRole("button")).toHaveText("思考·持续了几秒");
  } finally {
    callTool.resolve();
    finish.resolve();
    await runCleanup([
      () => rm(dir, { recursive: true, force: true }),
      () => server.close(),
      () => app?.close(),
    ]);
  }
});