Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Nov 17, 2023
1 parent 893d90e commit a40c96f
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 0 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,8 @@
"time-span": "^5.1.0",
"tsd": "^0.29.0",
"xo": "^0.56.0"
},
"ava": {
"serial": true
}
}
192 changes: 192 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,195 @@ test('`this` is preserved in throttled function', async t => {
await t.notThrowsAsync(thisFixture.foo());
t.is(await thisFixture.foo(), fixture);
});

for (const limit of [1, 5, 10]) {
test(`respects limit of ${limit} calls`, async t => {
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());
const promises = [];
const start = Date.now();

for (let i = 0; i < limit; i++) {
promises.push(throttled());
}

const results = await Promise.all(promises);
for (const time of results) {
t.true(inRange(time - start, {start: 0, end: interval}));
}
});
}

test('handles multiple instances independently', async t => {
const throttledOne = pThrottle({limit: 1, interval: 100})(() => 'one');
const throttledTwo = pThrottle({limit: 1, interval: 200})(() => 'two');

const resultOne = await throttledOne();
const resultTwo = await throttledTwo();

t.is(resultOne, 'one');
t.is(resultTwo, 'two');
});

test('disable and re-enable functionality', async t => {
const throttled = pThrottle({limit: 1, interval: 1000})(() => Date.now());
const start = Date.now();

await throttled(); // First call, should pass immediately.
throttled.isEnabled = false;
const timeDisabled = await throttled(); // Should pass immediately.
throttled.isEnabled = true;
const timeReEnabled = await throttled(); // Should be throttled.

t.true(timeDisabled - start < 100);
t.true(timeReEnabled - start >= 1000);
});

test('stability under high load', async t => {
const limit = 5;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());
const promises = [];

for (let i = 0; i < 100; i++) {
promises.push(throttled());
}

const results = await Promise.all(promises);
t.is(results.length, 100);
});

test('handles zero interval', async t => {
const throttled = pThrottle({limit: 1, interval: 0})(() => Date.now());
const start = Date.now();
await throttled();
const end = Date.now();
t.true(end - start < 50); // Small buffer to account for execution time
});

test('handles simultaneous calls', async t => {
const limit = 5;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());
const times = await Promise.all(Array.from({length: limit}).map(() => throttled()));

// Ensure all calls are within the same interval
for (let i = 1; i < times.length; i++) {
t.true(times[i] - times[0] < interval);
}
});

test('clears queue after abort', async t => {
const limit = 2;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());

try {
await throttled();
await throttled();
} catch {}

throttled.abort();

t.is(throttled.queueSize, 0);
});

test('allows immediate execution with high limit', async t => {
const limit = 10;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());
const start = Date.now();
const promises = Array.from({length: 5}, () => throttled());
const results = await Promise.all(promises);
const end = Date.now();

for (const time of results) {
t.true(time - start < 50);
}

t.true(end - start < 100);
});

test('queues calls beyond limit', async t => {
const limit = 2;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());
const start = Date.now();

const firstBatch = Promise.all([throttled(), throttled()]);
await delay(50); // Ensure the first batch is within the limit
const secondBatch = Promise.all([throttled(), throttled()]);

const results = await Promise.all([firstBatch, secondBatch]);
const end = Date.now();

// Check that the second batch was executed after the interval
for (const time of results[1]) {
t.true(time - start >= interval);
}

t.true(end - start >= interval);
});

test('resets interval after inactivity', async t => {
const limit = 1;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());

const firstCall = await throttled();
await delay(interval + 50); // Inactivity longer than the interval
const secondCall = await throttled();

t.true(secondCall - firstCall >= interval + 50);
});

test('maintains function execution order', async t => {
const limit = 2;
const interval = 100;
const throttled = pThrottle({limit, interval})(async value => value);
const results = await Promise.all([throttled(1), throttled(2), throttled(3)]);

t.deepEqual(results, [1, 2, 3]);
});

test('handles extremely short intervals', async t => {
const limit = 1;
const interval = 1; // Very short interval
const throttled = pThrottle({limit, interval})(() => {});
await throttled();
await delay(5); // Slight delay
await throttled();
t.pass(); // If it gets here without error, the test passes
});

test('executes immediately for limit greater than calls', async t => {
const limit = 10;
const interval = 100;
const throttled = pThrottle({limit, interval})(() => Date.now());
const start = Date.now();
const results = await Promise.all([throttled(), throttled()]);
const end = Date.now();

for (const time of results) {
t.true(time - start < 50);
}

t.true(end - start < 100);
});

test('manages rapid successive calls', async t => {
const limit = 3;
const interval = 50;
const throttled = pThrottle({limit, interval})(() => Date.now());
const results = [];

for (let i = 0; i < 10; i++) {
results.push(throttled());

// eslint-disable-next-line no-await-in-loop
await delay(10); // Small delay between calls
}

await Promise.all(results);
t.pass(); // Test passes if all promises resolve without error
});

0 comments on commit a40c96f

Please sign in to comment.