fix: retain verified Telegram message receipts for weekly briefs
This commit is contained in:
@@ -9,7 +9,7 @@ function fixture(overrides={}) {
|
||||
store:{ listUsers:()=>[{email:'one@example.test'}], getData:(email,key)=>key==='brief'?prefs.get(email):{chatId:'test-chat'} },
|
||||
buildBrief:()=>({bos:false,hafta:'Test'}),text:()=> 'Test metni',html:()=> '<p>Test metni</p>',
|
||||
telegramConfigured:()=>true,emailConfigured:()=>true,
|
||||
sendTelegram:async()=>{calls.push('telegram');return true;},
|
||||
sendTelegram:async()=>{calls.push('telegram');return {id:'test-chat:1'};},
|
||||
sendEmail:async()=>{calls.push('email');return {id:'test-receipt'};},
|
||||
warn:()=>{}, ...overrides,
|
||||
};
|
||||
@@ -45,7 +45,7 @@ test('false and missing receipts do not become successful sends',async()=>{
|
||||
});
|
||||
|
||||
test('opt-out during Telegram delivery prevents the following email',async()=>{
|
||||
const f=fixture({sendTelegram:async()=>{f.prefs.set('one@example.test',{kapali:true});return true;}});
|
||||
const f=fixture({sendTelegram:async()=>{f.prefs.set('one@example.test',{kapali:true});return {id:'test-chat:1'};}});
|
||||
const result=await f.send(async()=>[]);
|
||||
assert.equal(result.gonderilen,1);
|
||||
assert.equal(result.kapali,1);
|
||||
@@ -79,7 +79,7 @@ test('one recipient failure does not skip subsequent recipients; feed failure is
|
||||
test('long brief is sent completely as plain text with each part accounted for',async()=>{
|
||||
const content=('Ürün <test> & 🧪\n').repeat(700),sent=[];
|
||||
const f=fixture({text:()=>content,emailConfigured:()=>false,
|
||||
sendTelegram:async(chatId,text,options)=>{sent.push(text);assert.deepEqual(options,{parseMode:null});return true;}});
|
||||
sendTelegram:async(chatId,text,options)=>{sent.push(text);assert.deepEqual(options,{parseMode:null,returnReceipt:true});return {id:'test-chat:1'};}});
|
||||
const result=await f.send(async()=>[]);
|
||||
assert.equal(sent.join(''),content);
|
||||
assert.ok(sent.length>1);
|
||||
@@ -89,7 +89,7 @@ test('long brief is sent completely as plain text with each part accounted for',
|
||||
|
||||
test('a failed Telegram part stops subsequent parts but still attempts email',async()=>{
|
||||
let attempts=0;
|
||||
const f=fixture({text:()=> 'x'.repeat(12000),sendTelegram:async()=>{attempts++;if(attempts===2)throw new Error('Unavailable');return true;}});
|
||||
const f=fixture({text:()=> 'x'.repeat(12000),sendTelegram:async()=>{attempts++;if(attempts===2)throw new Error('Unavailable');return {id:'test-chat:1'};}});
|
||||
const result=await f.send(async()=>[]);
|
||||
assert.equal(attempts,2);
|
||||
assert.deepEqual(result.kanallar.telegram,{denenen:2,kabul:1,hata:1});
|
||||
|
||||
@@ -134,3 +134,15 @@ test('review queue exposes expired interrupted sends but does not allow reviewin
|
||||
assert.throws(()=>outbox.resolve(`${batch.id}:0`,'admin@example.test',{action:'skip',note:'Bu gönderim halen etkin durumdadır.'}),{status:409});
|
||||
assert.equal(outbox.queue(121001)[0].state,'uncertain');
|
||||
});
|
||||
|
||||
test('Telegram provider receipt is persisted for each message and missing receipt stays uncertain',async t=>{
|
||||
const {outbox}=fixture(t);
|
||||
const telegram={store:{listUsers:()=>[{email:'telegram@example.test'}],getData:(email,key)=>key==='telegram'?{chatId:'123'}:null},
|
||||
telegramConfigured:()=>true,emailConfigured:()=>false,sendTelegram:async()=>({id:'123:42',chatId:'123',messageId:42})};
|
||||
const sent=await sender(outbox,telegram)(async()=>[]);
|
||||
assert.equal(sent.gonderilen,1);assert.equal(outbox.inspect()[0].receipt,'123:42');
|
||||
const missing=await sender(outbox,{...telegram,clock:()=>new Date('2026-09-14T05:00:00Z'),sendTelegram:async()=>true})(async()=>[]);
|
||||
assert.equal(missing.hata,1);assert.equal(missing.gonderilen,0);
|
||||
const uncertain=outbox.inspect().find(row=>row.week==='2026-09-14');
|
||||
assert.equal(uncertain.state,'uncertain');assert.equal(uncertain.receipt,null);
|
||||
});
|
||||
|
||||
@@ -20,3 +20,27 @@ test('brief plain-text mode reaches Telegram request without HTML parsing or con
|
||||
else process.env.TELEGRAM_BOT_TOKEN=oldToken;
|
||||
}
|
||||
});
|
||||
|
||||
test('Telegram receipts preserve chat and message ids and reject incomplete or mismatched acceptance',async()=>{
|
||||
const oldFetch=globalThis.fetch,oldToken=process.env.TELEGRAM_BOT_TOKEN;
|
||||
process.env.TELEGRAM_BOT_TOKEN='synthetic-test-token';
|
||||
let body={ok:true,result:{message_id:42,chat:{id:-100123}}},httpOk=true;
|
||||
globalThis.fetch=async()=>({ok:httpOk,status:httpOk?200:502,json:async()=>body});
|
||||
try {
|
||||
const options={parseMode:null,returnReceipt:true};
|
||||
assert.deepEqual(await sendTelegram('-100123','Test',options),{id:'-100123:42',chatId:'-100123',messageId:42});
|
||||
for(const result of [undefined,{}, {message_id:0,chat:{id:-100123}}, {message_id:42,chat:{id:999}},
|
||||
{message_id:'42',chat:{id:-100123}}, {message_id:42,chat:{id:0}}, {message_id:Number.MAX_SAFE_INTEGER+1,chat:{id:-100123}}]) {
|
||||
body={ok:true,result};
|
||||
await assert.rejects(sendTelegram('-100123','Test',options),/belirsiz/);
|
||||
}
|
||||
body={ok:true,result:{message_id:42,chat:{id:-100123}}};httpOk=false;
|
||||
await assert.rejects(sendTelegram('-100123','Test',options),/HTTP 502/);
|
||||
httpOk=true;body={ok:'true',result:{message_id:42,chat:{id:-100123}}};
|
||||
await assert.rejects(sendTelegram('-100123','Test',options),/HTTP 200/);
|
||||
} finally {
|
||||
globalThis.fetch=oldFetch;
|
||||
if(oldToken===undefined)delete process.env.TELEGRAM_BOT_TOKEN;
|
||||
else process.env.TELEGRAM_BOT_TOKEN=oldToken;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user