import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as taskbuffer from '../ts/index.js'; import * as smartdelay from '@push.rocks/smartdelay'; // Test 1: Basic buffered execution with afterTask chain tap.test('should run buffered tasks with afterTask chain', async () => { let counter1 = 0; let counter2 = 0; let counter3 = 0; const task3 = new taskbuffer.Task({ name: 'buffered-chain-3', taskFunction: async () => { counter3++; await smartdelay.delayFor(50); }, buffered: true, bufferMax: 1, }); const task2 = new taskbuffer.Task({ name: 'buffered-chain-2', taskFunction: async () => { counter2++; await smartdelay.delayFor(50); }, buffered: true, bufferMax: 1, afterTask: () => task3, }); const task1 = new taskbuffer.Task({ name: 'buffered-chain-1', taskFunction: async () => { counter1++; await smartdelay.delayFor(50); }, buffered: true, bufferMax: 1, afterTask: () => task2, }); // Trigger 3 times with enough spacing for the chain to complete for (let i = 0; i < 3; i++) { task1.trigger(); await smartdelay.delayFor(250); // enough for chain of 3 x 50ms tasks } // Wait for final chain to finish await smartdelay.delayFor(500); // Each task in the chain should have run at least once expect(counter1).toBeGreaterThanOrEqual(1); expect(counter2).toBeGreaterThanOrEqual(1); expect(counter3).toBeGreaterThanOrEqual(1); // afterTask chain means task2 count should match task1 (each trigger chains) expect(counter2).toEqual(counter1); expect(counter3).toEqual(counter1); }); // Test 2: bufferMax limits concurrent buffered executions tap.test('should respect bufferMax for concurrent buffered calls', async () => { let running = 0; let maxRunning = 0; let totalRuns = 0; const task = new taskbuffer.Task({ name: 'buffer-max-test', taskFunction: async () => { running++; maxRunning = Math.max(maxRunning, running); totalRuns++; await smartdelay.delayFor(100); running--; }, buffered: true, bufferMax: 2, }); // Fire many triggers rapidly — only bufferMax should run concurrently for (let i = 0; i < 10; i++) { task.trigger(); } // Wait for all buffered executions to complete await smartdelay.delayFor(1000); expect(maxRunning).toBeLessThanOrEqual(2); expect(totalRuns).toBeGreaterThanOrEqual(1); }); // Test 3: bufferMax limits how many runs are queued during execution tap.test('should limit queued runs to bufferMax during execution', async () => { let runCount = 0; const task = new taskbuffer.Task({ name: 'buffer-queue-test', taskFunction: async () => { runCount++; await smartdelay.delayFor(100); }, buffered: true, bufferMax: 2, }); // Rapid-fire 5 triggers — bufferMax:2 means counter caps at 2 // so only 2 runs will happen (the initial run + 1 buffered rerun) task.trigger(); task.trigger(); task.trigger(); task.trigger(); task.trigger(); await smartdelay.delayFor(500); expect(runCount).toEqual(2); }); // Test 4: Triggers spaced after completion queue new runs tap.test('should re-trigger after previous buffered run completes', async () => { let runCount = 0; const task = new taskbuffer.Task({ name: 'retrigger-test', taskFunction: async () => { runCount++; await smartdelay.delayFor(50); }, buffered: true, bufferMax: 1, }); // First trigger starts execution task.trigger(); // Wait for it to complete await smartdelay.delayFor(100); // Second trigger starts a new execution (task is now idle) task.trigger(); await smartdelay.delayFor(100); // Third trigger task.trigger(); await smartdelay.delayFor(100); expect(runCount).toEqual(3); }); export default tap.start();