428 lines
12 KiB
JavaScript
428 lines
12 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
|
|
require('../src/common');
|
|
|
|
const registerScreensRoutes = require('../src/web/routes/signage/screens/routes');
|
|
const { renderScreenEditPage } = require('../src/web/pages');
|
|
|
|
test('screen edit page includes shared launcher downloads and base player url', async () => {
|
|
const handlers = {};
|
|
const app = {
|
|
get(path, ...routeHandlers) {
|
|
handlers[path] = routeHandlers;
|
|
}
|
|
};
|
|
|
|
let renderedArgs = null;
|
|
const pages = {
|
|
renderScreenEditPage(screen, data, message, currentUser) {
|
|
renderedArgs = { screen, data, message, currentUser };
|
|
return 'ok';
|
|
}
|
|
};
|
|
|
|
registerScreensRoutes(app, {
|
|
pool: {
|
|
async query() {
|
|
return [[]];
|
|
}
|
|
},
|
|
common: {
|
|
async fetchScreenById() {
|
|
return { id: 7, name: 'Demo Conference', slug: 'demo-conference', playlist_id: null };
|
|
},
|
|
async fetchScreenEditData() {
|
|
return { playlists: [] };
|
|
},
|
|
async fetchPlayerRegistrations() {
|
|
return [
|
|
{ identifier: 'player-alpha', public_base_url: 'http://alpha.example', last_seen_at: new Date().toISOString() },
|
|
{ identifier: 'player-beta', public_base_url: 'http://beta.example/', last_seen_at: new Date().toISOString() }
|
|
];
|
|
},
|
|
async fetchPlayerPublicBaseUrl() {
|
|
return 'http://player.example';
|
|
}
|
|
},
|
|
pages,
|
|
buildDashboardState: async () => ({ screens: [] }),
|
|
getScreenDeleteBlockMessage: async () => '',
|
|
getScreenConnections: async () => [],
|
|
playerPublicBaseUrl: 'http://player.example',
|
|
requirePermission() {
|
|
return function (_req, _res, next) {
|
|
next();
|
|
};
|
|
}
|
|
});
|
|
|
|
const handler = handlers['/screens/:id/edit'];
|
|
assert.equal(Array.isArray(handler), true);
|
|
|
|
const res = {
|
|
send(value) {
|
|
this.body = value;
|
|
},
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
}
|
|
};
|
|
|
|
await handler[1]({ params: { id: '7' }, query: {}, currentUser: { id: 1 } }, res, () => {});
|
|
|
|
assert.equal(res.body, 'ok');
|
|
assert.deepEqual(renderedArgs.screen.player_urls, [
|
|
{
|
|
identifier: 'player-alpha',
|
|
public_base_url: 'http://alpha.example',
|
|
player_url: 'http://alpha.example/screen/demo-conference'
|
|
},
|
|
{
|
|
identifier: 'player-beta',
|
|
public_base_url: 'http://beta.example',
|
|
player_url: 'http://beta.example/screen/demo-conference'
|
|
}
|
|
]);
|
|
assert.deepEqual(renderedArgs.screen.launcher_downloads, {
|
|
windows: '/downloads/kiosk/pulse-signage-kiosk.bat',
|
|
linux: '/downloads/kiosk/pulse-signage-kiosk.sh'
|
|
});
|
|
});
|
|
|
|
test('screen edit query route includes player urls for every registration', async () => {
|
|
const handlers = {};
|
|
const app = {
|
|
get(path, ...routeHandlers) {
|
|
handlers[path] = routeHandlers;
|
|
}
|
|
};
|
|
|
|
let renderedArgs = null;
|
|
const pages = {
|
|
renderScreenEditPage(screen, data, message, currentUser) {
|
|
renderedArgs = { screen, data, message, currentUser };
|
|
return 'ok';
|
|
}
|
|
};
|
|
|
|
registerScreensRoutes(app, {
|
|
pool: {
|
|
async query() {
|
|
return [[]];
|
|
}
|
|
},
|
|
common: {
|
|
async fetchScreenById() {
|
|
return { id: 7, name: 'Demo Conference', slug: 'demo-conference', playlist_id: null };
|
|
},
|
|
async fetchScreenEditData() {
|
|
return { playlists: [] };
|
|
},
|
|
async fetchPlayerRegistrations() {
|
|
return [
|
|
{ identifier: 'player-alpha', public_base_url: 'http://alpha.example', last_seen_at: new Date().toISOString() }
|
|
];
|
|
},
|
|
async fetchPlayerPublicBaseUrl() {
|
|
return 'http://player.example';
|
|
}
|
|
},
|
|
pages,
|
|
buildDashboardState: async () => ({ screens: [] }),
|
|
getScreenDeleteBlockMessage: async () => '',
|
|
getScreenConnections: async () => [],
|
|
playerPublicBaseUrl: 'http://player.example',
|
|
requirePermission() {
|
|
return function (_req, _res, next) {
|
|
next();
|
|
};
|
|
}
|
|
});
|
|
|
|
const handler = handlers['/screens'];
|
|
assert.equal(Array.isArray(handler), true);
|
|
|
|
const res = {
|
|
send(value) {
|
|
this.body = value;
|
|
},
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
}
|
|
};
|
|
|
|
await handler[1]({ query: { edit: '7' }, currentUser: { id: 1 } }, res, () => {});
|
|
|
|
assert.equal(res.body, 'ok');
|
|
assert.deepEqual(renderedArgs.screen.player_urls, [
|
|
{
|
|
identifier: 'player-alpha',
|
|
public_base_url: 'http://alpha.example',
|
|
player_url: 'http://alpha.example/screen/demo-conference'
|
|
}
|
|
]);
|
|
assert.deepEqual(renderedArgs.screen.launcher_downloads, {
|
|
windows: '/downloads/kiosk/pulse-signage-kiosk.bat',
|
|
linux: '/downloads/kiosk/pulse-signage-kiosk.sh'
|
|
});
|
|
});
|
|
|
|
test('screen edit page hides stale player registrations', async () => {
|
|
const handlers = {};
|
|
const app = {
|
|
get(path, ...routeHandlers) {
|
|
handlers[path] = routeHandlers;
|
|
}
|
|
};
|
|
|
|
let renderedArgs = null;
|
|
const now = Date.now();
|
|
const recentSeenAt = new Date(now - 10 * 1000).toISOString();
|
|
const staleSeenAt = new Date(now - 5 * 60 * 1000).toISOString();
|
|
const pages = {
|
|
renderScreenEditPage(screen, data, message, currentUser) {
|
|
renderedArgs = { screen, data, message, currentUser };
|
|
return 'ok';
|
|
}
|
|
};
|
|
|
|
registerScreensRoutes(app, {
|
|
pool: {
|
|
async query() {
|
|
return [[]];
|
|
}
|
|
},
|
|
common: {
|
|
async fetchScreenById() {
|
|
return { id: 7, name: 'Demo Conference', slug: 'demo-conference', playlist_id: null };
|
|
},
|
|
async fetchScreenEditData() {
|
|
return { playlists: [] };
|
|
},
|
|
async fetchPlayerRegistrations() {
|
|
return [
|
|
{ identifier: 'player-stale', public_base_url: 'http://stale.example', last_seen_at: staleSeenAt },
|
|
{ identifier: 'player-recent', public_base_url: 'http://recent.example', last_seen_at: recentSeenAt }
|
|
];
|
|
},
|
|
async fetchPlayerPublicBaseUrl() {
|
|
return 'http://player.example';
|
|
}
|
|
},
|
|
pages,
|
|
buildDashboardState: async () => ({ screens: [] }),
|
|
getScreenDeleteBlockMessage: async () => '',
|
|
getScreenConnections: async () => [],
|
|
formatDashboardDate(value) {
|
|
return `formatted:${String(value)}`;
|
|
},
|
|
playerPublicBaseUrl: 'http://player.example',
|
|
requirePermission() {
|
|
return function (_req, _res, next) {
|
|
next();
|
|
};
|
|
}
|
|
});
|
|
|
|
const handler = handlers['/screens/:id/edit'];
|
|
assert.equal(Array.isArray(handler), true);
|
|
|
|
const res = {
|
|
send(value) {
|
|
this.body = value;
|
|
},
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
}
|
|
};
|
|
|
|
await handler[1]({ params: { id: '7' }, query: {}, currentUser: { id: 1 } }, res, () => {});
|
|
|
|
assert.equal(res.body, 'ok');
|
|
assert.deepEqual(renderedArgs.screen.player_urls.map(function (player) {
|
|
return {
|
|
identifier: player.identifier,
|
|
public_base_url: player.public_base_url,
|
|
player_url: player.player_url
|
|
};
|
|
}), [
|
|
{
|
|
identifier: 'player-recent',
|
|
public_base_url: 'http://recent.example',
|
|
player_url: 'http://recent.example/screen/demo-conference'
|
|
}
|
|
]);
|
|
});
|
|
|
|
test('screen edit page renders player urls as an adminlte table', async () => {
|
|
const html = renderScreenEditPage(
|
|
{
|
|
id: 7,
|
|
name: 'Demo Conference',
|
|
slug: 'demo-conference',
|
|
playlist_id: null,
|
|
player_urls: [
|
|
{
|
|
identifier: 'player-alpha',
|
|
public_base_url: 'http://alpha.example',
|
|
player_url: 'http://alpha.example/screen/demo-conference'
|
|
}
|
|
]
|
|
},
|
|
{ playlists: [] },
|
|
'',
|
|
{ id: 1 }
|
|
);
|
|
|
|
assert.match(html, /Player URLs/);
|
|
assert.match(html, /<table/i);
|
|
assert.match(html, /card-body table-responsive p-0/);
|
|
assert.match(html, /table table-striped w-100 mb-0/);
|
|
assert.match(html, /player-alpha/);
|
|
});
|
|
|
|
test('screen launcher downloads are shared and attached', async () => {
|
|
const handlers = {};
|
|
const app = {
|
|
get(path, ...routeHandlers) {
|
|
handlers[path] = routeHandlers;
|
|
}
|
|
};
|
|
|
|
registerScreensRoutes(app, {
|
|
pool: {
|
|
async query() {
|
|
return [[]];
|
|
}
|
|
},
|
|
common: {
|
|
async fetchScreenById() {
|
|
return { id: 7, name: 'Demo Conference', slug: 'demo-conference', playlist_id: null };
|
|
},
|
|
async fetchScreenEditData() {
|
|
return { playlists: [] };
|
|
},
|
|
async fetchScreenPlayerUrls() {
|
|
return {
|
|
'demo-conference': 'http://player.example/screen/demo-conference'
|
|
};
|
|
},
|
|
async fetchPlayerPublicBaseUrl() {
|
|
return 'http://player.example';
|
|
}
|
|
},
|
|
pages: { renderScreenEditPage() { return 'ok'; } },
|
|
buildDashboardState: async () => ({ screens: [] }),
|
|
getScreenDeleteBlockMessage: async () => '',
|
|
getScreenConnections: async () => [],
|
|
playerPublicBaseUrl: 'http://player.example',
|
|
requirePermission() {
|
|
return function (_req, _res, next) {
|
|
next();
|
|
};
|
|
}
|
|
});
|
|
|
|
const windowsHandler = handlers['/downloads/kiosk/pulse-signage-kiosk.bat'];
|
|
assert.equal(Array.isArray(windowsHandler), true);
|
|
|
|
const res = {
|
|
headers: {},
|
|
statusCode: 200,
|
|
set(name, value) {
|
|
this.headers[name.toLowerCase()] = value;
|
|
},
|
|
attachment(filename) {
|
|
this.headers['content-disposition'] = `attachment; filename="${filename}"`;
|
|
},
|
|
type(value) {
|
|
this.headers['content-type'] = value;
|
|
},
|
|
send(value) {
|
|
this.body = value;
|
|
},
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
}
|
|
};
|
|
|
|
await windowsHandler[1]({ params: { id: '7' } }, res, () => {});
|
|
|
|
assert.equal(res.statusCode, 200);
|
|
assert.match(res.headers['content-disposition'], /pulse-signage-kiosk\.bat/);
|
|
assert.match(res.body, /TARGET_URL=http:\/\/player\.example/);
|
|
assert.match(res.body, /--kiosk/);
|
|
});
|
|
|
|
test('screen launcher downloads can target an explicit player url', async () => {
|
|
const handlers = {};
|
|
const app = {
|
|
get(path, ...routeHandlers) {
|
|
handlers[path] = routeHandlers;
|
|
}
|
|
};
|
|
|
|
registerScreensRoutes(app, {
|
|
pool: {
|
|
async query() {
|
|
return [[]];
|
|
}
|
|
},
|
|
common: {
|
|
async fetchScreenById() {
|
|
return { id: 7, name: 'Demo Conference', slug: 'demo-conference', playlist_id: null };
|
|
},
|
|
async fetchScreenEditData() {
|
|
return { playlists: [] };
|
|
},
|
|
async fetchPlayerPublicBaseUrl() {
|
|
return 'http://player.example';
|
|
}
|
|
},
|
|
pages: { renderScreenEditPage() { return 'ok'; } },
|
|
buildDashboardState: async () => ({ screens: [] }),
|
|
getScreenDeleteBlockMessage: async () => '',
|
|
getScreenConnections: async () => [],
|
|
playerPublicBaseUrl: 'http://player.example',
|
|
requirePermission() {
|
|
return function (_req, _res, next) {
|
|
next();
|
|
};
|
|
}
|
|
});
|
|
|
|
const windowsHandler = handlers['/downloads/kiosk/pulse-signage-kiosk.bat'];
|
|
assert.equal(Array.isArray(windowsHandler), true);
|
|
|
|
const res = {
|
|
headers: {},
|
|
statusCode: 200,
|
|
set(name, value) {
|
|
this.headers[name.toLowerCase()] = value;
|
|
},
|
|
attachment(filename) {
|
|
this.headers['content-disposition'] = `attachment; filename="${filename}"`;
|
|
},
|
|
type(value) {
|
|
this.headers['content-type'] = value;
|
|
},
|
|
send(value) {
|
|
this.body = value;
|
|
},
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
}
|
|
};
|
|
|
|
await windowsHandler[1]({ query: { playerUrl: 'http://player-b.example/screen/demo-conference' } }, res, () => {});
|
|
|
|
assert.equal(res.statusCode, 200);
|
|
assert.match(res.body, /TARGET_URL=http:\/\/player-b\.example\/screen\/demo-conference/);
|
|
assert.doesNotMatch(res.body, /TARGET_URL=http:\/\/player\.example/);
|
|
}); |