feat(housekeeping): load complete poll operator data

This commit is contained in:
Simo committed 2026-09-02 18:16:25 +02:00
1 parent de94b47cae
commit dba58cad4f
2 files changed
+405 -2

No files matched your search

@@ -280,6 +280,218 @@ describe("Content query", () => {
},
});
});
it("loads bounded poll summaries with operator counts and bound filters", async () => {
queryMocks.execute
.mockResolvedValueOnce([[{ total: 1 }]])
.mockResolvedValueOnce([
[
{
id: 7,
title: "Autumn plans",
status: "active",
updated_at: new Date("2026-09-01T08:00:00.000Z"),
show_results: 1,
multiple_choice: 0,
starts_at: new Date("2026-09-02T18:00:00.000Z"),
ends_at: null,
question_count: 3,
voter_count: 12,
answer_count: 30,
},
],
]);
const result = await loadProductionContentQuery({
routeId: "content.engagement.polls",
params: {},
list: {
...normalizedResponsePage,
search: "Autumn",
status: "active",
pageSize: 25,
offset: 0,
},
});
expect(result.items[0]?.privatePayload).toEqual({
kind: "poll-summary",
showResults: true,
multipleChoice: false,
startsAt: "2026-09-02T18:00:00.000Z",
endsAt: null,
questionCount: 3,
voterCount: 12,
answerCount: 30,
});
const sql = JSON.stringify(queryMocks.execute.mock.calls);
expect(sql).toContain("%autumn%");
expect(sql).toContain("active");
});
it("returns the stable poll-create payload without database access", async () => {
const result = await loadProductionContentQuery({
routeId: "content.engagement.poll-create",
params: {},
list: { ...normalizedResponsePage, search: "", pageSize: 25, offset: 0 },
});
expect(result).toEqual({
kind: "engagement",
items: [
{
id: "create",
title: "Create poll",
href: "/ase-next/content/engagement/polls/create",
privatePayload: { kind: "poll-create" },
},
],
total: 1,
partialDependencies: [],
});
expect(queryMocks.execute).not.toHaveBeenCalled();
});
it("loads selected poll results from bounded grouped aggregates and response pages", async () => {
queryMocks.execute
.mockResolvedValueOnce([
[
{
id: 7,
title: "Autumn plans",
description: "Complete poll",
status: "active",
updated_at: new Date("2026-09-01T08:00:00.000Z"),
show_results: 1,
multiple_choice: 0,
starts_at: new Date("2026-09-02T18:00:00.000Z"),
ends_at: null,
question_count: 2,
voter_count: 12,
answer_count: 30,
},
],
])
.mockResolvedValueOnce([
[
{
id: 21,
question: "Favourite colour?",
type: "single",
sort_order: 0,
options: "Red\nBlue",
},
{
id: 22,
question: "What should improve?",
type: "text",
sort_order: 1,
options: "",
},
],
])
.mockResolvedValueOnce([
[
{ question_id: 21, answer: "Red", answer_count: 3 },
{ question_id: 21, answer: "Blue", answer_count: 1 },
],
])
.mockResolvedValueOnce([[{ total: 51 }]])
.mockResolvedValueOnce([
[
{
id: 1,
question_id: 22,
user_id: 9,
username: "Alice",
answer: "More events",
created_at: new Date("2026-09-02T20:00:00.000Z"),
},
{
id: 2,
question_id: 22,
user_id: 10,
username: null,
answer: "Better prizes",
created_at: new Date("2026-09-02T19:00:00.000Z"),
},
],
]);
const result = await loadProductionContentQuery({
routeId: "content.engagement.poll-detail",
params: { id: "7" },
list: {
...normalizedResponsePage,
search: "",
pageSize: 25,
offset: 0,
responseQuestionId: "22",
responsePageSize: 25,
responseOffset: 25,
},
});
expect(result.items[0]?.privatePayload).toMatchObject({
kind: "poll-detail",
questions: [
{
id: "21",
options: ["Red", "Blue"],
answerCount: 4,
choiceResults: [
{ option: "Red", count: 3 },
{ option: "Blue", count: 1 },
],
},
{
id: "22",
type: "text",
options: [],
answerCount: 0,
choiceResults: [],
},
],
textResponses: {
questionId: "22",
total: 51,
pageSize: 25,
offset: 25,
items: [
{ userId: "9", username: "Alice", answer: "More events" },
{ userId: "10", username: null, answer: "Better prizes" },
],
},
});
const sql = JSON.stringify(queryMocks.execute.mock.calls);
expect(sql).toContain("LIMIT 101");
expect(sql).toContain("LIMIT 10001");
expect(sql).toContain("7");
expect(sql).toContain("22");
expect(sql).toContain("25");
expect(queryMocks.execute).toHaveBeenCalledTimes(5);
});
it("returns a valid empty detail result when the selected poll is missing", async () => {
queryMocks.execute.mockResolvedValueOnce([[]]);
await expect(
loadProductionContentQuery({
routeId: "content.engagement.poll-detail",
params: { id: "7" },
list: {
...normalizedResponsePage,
search: "",
pageSize: 25,
offset: 0,
},
}),
).resolves.toEqual({
kind: "engagement",
items: [],
total: 0,
partialDependencies: [],
});
});
it("loads only the selected event with all related operator data", async () => {
queryMocks.execute