We'll learn how to functionally test a registration endpoint using a test database. We'll learn about global transactions and how we can use them to easily reset our database between tests and confirm database state with Lucid.
Now that we have a separate database for our tests, we can send API requests to our app, and our app will work within our siloed test database.
Our registration flow will be perfect for these tests, and we've worked with a portion of it before in our fakes lesson when we verified that one of its methods sent a welcome email.
node ace make:test auth --suite=functional
Copied!
Cool, we'll test that our endpoint should "allow a user to register," and we know that this endpoint will attempt to send an email, so we'll want to fake our email service. We can also confirm that the email has been sent.
Now, our database is resetting between our test runs, but not between each test. So, if we were to add another test, our test@test.com would already exist in that test. It's best practice not to allow side effects to persist between tests. This will ensure we don't have to worry about working with unique emails and the like between all our tests.
For this, we can use our test group's each hook and our db testUtils again. If we aren't using transactions within our endpoints, then we can use a global transaction via:
We are not, at least not in authentication, so we're safe to use the transaction.
Let's add another test to ensure an email that already exists in our database can't register again.
test("fail to register user when email is already taken", async ({ client, route, cleanup,}) => { const { mails } = mail.fake(); cleanup(() => mail.restore()); const user = await User.create({ fullName: "Test User", email: "test@test.com", password: "something", }); mails.assertNotSent(WelcomeEmailNotification);});
Copied!
First, we want to create a user so that a user already exists within our database for this test. Then, we can render our request and assert that the user should be redirected back to the defined referer, and we get our email validation rule flashed.
test("fail to register user when email is already taken", async ({ client, route, cleanup,}) => { const { mails } = mail.fake(); cleanup(() => mail.restore()); const user = await User.create({ fullName: "Test User", email: "test@test.com", password: "something", }); const response = await client .post(route("auth.register.store")) .withCsrfToken() .header("Referer", route("auth.register.show")) .form({ fullName: user.fullName, email: user.email, password: "something", }) .redirects(0); response.assertHeader("Location", route("auth.register.show")); response.assertFlashMessage("errors.email", [ "The email has already been taken", ]); mails.assertNotSent(WelcomeEmailNotification);});