correct async/await usages, improve email tests (#15408)

This commit is contained in:
negue
2025-03-17 22:11:38 +01:00
committed by GitHub
parent 8327e69bdd
commit 0c6e254742
4 changed files with 49 additions and 30 deletions

View File

@@ -171,23 +171,23 @@ describe('emails', () => {
expect(got.post).not.to.be.called; expect(got.post).not.to.be.called;
}); });
it('throws error when mail target is only a string', () => { it('throws error when mail target is only a string', async () => {
const emailType = 'an email type'; const emailType = 'an email type';
const mailingInfo = 'my email'; const mailingInfo = 'my email';
expect(sendTxn(mailingInfo, emailType)).to.throw; await expect(sendTxn(mailingInfo, emailType)).to.be.rejectedWith('Argument Error mailingInfoArray: does not contain email or _id');
}); });
it('throws error when mail target has no _id or email', () => { it('throws error when mail target has no _id or email', async () => {
const emailType = 'an email type'; const emailType = 'an email type';
const mailingInfo = { const mailingInfo = {
}; };
expect(sendTxn(mailingInfo, emailType)).to.throw; await expect(sendTxn(mailingInfo, emailType)).to.be.rejectedWith('Argument Error mailingInfoArray: does not contain email or _id');
}); });
it('throws error when variables not an array', () => { it('throws error when variables not an array', async () => {
const emailType = 'an email type'; const emailType = 'an email type';
const mailingInfo = { const mailingInfo = {
name: 'my name', name: 'my name',
@@ -195,9 +195,10 @@ describe('emails', () => {
}; };
const variables = {}; const variables = {};
expect(sendTxn(mailingInfo, emailType, variables)).to.throw; await expect(sendTxn(mailingInfo, emailType, variables)).to.be.rejectedWith('Argument Error variables: is not an array');
}); });
it('throws error when variables array not contain name/content', () => {
it('throws error when variables array not contain name/content', async () => {
const emailType = 'an email type'; const emailType = 'an email type';
const mailingInfo = { const mailingInfo = {
name: 'my name', name: 'my name',
@@ -209,8 +210,9 @@ describe('emails', () => {
}, },
]; ];
expect(sendTxn(mailingInfo, emailType, variables)).to.throw; await expect(sendTxn(mailingInfo, emailType, variables)).to.be.rejectedWith('Argument Error variables: does not contain name or content');
}); });
it('throws no error when variables array contain name but no content', () => { it('throws no error when variables array contain name but no content', () => {
const emailType = 'an email type'; const emailType = 'an email type';
const mailingInfo = { const mailingInfo = {

View File

@@ -120,9 +120,12 @@ api.inviteToQuest = {
// send out invites // send out invites
const inviterVars = getUserInfo(user, ['name', 'email']); const inviterVars = getUserInfo(user, ['name', 'email']);
const membersToEmail = members.filter(async member => { const membersToEmail = [];
for (const member of members) {
// send push notifications while filtering members before sending emails // send push notifications while filtering members before sending emails
if (member.preferences.pushNotifications.invitedQuest !== false) { if (member.preferences.pushNotifications.invitedQuest !== false) {
// eslint-disable-next-line no-await-in-loop
await sendPushNotification( await sendPushNotification(
member, member,
{ {
@@ -141,8 +144,11 @@ api.inviteToQuest = {
quest, quest,
}); });
return member.preferences.emailNotifications.invitedQuest !== false; if (member.preferences.emailNotifications.invitedQuest !== false) {
}); membersToEmail.push(member);
}
}
sendTxnEmail(membersToEmail, `invite-${quest.boss ? 'boss' : 'collection'}-quest`, [ sendTxnEmail(membersToEmail, `invite-${quest.boss ? 'boss' : 'collection'}-quest`, [
{ name: 'QUEST_NAME', content: quest.text() }, { name: 'QUEST_NAME', content: quest.text() },
{ name: 'INVITER', content: inviterVars.name }, { name: 'INVITER', content: inviterVars.name },

View File

@@ -65,7 +65,13 @@ export function getGroupUrl (group) {
return groupUrl; return groupUrl;
} }
// Send a transactional email using Mandrill through the external email server /**
* Send a transactional email using Mandrill through the external email server
*
* Individual "canSend" per type needs to be done before,
* internally it checks by `getUserInfo` if the
* `unsubscribeFromAll` is set to true, if so it won't send the email.
*/
export async function sendTxn (mailingInfoArray, emailType, variables, personalVariables) { export async function sendTxn (mailingInfoArray, emailType, variables, personalVariables) {
if (!Array.isArray(mailingInfoArray)) { if (!Array.isArray(mailingInfoArray)) {
mailingInfoArray = [mailingInfoArray]; // eslint-disable-line no-param-reassign mailingInfoArray = [mailingInfoArray]; // eslint-disable-line no-param-reassign
@@ -73,7 +79,7 @@ export async function sendTxn (mailingInfoArray, emailType, variables, personalV
for (const entry of mailingInfoArray) { for (const entry of mailingInfoArray) {
if (typeof entry === 'string' if (typeof entry === 'string'
&& (typeof entry._id === 'undefined' && typeof entry.email === 'undefined') || (typeof entry._id === 'undefined' && typeof entry.email === 'undefined')
) { ) {
throw new Error('Argument Error mailingInfoArray: does not contain email or _id'); throw new Error('Argument Error mailingInfoArray: does not contain email or _id');
} }
@@ -100,7 +106,7 @@ export async function sendTxn (mailingInfoArray, emailType, variables, personalV
// Always send reset-password emails // Always send reset-password emails
// Don't check canSend for non registered users as already checked before // Don't check canSend for non registered users as already checked before
.filter(mailingInfo => mailingInfo.email .filter(mailingInfo => mailingInfo.email
&& (!mailingInfo._id || mailingInfo.canSend || emailType === 'reset-password')); && (!mailingInfo._id || mailingInfo.canSend || emailType === 'reset-password'));
// Personal variables are personal to each email recipient, if they are missing // Personal variables are personal to each email recipient, if they are missing
// we manually create a structure for them with RECIPIENT_NAME and RECIPIENT_UNSUB_URL // we manually create a structure for them with RECIPIENT_NAME and RECIPIENT_UNSUB_URL

View File

@@ -770,22 +770,27 @@ schema.methods.startQuest = async function startQuest (user) {
const membersToEmail = []; const membersToEmail = [];
// send notifications and webhooks in the background without blocking // send notifications and webhooks in the background without blocking
await members.forEach(async member => { for (const member of members) {
if (member._id !== user._id) { if (member._id === user._id) {
// send push notifications and filter users that disabled emails // early "exit", saving one indention level
if (member.preferences.emailNotifications.questStarted !== false) { // eslint-disable-next-line no-continue
membersToEmail.push(member); continue;
} }
// send push notifications and filter users that disabled emails // add email to send if that user did not disabled this email
if (member.preferences.pushNotifications.questStarted !== false) { if (member.preferences.emailNotifications.questStarted !== false) {
const memberLang = member.preferences.language; membersToEmail.push(member);
await sendPushNotification(member, { }
title: quest.text(memberLang),
message: shared.i18n.t('questStarted', memberLang), // send push notifications if that user did not disabled this notifications
identifier: 'questStarted', if (member.preferences.pushNotifications.questStarted !== false) {
}); const memberLang = member.preferences.language;
} // eslint-disable-next-line no-await-in-loop
await sendPushNotification(member, {
title: quest.text(memberLang),
message: shared.i18n.t('questStarted', memberLang),
identifier: 'questStarted',
});
} }
// Send webhooks // Send webhooks
@@ -794,7 +799,7 @@ schema.methods.startQuest = async function startQuest (user) {
group: this, group: this,
quest, quest,
}); });
}); }
// Send emails in bulk // Send emails in bulk
sendTxnEmail(membersToEmail, 'quest-started', [ sendTxnEmail(membersToEmail, 'quest-started', [