| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- import { describe, expect, test } from "bun:test"
- import {
- findDrift,
- glossaryFile,
- modelVariants,
- parseTranslationArgs,
- runPool,
- sessionIDFromEvents,
- sessionModels,
- targetFiles,
- textFromEvents,
- translationConfig,
- unexpectedChanges,
- } from "./translate-app"
- describe("translate app", () => {
- test("parses one locale with the public model defaults", () => {
- expect(parseTranslationArgs(["fr"])).toEqual({
- target: "fr",
- concurrency: 1,
- model: "opencode/gpt-5.5",
- variant: "xhigh",
- dryRun: false,
- check: false,
- help: false,
- })
- })
- test("parses all locales with bounded concurrency overrides", () => {
- expect(
- parseTranslationArgs([
- "all",
- "--concurrency",
- "7",
- "--model",
- "opencode/gpt-5.4",
- "--variant",
- "high",
- "--dry-run",
- ]),
- ).toEqual({
- target: "all",
- concurrency: 7,
- model: "opencode/gpt-5.4",
- variant: "high",
- dryRun: true,
- check: false,
- help: false,
- })
- })
- test("rejects unsupported targets and invalid concurrency", () => {
- expect(() => parseTranslationArgs(["en"])).toThrow("Unknown locale")
- expect(() => parseTranslationArgs(["fr", "de"])).toThrow("one locale")
- expect(() => parseTranslationArgs(["all", "--concurrency", "0"])).toThrow("positive integer")
- })
- test("parses fresh-process parity checks without requesting translation", () => {
- expect(parseTranslationArgs(["fr", "--check"]).check).toBe(true)
- })
- test("limits each locale to its app surfaces", () => {
- expect(targetFiles("fr")).toEqual([
- "packages/app/src/i18n/fr.ts",
- "packages/ui/src/i18n/fr.ts",
- "packages/desktop/src/renderer/i18n/fr.ts",
- ])
- expect(targetFiles("tr")).toEqual(["packages/app/src/i18n/tr.ts", "packages/ui/src/i18n/tr.ts"])
- })
- test("maps product locale codes to their glossaries", () => {
- expect(glossaryFile("fr")).toBe(".opencode/glossary/fr.md")
- expect(glossaryFile("zh")).toBe(".opencode/glossary/zh-cn.md")
- expect(glossaryFile("zht")).toBe(".opencode/glossary/zh-tw.md")
- })
- test("finds key and placeholder drift", () => {
- expect(
- findDrift(
- { keep: "Hello {{name}}", missing: "Missing", changed: "{{one}} {{two}}" },
- { keep: "Bonjour {{name}}", extra: "Extra", changed: "{{one}}" },
- ),
- ).toEqual({ missing: ["missing"], extra: ["extra"], placeholders: ["changed"] })
- })
- test("runs work with the requested maximum concurrency", async () => {
- const active = new Set<number>()
- const peaks: number[] = []
- const result = await runPool([1, 2, 3, 4, 5], 2, async (item) => {
- active.add(item)
- peaks.push(active.size)
- await Bun.sleep(5)
- active.delete(item)
- return item * 2
- })
- expect(result).toEqual([2, 4, 6, 8, 10])
- expect(Math.max(...peaks)).toBe(2)
- })
- test("reads the actual model and variant from the completed session", () => {
- expect(sessionIDFromEvents('shared: https://example.test\n{"type":"step_start","sessionID":"ses_test"}\n')).toBe(
- "ses_test",
- )
- expect(
- sessionModels({
- messages: [
- { info: { role: "user" } },
- {
- info: {
- role: "assistant",
- providerID: "opencode",
- modelID: "gpt-5.5",
- variant: "xhigh",
- },
- },
- ],
- }),
- ).toEqual([{ model: "opencode/gpt-5.5", variant: "xhigh" }])
- expect(
- textFromEvents(
- 'shared: https://example.test\n{"type":"text","sessionID":"ses_test","part":{"text":"finished"}}\n',
- ),
- ).toBe("finished")
- })
- test("resolves variants from verbose model output", () => {
- const output = `opencode/other
- {"variants":{}}
- opencode/gpt-5.5
- {"variants":{"high":{"reasoningEffort":"high"},"xhigh":{"reasoningEffort":"xhigh"}}}
- opencode/next
- {"variants":{}}
- `
- expect(modelVariants(output, "opencode/gpt-5.5")).toEqual({
- high: { reasoningEffort: "high" },
- xhigh: { reasoningEffort: "xhigh" },
- })
- })
- test("disables side effects and scopes edits for the translation agent", () => {
- const config = translationConfig("translate-app-fr", "opencode/gpt-5.5", ["packages/app/src/i18n/fr.ts"])
- expect(config.share).toBe("disabled")
- expect(config.formatter).toBe(false)
- expect(config.lsp).toBe(false)
- expect(config.agent["translate-app-fr"].permission.edit).toEqual({
- "*": "deny",
- "packages/app/src/i18n/fr.ts": "allow",
- })
- })
- test("detects edits outside the locale targets", () => {
- expect(
- unexpectedChanges(
- { "script/translate-app.ts": "before" },
- {
- "script/translate-app.ts": "before",
- "packages/app/src/i18n/fr.ts": "translated",
- "packages/app/src/app.tsx": "unexpected",
- },
- ["packages/app/src/i18n/fr.ts"],
- ),
- ).toEqual(["packages/app/src/app.tsx"])
- expect(unexpectedChanges({ "already-dirty.ts": "before" }, { "already-dirty.ts": "after" }, [])).toEqual([
- "already-dirty.ts",
- ])
- })
- })
|