test(ui-models): cover the failure paths, and share the one message reader

The per-file coverage gate caught three uncovered paths in the error handling
this round added: the page banner for a failed row removal, the editor card's
transport-rejection catch, and `store.fail` itself.

Two of them are one click each — Remove with a rejecting write, Apply with a
rejecting write — so they are covered through the UI rather than by calling
the helpers directly. The third was a duplicated `error instanceof Error ?
error.message : String(error)` in two files; it becomes one exported
`messageOf`, which removes the branch from both call sites and gives the
fallback arm a home a direct unit test can reach (the lint rule forbids
rejecting a promise with a non-Error, so a rejection cannot exercise it).
This commit is contained in:
Yichen Jiang
2026-07-30 20:36:28 +08:00
parent af7dd4e340
commit f5d21af60b
5 changed files with 48 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
/** Page-store join: directory × namespaces × credentials, with last-good rows on failure. */
import { describe, expect, it } from 'vitest'
import type { RpcResponse } from '@deepseek-ai/dsh-client-connection/client'
import { ModelsSettingsStore } from '../src/client/store.ts'
import { messageOf, ModelsSettingsStore } from '../src/client/store.ts'
let nextRpc = 0
function ok<T>(value: T): RpcResponse<T> {
@@ -227,3 +227,13 @@ describe('edge joins', () => {
expect(store.store.getSnapshot().rows).toHaveLength(4)
})
})
describe('messageOf', () => {
it('reads an Error message, and stringifies anything else a rejection may carry', () => {
// The wire layer rejects with an Error, but a host or a runtime can reject
// with any value, and the page still has to render something.
expect(messageOf(new Error('connection lost'))).toBe('connection lost')
expect(messageOf('the host refused')).toBe('the host refused')
expect(messageOf(undefined)).toBe('undefined')
})
})