74 lines
5.4 KiB
JavaScript
74 lines
5.4 KiB
JavaScript
import test from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import {bildirimleriIsle,bildirilebilir} from '../server/notifier.mjs';
|
||
const future={id:'future-tender',tarih:'10.09.2026',saat:'10:00',durum:'Açık',baslik:'Laboratuvar'};
|
||
const now=()=>new Date('2026-09-06T10:00:00Z');
|
||
test('notification eligibility excludes expired cancelled and unknown deadlines',()=>{
|
||
assert.equal(bildirilebilir(future,now()),true);
|
||
for(const patch of [{durum:'İptal'},{durum:'Sonuçlandı'},{id:'hist-1'},{tarih:'01.09.2026'},{saat:''},{tarih:''}])assert.equal(bildirilebilir({...future,...patch},now()),false);
|
||
});
|
||
test('delivery failure retains pending items and batches acknowledge only included tenders',async()=>{
|
||
const rows=Array.from({length:28},(_,i)=>({...future,id:'t-'+i,ikn:'2026/'+i,baslik:'Laboratuvar '+i}));
|
||
const subscription={id:1,email:'qa@example.test',initialized:true,sonGorulenler:[]};
|
||
const sent=[],messages=[];let fail=true;
|
||
const dependencies={now,configured:()=>true,telegramReady:()=>false,readSubscriptions:()=>[subscription],reserve:(id,payload,ids)=>({id:'test-delivery',payload,tenderIds:ids}),accepted:delivery=>{sent.push(delivery.tenderIds);subscription.sonGorulenler.push(...delivery.tenderIds);},failed:()=>{},deliverEmail:async message=>{if(fail)throw new Error('provider unavailable');messages.push(message);return {id:'provider-test'};}};
|
||
assert.equal((await bildirimleriIsle(async()=>({tenders:rows}),{},dependencies)).hata,1);assert.equal(sent.length,0);
|
||
fail=false;assert.equal((await bildirimleriIsle(async()=>({tenders:rows}),{},dependencies)).gonderilen,1);assert.equal(sent[0].length,25);assert.match(messages[0].html,/>Laboratuvar 24</);assert.doesNotMatch(messages[0].html,/>Laboratuvar 25</);
|
||
await bildirimleriIsle(async()=>({tenders:rows}),{},dependencies);assert.equal(sent[1].length,3);assert.match(messages[1].html,/>Laboratuvar 27</);
|
||
await bildirimleriIsle(async()=>({tenders:rows}),{},dependencies);assert.equal(sent.length,2);
|
||
});
|
||
test('baseline is distinct from delivery and overlapping turns do not send twice',async()=>{
|
||
let release;const pending=new Promise(resolve=>release=resolve);let baseline=0;
|
||
const dependencies={now,configured:()=>true,telegramReady:()=>false,readSubscriptions:()=>[{id:1,initialized:false}],saveBaseline:()=>baseline++,deliverEmail:()=>assert.fail('baseline must not send')};
|
||
const first=bildirimleriIsle(async()=>{await pending;return {tenders:[future]};},{},dependencies);
|
||
assert.equal((await bildirimleriIsle(()=>assert.fail(),{},dependencies)).atlandi,'önceki tur sürüyor');
|
||
release();await first;assert.equal(baseline,1);
|
||
});
|
||
|
||
|
||
test('unreadable source never establishes baseline or touches delivery state, and next turn recovers',async()=>{
|
||
let baseline=0;
|
||
const deps={now,configured:()=>true,readSubscriptions:()=>[{id:1,initialized:false}],
|
||
saveBaseline:()=>baseline++,reserve:()=>assert.fail('invalid source must not reserve'),
|
||
accepted:()=>assert.fail('invalid source must not acknowledge'),deliverEmail:()=>assert.fail('must not deliver')};
|
||
for(const payload of [null,{}, {success:false,tenders:[]},{tenders:{}},{tenders:[null]},
|
||
{tenders:[{...future,id:''}]},{tenders:[{...future,baslik:''}]},
|
||
{tenders:[future,future]},{tenders:[{...future,items:{}}]},
|
||
{tenders:[{...future,items:[null]}]}]) {
|
||
await assert.rejects(bildirimleriIsle(async()=>payload,{},deps),/kaynağı geçersiz/);
|
||
assert.equal(baseline,0);
|
||
}
|
||
await bildirimleriIsle(async()=>({success:true,tenders:[]}),{},deps);
|
||
assert.equal(baseline,1,'a valid empty feed is distinct from an unreadable feed');
|
||
});
|
||
|
||
test('subscription criteria remain plain text in outgoing digest HTML',async()=>{
|
||
let message;
|
||
const criteria='<a href="https://example.test">Laboratuvar</a>';
|
||
const deps={now,configured:()=>true,telegramReady:()=>false,
|
||
readSubscriptions:()=>[{id:1,email:'qa@example.test',initialized:true,anahtar:criteria}],
|
||
reserve:(id,payload,tenderIds)=>({id:'escaped-test',payload,tenderIds}),accepted:()=>{},failed:()=>{},
|
||
deliverEmail:async payload=>{message=payload;return {id:'local-test'};}};
|
||
await bildirimleriIsle(async()=>({tenders:[{...future,baslik:criteria}]}),{},deps);
|
||
assert.ok(message);
|
||
assert.ok(message.html.includes('Kriteriniz: Anahtar: <a href="https://example.test">Laboratuvar</a>'));
|
||
assert.ok(!message.html.includes(criteria));
|
||
assert.ok(message.subject.includes(criteria),'the non-HTML subject retains the literal criterion');
|
||
});
|
||
|
||
test('pending digest is held before provider replay when its deadline or eligibility changed',async()=>{
|
||
const pinned={...future};
|
||
for(const current of [[],[{...future,durum:'İptal'}],[{...future,tarih:'01.09.2026'}],
|
||
[{...future,saat:''}],[{...future,tarih:'11.09.2026'}]]) {
|
||
let held=0;
|
||
const delivery={id:'pending',lease:'test',tenderIds:[future.id],payload:{digest:[pinned],html:'original'}};
|
||
const deps={now,configured:()=>true,telegramReady:()=>false,
|
||
readSubscriptions:()=>[{id:1,email:'qa',initialized:true,deliveryPending:true}],reserve:()=>delivery,
|
||
hold:(job,reason)=>{assert.equal(job,delivery);assert.match(reason,/incelemesi/);held++;},
|
||
accepted:()=>assert.fail('must not mark as delivered'),deliverEmail:()=>assert.fail('must not replay stale email')};
|
||
const result=await bildirimleriIsle(async()=>({tenders:current}),{},deps);
|
||
assert.equal(held,1);assert.equal(result.hata,1);assert.equal(result.gonderilen,0);
|
||
assert.equal(delivery.payload.html,'original');
|
||
}
|
||
});
|