Originally posted at michaelzanggl.com. Subscribe to my newsletter to never miss out on new content.
Adonis lets you write really clean tests and is a good candidate for test driven development. I will show how to get started with testing as well as some common techniques regarding the database setup. You can read up about more things in the official docs https://adonisjs.com/docs/4.1/.
Setup
adonis install @adonisjs/vow
Next, add vowProvider under start/app.js
in the aceProviders
array.
const aceProviders = [
'@adonisjs/vow/providers/VowProvider',
]
Finally, run adonis test
to run all tests.
Dealing with Database
Installing vow creates the two files vowfile.js
and .env.testing
, as well as an example test.
Test database
Copy over the database settings from your .env
to .env.testing
. Make sure to change DB_DATABASE
to a different database for testing. To make the tests run faster, pick sqlite as the DB_CONNECTION
(You need to install the npm dependency sqlite3 for it).
Migrations
If you use migrations, you can easily fill your new testing database before running tests and reset it again after running them.
Simply go inside the file vowfile.js
and uncomment all the lines needed for migrations. In essence, this is what the file looks like
'use strict'
const ace = require('@adonisjs/ace')
module.exports = (cli, runner) => {
runner.before(async () => {
use('Adonis/Src/Server').listen(process.env.HOST, process.env.PORT)
await ace.call('migration:run', {}, { silent: true })
})
runner.after(async () => {
use('Adonis/Src/Server').getInstance().close()
await ace.call('migration:reset', {}, { silent: true })
})
}
Resetting transactions after each test
You don't want a test to accidentally depend on data inserted by a different test. To keep tests simple, it's best to rollback all inserted data after each test. We can do this by using the DatabaseTransactions trait. All queries get wrapped in a transaction that gets rolled back automatically.
Here is an example:
'use strict'
const { test, trait } = use('Test/Suite')('suite name')
trait('DatabaseTransactions')
test('name of test', async ({ assert }) => { })
Model factories
We often rely on data in the database for our tests. It would be quite painful though to always insert the data manually. To make life simple, we can create model factories inside database/factory.js
. Here is an example for a user factory:
const Factory = use('Factory')
Factory.blueprint('App/Models/User', (faker, i, data) => {
return {
username: faker.username(),
email: faker.email(),
password: 'test-password',
...data,
}
})
Inside the tests, you can now create users easily
const Factory = use('Factory')
Factory.model('App/Models/User').create()
We can also override factory data.
const Factory = use('Factory')
Factory.model('App/Models/User').create({ email: 'email@test.com' })
Examples
Browser test & Faking emails
'use strict'
const { test, trait } = use('Test/Suite')('ForgotPasswordController')
const Factory = use('Factory')
const Mail = use('Mail')
trait('Test/ApiClient')
trait('DatabaseTransactions')
test('sends forgot password email to user', async ({ assert, client }) => {
Mail.fake()
const user = await Factory.model('App/Models/User').create()
await client.post('/password/forgot').send({ email: user.email }).end()
const mail = Mail.pullRecent()
assert.equal(mail.message.to[0].address, user.email)
assert.equal(mail.message.subject, 'Password Reset')
Mail.restore()
})
Checking controller response
test('resets password with correct token', async ({ assert, client }) => {
const user = await Factory.model('App/Models/User').create()
const token = await (new TokenService).generateToken(user.email)
const response = await client.post('/password/reset').send({ email: user.email, token, password: 'new password' }).end()
await user.reload()
response.assertStatus(200)
response.assertJSON({ message: 'Password reset successful.' })
assert.isTrue(await user.verify('new password'))
})
This should give you a good idea on how to get started with testing with the adonis framework. Make sure to read the official docs for more information.
Read more about faking mails, events and dependencies in an ioc container here: https://adonisjs.com/docs/4.1/testing-fakes
Read more about http tests, different request types, authentication, sessions and assertion types here: https://adonisjs.com/docs/4.1/api-tests
Have fun testing and TDDing!
If this article helped you, I have a lot more tips on simplifying writing software here.
Top comments (1)
That is amazing, and so much helpfull. This post is so hard to find, please, post again in a Adonis Forum, i have im sure you will help tons of devs like me <3