Skip to content

Testing ​

Turn the guard off ​

In unit and end-to-end tests that are not about the captcha, let every request through with skipIf:

ts
TurnstileModule.forRoot({
  secretKey: process.env.TURNSTILE_SECRET_KEY,
  skipIf: process.env.NODE_ENV === 'test',
});

With skipIf: true the module also starts without a secret key, so test environments do not need one.

Stub the service ​

To test how your app handles a passed or a rejected token, replace TurnstileService with createTurnstileServiceStub. It answers every token without a network call, the same way Cloudflare's test keys do:

ts
import { Test } from '@nestjs/testing';
import {
  createTurnstileServiceStub,
  TurnstileService,
} from 'nest-cloudflare-turnstile';
import { AppModule } from '../src/app.module';

const moduleRef = await Test.createTestingModule({ imports: [AppModule] })
  .overrideProvider(TurnstileService)
  .useValue(createTurnstileServiceStub('fail'))
  .compile();
VerdictAnswer
'pass' (default)Accepts every token. The hostname and action checks are skipped, as with test keys.
'fail'Rejects the token with invalid-input-response
'spent'Rejects the token with timeout-or-duplicate
an objectReturns that verdict as is, for example to test action, cdata or validateResult

The rest of the module stays real, so exceptionFactory, validateResult and @TurnstileResult() behave as they do in production. The stub replaces the service that checks the secret key at start-up, so the test module starts without one.

Cloudflare test keys ​

Cloudflare publishes keys that skip the real challenge. Pair a test site key in the browser with a test secret key on the server:

Site keyWidget behavior
1x00000000000000000000AAAlways passes, visible
2x00000000000000000000ABAlways fails, visible
1x00000000000000000000BBAlways passes, invisible
2x00000000000000000000BBAlways fails, invisible
3x00000000000000000000FFForces an interactive challenge
Secret keySiteverify answer
1x0000000000000000000000000000000AAAlways passes
2x0000000000000000000000000000000AAAlways fails (invalid-input-response)
3x0000000000000000000000000000000AAToken already spent (timeout-or-duplicate)

Test site keys produce the dummy token XXXX.DUMMY.TOKEN.XXXX, which only test secret keys accept. That makes them handy for checking your error handling without mocks:

ts
TurnstileModule.forRoot({
  secretKey: '2x0000000000000000000000000000000AA',
});
// Any request with a token now gets the "invalid" response.

Test results report example.com as the hostname and carry no action, so the guard skips the expectedHostname and expectedAction checks for them.

Never ship a test secret key

With 1x0000000000000000000000000000000AA, every request that carries a token passes. The module logs a warning when a test secret key runs with NODE_ENV=production.

Source: Cloudflare's testing docs.