Files
next-ai-draw-io/tests/unit/admin-secret-input.test.tsx
T
dayuan.jiang 3193d20e00 fix(model-config): keep model selection valid and fix admin panel edge cases
- Fall back to the default server model when a saved one disappears
- Sync model config across tabs
- Validation uses the base path and sends the access code
- Model ids edited as drafts (no empty, duplicate or padded ids)
- Credential changes reset validation; stale validation results are dropped
- Admin: generateId over HTTP, env-locked group switches, discard and toggle fixes,
  clearing a secret field keeps the saved key, first provider not auto-default when .env sets AI_MODEL
- Model selector items use unique values
2026-10-03 17:45:41 +09:00

88 lines
2.8 KiB
TypeScript

import { cleanup, fireEvent, render, screen } from "@testing-library/react"
import type { ReactNode } from "react"
import { afterEach, describe, expect, it, vi } from "vitest"
import { SecretInput, SettingField } from "@/app/[lang]/admin/setting-field"
import { DictionaryProvider } from "@/hooks/use-dictionary"
import type { SettingDef } from "@/lib/admin/settings-registry"
import type { Dictionary } from "@/lib/i18n/dictionaries"
import en from "@/lib/i18n/dictionaries/en.json"
const STORED = { isSet: true as const, hint: "…abcd" }
function withDict(node: ReactNode) {
return (
<DictionaryProvider dictionary={en as unknown as Dictionary}>
{node}
</DictionaryProvider>
)
}
function typeInto(label: string, text: string) {
fireEvent.change(screen.getByLabelText(label, { selector: "input" }), {
target: { value: text },
})
}
afterEach(cleanup)
describe("SecretInput", () => {
it("reverts to a key saved after mount instead of deleting it", () => {
const onChange = vi.fn()
const props = { id: "secret", keepOnEmpty: true, onChange }
// New provider: nothing stored at mount, then saved
const { rerender } = render(
withDict(
<>
<label htmlFor="secret">secret</label>
<SecretInput {...props} value={undefined} />
</>,
),
)
rerender(
withDict(
<>
<label htmlFor="secret">secret</label>
<SecretInput {...props} value={STORED} />
</>,
),
)
rerender(
withDict(
<>
<label htmlFor="secret">secret</label>
<SecretInput {...props} value="abc" />
</>,
),
)
typeInto("secret", "")
expect(onChange).toHaveBeenLastCalledWith(STORED)
})
})
describe("SettingField secret", () => {
const def: SettingDef = {
key: "LANGFUSE_SECRET_KEY",
group: "observability",
type: "secret",
label: "Langfuse Secret Key",
}
it("drops the pending change when a saved secret is typed over and cleared", () => {
const onChange = vi.fn()
const props = {
def,
state: { key: def.key, source: "file" as const, value: STORED },
disabled: false,
onChange,
}
const { rerender } = render(
withDict(<SettingField {...props} pendingValue={undefined} />),
)
rerender(withDict(<SettingField {...props} pendingValue="a" />))
typeInto(en.admin.settings.LANGFUSE_SECRET_KEY.label, "")
expect(onChange).toHaveBeenLastCalledWith(undefined)
})
})