返回 DeepSeek-Reasonix
responsive-dock.mjs
根目录 / desktop / frontend / bench / responsive-dock.mjs
1 import assert from "node:assert/strict";
2 import path from "node:path";
3 import { fileURLToPath } from "node:url";
4 import { createServer } from "vite";
5 import { copyFile, mkdtemp, rm } from "node:fs/promises";
6 import { createRequire } from "node:module";
7 import { tmpdir } from "node:os";
8 import { selectSession } from "./app-page-actions.mjs";
9
10 const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
11 process.env.PLAYWRIGHT_BROWSERS_PATH ||= path.join(root, ".pw-browsers");
12 const { chromium, _electron } = await import("playwright");
13 const native = process.argv.includes("--electron");
14 const server = await createServer({ root, server: { host: "127.0.0.1", port: 0, hmr: false }, logLevel: "error" });
15 await server.listen();
16 let browser, electronApp, profile;
17 try {
18 let page;
19 if (native) {
20 profile = await mkdtemp(path.join(tmpdir(), "reasonix-responsive-dock-"));
21 const main = path.join(profile, "main.cjs");
22 await copyFile(path.join(root, "bench/transcript-layout-electron.cjs"), main);
23 const requireElectron = createRequire(path.join(root, "../electron/package.json"));
24 electronApp = await _electron.launch({ executablePath: requireElectron("electron"), args: [main],
25 env: { ...process.env, REASONIX_LAYOUT_URL: "about:blank" } });
26 page = await electronApp.firstWindow();
27 } else {
28 browser = await chromium.launch({ headless: true });
29 page = await browser.newPage();
30 }
31 const resize = async (width, height) => {
32 if (electronApp) await electronApp.evaluate(({ BrowserWindow }, size) => BrowserWindow.getAllWindows()[0].setContentSize(size.width, size.height), { width, height });
33 else await page.setViewportSize({ width, height });
34 };
35 await resize(1600, 1000);
36 const errors = [];
37 page.on("pageerror", error => errors.push(error.message));
38 await page.addInitScript(() => localStorage.setItem("reasonix-lang", "en"));
39 await page.goto(`http://127.0.0.1:${server.httpServer.address().port}/?mock=bench&bench=1`);
40 await page.locator("textarea.composer__input:not([aria-hidden=true])").waitFor();
41 await selectSession(page, "bench:small-6t");
42 await page.getByRole("tab", { name: "Overview", exact: true }).waitFor();
43 const dock = page.locator(".workbench-dock");
44 const near = async (width) => {
45 try {
46 await page.waitForFunction(expected => Math.abs((document.querySelector(".workbench-dock")?.getBoundingClientRect().width ?? 0) - expected) < 2, width);
47 } catch (error) {
48 console.error(await page.evaluate(() => [".layout", ".chat-pane", ".workbench-dock"].map(selector => {
49 const el = document.querySelector(selector);
50 return { selector, className: el?.className, rect: el?.getBoundingClientRect().toJSON(), grid: el && getComputedStyle(el).gridTemplateColumns };
51 })));
52 throw error;
53 }
54 };
55 await near(720);
56 const splitter = page.locator(".workspace-panel-resizer");
57 await splitter.focus();
58 await page.keyboard.press("ArrowLeft");
59 await near(736);
60 const saved = await page.evaluate(() => localStorage.getItem("reasonix.layoutPreferences.v1"));
61 await dock.getByRole("button", { name: "Close workspace panel", exact: true }).click();
62 await dock.waitFor({ state: "detached" });
63 await page.locator(".topicbar__chrome-btn--workspace[aria-pressed=false]").click();
64 await near(736);
65 // Browser-only mock has no Electron host/menu entry. Mount the actual browser
66 // panel through its tab store; native page sizing has separate host tests.
67 await page.evaluate(async () => {
68 const { useActivityBarStore } = await import("/src/store/activityBar.ts");
69 useActivityBarStore.getState().openEntry("browser", "Browser");
70 });
71 await page.locator(".browser-panel").waitFor();
72 for (const width of [1100, 1024, 1000, 800, 768]) {
73 console.log(`checking split layout at ${width}`);
74 await resize(width, 900);
75 // Read the actual sidebar preference rather than assuming a platform width.
76 await page.waitForFunction(w => {
77 const chat = document.querySelector(".chat-pane").getBoundingClientRect();
78 const dock = document.querySelector(".workbench-dock").getBoundingClientRect();
79 return chat.width >= 399 && dock.width >= 299 && dock.right <= w + 1 && chat.right <= dock.left + 1;
80 }, width);
81 assert(await dock.isVisible(), `dock visible at ${width}`);
82 if (width === 800) {
83 await page.locator('button[aria-label="Terminal"][aria-pressed]').click();
84 await page.waitForFunction(() => {
85 const drawer = document.querySelector(".terminal-drawer")?.getBoundingClientRect();
86 return drawer && drawer.width >= 399 && drawer.height > 100;
87 });
88 await page.locator('button[aria-label="Terminal"][aria-pressed]').click();
89 }
90 }
91 for (const width of [767, 600, 390]) {
92 console.log(`checking fullscreen at ${width}`);
93 await resize(width, 800);
94 await near(width);
95 assert.equal(await page.locator(".chat-pane").isVisible(), false, "fullscreen removes covered chat controls from focus");
96 assert.equal(await splitter.count(), 0, "fullscreen has no resize handle");
97 const rect = await dock.boundingBox();
98 assert(rect.x >= -1 && rect.x + rect.width <= width + 1);
99 await dock.getByRole("button", { name: "Close workspace panel", exact: true }).click();
100 assert(await page.locator(".chat-pane").isVisible(), "closing fullscreen returns to chat");
101 await page.locator(".topicbar__chrome-btn--workspace[aria-pressed=false]").click();
102 await near(width);
103 }
104 await resize(1600, 1000);
105 await near(736);
106 assert.equal(await page.evaluate(() => localStorage.getItem("reasonix.layoutPreferences.v1")), saved);
107 await page.reload();
108 await near(736);
109 const handle = await splitter.boundingBox();
110 await page.mouse.move(handle.x, handle.y + handle.height / 2);
111 await page.mouse.down();
112 await page.mouse.move(handle.x - 64, handle.y + handle.height / 2, { steps: 5 });
113 await page.mouse.up();
114 await near(800);
115 assert.deepEqual(errors, []);
116 console.log(`responsive dock ${native ? "Electron" : "browser"}: initial ratio, keyboard/pointer resize, Browser tab, narrow fullscreen, close/reopen and restart passed`);
117 } finally {
118 await browser?.close();
119 await electronApp?.close();
120 await server.close();
121 if (profile) await rm(profile, { recursive: true, force: true });
122 }
123
123 lines Plain Text