test: add core reply-end-controls unit tests / 新增 core state-store-policy-callback 測試

This commit is contained in:
Alice (OpenClaw)
2026-05-13 11:46:28 +08:00
parent ca55445bcb
commit 73a6da8d12
2 changed files with 106 additions and 0 deletions

View File

@@ -4,9 +4,11 @@
"private": true,
"type": "module",
"scripts": {
"test": "tsx --test tests/**/*.test.mjs",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"tsx": "^4.20.6",
"typescript": "^5.9.3"
}
}

104
tests/core.test.mjs Normal file
View File

@@ -0,0 +1,104 @@
import test from "node:test"
import assert from "node:assert/strict"
import fs from "node:fs"
import os from "node:os"
import path from "node:path"
import { buildReplyEndState, clearReplyEndStateForConversation, getReplyEndState, setReplyEndState } from "../src/core/state.ts"
import { evaluateReplyEndPolicy } from "../src/core/policy.ts"
import { parseTelegramCallbackData, normalizeTelegramCallback } from "../src/core/callback-contract.ts"
import { resolveReplyEndStateFile, readReplyEndStateMap, saveReplyEndState, loadReplyEndState, removeReplyEndState } from "../src/core/store.ts"
test("parseTelegramCallbackData parses continue and stop", () => {
assert.equal(parseTelegramCallbackData("rec:continue"), "continue")
assert.equal(parseTelegramCallbackData("rec:stop"), "stop")
assert.equal(parseTelegramCallbackData("other"), null)
})
test("normalizeTelegramCallback returns normalized event", () => {
const event = normalizeTelegramCallback({
callbackData: "rec:continue",
conversationId: "telegram:1",
sessionKey: "session-1",
sourceMessageId: "100",
sourceCallbackId: "cb-1",
timestamp: "2026-05-13T00:00:00Z",
})
assert.deepEqual(event, {
choice: "continue",
conversationId: "telegram:1",
sessionKey: "session-1",
sourceMessageId: "100",
sourceCallbackId: "cb-1",
channel: "telegram",
timestamp: "2026-05-13T00:00:00Z",
})
})
test("state helpers build and update reply-end state", () => {
const state = buildReplyEndState({
choice: "stop",
conversationId: "telegram:1",
sessionKey: null,
sourceMessageId: "101",
sourceCallbackId: "cb-2",
channel: "telegram",
timestamp: "2026-05-13T00:01:00Z",
})
let stateMap = {}
stateMap = setReplyEndState(stateMap, "telegram:1", state)
assert.equal(getReplyEndState(stateMap, "telegram:1")?.lastChoice, "stop")
stateMap = clearReplyEndStateForConversation(stateMap, "telegram:1")
assert.equal(getReplyEndState(stateMap, "telegram:1"), null)
})
test("policy suppresses continuation only for active stop without typed follow-up", () => {
assert.deepEqual(evaluateReplyEndPolicy({ state: null, hasTypedUserFollowup: false }), {
suppressProactiveContinuation: false,
})
assert.deepEqual(
evaluateReplyEndPolicy({
state: {
lastChoice: "stop",
lastChoiceAt: "2026-05-13T00:02:00Z",
sourceMessageId: "102",
sourceCallbackId: "cb-3",
active: true,
},
hasTypedUserFollowup: false,
}),
{ suppressProactiveContinuation: true }
)
assert.deepEqual(
evaluateReplyEndPolicy({
state: {
lastChoice: "stop",
lastChoiceAt: "2026-05-13T00:02:00Z",
sourceMessageId: "102",
sourceCallbackId: "cb-3",
active: true,
},
hasTypedUserFollowup: true,
}),
{ suppressProactiveContinuation: false }
)
})
test("store helpers persist and load reply-end state", () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "reply-end-controls-"))
const filePath = resolveReplyEndStateFile(tempDir)
const state = {
lastChoice: "continue",
lastChoiceAt: "2026-05-13T00:03:00Z",
sourceMessageId: "103",
sourceCallbackId: "cb-4",
active: true,
}
saveReplyEndState(filePath, "telegram:2", state)
const map = readReplyEndStateMap(filePath)
assert.equal(map["telegram:2"].lastChoice, "continue")
const loaded = loadReplyEndState(filePath, "telegram:2")
assert.equal(loaded?.sourceMessageId, "103")
removeReplyEndState(filePath, "telegram:2")
assert.equal(loadReplyEndState(filePath, "telegram:2"), null)
})