Make API and RSS refresh notifications change-only
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const { refreshApiSource, refreshRssFeed } = require('../src/web/lib/data-source-refresh');
|
||||
|
||||
function createConnection(options) {
|
||||
const state = Object.assign({
|
||||
rssItemSnapshots: [],
|
||||
slideRows: [],
|
||||
screenRows: []
|
||||
}, options || {});
|
||||
const calls = [];
|
||||
|
||||
return {
|
||||
calls,
|
||||
async beginTransaction() {
|
||||
calls.push(['beginTransaction']);
|
||||
},
|
||||
async commit() {
|
||||
calls.push(['commit']);
|
||||
},
|
||||
async rollback() {
|
||||
calls.push(['rollback']);
|
||||
},
|
||||
release() {
|
||||
calls.push(['release']);
|
||||
},
|
||||
async query(sql, params) {
|
||||
calls.push(['query', sql, params]);
|
||||
|
||||
if (sql.includes('SELECT item_json')) {
|
||||
return [state.rssItemSnapshots.map(function (itemJson) {
|
||||
return { item_json: itemJson };
|
||||
})];
|
||||
}
|
||||
|
||||
if (sql.includes('SELECT id, content_json FROM c_slides')) {
|
||||
return [state.slideRows];
|
||||
}
|
||||
|
||||
if (sql.includes('SELECT DISTINCT s.slug')) {
|
||||
return [state.screenRows];
|
||||
}
|
||||
|
||||
return [[]];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test('refreshApiSource notifies players only when the API snapshot changes', async () => {
|
||||
const connection = createConnection({
|
||||
slideRows: [{ id: 10, content_json: JSON.stringify({ source_id: 7 }) }],
|
||||
screenRows: [{ slug: 'screen-a' }]
|
||||
});
|
||||
const notifyCalls = [];
|
||||
const pool = {
|
||||
async getConnection() {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
const common = {
|
||||
async fetchApiSourceResponse() {
|
||||
return {
|
||||
responseJson: JSON.stringify({ value: 'new' }, null, 2),
|
||||
responseStatus: 200,
|
||||
responseContentType: 'application/json'
|
||||
};
|
||||
},
|
||||
parseJsonSafe(value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
};
|
||||
|
||||
await refreshApiSource(pool, common, {
|
||||
id: 7,
|
||||
last_response_json: JSON.stringify({ value: 'old' }, null, 2)
|
||||
}, 42, async function (slugs, payload) {
|
||||
notifyCalls.push({ slugs, payload });
|
||||
});
|
||||
|
||||
assert.deepEqual(notifyCalls, [{ slugs: ['screen-a'], payload: 'refresh' }]);
|
||||
});
|
||||
|
||||
test('refreshApiSource skips notifications when the API snapshot is unchanged', async () => {
|
||||
const connection = createConnection({
|
||||
slideRows: [{ id: 10, content_json: JSON.stringify({ source_id: 7 }) }],
|
||||
screenRows: [{ slug: 'screen-a' }]
|
||||
});
|
||||
const notifyCalls = [];
|
||||
const pool = {
|
||||
async getConnection() {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
const snapshot = JSON.stringify({ value: 'same' }, null, 2);
|
||||
const common = {
|
||||
async fetchApiSourceResponse() {
|
||||
return {
|
||||
responseJson: snapshot,
|
||||
responseStatus: 200,
|
||||
responseContentType: 'application/json'
|
||||
};
|
||||
},
|
||||
parseJsonSafe(value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
};
|
||||
|
||||
await refreshApiSource(pool, common, {
|
||||
id: 7,
|
||||
last_response_json: snapshot
|
||||
}, 42, async function (slugs, payload) {
|
||||
notifyCalls.push({ slugs, payload });
|
||||
});
|
||||
|
||||
assert.deepEqual(notifyCalls, []);
|
||||
});
|
||||
|
||||
test('refreshRssFeed notifies players only when the RSS items change', async () => {
|
||||
const connection = createConnection({
|
||||
rssItemSnapshots: [JSON.stringify({ title: 'Old item' })],
|
||||
slideRows: [{ id: 11, content_json: JSON.stringify({ feed_id: 9 }) }],
|
||||
screenRows: [{ slug: 'screen-b' }]
|
||||
});
|
||||
const notifyCalls = [];
|
||||
const pool = {
|
||||
async getConnection() {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
const common = {
|
||||
async fetchRssFeedItems() {
|
||||
return [{ title: 'New item' }];
|
||||
},
|
||||
async replaceRssFeedItems() {
|
||||
return 1;
|
||||
},
|
||||
parseJsonSafe(value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
};
|
||||
|
||||
await refreshRssFeed(pool, common, 9, 'https://example.com/feed.xml', 10, 42, async function (slugs, payload) {
|
||||
notifyCalls.push({ slugs, payload });
|
||||
});
|
||||
|
||||
assert.deepEqual(notifyCalls, [{ slugs: ['screen-b'], payload: 'refresh' }]);
|
||||
});
|
||||
|
||||
test('refreshRssFeed skips notifications when the RSS items are unchanged', async () => {
|
||||
const snapshot = JSON.stringify({ title: 'Same item' });
|
||||
const connection = createConnection({
|
||||
rssItemSnapshots: [snapshot],
|
||||
slideRows: [{ id: 11, content_json: JSON.stringify({ feed_id: 9 }) }],
|
||||
screenRows: [{ slug: 'screen-b' }]
|
||||
});
|
||||
const notifyCalls = [];
|
||||
const pool = {
|
||||
async getConnection() {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
const common = {
|
||||
async fetchRssFeedItems() {
|
||||
return [{ title: 'Same item' }];
|
||||
},
|
||||
async replaceRssFeedItems() {
|
||||
return 1;
|
||||
},
|
||||
parseJsonSafe(value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
};
|
||||
|
||||
await refreshRssFeed(pool, common, 9, 'https://example.com/feed.xml', 10, 42, async function (slugs, payload) {
|
||||
notifyCalls.push({ slugs, payload });
|
||||
});
|
||||
|
||||
assert.deepEqual(notifyCalls, []);
|
||||
});
|
||||
Reference in New Issue
Block a user