Add onboarding weather and template gradients
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m53s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 34s

This commit is contained in:
2026-08-28 20:05:23 +01:00
parent aa07a78912
commit 3960931ebe
80 changed files with 12750 additions and 519 deletions
+79 -14
View File
@@ -97,6 +97,84 @@ function createPlayerRouteOptions(overrides) {
}, overrides);
}
test('local player serves a neutral shell for direct screen URLs', async () => {
const { app, handlers } = createAppAndHandlers();
registerPlayerRoutes(app, {
app,
pool: {
async query(sql) {
if (String(sql).includes('FROM d_onboarding_devices d')) {
return [[{ slug: 'target-screen' }]];
}
return [[]];
}
},
common: { renderPlayerPage() { return 'online'; } },
...createPlayerRouteOptions({
playerDeviceId: 'player-local'
})
});
const movedResponse = createResponse();
await handlers['/screen/:slug']({ params: { slug: 'target-screen' }, query: { clientId: 'tab-local' }, headers: {} }, movedResponse);
assert.equal(movedResponse.statusCode, 200);
assert.equal(movedResponse.body, 'online');
const oldResponse = createResponse();
await handlers['/screen/:slug']({ params: { slug: 'old-screen' }, query: { clientId: 'tab-local' }, headers: {} }, oldResponse);
assert.equal(oldResponse.statusCode, 200);
assert.equal(oldResponse.body, 'online');
});
test('remote player serves a neutral shell for direct screen URLs', async () => {
const { app, handlers } = createAppAndHandlers();
const originalFetch = global.fetch;
global.fetch = async function (url) {
if (String(url).includes('/api/onboarding/status')) {
return {
status: 200,
headers: { get() { return 'application/json'; } },
async json() {
return { screenId: 27, screenSlug: 'target-screen' };
}
};
}
return {
status: 200,
headers: { get() { return 'application/json'; } },
async json() {
return { screen: { slug: 'target-screen' } };
}
};
};
try {
registerPlayerRoutes(app, {
app,
pool: null,
common: { renderPlayerPage() { return 'online'; } },
...createPlayerRouteOptions({
bridgeBaseUrl: 'http://bridge.test',
playerDeviceId: 'player-remote'
})
});
const movedResponse = createResponse();
await handlers['/screen/:slug']({ params: { slug: 'target-screen' }, query: { clientId: 'tab-remote' }, headers: {} }, movedResponse);
await new Promise((resolve) => setImmediate(resolve));
assert.equal(movedResponse.statusCode, 200);
assert.equal(movedResponse.body, 'online');
const oldResponse = createResponse();
await handlers['/screen/:slug']({ params: { slug: 'old-screen' }, query: { clientId: 'tab-remote' }, headers: {} }, oldResponse);
await new Promise((resolve) => setImmediate(resolve));
assert.equal(oldResponse.statusCode, 200);
assert.equal(oldResponse.body, 'online');
} finally {
global.fetch = originalFetch;
}
});
test('screen route reports the request origin for the player public base url', async () => {
const { app, handlers } = createAppAndHandlers();
let reportedBaseUrl = null;
@@ -249,20 +327,7 @@ test('screen route renders the shell when playlist data is missing', async () =>
assert.equal(res.statusCode, 200);
assert.match(String(res.body), /Loading screen/);
assert.deepEqual(renderCalls, [
{
slug: 'test2',
data: {
screen: { id: 7, slug: 'test2' },
playlist: null,
slides: [],
rssFeeds: [],
apiSources: [],
timetableGroups: [],
revision: 'abc123'
}
}
]);
assert.deepEqual(renderCalls, [{ slug: 'test2', data: null }]);
});
test('playlist api route returns 404, etag, and 304 responses', async () => {