根本原因: 原本的「今日羽球報名」bot 寫在 Node-RED 的 function 節點裡,不易測試與擴充; 羽球團又需要在 Telegram 群組內直接記分、看發球者,並把戰績寫進 web 版共用的 DB。 影響: 同一個 bot(@JianMiauBadmintonBot)改由本專案服務:報名指令、按鈕、暱稱、 週一 10:00 排程、白名單行為與訊息格式皆與 Node-RED 版相同,舊訊息按鈕仍可用; 另新增 /記分(/score、/new)記分板,並在結束/再一局時寫入共用的 history 表。 修法: - signup.js:逐句移植 Node-RED bd_sm 狀態機(attendance / tg_poll / tg_members) - scoreboard.js + match.js + render.js:羽球規則(發球區、換位、Deuce、30 分封頂)、 上排 1 2/下排 4 3 版面、從今日出席選人開局、⏱ 結算、兩段式結束確認、 開局者/管理員權限、scoreList(web 版格式) - history.js:寫入 history 表,欄位與 web 版 ensureHistoryTable 相同 - scripts/nodered-switch.mjs:透過 admin API 暫停/恢復 Node-RED 舊流程 - 單元測試 23 項(規則、報名、選人、結算、權限、歷史寫入),Dockerfile / compose Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
56 lines
2.0 KiB
JavaScript
56 lines
2.0 KiB
JavaScript
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { addPoint, createMatch, setFirstServer, settleMatch } from '../src/match.js'
|
|
import { buildHistoryPayload, saveHistory } from '../src/history.js'
|
|
|
|
test('buildHistoryPayload:欄位對齊 web 版 history(雙打)', () => {
|
|
const m = createMatch(['Gary', '蓉蓉'], ['柏威', '小念'])
|
|
setFirstServer(m, 0)
|
|
addPoint(m, 0)
|
|
addPoint(m, 1)
|
|
settleMatch(m)
|
|
const now = new Date('2026-08-17T20:30:00+08:00') // 週一
|
|
const p = buildHistoryPayload(m, now)
|
|
assert.deepEqual(p, {
|
|
time: Math.floor(now.getTime() / 1000),
|
|
dayOfWeek: 1,
|
|
score: [1, 1],
|
|
winScore: 21,
|
|
type: 0,
|
|
players: ['Gary', '蓉蓉', '柏威', '小念'],
|
|
team: [['Gary', '蓉蓉'], ['柏威', '小念']],
|
|
scoreList: [[0, 0, 0, 0], [1, 1, 0, 1]],
|
|
})
|
|
})
|
|
|
|
test('buildHistoryPayload:單打 players 以 [p1,p1,p3,p3] 讓 players[starter] 對得到人', () => {
|
|
const m = createMatch(['A'], ['B'], 15)
|
|
setFirstServer(m, 1)
|
|
addPoint(m, 1)
|
|
const p = buildHistoryPayload(m)
|
|
assert.equal(p.type, 1)
|
|
assert.equal(p.winScore, 15)
|
|
assert.deepEqual(p.players, ['A', 'A', 'B', 'B'])
|
|
assert.deepEqual(p.team, [['A'], ['B']])
|
|
assert.equal(p.players[p.scoreList[0][1]], 'B')
|
|
})
|
|
|
|
test('saveHistory:先 ensure table 再 INSERT,回傳 insertId', async () => {
|
|
const sqls = []
|
|
const query = async (sql, params) => {
|
|
sqls.push({ sql: sql.replace(/\s+/g, ' ').trim(), params })
|
|
return sql.includes('INSERT') ? { insertId: 42 } : []
|
|
}
|
|
const m = createMatch(['A', 'B'], ['C', 'D'])
|
|
setFirstServer(m, 0)
|
|
addPoint(m, 0)
|
|
const id = await saveHistory(m, { query, table: 'history_test' })
|
|
assert.equal(id, 42)
|
|
assert.match(sqls[0].sql, /CREATE TABLE IF NOT EXISTS `history_test`/)
|
|
assert.match(sqls[1].sql, /INSERT INTO `history_test` \(time, dayOfWeek, score, winScore, type, players, team, scoreList\)/)
|
|
assert.equal(sqls[1].params[2], '[1,0]')
|
|
assert.equal(sqls[1].params[5], '["A","B","C","D"]')
|
|
assert.equal(sqls[1].params[6], '[["A","B"],["C","D"]]')
|
|
assert.equal(sqls[1].params[7], '[[0,0,0,0]]')
|
|
})
|