Add template animation editor
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const http = require('http');
|
||||
const WebSocket = require('ws');
|
||||
|
||||
require('../src/common');
|
||||
|
||||
const { createPageAuthToken } = require('../src/request-auth');
|
||||
const { createPlayerRuntime } = require('../src/player/runtime');
|
||||
|
||||
const originalSecret = process.env.PULSE_SIGNAGE_SHARED_SECRET;
|
||||
|
||||
test.after(() => {
|
||||
if (originalSecret === undefined) {
|
||||
delete process.env.PULSE_SIGNAGE_SHARED_SECRET;
|
||||
} else {
|
||||
process.env.PULSE_SIGNAGE_SHARED_SECRET = originalSecret;
|
||||
}
|
||||
});
|
||||
|
||||
function waitFor(predicate, timeoutMs = 1000) {
|
||||
const start = Date.now();
|
||||
return new Promise((resolve, reject) => {
|
||||
const tick = () => {
|
||||
const value = predicate();
|
||||
if (value) {
|
||||
return resolve(value);
|
||||
}
|
||||
if (Date.now() - start > timeoutMs) {
|
||||
return reject(new Error('Timed out waiting for runtime state.'));
|
||||
}
|
||||
setTimeout(tick, 25);
|
||||
};
|
||||
tick();
|
||||
});
|
||||
}
|
||||
|
||||
test('player runtime snapshots websocket state and checks live names', async () => {
|
||||
process.env.PULSE_SIGNAGE_SHARED_SECRET = 'runtime-secret';
|
||||
|
||||
const runtime = createPlayerRuntime({ pool: null });
|
||||
const server = http.createServer();
|
||||
runtime.installWebsocket(server);
|
||||
|
||||
await new Promise((resolve) => server.listen(0, resolve));
|
||||
const { port } = server.address();
|
||||
const token = createPageAuthToken({ scope: 'player', slug: 'test2' });
|
||||
const client = new WebSocket(`ws://127.0.0.1:${port}/ws/screens/test2?auth=${encodeURIComponent(token)}`);
|
||||
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
client.once('open', resolve);
|
||||
client.once('error', reject);
|
||||
});
|
||||
|
||||
client.send(JSON.stringify({
|
||||
type: 'state',
|
||||
clientId: 'client-1',
|
||||
clientName: ' Lobby Player ',
|
||||
deviceId: 'device 123!?',
|
||||
userAgent: 'Mozilla/5.0 (unit test)',
|
||||
viewport: { width: 1920, height: 1080 },
|
||||
page: 'http://localhost:8081/screen/test2',
|
||||
paused: true,
|
||||
blackout: false,
|
||||
currentSlide: { id: 9, title: 'Intro', kind: 'slide', playlistSignature: 'sig' }
|
||||
}));
|
||||
|
||||
await waitFor(() => {
|
||||
const snapshot = runtime.snapshotConnections('test2')[0];
|
||||
return snapshot && snapshot.clientName === 'Lobby Player' ? snapshot : null;
|
||||
});
|
||||
const snapshot = runtime.snapshotConnections('test2')[0];
|
||||
|
||||
assert.equal(snapshot.clientName, 'Lobby Player');
|
||||
assert.equal(snapshot.deviceId, 'device123');
|
||||
assert.match(snapshot.label, /Lobby Player/);
|
||||
assert.equal(snapshot.paused, true);
|
||||
assert.equal(snapshot.currentSlideId, 9);
|
||||
assert.equal(snapshot.currentSlideTitle, 'Intro');
|
||||
assert.equal(await runtime.isClientNameAvailableOnScreen(null, 'Lobby Player', 'other-device'), false);
|
||||
assert.equal(await runtime.isClientNameAvailableOnScreen(null, 'Lobby Player', 'device123'), true);
|
||||
assert.equal(await runtime.isClientNameAvailableOnScreen(null, 'Other Name', 'device123'), true);
|
||||
} finally {
|
||||
client.close();
|
||||
await new Promise((resolve) => server.close(resolve));
|
||||
}
|
||||
});
|
||||
|
||||
test('player runtime sends targeted and broadcast commands to live sockets', async () => {
|
||||
process.env.PULSE_SIGNAGE_SHARED_SECRET = 'runtime-secret';
|
||||
|
||||
const runtime = createPlayerRuntime({ pool: null });
|
||||
const server = http.createServer();
|
||||
runtime.installWebsocket(server);
|
||||
|
||||
await new Promise((resolve) => server.listen(0, resolve));
|
||||
const { port } = server.address();
|
||||
const token = createPageAuthToken({ scope: 'player', slug: 'test2' });
|
||||
const clientA = new WebSocket(`ws://127.0.0.1:${port}/ws/screens/test2?auth=${encodeURIComponent(token)}`);
|
||||
const clientB = new WebSocket(`ws://127.0.0.1:${port}/ws/screens/test2?auth=${encodeURIComponent(token)}`);
|
||||
|
||||
function openClient(client) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.once('open', resolve);
|
||||
client.once('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForMessage(client) {
|
||||
return new Promise((resolve) => {
|
||||
client.once('message', (raw) => {
|
||||
resolve(JSON.parse(String(raw)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await Promise.all([openClient(clientA), openClient(clientB)]);
|
||||
|
||||
clientA.send(JSON.stringify({ type: 'state', clientId: 'client-a', clientName: 'Alpha', deviceId: 'device-a', page: 'http://localhost:8081/screen/test2' }));
|
||||
clientB.send(JSON.stringify({ type: 'state', clientId: 'client-b', clientName: 'Beta', deviceId: 'device-b', page: 'http://localhost:8081/screen/test2' }));
|
||||
|
||||
await waitFor(() => {
|
||||
const connections = runtime.snapshotConnections('test2');
|
||||
return connections.length === 2 && connections.every((connection) => connection.clientName);
|
||||
});
|
||||
const [firstConnection, secondConnection] = runtime.snapshotConnections('test2');
|
||||
|
||||
const targetedMessagePromise = waitForMessage(clientA);
|
||||
const targetedCount = await runtime.sendCommandToConnection('test2', firstConnection.id, { action: 'pause' });
|
||||
assert.equal(targetedCount, 1);
|
||||
const targetedMessage = await targetedMessagePromise;
|
||||
assert.equal(targetedMessage.type, 'command');
|
||||
assert.equal(targetedMessage.action, 'pause');
|
||||
assert.equal(targetedMessage.targetConnectionId, firstConnection.id);
|
||||
|
||||
const broadcastPromises = [waitForMessage(clientA), waitForMessage(clientB)];
|
||||
const broadcastCount = await runtime.broadcastCommand('test2', 'resume');
|
||||
assert.equal(broadcastCount, 2);
|
||||
const [broadcastA, broadcastB] = await Promise.all(broadcastPromises);
|
||||
assert.equal(broadcastA.type, 'command');
|
||||
assert.equal(broadcastA.command, 'resume');
|
||||
assert.equal(broadcastB.type, 'command');
|
||||
assert.equal(broadcastB.command, 'resume');
|
||||
assert.equal(broadcastA.targetConnectionId, undefined);
|
||||
assert.equal(broadcastB.targetConnectionId, undefined);
|
||||
|
||||
assert.equal(await runtime.sendCommandToConnection('test2', 'missing', 'pause'), 0);
|
||||
assert.equal(secondConnection.clientName, 'Beta');
|
||||
} finally {
|
||||
clientA.close();
|
||||
clientB.close();
|
||||
await new Promise((resolve) => server.close(resolve));
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user