Consider the faux account creation code below:
export const accounts = [];
export const emails = [];
export async function createAccount(name, email) {
accounts.push({name, email});
void sendEmail(email);
}
async function sendEmail(email) {
setTimeout(0, () => emails.push(`Account created to ${email}`));
}
The createAccount()
function “saves” an account in the array, and then “sends an email” reporting the account was created. Note that createAccount()
does not wait for the email to be sent, since it can take some time.
Now, we write a test to ensure the email is sent:
import {assert} from 'chai';
import {createAccount, emails} from './index.js';
describe('test', async () => {
it('test', async() => {
await createAccount('John Doe', '[email protected]');
assert(emails[0], 'Account created to [email protected]');
});
});
Of course, though, the test does not pass…
$ npm run test
> [email protected] test
> mocha test.js
test
1) test
0 passing (5ms)
1 failing
1) test
test:
AssertionError: Account created to [email protected]
at Context.<anonymous> (file:///home/me/sandbox/foo/test.js:7:5)
…because the sendEmail()
function, being called asynchronously, did not yet “send” the email.
But I really want to test if the email was eventually sent!
How could I test that?
Ideally, it would not:
- involve exposing the
sendEmail()
return value; - involve sleeps/timeouts.
Any ideas?
Appendix
To make things easier to test, you can use this package.json
:
{
"name": "foo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha test.js"
},
"type": "module",
"author": "",
"license": "ISC",
"devDependencies": {
"chai": "^5.1.1",
"mocha": "^10.6.0"
}
}