Files
pulse-signage/test/api-source-request.test.js
lzstealth 98f969ca0f
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
Release v2.11.1
2026-09-04 15:43:55 +01:00

138 lines
5.5 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const { fetchApiSourceResponse, buildApiSourcePayload } = require('../src/data/api-sources');
function jsonResponse(status, body) {
return {
status: status,
ok: status >= 200 && status < 300,
headers: { get: () => 'application/json' },
text: async () => JSON.stringify(body)
};
}
test('API source payload accepts POST request and token-login settings', () => {
const payload = buildApiSourcePayload({
body: {
name: 'Protected report',
api_url: 'https://example.com/report',
request_method: 'POST',
request_body_json: '{"site_id":42}',
auth_method: 'token_login',
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',
update_interval_unit: 'minutes'
}
});
assert.equal(payload.requestMethod, 'POST');
assert.equal(payload.requestBodyJson, '{"site_id":42}');
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 () => {
const originalFetch = global.fetch;
const calls = [];
let loginCount = 0;
let apiCount = 0;
global.fetch = async function (url, options) {
calls.push({ url, options });
if (url === 'https://example.com/login') {
loginCount += 1;
return jsonResponse(200, { accessToken: 'token-' + loginCount, expires_in: 300 });
}
apiCount += 1;
return apiCount === 1
? jsonResponse(401, { error: 'expired' })
: jsonResponse(200, { items: [{ id: 1 }] });
};
try {
const result = await fetchApiSourceResponse({
id: 987654,
api_url: 'https://example.com/report',
request_method: 'POST',
request_body_json: JSON.stringify({ site_id: 42 }),
auth_method: 'token_login',
token_url: 'https://example.com/login',
token_request_body_json: JSON.stringify({ username: 'demo', password: 'secret' }),
token_response_path: 'accessToken',
token_header_name: 'Authorization',
token_header_prefix: 'Bearer'
});
assert.deepEqual(JSON.parse(result.responseJson), { items: [{ id: 1 }] });
assert.equal(loginCount, 2);
assert.equal(apiCount, 2);
assert.equal(calls[0].options.method, 'POST');
assert.equal(calls[0].options.headers['Content-Type'], 'application/json');
assert.deepEqual(JSON.parse(calls[0].options.body), { username: 'demo', password: 'secret' });
assert.equal(calls[1].options.headers.Authorization, 'Bearer token-1');
assert.equal(calls[3].options.headers.Authorization, 'Bearer token-2');
assert.deepEqual(JSON.parse(calls[3].options.body), { site_id: 42 });
} finally {
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;
}
});