124 lines
3.4 KiB
JavaScript
124 lines
3.4 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import { fetchJson } from '../web/resolver/utils/api_client.js';
|
|
|
|
function response({ body = null, ok = true, status = 200, statusText = 'OK' } = {}) {
|
|
return {
|
|
ok,
|
|
status,
|
|
statusText,
|
|
async json() {
|
|
return body;
|
|
},
|
|
};
|
|
}
|
|
|
|
test('fetchJson adds JSON headers and returns decoded response data', async () => {
|
|
const calls = [];
|
|
const apiClient = {
|
|
async fetchApi(endpoint, options) {
|
|
calls.push([endpoint, options]);
|
|
return response({ body: { value: 42 } });
|
|
},
|
|
};
|
|
|
|
const result = await fetchJson('/model_resolver/example', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ input: 'value' }),
|
|
}, 'Load example', { apiClient });
|
|
|
|
assert.deepEqual(result, { value: 42 });
|
|
assert.deepEqual(calls, [[
|
|
'/model_resolver/example',
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify({ input: 'value' }),
|
|
headers: { 'Content-Type': 'application/json' },
|
|
},
|
|
]]);
|
|
});
|
|
|
|
test('fetchJson preserves raw responses and handles no-content responses', async () => {
|
|
const rawResponse = response({ body: { raw: true } });
|
|
const apiClient = {
|
|
async fetchApi(endpoint) {
|
|
return endpoint === '/raw'
|
|
? rawResponse
|
|
: response({ status: 204, statusText: 'No Content' });
|
|
},
|
|
};
|
|
|
|
assert.equal(
|
|
await fetchJson('/raw', { raw: true }, 'Load raw response', { apiClient }),
|
|
rawResponse
|
|
);
|
|
assert.equal(
|
|
await fetchJson('/empty', {}, 'Load empty response', { apiClient }),
|
|
null
|
|
);
|
|
});
|
|
|
|
test('fetchJson reports server errors and respects silent requests', async () => {
|
|
const notifications = [];
|
|
const logs = [];
|
|
const apiClient = {
|
|
async fetchApi(endpoint) {
|
|
return response({
|
|
ok: false,
|
|
status: endpoint === '/silent-error' ? 503 : 400,
|
|
statusText: 'Request failed',
|
|
body: { error: 'Backend rejected request' },
|
|
});
|
|
},
|
|
};
|
|
|
|
await assert.rejects(
|
|
fetchJson('/error', {}, 'Load failed', {
|
|
apiClient,
|
|
notify: (message, type) => notifications.push([message, type]),
|
|
logError: (...args) => logs.push(args),
|
|
}),
|
|
error => error.message === 'Backend rejected request' && error.status === 400
|
|
);
|
|
assert.deepEqual(notifications, [['Backend rejected request', 'error']]);
|
|
assert.equal(logs.length, 1);
|
|
assert.match(logs[0][0], /Load failed failed/);
|
|
|
|
await assert.rejects(
|
|
fetchJson('/silent-error', { silent: true }, 'Silent failure', {
|
|
apiClient,
|
|
notify: (message, type) => notifications.push([message, type]),
|
|
logError: (...args) => logs.push(args),
|
|
}),
|
|
error => error.status === 503
|
|
);
|
|
assert.deepEqual(notifications, [['Backend rejected request', 'error']]);
|
|
});
|
|
|
|
test('fetchJson can return null for best-effort HTTP errors without logging or notifying', async () => {
|
|
const notifications = [];
|
|
const logs = [];
|
|
const apiClient = {
|
|
async fetchApi() {
|
|
return response({
|
|
ok: false,
|
|
status: 503,
|
|
statusText: 'Service unavailable',
|
|
body: { error: 'Backend temporarily unavailable' },
|
|
});
|
|
},
|
|
};
|
|
|
|
const result = await fetchJson('/best-effort-error', { silent: true }, 'Refresh metadata', {
|
|
apiClient,
|
|
notify: (message, type) => notifications.push([message, type]),
|
|
logError: (...args) => logs.push(args),
|
|
throwOnHttpError: false,
|
|
});
|
|
|
|
assert.equal(result, null);
|
|
assert.deepEqual(notifications, []);
|
|
assert.deepEqual(logs, []);
|
|
});
|