Advanced

Testing with Japa

Authenticate functional HTTP tests effortlessly using the simpleAuthApiClient Japa plugin.

@eienjs/adonisjs-simple-auth provides an official plugin for @japa/api-client that adds a .withApiKey() macro to ApiRequest. When called on a test request, it automatically reads apiKeyHeader and apiKeyValue from your config/simpleauth.ts file and attaches the header to the outgoing request.

Registering the Plugin

Open tests/bootstrap.ts and register simpleAuthApiClient(app) in your plugins array right after apiClient():

tests/bootstrap.ts
import type { Config } from '@japa/runner/types';
import app from '@adonisjs/core/services/app';
import { simpleAuthApiClient } from '@eienjs/adonisjs-simple-auth/plugins/api_client';
import { apiClient } from '@japa/api-client';
import { assert } from '@japa/assert';
import { pluginAdonisJS } from '@japa/plugin-adonisjs';

export const plugins: Config['plugins'] = [
  assert(),
  apiClient(),
  pluginAdonisJS(app),
  simpleAuthApiClient(app),
];
@japa/api-client (^3.2.1) must be installed in your project and config/simpleauth.ts must export a configuration created with defineConfig.

Writing Authenticated Tests

Once the plugin is registered, chain .withApiKey() onto any client request in your functional tests:

tests/functional/users.spec.ts
import { test } from '@japa/runner';

test.group('Users API', () => {
  test('returns 401 when API key header is not provided', async ({ client }) => {
    const response = await client.get('/api/v1/users');

    response.assertStatus(401);
    response.assertBodyContains({
      errors: [{ message: 'Unauthorized access' }],
    });
  });

  test('returns users list when authenticated with withApiKey()', async ({ client }) => {
    const response = await client.get('/api/v1/users').withApiKey();

    response.assertStatus(200);
  });
});

How .withApiKey() Works

  1. Resolves your config/simpleauth.ts configuration via AdonisJS configProvider.
  2. Registers the withApiKey() macro on ApiRequest and augments @japa/api-client TypeScript types automatically.
  3. Registers an ApiClient.setup hook that inspects whether .withApiKey() was called on the current request, and if so, sets request.header(config.apiKeyHeader, config.apiKeyValue.release()).
Because the hook is scoped per request via a symbol flag, requests that do not call .withApiKey() remain unauthenticated, making it easy to test both authorized and unauthorized scenarios in the same test group.