Pragmatic Testing in AdonisJS with Japa #6.0

The Auth Plugin

In This Lesson

We'll learn how to test authenticated routes in AdonisJS/Japa. First, we'll install and register the Auth API Client plugin. Then, we'll learn how to use our User Factory to create a user and login as them for our test's request.

Created by
@tomgobich
Published

Notes Used to Craft this Lesson

Similar to session and shield, AdonisJS Auth has an API Client plugin we can use to add helpful authentication methods for our tests.

import { authApiClient } from "@adonisjs/auth/plugins/api_client";

// ...

export const plugins: Config["plugins"] = [
  assert(),
  openapi({
    schemas: [new URL("../docs/openapi.json", import.meta.url)],
  }),
  apiClient(),
  pluginAdonisJS(app),
  authApiClient(app),
  sessionApiClient(app),
  shieldApiClient(),
  disallowPinnedTests({
    disallow: !!process.env.CI,
  }),
];
Copied!
  • tests
  • bootstrap.ts

With this added, we can provide a user we want to log in as for our requests via a loginAs method directly on our client. This accepts our user, which we can create using our factory.

For this, we have an account settings page protected by the auth middleware. This middleware requires the user to be authenticated in order for them to access the route, so lets write a test to confirm that.

node ace make:test settings/account --suite=functional
Copied!

We'll want to test that it should "allow an authenticated user to view the page."

test.group("Settings account", (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction());

  test("allow an authenticated user to view the page", async ({
    assert,
    client,
    route,
  }) => {});
});
Copied!

Next, we'll need a user to actually exist in our database for our request to find and use, so we'll create a user

test.group("Settings account", (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction());

  test("allow an authenticated user to view the page", async ({
    assert,
    client,
    route,
  }) => {
    const user = await UserFactory.create();
  });
});
Copied!

Then, we can send our request and make a few assertions to ensure the status is successful and that "Account Settings" is somewhere on the rendered page.

test.group("Settings account", (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction());

  test("allow an authenticated user to view the page", async ({
    assert,
    client,
    route,
  }) => {
    const user = await UserFactory.create();
    const response = await client.get(route("settings.account"));

    response.assertOk();
    response.assertTextIncludes("Account Settings");
  });
});
Copied!

And, we can see it's failing to find our "Account Settings." We can dump our response to see what was rendered out.

test.group("Settings account", (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction());

  test("allow an authenticated user to view the page", async ({
    assert,
    client,
    route,
  }) => {
    const user = await UserFactory.create();
    const response = await client.get(route("settings.account"));

    response.dump();

    response.assertOk();
    response.assertTextIncludes("Account Settings");
  });
});
Copied!

Which, it looks like it is rendering "access denied," meaning we got blocked by the auth middleware. Perfect, because we haven't actually logged in via our test yet, so really we've just confirmed our route is auth-protected.

Let's go ahead and use the loginAs method on our client to log in for the request.

test.group("Settings account", () => {
  test("allow an authenticated user to view the page", async ({
    assert,
    client,
    route,
  }) => {
    const user = await UserFactory.create();
    const response = await client
      .get(route("settings.account"))
      .loginAs(user);

    response.assertOk();
    response.assertTextIncludes("Account Settings");
  });
});
Copied!

Fantastic, now it is successful!

Lastly, to note, if you are using multiple authentication guards, there is also a withGuard method that the Auth API Client plugin added as well, which will allow you to specify which guard you'd like to use for the client request. When omitted, it'll use your default guard.

test("allow an authenticated user to view the page", async ({
  assert,
  client,
  route,
}) => {
  const user = await UserFactory.create();
  const response = await client
    .get(route("settings.account"))
    .withGuard("web")
    .loginAs(user);

  response.assertOk();
  response.assertTextIncludes("Account Settings");
});
Copied!

Join the Discussion 0 comments

Create a free account to join in on the discussion
robot comment bubble

Be the first to comment!