Trapping emails sent inside event listeners with Japa #3732
-
My tests are failing as emails are not being sent within the event handler. Event.on('user::created', async (user) => {
// Emitted when a new user is created
const token = await new TokenService().generateToken(user, TokenTypes.EMAIL)
await new VerifyEmail(user, token).send()
}) Or this code (notice the removal of the async keyword) Event.on('user::created', (user) => {
// Emitted when a new user is created
console.log('hello')
console.log(user)
}) This test will always fail to catch the email and it also doesn't log anything from the event handler nor from the inside of test('Verify Email', async ({ client }, done) => {
const mailer = Mail.fake()
Event.emit('user::created', testUser)
// check if email is sent
await assert.isTrue(
mailer.exists((mail) => {
console.log(mail)
done()
return mail.subject === '[T9r9iba] Verify your email'
})
)
}).waitForDone() I have also tried using a Note: testing for the event capture works. for example the following test works fine test('Register a new user (Signup)')
.with([
{
username: 'test1234',
email: 'test-register@email.com',
password: 'test1234',
},
])
.run(async ({ client, assert }, userData) => {
Mail.fake()
const emitter = Event.fake()
const response = await client.post('/auth/register').json(userData)
const testUser = await User.findBy('email', userData.email)
response.assertBodyContains({
username: userData.username,
email: userData.email,
status: AccountStatus.PENDING,
})
// catch event
assert.isTrue(
emitter.exists((event) => {
return event.name === 'user::created' && event.data.id === testUser?.id
})
)
// check if user is created
assert.isNotNull(testUser)
// check if user is logged in (probably need to stub auth.login)
const user = await User.findBy('id', response.session().auth_web)
assert.isNotNull(user)
assert.isTrue(user?.username === userData.username)
// restore
Event.restore()
Mail.restore()
}) I would appreciate if someone could guide me on this issue and explain how I can trap emails inside the event handlers. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 6 replies
-
Focusing on the following code block. test('Verify Email', async ({ client }, done) => {
const mailer = Mail.fake()
Event.emit('user::created', testUser)
// check if email is sent
await assert.isTrue(
mailer.exists((mail) => {
console.log(mail)
done()
return mail.subject === '[T9r9iba] Verify your email'
})
)
}).waitForDone() This is expected, because the events are emitted outside of the event loop. Infact, that is the purpose of events. Do not block the current event loop and do the thing in the background. If you await the test('Verify Email', async ({ client }) => {
const mailer = Mail.fake()
await Event.emit('user::created', testUser)
await assert.isTrue(
mailer.exists((mail) => {
console.log(mail)
return mail.subject === '[T9r9iba] Verify your email'
})
)
}) |
Beta Was this translation helpful? Give feedback.
-
Now, lemme share something which is a bit unrelated to the issue itself. You are testing too many things in a single test. This is how it looks like to me right now.
This needs to be split into multiple tests, as one test has too many responsibilities right now. It should be. First test
.run(async ({ client, assert }, userData) => {
const emitter = Event.fake()
const response = await client.post('/auth/register').json(userData)
response.assertStatus(200)
response.assertBodyContains({
username: userData.username,
email: userData.email,
status: AccountStatus.PENDING,
})
// catch event
assert.isTrue(
emitter.exists((event) => {
return event.name === 'user::created' && event.data.id === testUser?.id
})
)
// check if user is created
const user = await User.findBy('id', response.session().auth_web)
assert.isNotNull(user)
assert.isTrue(user?.username === userData.username)
// Restore emitter
Event.restore()
}) Second testIt should test if the event is emitted, it does trigger the Mail.send function. test('Verify Email', async ({ client }) => {
const mailer = Mail.fake()
await Event.emit('user::created', testUser)
await assert.isTrue(
mailer.exists((mail) => {
console.log(mail)
return mail.subject === '[T9r9iba] Verify your email'
})
)
}) |
Beta Was this translation helpful? Give feedback.
Focusing on the following code block.
This is expected, because the events are emitted outside of the event loop. Infact, that is the purpose of events. Do not block the current event loop and do the thing in the background.
If you await the
Event.emit
call, then it will be part of the same event loop. Also, do not usedone
andwai…