fix: make timeline activation durable and visible
This commit is contained in:
@@ -120,6 +120,16 @@ const PLAYBACK_DETAIL = {
|
||||
snapshot: GROUP.playback,
|
||||
};
|
||||
|
||||
const TIMELINE = {
|
||||
description: null,
|
||||
eligibleFrom: null,
|
||||
eligibleUntil: null,
|
||||
id: "timeline-1",
|
||||
name: "Sunday morning",
|
||||
revision: 3,
|
||||
updatedAt: "2026-08-30T15:00:00.000Z",
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement("div");
|
||||
document.body.append(container);
|
||||
@@ -194,6 +204,78 @@ describe("Signage dashboard", () => {
|
||||
expect(container.querySelector("[data-testid='signage-controls']")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows which timeline remains active after the dashboard data is reloaded", async () => {
|
||||
const host = createFakeHost({
|
||||
permissions: ["signage.view", "signage.playback.control"],
|
||||
routes: [
|
||||
{ method: "GET", path: "settings", respond: () => jsonResponse(FAKE_SETTINGS) },
|
||||
{ method: "GET", path: "channel-groups", respond: () => jsonResponse({ groups: [GROUP] }) },
|
||||
{
|
||||
method: "GET",
|
||||
path: "timelines",
|
||||
respond: () => jsonResponse({ timelines: [TIMELINE] }),
|
||||
},
|
||||
{ method: "GET", path: "playback/group-1", respond: () => jsonResponse(PLAYBACK_DETAIL) },
|
||||
{ method: "GET", path: "providers", respond: () => jsonResponse({ providers: [] }) },
|
||||
],
|
||||
});
|
||||
|
||||
await render(<SignageDashboard context={host.context} />);
|
||||
expect(container.textContent).toContain("Active: Sunday morning");
|
||||
await click(
|
||||
[...container.querySelectorAll("[role='tab']")].find(
|
||||
(candidate) => candidate.textContent === "Timelines",
|
||||
),
|
||||
);
|
||||
|
||||
expect(container.textContent).toContain("Active in Main");
|
||||
expect(buttonNamed("Active")?.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps a failed activation visible instead of pretending it succeeded", async () => {
|
||||
const inactiveGroup = {
|
||||
...GROUP,
|
||||
playback: { ...GROUP.playback, activeTimelineId: null, currentSelectionId: null },
|
||||
};
|
||||
const host = createFakeHost({
|
||||
permissions: ["signage.view", "signage.playback.control"],
|
||||
routes: [
|
||||
{ method: "GET", path: "settings", respond: () => jsonResponse(FAKE_SETTINGS) },
|
||||
{
|
||||
method: "GET",
|
||||
path: "channel-groups",
|
||||
respond: () => jsonResponse({ groups: [inactiveGroup] }),
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
path: "timelines",
|
||||
respond: () => jsonResponse({ timelines: [TIMELINE] }),
|
||||
},
|
||||
{ method: "GET", path: "playback/group-1", respond: () => jsonResponse(PLAYBACK_DETAIL) },
|
||||
{ method: "GET", path: "providers", respond: () => jsonResponse({ providers: [] }) },
|
||||
{
|
||||
method: "POST",
|
||||
path: "playback/group-1/activate",
|
||||
respond: () =>
|
||||
errorResponse("SIGNAGE_CONFLICT", "The request conflicts with the current state.", 409),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await render(<SignageDashboard context={host.context} />);
|
||||
await click(
|
||||
[...container.querySelectorAll("[role='tab']")].find(
|
||||
(candidate) => candidate.textContent === "Timelines",
|
||||
),
|
||||
);
|
||||
await click(buttonNamed("Activate"));
|
||||
|
||||
expect(container.textContent).toContain("Sunday morning");
|
||||
expect(container.querySelector("[role='alert']")?.textContent).toContain(
|
||||
"The request conflicts with the current state.",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows Signage's own sanitized reason when a save is refused", async () => {
|
||||
const host = createFakeHost({
|
||||
permissions: ["signage.view", "signage.timelines.manage"],
|
||||
|
||||
Reference in New Issue
Block a user