···188188 expect(logger.warn).toHaveBeenCalledWith('Skipping post - After MAX_DATE [Wed, 01 Jan 2025 00:00:00 GMT]');
189189 });
190190191191+ // New tests for MIN_DATE and MAX_DATE functionality
192192+ describe('Date Filtering', () => {
193193+ test('should include posts exactly on MIN_DATE', async () => {
194194+ process.env.MIN_DATE = '2024-01-01';
195195+196196+ const exactMinDatePost = {
197197+ creation_timestamp: new Date('2024-01-01').getTime() / 1000,
198198+ title: 'Exact Min Date Post',
199199+ media: [{
200200+ creation_timestamp: new Date('2024-01-01').getTime() / 1000,
201201+ title: 'Exact Min Date Media'
202202+ }]
203203+ };
204204+205205+ (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify([exactMinDatePost]));
206206+207207+ await main();
208208+209209+ // The post should be processed, not skipped
210210+ expect(logger.warn).not.toHaveBeenCalledWith(
211211+ expect.stringContaining('Skipping post - Before MIN_DATE')
212212+ );
213213+ expect(InstagramMediaProcessor).toHaveBeenCalledWith(
214214+ expect.arrayContaining([expect.objectContaining({ title: 'Exact Min Date Post' })]),
215215+ expect.any(String)
216216+ );
217217+ });
218218+219219+ test('should exclude posts exactly on MAX_DATE', async () => {
220220+ process.env.MAX_DATE = '2024-01-01';
221221+222222+ const exactMaxDatePost = {
223223+ creation_timestamp: new Date('2024-01-01').getTime() / 1000,
224224+ title: 'Exact Max Date Post',
225225+ media: [{
226226+ creation_timestamp: new Date('2024-01-01').getTime() / 1000,
227227+ title: 'Exact Max Date Media'
228228+ }]
229229+ };
230230+231231+ (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify([exactMaxDatePost]));
232232+233233+ await main();
234234+235235+ // The post should be processed, not skipped (MAX_DATE is exclusive)
236236+ expect(logger.warn).not.toHaveBeenCalledWith(
237237+ expect.stringContaining('Skipping post - After MAX_DATE')
238238+ );
239239+ expect(InstagramMediaProcessor).toHaveBeenCalledWith(
240240+ expect.arrayContaining([expect.objectContaining({ title: 'Exact Max Date Post' })]),
241241+ expect.any(String)
242242+ );
243243+ });
244244+245245+ test('should filter posts with both MIN_DATE and MAX_DATE set', async () => {
246246+ process.env.MIN_DATE = '2023-01-01';
247247+ process.env.MAX_DATE = '2025-01-01';
248248+249249+ const posts = [
250250+ {
251251+ creation_timestamp: new Date('2022-01-01').getTime() / 1000, // Too old
252252+ title: 'Too Old Post',
253253+ media: [{ creation_timestamp: new Date('2022-01-01').getTime() / 1000, title: 'Old Media' }]
254254+ },
255255+ {
256256+ creation_timestamp: new Date('2023-06-01').getTime() / 1000, // In range
257257+ title: 'In Range Post 1',
258258+ media: [{ creation_timestamp: new Date('2023-06-01').getTime() / 1000, title: 'In Range Media 1' }]
259259+ },
260260+ {
261261+ creation_timestamp: new Date('2024-06-01').getTime() / 1000, // In range
262262+ title: 'In Range Post 2',
263263+ media: [{ creation_timestamp: new Date('2024-06-01').getTime() / 1000, title: 'In Range Media 2' }]
264264+ },
265265+ {
266266+ creation_timestamp: new Date('2026-01-01').getTime() / 1000, // Too new
267267+ title: 'Too New Post',
268268+ media: [{ creation_timestamp: new Date('2026-01-01').getTime() / 1000, title: 'New Media' }]
269269+ }
270270+ ];
271271+272272+ (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(posts));
273273+274274+ await main();
275275+276276+ // Should skip the too old post
277277+ expect(logger.warn).toHaveBeenCalledWith(
278278+ 'Skipping post - Before MIN_DATE: [Sat, 01 Jan 2022 00:00:00 GMT]'
279279+ );
280280+281281+ // Should skip the too new post
282282+ expect(logger.warn).toHaveBeenCalledWith(
283283+ 'Skipping post - After MAX_DATE [Thu, 01 Jan 2026 00:00:00 GMT]'
284284+ );
285285+286286+ // Should process the in-range posts
287287+ expect(InstagramMediaProcessor).toHaveBeenCalledWith(
288288+ expect.arrayContaining([
289289+ expect.objectContaining({ title: 'In Range Post 1' }),
290290+ expect.objectContaining({ title: 'In Range Post 2' })
291291+ ]),
292292+ expect.any(String)
293293+ );
294294+ });
295295+296296+ test('should use media timestamp when post timestamp is missing', async () => {
297297+ process.env.MIN_DATE = '2023-01-01';
298298+ process.env.MAX_DATE = '2025-01-01';
299299+300300+ const posts = [
301301+ {
302302+ // No creation_timestamp at post level
303303+ title: 'Post with only media timestamp',
304304+ media: [{
305305+ creation_timestamp: new Date('2024-01-01').getTime() / 1000,
306306+ title: 'Media with timestamp'
307307+ }]
308308+ },
309309+ {
310310+ // No creation_timestamp at post level
311311+ title: 'Post with old media timestamp',
312312+ media: [{
313313+ creation_timestamp: new Date('2022-01-01').getTime() / 1000,
314314+ title: 'Too old media'
315315+ }]
316316+ }
317317+ ];
318318+319319+ (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(posts));
320320+321321+ await main();
322322+323323+ // Should skip the post with old media timestamp
324324+ expect(logger.warn).toHaveBeenCalledWith(
325325+ 'Skipping post - Before MIN_DATE: [Sat, 01 Jan 2022 00:00:00 GMT]'
326326+ );
327327+328328+ // Should process the post with valid media timestamp
329329+ expect(InstagramMediaProcessor).toHaveBeenCalledWith(
330330+ expect.arrayContaining([
331331+ expect.objectContaining({ title: 'Post with only media timestamp' })
332332+ ]),
333333+ expect.any(String)
334334+ );
335335+ });
336336+ });
337337+191338 test('should handle posts with missing dates', async () => {
192339 const invalidPost = {
193340 title: 'Invalid Post',
-1
src/instagram-to-bluesky.ts
···201201 continue;
202202 }
203203204204- // TODO add unit test for min max posts.
205204 // If MIN_DATE configured validate the creation date is after the minimum date config.
206205 if (MIN_DATE && checkDate && checkDate < MIN_DATE) {
207206 logger.warn(