Skip to content

Testing ​

The plugin runs unchanged on the in-memory testing driver - SET NX PX and the CAS Lua scripts execute through production code with no Redis.

typescript
import { Test } from '@nestjs/testing';
import { RedisTestingModule } from '@nestjs-redisx/testing';
import { DedupPlugin, DEDUP_SERVICE, type IDedupService } from '@nestjs-redisx/dedup';

describe('WebhookService', () => {
  it('handles each event id once', async () => {
    const app = await Test.createTestingModule({
      imports: [RedisTestingModule.forRoot({ plugins: [new DedupPlugin()] })],
    }).compile();
    await app.init();

    const dedup = app.get<IDedupService>(DEDUP_SERVICE);
    let handled = 0;

    await Promise.all(
      Array.from({ length: 5 }, () => dedup.dedupe('evt:1', async () => void handled++)),
    );

    expect(handled).toBe(1); // concurrent duplicates admitted exactly one

    await app.close();
  });
});

Testing Failure Re-Admission ​

typescript
await expect(
  dedup.dedupe('evt:2', async () => { throw new Error('transient'); }),
).rejects.toThrow('transient');

// the failed first released its marker - the retry runs
expect(await dedup.dedupe('evt:2', async () => 'retried')).toBe('retried');

Testing Window Expiry ​

Use a short per-call window and real timers:

typescript
expect(await dedup.isFirst('k', { window: 100 })).toBe(true);
expect(await dedup.isFirst('k', { window: 100 })).toBe(false);
await new Promise((r) => setTimeout(r, 140));
expect(await dedup.isFirst('k', { window: 100 })).toBe(true); // new window

Simulating a Second Instance ​

typescript
import { DedupService, DEDUP_STORE, type IDedupStore } from '@nestjs-redisx/dedup';

const nodeB = new DedupService({}, app.get<IDedupStore>(DEDUP_STORE));
const [a, b] = await Promise.all([dedupA.isFirst('race'), nodeB.isFirst('race')]);
expect([a, b].filter(Boolean)).toHaveLength(1); // exactly one winner

Released under the MIT License.