feat(couverture): 100pc API/MCP/tests/docs - volet 2
CI / build-and-test (push) Successful in 14m6s

- tests: server/tests/api_coverage2.test.mjs (23 cas offline-safe) :
  oauth (status/url/connections/preview), channels (validations),
  subscriptions batch + groupes CRUD, transcripts history, likes/history
  DELETE, playlists public/view/reorder, telemetry summary, downloads
  401/403/400, ai 503, twitch-token, config.js, rumble 400
- mcp v1.1.0 : 4 outils authentifies (list_playlists/likes/
  subscriptions/watch_history, NEWTUBE_TOKEN) + tests stub
- openapi.json v1.1 : 15 chemins documentes (sante, recherche,
  details, trending, transcript, auth, prefs, likes, subs, downloads,
  oauth, playlists) ; guide maj (11 outils)
This commit is contained in:
2026-09-27 18:51:50 -04:00
parent 1812b86dd4
commit 148a00e60f
7 changed files with 405 additions and 8 deletions
+27
View File
@@ -23,6 +23,10 @@ const stub = http.createServer((req, res) => {
if (u.pathname === '/api/trending') return json(200, { provider: 'yt', items: [{ id: 't1' }] });
if (u.pathname === '/api/transcript/youtube/v1') return json(200, { lang: 'fr', available: true, languages: ['fr', 'en'], lines: LINES });
if (u.pathname === '/api/transcript/youtube/none') return json(200, { lang: null, available: false, languages: [], lines: [], reason: 'no_subtitles' });
if (u.pathname === '/api/playlists') return json(200, [{ id: 'p1', title: 'Ma playlist' }]);
if (u.pathname === '/api/user/likes') return json(200, [{ provider: 'youtube', videoId: 'v1' }]);
if (u.pathname === '/api/subscriptions') return json(200, { items: [{ subscriptionId: 1 }], ttl: 1 });
if (u.pathname === '/api/user/history/watch') return json(200, [{ provider: 'youtube', videoId: 'v1' }]);
return json(404, { error: 'not_found' });
});
await new Promise((r) => stub.listen(0, '127.0.0.1', r));
@@ -98,4 +102,27 @@ describe('MCP tools (stub API)', () => {
assert.ok(m.error);
assert.equal(m.error.code, -32602);
});
it('outils authentifiés sans token -> isError NEWTUBE_TOKEN', async () => {
const m = await rpc(proc, 100, 'tools/call', { name: 'list_playlists', arguments: {} });
assert.equal(m.result.isError, true);
assert.match(m.result.content[0].text, /NEWTUBE_TOKEN/);
});
it('outils authentifiés avec token (stub)', async () => {
const authed = spawn(process.execPath, ['./mcp/server.mjs'], { env: { ...process.env, NEWTUBE_API_URL: STUB_URL, NEWTUBE_TOKEN: 'dummy-jwt' } });
try {
await rpc(authed, 1, 'initialize');
for (const [id, name, args, re] of [
[201, 'list_playlists', {}, /playlist/],
[202, 'list_likes', {}, /likée/],
[203, 'list_subscriptions', {}, /abonnement/],
[204, 'list_watch_history', {}, /historique/],
]) {
const m = await rpc(authed, id, 'tools/call', { name, arguments: args });
assert.equal(m.result.isError, undefined, `${name}: ${m.result.content?.[0]?.text?.slice(0, 200)}`);
assert.match(m.result.content[0].text, re);
}
} finally {
authed.kill();
}
});
});