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

This commit is contained in:
2026-09-04 15:43:55 +01:00
parent 2c150b5b2e
commit 98f969ca0f
104 changed files with 3559 additions and 447 deletions
+54
View File
@@ -23,6 +23,9 @@ test('API source payload accepts POST request and token-login settings', () => {
token_url: 'https://example.com/login',
token_request_body_json: '{"username":"demo","password":"secret"}',
token_response_path: 'data.accessToken',
token_refresh_url: 'https://example.com/refresh',
token_refresh_request_body_json: '{"grant_type":"refresh_token","refresh_token":"{{refresh_token}}"}',
token_refresh_response_path: 'data.refreshToken',
token_header_name: 'Authorization',
token_header_prefix: 'Bearer',
update_interval_value: '5',
@@ -35,6 +38,8 @@ test('API source payload accepts POST request and token-login settings', () => {
assert.equal(payload.authMethod, 'token_login');
assert.equal(payload.tokenUrl, 'https://example.com/login');
assert.equal(payload.tokenResponsePath, 'data.accessToken');
assert.equal(payload.tokenRefreshUrl, 'https://example.com/refresh');
assert.equal(payload.tokenRefreshResponsePath, 'data.refreshToken');
});
test('API source sends login POST, uses token, and refreshes once after 401', async () => {
@@ -81,3 +86,52 @@ test('API source sends login POST, uses token, and refreshes once after 401', as
global.fetch = originalFetch;
}
});
test('API source reuses an unexpired token and refreshes it after expiry', async () => {
const originalFetch = global.fetch;
const originalDateNow = Date.now;
const calls = [];
let currentTime = 1000000;
Date.now = () => currentTime;
global.fetch = async function (url, options) {
calls.push({ url, options });
if (url === 'https://example.com/login') {
return jsonResponse(200, { access_token: 'initial-token', refresh_token: 'initial-refresh', expires_in: 120 });
}
if (url === 'https://example.com/refresh') {
return jsonResponse(200, { access_token: 'refreshed-token', refresh_token: 'rotated-refresh', expires_in: 300 });
}
return jsonResponse(200, { items: [] });
};
const source = {
id: 987655,
api_url: 'https://example.com/report',
auth_method: 'token_login',
token_url: 'https://example.com/login',
token_request_body_json: JSON.stringify({ username: 'demo', password: 'secret' }),
token_refresh_url: 'https://example.com/refresh',
token_refresh_request_body_json: JSON.stringify({ grant_type: 'refresh_token', refresh_token: '{{refresh_token}}' })
};
try {
await fetchApiSourceResponse(source);
await fetchApiSourceResponse(source);
assert.equal(calls.filter(call => call.url === 'https://example.com/login').length, 1);
assert.equal(calls.filter(call => call.url === 'https://example.com/report').length, 2);
currentTime += 120000;
await fetchApiSourceResponse(source);
assert.equal(calls.filter(call => call.url === 'https://example.com/refresh').length, 1);
assert.deepEqual(JSON.parse(calls[3].options.body), { grant_type: 'refresh_token', refresh_token: 'initial-refresh' });
assert.equal(calls[4].options.headers.Authorization, 'Bearer refreshed-token');
currentTime += 300000;
await fetchApiSourceResponse(source);
assert.equal(calls.filter(call => call.url === 'https://example.com/refresh').length, 2);
assert.deepEqual(JSON.parse(calls[5].options.body), { grant_type: 'refresh_token', refresh_token: 'rotated-refresh' });
} finally {
Date.now = originalDateNow;
global.fetch = originalFetch;
}
});