Release 2.16.2
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m13s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 31s

This commit is contained in:
lzstealth committed 2026-10-21 01:38:22 +01:00
1 parent 8ce8228091
commit 49df51d92f
32 files changed
+390 -172

No files matched your search

+70
View File
@@ -195,6 +195,57 @@ test('server and browser rich-text rendering stay in sync', () => {
assert.equal(browserContext.renderEditorJsContent(value), renderEditorJsContent(value));
});
test('shared API item selection treats object paths as one item and preserves array/root behavior', () => {
const helpers = require('../src/web/public/js/shared/placeholder-utils');
const campaign = { name: 'Campaign', amount_raised: { value: '200' }, goal: { value: '1000' } };
const response = { data: campaign };
assert.deepEqual(helpers.resolveApiItems(response, 'data'), [campaign]);
assert.deepEqual(helpers.resolveApiItems(response, ''), [response]);
assert.deepEqual(helpers.resolveApiItems(response, 'missing'), []);
assert.deepEqual(helpers.resolveApiItems(response, 'data.name'), []);
assert.deepEqual(helpers.resolveApiItems(response, 'data.absent.nested'), []);
assert.deepEqual(helpers.resolveApiItems({ data: null }, 'data'), []);
assert.deepEqual(helpers.resolveApiItems({ data: {} }, 'data'), [{}]);
const rows = [campaign];
for (const key of ['items', 'results', 'data']) {
assert.equal(helpers.resolveApiItems({ [key]: rows }, ''), rows);
assert.equal(helpers.resolveApiItems({ [key]: rows }, key), rows);
}
assert.equal(helpers.resolveApiItems(rows, ''), rows);
assert.deepEqual(helpers.resolveApiItems({ data: rows }, 'data[0]'), [campaign]);
const sandbox = { window: {} };
vm.runInNewContext(fs.readFileSync(require.resolve('../src/web/public/js/shared/placeholder-utils.js'), 'utf8'), sandbox);
assert.equal(JSON.stringify(sandbox.window.placeholderUtils.resolveApiItems(response, 'data')), JSON.stringify([campaign]));
});
test('API editor and player resolve object paths, root overrides, and numeric placeholders consistently', () => {
let editor;
const campaign = { name: 'Campaign', amount_raised: { value: '200' }, goal: { value: '1000' } };
const response = { data: campaign };
const sources = [{ id: 4, items_path: 'data', responseJson: response }];
const context = {
window: {
pulseRegionTypes: { register(_type, definition) { editor = definition; } },
pulsePlayerRegionTypes: { register() {} }
},
initialData: { apiSources: sources },
escapeHtml: String
};
for (const file of ['../src/web/public/js/shared/placeholder-utils.js', '../src/web/public/js/regions/type/api.js', '../src/player/regions/api.js']) {
vm.runInNewContext(fs.readFileSync(require.resolve(file), 'utf8'), context);
}
assert.equal(editor.getItems(4, sources)[0], campaign);
assert.equal(editor.getItemCount(4, sources), 1);
assert.equal(context.getApiItem(4, 1), campaign);
assert.equal(context.getApiItem(4, 2), null);
assert.equal(editor.getItems(4, sources, '')[0], response);
assert.equal(context.getApiItem(4, 1, ''), response);
assert.equal(editor.getItemCount(4, sources, 'missing'), 0);
assert.equal(context.getApiItem(4, 1, 'missing'), null);
assert.equal(context.substituteApiVariables('{{amount_raised.value}}', campaign, 4), '200');
assert.match(context.substituteApiVariables('{{progress(amount_raised.value,goal.value)}}', campaign, 4), /width:20%/);
});
test('shared API progress placeholder renders a clamped bar from numeric fields', () => {
const sandbox = { window: {} };
vm.runInNewContext(fs.readFileSync(require.resolve('../src/web/public/js/shared/placeholder-utils.js'), 'utf8'), sandbox);
@@ -237,6 +288,25 @@ test('shared API progress placeholder renders a clamped bar from numeric fields'
assert.match(literalMarkup, /aria-valuenow="30"/);
});
test('progress placeholders ignore rich-text formatting inside numeric and field arguments', () => {
const sandbox = { window: {} };
vm.runInNewContext(fs.readFileSync(require.resolve('../src/web/public/js/shared/placeholder-utils.js'), 'utf8'), sandbox);
const placeholderUtils = sandbox.window.placeholderUtils;
const literal = 'progress(<span style="font-family: \'Ubuntu Regular\', Helvetica, sans-serif; font-size: 96px; color: #ffffff;">200</span>,<span style="font-family: \'Ubuntu Regular\', Helvetica, sans-serif; font-size: 96px; color: #ffffff;">1000</span>,#F47B20,#2D2D2D,pill)';
assert.equal(placeholderUtils.isProgressPlaceholderExpression(literal), true);
const markup = placeholderUtils.renderProgressPlaceholder({}, literal);
assert.match(markup, /aria-valuenow="20"/);
assert.match(markup, /width:20%/);
assert.match(markup, /background-color:#f47b20/);
assert.match(markup, /background-color:#2d2d2d/);
assert.doesNotMatch(markup, /Ubuntu|font-size:96px/);
const fields = placeholderUtils.renderProgressPlaceholder(
{ raised: { value: 200 }, target: { amount: 1000 } },
'progress(<strong><span>raised.value</span></strong>,<em>target.amount</em>,pill)'
);
assert.match(fields, /aria-valuenow="20"/);
});
test('shared placeholder transforms support arithmetic', () => {
const sandbox = { window: {} };
vm.runInNewContext(fs.readFileSync(require.resolve('../src/web/public/js/shared/placeholder-utils.js'), 'utf8'), sandbox);