46 lines
2.8 KiB
JavaScript
46 lines
2.8 KiB
JavaScript
import {test} from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import {requestOfferAssistant} from '../src/services/offerAssistant.js';
|
||
const body={ikn:'2026/123',text:'Private source'};
|
||
test('account switch while inventory loads cannot send private context under the next account',async()=>{
|
||
let token='first', calls=0;
|
||
await assert.rejects(requestOfferAssistant({url:'/draft',body,readToken:()=>token,
|
||
listDocuments:async()=>{token='second';return {belgeler:[{ad:'Private document',tur:'firma'}]};},
|
||
fetcher:async()=>{calls++;return Response.json({success:true});}}),/Oturum veya ihale değişti/);
|
||
assert.equal(calls,0);
|
||
});
|
||
test('inventory errors stop generation and do not silently become empty documents',async()=>{
|
||
let calls=0;
|
||
for(const listDocuments of [async()=>{throw Error('Inventory unavailable');},async()=>({})]) {
|
||
await assert.rejects(requestOfferAssistant({url:'/draft',body,readToken:()=>'first',listDocuments,
|
||
fetcher:async()=>{calls++;return Response.json({});}}));
|
||
}
|
||
assert.equal(calls,0);
|
||
});
|
||
test('generation uses only company or matching tender documents and retains starting authorization',async()=>{
|
||
const result=await requestOfferAssistant({url:'/draft',body,readToken:()=>'first',
|
||
listDocuments:async()=>({belgeler:[{ad:'Company',tur:'firma'},{ad:'Source',tur:'ihale',ikn:'2026/123'},{ad:'Other tender',tur:'ihale',ikn:'2026/999'}]}),
|
||
fetcher:async(url,options)=>{
|
||
assert.equal(options.headers.Authorization,'Bearer first');
|
||
assert.deepEqual(JSON.parse(options.body).belgeler,[{ad:'Company'},{ad:'Source'}]);
|
||
return Response.json({success:true,bolumler:[]});
|
||
}});
|
||
assert.equal(result.success,true);
|
||
});
|
||
test('late answer is rejected after account or active tender changes',async()=>{
|
||
for (const change of ['account','view']) {
|
||
let token='first', mounted=true;
|
||
await assert.rejects(requestOfferAssistant({url:'/ask',body,readToken:()=>token,isCurrent:()=>mounted,
|
||
fetcher:async()=>{if(change==='account')token='second';else mounted=false;return Response.json({cevap:'Private answer'});}}),/Oturum veya ihale değişti/);
|
||
}
|
||
});
|
||
test('HTML, null and incomplete success responses cannot replace a valid existing result',async()=>{
|
||
for(const response of [new Response('<html>Gateway</html>'),Response.json(null),Response.json({}),Response.json({success:true,maddeler:[{durum:'unknown'}]})]) {
|
||
await assert.rejects(requestOfferAssistant({url:'/api/ai/teklif-denetim',body,readToken:()=>'first',fetcher:async()=>response}));
|
||
}
|
||
});
|
||
test('a stalled AI request times out instead of locking the assistant indefinitely',async()=>{
|
||
await assert.rejects(requestOfferAssistant({url:'/api/ai/belge-sor',body,readToken:()=>'first',timeoutMs:5,
|
||
fetcher:async(url,{signal})=>new Promise((resolve,reject)=>signal.addEventListener('abort',()=>reject(new DOMException('Aborted','AbortError')),{once:true}))}),/zaman aşımı/);
|
||
});
|