Phase 4: sync the site's published news posts into the Protocol 2.1 News gump. - uoLinkClient.postNews / deleteNews. - utils/newsGump.js — a STATE SYNC (not a one-shot announce leg): an article stays in the gump while its post is published news and is pulled when it leaves that state. buildArticle renders a compact gump-HTML block (centred title + plain-text excerpt — the gump supports only a small HTML subset) with a "more info" link to /site/news and an optional gump image from the `news_gump_image` setting. Every call is best-effort / never-throws. - Hooked into the posts pipeline alongside the existing announce enqueue: syncPost on create/update/publish (fresh publish announces; edits refresh silently; leaving published-news pulls the article), removePost on delete. - reassertAll() runs in uoLinkSocket.backfill on every WS (re)connect — reconciles the gump to our source of truth and recovers any article whose original live push failed (silent, so a reconnect never re-proclaims old news). Server 185/185, swagger regenerated. Refs .plans/protocol2-integration.md (Phase 4). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
2.8 KiB
JavaScript
70 lines
2.8 KiB
JavaScript
const { test, beforeEach, afterEach } = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
|
|
// Exercise the News-gump sync decisions against a fake sidecar client by
|
|
// monkeypatching the shared modules newsGump require()s (same instance) — no DB,
|
|
// no network.
|
|
const uoLinkClient = require('../src/utils/uoLinkClient')
|
|
const settings = require('../src/model/settings/settings.model')
|
|
const newsGump = require('../src/utils/newsGump')
|
|
|
|
let calls
|
|
const saved = {}
|
|
|
|
beforeEach(() => {
|
|
calls = { post: [], del: [] }
|
|
saved.postNews = uoLinkClient.postNews
|
|
saved.deleteNews = uoLinkClient.deleteNews
|
|
saved.get = settings.get
|
|
uoLinkClient.postNews = async (article) => { calls.post.push(article); return { ok: true, status: 200 } }
|
|
uoLinkClient.deleteNews = async (id) => { calls.del.push(id); return { ok: true, status: 200 } }
|
|
settings.get = async () => null // no gump image configured
|
|
})
|
|
|
|
afterEach(() => {
|
|
uoLinkClient.postNews = saved.postNews
|
|
uoLinkClient.deleteNews = saved.deleteNews
|
|
settings.get = saved.get
|
|
})
|
|
|
|
const newsPost = (over = {}) => ({ id: 42, category: 'news', published: true, title: 'Double XP Weekend', excerpt: 'Starts Friday.', body: null, ...over })
|
|
|
|
test('buildArticle centres the title, links the news list, and respects announce', async () => {
|
|
const a = await newsGump.buildArticle(newsPost(), { announce: false })
|
|
assert.equal(a.id, '42')
|
|
assert.match(a.body, /<CENTER>Double XP Weekend<\/CENTER>/)
|
|
assert.match(a.body, /Starts Friday\./)
|
|
assert.match(a.url, /\/site\/news$/)
|
|
assert.equal(a.announce, false)
|
|
})
|
|
|
|
test('a fresh publish into news pushes with announce=true', async () => {
|
|
await newsGump.syncPost(newsPost(), { wasPublished: false, wasNews: false })
|
|
assert.equal(calls.post.length, 1)
|
|
assert.equal(calls.post[0].announce, true)
|
|
assert.equal(calls.del.length, 0)
|
|
})
|
|
|
|
test('an edit of already-published news refreshes silently (announce=false)', async () => {
|
|
await newsGump.syncPost(newsPost({ title: 'Edited' }), { wasPublished: true, wasNews: true })
|
|
assert.equal(calls.post.length, 1)
|
|
assert.equal(calls.post[0].announce, false)
|
|
})
|
|
|
|
test('unpublishing published news pulls the article from the gump', async () => {
|
|
await newsGump.syncPost(newsPost({ published: false }), { wasPublished: true, wasNews: true })
|
|
assert.equal(calls.post.length, 0)
|
|
assert.deepEqual(calls.del, ['42'])
|
|
})
|
|
|
|
test('a draft never-published news post does nothing', async () => {
|
|
await newsGump.syncPost(newsPost({ published: false }), { wasPublished: false, wasNews: false })
|
|
assert.equal(calls.post.length, 0)
|
|
assert.equal(calls.del.length, 0)
|
|
})
|
|
|
|
test('a non-news post (e.g. screenshot) is never pushed', async () => {
|
|
await newsGump.syncPost(newsPost({ category: 'screenshot' }), { wasPublished: false, wasNews: false })
|
|
assert.equal(calls.post.length, 0)
|
|
})
|