fix: align server deadlines and follow consumers with preparation state
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { test, after } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { mkdtempSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const dir = mkdtempSync(join(tmpdir(), 'ihaleist-feed-'));
|
||||
process.env.IHALEIST_USER_DATA_DIR = dir;
|
||||
const store = await import('../server/user-store.mjs');
|
||||
const { ihaleFiltrele, yaklasanIhaleler, trTarih } = await import('../server/feeds-mcp.mjs');
|
||||
const { briefMetni, briefHtml, briefScheduleKey } = await import('../server/brief.mjs');
|
||||
after(() => rmSync(dir, { recursive: true, force: true }));
|
||||
const email = 'dates@example.test';
|
||||
const rows = [
|
||||
{ id:'past', ikn:'2026/1', tarih:'06.09.2026', saat:'00:00' },
|
||||
{ id:'future', ikn:'2026/2', tarih:'06.09.2026', saat:'10:00' },
|
||||
{ id:'unknown', ikn:'2026/3', tarih:'06.09.2026', saat:'' },
|
||||
{ id:'invalid', ikn:'2026/4', tarih:'31.09.2026', saat:'10:00' },
|
||||
{ id:'unfollowed', ikn:'2026/5', tarih:'07.09.2026', saat:'10:00' },
|
||||
];
|
||||
const now = new Date('2026-09-05T21:30:00Z'); // Istanbul Sep 6, 00:30; UTC still Sep 5.
|
||||
|
||||
test('RSS and MCP use Istanbul deadlines regardless of server timezone', () => {
|
||||
const previous = process.env.TZ;
|
||||
try {
|
||||
for (const zone of ['UTC', 'America/Los_Angeles', 'Europe/Istanbul']) {
|
||||
process.env.TZ = zone;
|
||||
assert.deepEqual(ihaleFiltrele(rows, {}, now).map(t => t.id), ['future','unknown','invalid','unfollowed']);
|
||||
assert.equal(trTarih('6/9/2026').toISOString(), '2026-09-05T21:00:00.000Z');
|
||||
assert.equal(trTarih('31.09.2026'), null);
|
||||
assert.equal(trTarih('06.09.2026 garbage'), null);
|
||||
}
|
||||
} finally {
|
||||
if (previous === undefined) delete process.env.TZ;
|
||||
else process.env.TZ = previous;
|
||||
}
|
||||
});
|
||||
|
||||
test('upcoming API reads saved follows, rejects stale unfollows and includes out-of-pool snapshots', () => {
|
||||
store.setData(email, 'takip', ['2026/5']);
|
||||
for (const t of rows) store.saveTenderState(email, t.ikn, { takipte: t.id !== 'unfollowed' }, t, 0);
|
||||
const outside = { id:'outside', ikn:'2026/6', tarih:'07.09.2026', saat:'09:00' };
|
||||
store.saveTenderState(email, outside.ikn, { takipte:true }, outside, 0);
|
||||
const result = yaklasanIhaleler(email, rows, 14, now);
|
||||
assert.deepEqual(result.map(t => t.ikn), ['2026/2','2026/3','2026/6']);
|
||||
assert.equal(result[0].kalan_gun, 0);
|
||||
assert.equal(result[0].son_teklif_zamani, '2026-09-06T07:00:00.000Z');
|
||||
assert.equal(result[1].saat_dogrulanmali, true);
|
||||
assert.equal(result[1].son_teklif_zamani, null);
|
||||
assert.equal(result[2].kalan_gun, 1);
|
||||
assert.deepEqual(yaklasanIhaleler('other@example.test', rows, 14, now), []);
|
||||
assert.ok(!store.getTrackedTenderKeys(email).includes('2026/5'));
|
||||
const brief = { hafta:'Test haftası', yaklasan:result, sonuclar:[] };
|
||||
for (const output of [briefMetni(brief), briefHtml(brief)]) {
|
||||
assert.match(output, /10:00 \(Türkiye saati\)/);
|
||||
assert.match(output, /saat doğrulanmalı/);
|
||||
}
|
||||
});
|
||||
|
||||
test('weekly notification schedule starts at Monday 08:00 Istanbul', () => {
|
||||
assert.equal(briefScheduleKey(new Date('2026-09-07T04:59:59Z')), null);
|
||||
assert.equal(briefScheduleKey(new Date('2026-09-07T05:00:00Z')), '2026-8-7');
|
||||
assert.equal(briefScheduleKey(new Date('2026-09-07T20:59:59Z')), '2026-8-7');
|
||||
assert.equal(briefScheduleKey(new Date('2026-09-07T21:00:00Z')), null);
|
||||
});
|
||||
Reference in New Issue
Block a user