Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/app/e2e/onboarding/home-suggestion-chips.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ test("@smoke composer placeholder is the static home string", async ({ page, pro
const label = await editor.getAttribute("aria-label")
// i18n source: packages/app/src/i18n/{zh,en}.ts → prompt.placeholder.home
if (locale === "zh") {
expect(label).toBe("输入你的任务,@ 引用文件")
expect(label).toBe("输入你的任务,@ 引用文件,/ 唤起命令")
} else {
expect(label).toBe("Type your task, or @ to mention files")
expect(label).toBe("Type your task, @ to mention files, / for commands")
}
})

Expand Down
70 changes: 70 additions & 0 deletions packages/app/e2e/snap/prompt-placeholder.snap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { test } from "../fixtures"
import { promptSelector } from "../selectors"
import { composeGrid, snapOutputPath, type Shot } from "./_compose"

test.use({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 2 })
Comment thread
Astro-Han marked this conversation as resolved.

async function snapComposer(page: import("@playwright/test").Page, name: string): Promise<Shot> {
const prompt = page.locator(promptSelector)
await prompt.waitFor({ state: "visible", timeout: 30_000 })
const placeholder = page.locator('[data-component="prompt-placeholder"]')
await placeholder.waitFor({ state: "visible", timeout: 30_000 })
return { name, buf: await prompt.screenshot() }
}

// Locale-independent right-panel toggle. The shared `openRightPanel` helper
// looks up the button by English aria name and would not find it after the
// snap switches the app to zh.
async function ensureRightPanelOpen(page: import("@playwright/test").Page) {
const toggle = page.locator('[aria-controls="right-panel"]').first()
await toggle.waitFor({ state: "visible", timeout: 30_000 })
const expanded = await toggle.getAttribute("aria-expanded")
if (expanded === "true") return
await toggle.click()
await page.locator('#right-panel').waitFor({ state: "visible", timeout: 5_000 })
}

// 768px matches the Electron window minWidth from packages/desktop-electron/src/main/windows.ts.
// The placeholder element has `truncate whitespace-nowrap`, so the narrow shot is the only
// way to catch the `/ for commands` hint being clipped at the smallest supported window.
// The "squeezed" row also opens the right panel so the prompt width is realistically narrow
// (window minWidth - sidebar - right panel) instead of just window minWidth.
const NARROW_WIDTH = 768

test("prompt-placeholder", async ({ page, project }) => {
test.setTimeout(180_000)
Comment thread
Astro-Han marked this conversation as resolved.

await project.open()
const enShot = await snapComposer(page, "en-1440")

await page.setViewportSize({ width: NARROW_WIDTH, height: 900 })
const enNarrowShot = await snapComposer(page, "en-768")

await ensureRightPanelOpen(page)
const enSqueezedShot = await snapComposer(page, "en-768+rightpanel")

// Client-side locale is sourced from localStorage. Set it, reload, re-snap all widths.
// Also clear persisted layout state so the right panel returns to its default closed
// state for the zh baseline/narrow shots — opening it for the en squeezed shot writes
// `rightPanel.opened: true` into `pawwork.global.dat:layout`, which survives reload.
await page.evaluate(() => {
localStorage.setItem("pawwork.global.dat:language", JSON.stringify({ locale: "zh" }))
localStorage.removeItem("pawwork.global.dat:layout")
})
await page.setViewportSize({ width: 1440, height: 900 })
await page.reload()
const zhShot = await snapComposer(page, "zh-1440")

await page.setViewportSize({ width: NARROW_WIDTH, height: 900 })
const zhNarrowShot = await snapComposer(page, "zh-768")

await ensureRightPanelOpen(page)
const zhSqueezedShot = await snapComposer(page, "zh-768+rightpanel")

const out = snapOutputPath("prompt-placeholder")
await composeGrid(
[enShot, enNarrowShot, enSqueezedShot, zhShot, zhNarrowShot, zhSqueezedShot],
out,
)
process.stdout.write(`\n[snap] prompt-placeholder grid -> ${out}\n\n`)
})
16 changes: 16 additions & 0 deletions packages/app/src/components/prompt-input/placeholder.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { describe, expect, test } from "bun:test"
import { dict as en } from "@/i18n/en"
import { dict as zh } from "@/i18n/zh"
import { promptPlaceholder } from "./placeholder"

describe("promptPlaceholder", () => {
Expand All @@ -17,3 +19,17 @@ describe("promptPlaceholder", () => {
expect(promptPlaceholder({ mode: "normal", commentCount: 0, t })).toBe("prompt.placeholder.home")
})
})

describe("prompt.placeholder.home copy", () => {
test("hints at both @ for files and / for commands in English", () => {
const copy = en["prompt.placeholder.home"]
expect(copy).toContain("@")
expect(copy).toContain("/")
})

test("hints at both @ for files and / for commands in Chinese", () => {
const copy = zh["prompt.placeholder.home"]
expect(copy).toContain("@")
expect(copy).toContain("/")
})
})
2 changes: 1 addition & 1 deletion packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export const dict = {
"variant.max": "Max",

"prompt.placeholder.shell": "Enter shell command...",
"prompt.placeholder.home": "Type your task, or @ to mention files",
"prompt.placeholder.home": "Type your task, @ to mention files, / for commands",
Comment thread
Astro-Han marked this conversation as resolved.
"prompt.placeholder.summarizeComments": "Summarize comments…",
"prompt.placeholder.summarizeComment": "Summarize comment…",
"prompt.mode.shell": "Shell",
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export const dict = {
"variant.max": "最高",

"prompt.placeholder.shell": "输入 shell 命令...",
"prompt.placeholder.home": "输入你的任务,@ 引用文件",
"prompt.placeholder.home": "输入你的任务,@ 引用文件,/ 唤起命令",
"prompt.placeholder.summarizeComments": "总结评论…",
"prompt.placeholder.summarizeComment": "总结该评论…",
"prompt.mode.shell": "Shell",
Expand Down
Loading