Pragmatic Testing in AdonisJS with Japa #5.3

Testing Model Logic

In This Lesson

We'll learn how to Unit Test AdonisJS Model logic using Japa. We'll test a password reset token's validity to show instance-level tests. Then, we'll test its generate and verify methods to show static methods.

Created by
@tomgobich
Published

Models can have logic within them; sometimes this is a simple getter, and other times it's more complex methods. So, let's take a moment to cover how we can create unit tests to ensure this logic does what we expect.

node ace make:test models/password_reset_token --suite=unit
Copied!

Within our PasswordResetToken we have a getter, isValid. This is a rather straightforward getter that you might not otherwise have a test for, but for educational purposes, let's test it anyway.

First, let's ensure a future-dated expiry is considered valid. Remember, our factory uses a future-dated expiry by default.

test.group("Models password reset token", () => {
  test("isValid should be truthy when expiresAt is in the future", async ({
    assert,
  }) => {
    const token = await PasswordResetTokenFactory.makeStubbed();

    assert.isTrue(token.isValid);
  });
});
Copied!

Simple enough, next let's ensure an expiry in the past is considered invalid. For this, we make use of our invalid state in our factory.

test.group("Models password reset token", () => {
  // ...

  test("isValid should be falsy when expiresAt is in the past", async ({
    assert,
  }) => {
    const token = await PasswordResetTokenFactory.apply(
      "invalid"
    ).makeStubbed();

    assert.isFalse(token.isValid);
  });
});
Copied!

Okay, let's kick it up a notch with our generate method. This returns a random string that's 32 chars long and an encrypted version of that string. So, let's assert both of those.

test("generate should create a value and an encrypted version of that value", ({
  assert,
}) => {
  const { value, encryptedValue } = PasswordResetToken.generate();

  assert.lengthOf(value, 32);
  assert.equal(value, encryption.decrypt(encryptedValue));
});
Copied!

Great, next we go a step further with our verify method. For this, we'll need a valid token with an associated user.

test("verify should return as valid with a valid token", async ({ assert }) => {
  // create a token with a user
  const token = await PasswordResetTokenFactory.with("user").create();
  // encrypt the generated token
  const encryptedValue = encryption.encrypt(token.value);
  // run our verify method
  const result = await PasswordResetToken.verify(encryptedValue);

  assert.isTrue(result.isValid);
  assert.strictEqual(token.user.id, result.user?.id);
  assert.strictEqual(token.value, result.token?.value);
});
Copied!

Lastly, we need our sad path testing an invalid token.

test("verify should return as invalid with an invalid token", async ({
  assert,
}) => {
  const token = await PasswordResetTokenFactory.with("user")
    .apply("invalid")
    .create();
  const encryptedValue = encryption.encrypt(token.value);
  const result = await PasswordResetToken.verify(encryptedValue);

  assert.isFalse(result.isValid);
  assert.strictEqual(token.user.id, result.user?.id);
  assert.strictEqual(token.value, result.token?.value);
});
Copied!

Join the Discussion 0 comments

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

Be the first to comment!