mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo.git
synced 2026-09-22 17:22:01 -07:00
- Indexer maintains topicSummaries and topicRecency for topic messages and follows, idempotently, moving each room's recency record to its newest post. - DB adds the two index stores and serves GET /topics from them with limit/offset pagination, without iterating the rooms store. Adds util/room/backfill-topic-indexes.js to build the indexes idempotently. - Client topics page loads 50 per page with Previous/Next. By coder.
137 lines
4.2 KiB
JavaScript
137 lines
4.2 KiB
JavaScript
import { assert } from 'chai'
|
|
import sinon from 'sinon'
|
|
import TopicsRESTControllerLib from '../../../src/controllers/rest-api/topics/controller.js'
|
|
|
|
describe('#TopicsRESTController', () => {
|
|
let uut
|
|
let sandbox
|
|
|
|
beforeEach(() => {
|
|
sandbox = sinon.createSandbox()
|
|
uut = new TopicsRESTControllerLib({
|
|
adapters: {},
|
|
useCases: {
|
|
listTopics: {
|
|
execute: sandbox.stub().resolves({
|
|
topics: [
|
|
{ room: 'bitcoin', postCount: 2 },
|
|
{ room: 'cash', postCount: 1 }
|
|
]
|
|
})
|
|
},
|
|
listTopicPosts: {
|
|
execute: sandbox.stub().resolves({
|
|
posts: [{ txid: 'post-300', blockHeight: 300 }],
|
|
pagination: { limit: 100, offset: 0, total: 1, hasMore: false }
|
|
})
|
|
},
|
|
topicFollowState: {
|
|
execute: sandbox.stub().resolves({
|
|
room: 'bitcoin',
|
|
addr: 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d',
|
|
following: true
|
|
})
|
|
},
|
|
listTopicFollowers: {
|
|
execute: sandbox.stub().resolves({
|
|
room: 'bitcoin',
|
|
followers: ['bitcoincash:a', 'bitcoincash:b']
|
|
})
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
afterEach(() => sandbox.restore())
|
|
|
|
it('should return topics from use case', async () => {
|
|
const ctx = { query: { limit: '2', offset: '4' }, body: null, throw: sandbox.stub() }
|
|
await uut.getTopics(ctx)
|
|
|
|
assert.equal(uut.useCases.listTopics.execute.callCount, 1)
|
|
assert.deepEqual(uut.useCases.listTopics.execute.firstCall.args[0], { limit: '2', offset: '4' })
|
|
assert.equal(ctx.body.topics.length, 2)
|
|
assert.equal(ctx.body.topics[0].room, 'bitcoin')
|
|
})
|
|
|
|
it('should return topic posts from use case', async () => {
|
|
const ctx = {
|
|
params: { room: 'bitcoin' },
|
|
query: { limit: '50', offset: '0' },
|
|
body: null,
|
|
throw: sandbox.stub()
|
|
}
|
|
await uut.getTopicPosts(ctx)
|
|
|
|
assert.equal(uut.useCases.listTopicPosts.execute.callCount, 1)
|
|
assert.deepEqual(uut.useCases.listTopicPosts.execute.firstCall.args[0], {
|
|
room: 'bitcoin',
|
|
limit: '50',
|
|
offset: '0'
|
|
})
|
|
assert.equal(ctx.body.posts.length, 1)
|
|
assert.equal(ctx.body.posts[0].txid, 'post-300')
|
|
})
|
|
|
|
it('should return topic follow state from use case', async () => {
|
|
const ctx = {
|
|
params: { room: 'bitcoin' },
|
|
query: { addr: 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d' },
|
|
body: null,
|
|
throw: sandbox.stub()
|
|
}
|
|
await uut.getTopicFollowState(ctx)
|
|
|
|
assert.equal(uut.useCases.topicFollowState.execute.callCount, 1)
|
|
assert.deepEqual(uut.useCases.topicFollowState.execute.firstCall.args[0], {
|
|
room: 'bitcoin',
|
|
addr: 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d'
|
|
})
|
|
assert.equal(ctx.body.following, true)
|
|
})
|
|
|
|
it('should return topic followers from use case', async () => {
|
|
const ctx = {
|
|
params: { room: 'bitcoin' },
|
|
body: null,
|
|
throw: sandbox.stub()
|
|
}
|
|
await uut.getTopicFollowers(ctx)
|
|
|
|
assert.equal(uut.useCases.listTopicFollowers.execute.callCount, 1)
|
|
assert.deepEqual(uut.useCases.listTopicFollowers.execute.firstCall.args[0], {
|
|
room: 'bitcoin'
|
|
})
|
|
assert.deepEqual(ctx.body.followers, ['bitcoincash:a', 'bitcoincash:b'])
|
|
})
|
|
|
|
it('should throw a 500 when the use case fails without a status', async () => {
|
|
uut.useCases.listTopics.execute = sandbox.stub().rejects(new Error('boom'))
|
|
const ctx = { query: {}, body: null, throw: sandbox.stub() }
|
|
|
|
await uut.getTopics(ctx)
|
|
|
|
assert.equal(ctx.throw.callCount, 1)
|
|
assert.equal(ctx.throw.firstCall.args[0], 500)
|
|
assert.equal(ctx.throw.firstCall.args[1], 'boom')
|
|
})
|
|
|
|
it('should preserve the status when the use case throws a statused error', async () => {
|
|
const err = new Error('room is required')
|
|
err.status = 400
|
|
uut.useCases.listTopicPosts.execute = sandbox.stub().rejects(err)
|
|
const ctx = {
|
|
params: {},
|
|
query: {},
|
|
body: null,
|
|
throw: sandbox.stub()
|
|
}
|
|
|
|
await uut.getTopicPosts(ctx)
|
|
|
|
assert.equal(ctx.throw.callCount, 1)
|
|
assert.equal(ctx.throw.firstCall.args[0], 400)
|
|
assert.equal(ctx.throw.firstCall.args[1], 'room is required')
|
|
})
|
|
})
|