feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
import { expect, test, type Page } from "@playwright/test";
|
||||
import { installMockBridge } from "../helpers/bridge";
|
||||
|
||||
const TERM = 'section[aria-label="Buzz Term"]';
|
||||
const NAMED = 0x0100_0000;
|
||||
const FG = NAMED | 256;
|
||||
const BG = NAMED | 257;
|
||||
|
||||
/**
|
||||
* The shipped mock bridge throws on every `terminal_*` command, so Buzz Term is
|
||||
* unreachable through `installMockBridge` alone. This pre-creates
|
||||
* `__TAURI_INTERNALS__` and traps the `invoke` assignment `mockIPC` makes:
|
||||
* terminal commands are answered here, everything else falls through to the
|
||||
* real mock bridge.
|
||||
*/
|
||||
async function installTerminalBackend(page: Page) {
|
||||
await page.addInitScript(() => {
|
||||
const w = window as typeof window & {
|
||||
isTauri?: boolean;
|
||||
__TAURI_INTERNALS__?: Record<string, unknown>;
|
||||
__SAMI_TERM__?: unknown;
|
||||
};
|
||||
w.isTauri = true;
|
||||
const state = {
|
||||
deliver: null as ((message: unknown) => void) | null,
|
||||
scrolls: [] as number[],
|
||||
inputs: [] as string[],
|
||||
subscriptionId: "sami-sub-1",
|
||||
columns: 80,
|
||||
screenLines: 24,
|
||||
sequence: 0,
|
||||
};
|
||||
w.__SAMI_TERM__ = state;
|
||||
|
||||
const internals: Record<string, unknown> = {};
|
||||
let inner: ((cmd: string, args: unknown, opts: unknown) => unknown) | null =
|
||||
null;
|
||||
Object.defineProperty(internals, "invoke", {
|
||||
configurable: true,
|
||||
get:
|
||||
() => (cmd: string, args: Record<string, unknown>, opts: unknown) => {
|
||||
switch (cmd) {
|
||||
case "terminal_attach": {
|
||||
const channel = args.onFrame as {
|
||||
onmessage: (m: unknown) => void;
|
||||
};
|
||||
state.deliver = (message) => channel.onmessage(message);
|
||||
return Promise.resolve({
|
||||
sessionId: `sami-session-${state.sequence}`,
|
||||
subscriptionId: state.subscriptionId,
|
||||
viewport: {
|
||||
generation: 1,
|
||||
columns: state.columns,
|
||||
screenLines: state.screenLines,
|
||||
},
|
||||
});
|
||||
}
|
||||
case "terminal_resize":
|
||||
state.columns = args.columns as number;
|
||||
state.screenLines = args.rows as number;
|
||||
return Promise.resolve({
|
||||
generation: 1,
|
||||
columns: state.columns,
|
||||
screenLines: state.screenLines,
|
||||
});
|
||||
case "terminal_input":
|
||||
state.inputs.push(args.data as string);
|
||||
return Promise.resolve(null);
|
||||
case "terminal_scroll":
|
||||
state.scrolls.push(args.lines as number);
|
||||
return Promise.resolve(null);
|
||||
case "terminal_viewport_ready":
|
||||
case "terminal_ack":
|
||||
case "terminal_focus":
|
||||
case "terminal_detach":
|
||||
case "terminal_close":
|
||||
return Promise.resolve(null);
|
||||
default:
|
||||
if (!inner) throw new Error(`no mock bridge for ${cmd}`);
|
||||
return inner(cmd, args, opts);
|
||||
}
|
||||
},
|
||||
set: (fn: (cmd: string, args: unknown, opts: unknown) => unknown) => {
|
||||
inner = fn;
|
||||
},
|
||||
});
|
||||
w.__TAURI_INTERNALS__ = internals;
|
||||
});
|
||||
}
|
||||
|
||||
async function pushFrame(
|
||||
page: Page,
|
||||
rows: { line: number; text: string }[],
|
||||
cursor: { line: number; column: number },
|
||||
) {
|
||||
await page.evaluate(
|
||||
({ rows, cursor, fg, bg }) => {
|
||||
const state = (
|
||||
window as typeof window & {
|
||||
__SAMI_TERM__: {
|
||||
deliver: ((m: unknown) => void) | null;
|
||||
subscriptionId: string;
|
||||
columns: number;
|
||||
screenLines: number;
|
||||
sequence: number;
|
||||
};
|
||||
}
|
||||
).__SAMI_TERM__;
|
||||
state.sequence += 1;
|
||||
state.deliver?.({
|
||||
type: "frame",
|
||||
payload: {
|
||||
subscriptionId: state.subscriptionId,
|
||||
sequence: state.sequence,
|
||||
bracketedPaste: false,
|
||||
focusReporting: false,
|
||||
full: true,
|
||||
viewport: {
|
||||
generation: 1,
|
||||
columns: state.columns,
|
||||
screenLines: state.screenLines,
|
||||
},
|
||||
cursor: { ...cursor, visible: true },
|
||||
rows: rows.map(({ line, text }) => ({
|
||||
line,
|
||||
spans: [
|
||||
{
|
||||
style: { fg, bg, flags: 0 },
|
||||
clusters: [...text].map((ch, index) => ({
|
||||
column: index,
|
||||
text: ch,
|
||||
width: 1,
|
||||
})),
|
||||
},
|
||||
],
|
||||
})),
|
||||
},
|
||||
});
|
||||
},
|
||||
{ rows, cursor, fg: FG, bg: BG },
|
||||
);
|
||||
}
|
||||
|
||||
async function reveal(page: Page) {
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
await installTerminalBackend(page);
|
||||
await installMockBridge(page);
|
||||
await page.goto("/");
|
||||
await expect(page.getByTestId("home-inbox-list")).toBeVisible();
|
||||
// Buzz Term needs a channel: TerminalBootstrap's context is null on Home, so
|
||||
// no session spawns and the chord is inert.
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await page.keyboard.press("Meta+j");
|
||||
await expect(page.locator(TERM)).toHaveAttribute(
|
||||
"data-terminal-owner",
|
||||
"terminal",
|
||||
);
|
||||
// The dock opens in the normal app surface now; unlike the removed
|
||||
// full-screen takeover, it must not fade that surface away. Wait for the
|
||||
// dock's own height transition before interacting with its viewport.
|
||||
await expect(page.locator(TERM)).toHaveAttribute(
|
||||
"data-terminal-mode",
|
||||
"docked",
|
||||
);
|
||||
await expect(page.locator(TERM)).toBeVisible();
|
||||
await expect
|
||||
.poll(async () => page.locator(TERM).evaluate((el) => el.clientHeight))
|
||||
.toBeGreaterThanOrEqual(180);
|
||||
}
|
||||
|
||||
test("scrollback: wheel over Buzz Term reaches terminal_scroll", async ({
|
||||
page,
|
||||
}) => {
|
||||
await reveal(page);
|
||||
await pushFrame(page, [{ line: 0, text: "buzz@term:~$ " }], {
|
||||
line: 0,
|
||||
column: 13,
|
||||
});
|
||||
await page.mouse.move(640, 500);
|
||||
await page.mouse.wheel(0, -17 * 5);
|
||||
await page.mouse.wheel(0, 17 * 2);
|
||||
const scrolls = await page.evaluate(
|
||||
() =>
|
||||
(window as typeof window & { __SAMI_TERM__: { scrolls: number[] } })
|
||||
.__SAMI_TERM__.scrolls,
|
||||
);
|
||||
console.log("SCROLLS", JSON.stringify(scrolls));
|
||||
expect(scrolls).toEqual([-5, 2]);
|
||||
});
|
||||
|
||||
test("terminal viewport click retains keyboard input ownership", async ({
|
||||
page,
|
||||
}) => {
|
||||
await reveal(page);
|
||||
const input = page.getByLabel("Terminal input");
|
||||
await expect(input).toBeFocused();
|
||||
|
||||
await page
|
||||
.locator(".buzz-terminal-viewport")
|
||||
.click({ position: { x: 40, y: 40 } });
|
||||
await expect(input).toBeFocused();
|
||||
|
||||
await page.keyboard.type("FOCUS_KEYSTROKE");
|
||||
await expect
|
||||
.poll(async () =>
|
||||
page.evaluate(() =>
|
||||
(
|
||||
window as typeof window & { __SAMI_TERM__: { inputs: string[] } }
|
||||
).__SAMI_TERM__.inputs.join(""),
|
||||
),
|
||||
)
|
||||
.toContain("FOCUS_KEYSTROKE");
|
||||
});
|
||||
|
||||
test("concealed terminal viewport does not steal Buzz focus", async ({
|
||||
page,
|
||||
}) => {
|
||||
await reveal(page);
|
||||
await page.keyboard.press("Meta+j");
|
||||
await expect(page.locator(TERM)).toHaveCount(0);
|
||||
|
||||
const input = page.getByLabel("Terminal input");
|
||||
await expect(input).toHaveCount(0);
|
||||
await page.getByTestId("chat-title").click();
|
||||
await page.keyboard.type("BUZZ_KEYSTROKE");
|
||||
const terminalInputs = await page.evaluate(
|
||||
() =>
|
||||
(window as typeof window & { __SAMI_TERM__: { inputs: string[] } })
|
||||
.__SAMI_TERM__.inputs,
|
||||
);
|
||||
expect(terminalInputs.join("")).not.toContain("BUZZ_KEYSTROKE");
|
||||
});
|
||||
Reference in New Issue
Block a user