Files
habitica/test/api/unit/libs/email.test.js
Phillip Thelen 9d16ab7dba Sign in with Apple (#11793)
* add date check

* achievements modal polishing

* refresh private-messages page when you are already on it

* add countbadge knob to change the example

* fix lint

* typos

* typos

* typos

* add toggle for achievements categories

* typo

* fix test

* fix edit avatar modal cannot be closed

* WIP(settings): subscriber page improvements

* WIP(subscriptions): more design build-out

* fix(css): disabled button styles

* fix(css): better Amazon targeting

* fix hide tooltip + align header correctly

* disable perfect scroll

* load messages on refresh event

* fix header label + conversation actions not breaking layout on hover

* WIP(g1g1): notif

* WIP(g1g1): notif cont'd

* fix(test): snowball change

* fix(event): feature NYE card

* chore(sprites): compile

* fix(bgs): include TT required field

* add gifting banner to the max height calculation

* chore(event): enable winter customizations

* WIP(gifting): partial modal implementation

* feat(gifting): select giftee modal

* fix(gifting): notification order, modal dismiss

* Begin implementing sign in with apple

# Conflicts:
#	package-lock.json
#	website/common/script/constants.js
#	website/server/libs/auth/social.js
#	website/server/models/user/schema.js

* Add apple sign in button to website

* fix lint errors

* fix config json

* fix(modals): correct some repops

* fix(gifting): style updates

* fix(buy): modal style changes

* fix(modals): also clean out "prev"

* Attempt workaround for sign in with apple on android

* temporarily log everything as error

* refactor(modals): hide in dismiss event

* fix temporary test failure

* changes to sign in with apple

* fix: first batch of layout issues for private messages + auto sizing textarea

* fix(modals): new dismiss logic

* fix(modals): new dismiss no go??

* Only use email scope

* print debugging

* .

* ..

* ...

* username second line - open profile on face-avatar/conversation name - fix textarea height

* temporarily disable apple auth and just return data for debugging

* Hopefully this works

* .....

* WIP(subscription): unsubscribed state

* .

* ..

* MAYBE THIS ACTUALLY WORKS???

* Implement apple sign in

* fix some urls

* fix urls

* fix redirect and auth

* attempt to also request name

* fix lint error

* WIP(subscription): partial subscribed

* chore(sprites): compile

* Change approach so that it actually works

* fix config error

* fix lint errors

* Fix

* fix lint error

* lint error

* WIP(subscription): finish subscribed

* refresh on sync

* new "you dont have any messages" style + changed min textarea height

* new conversationItem style / layout

* reset message unread on reload

* chore(npm): update package-locks

* fix styles / textarea height

* feat(subscription): revised sub page RC

* list optOut / chatRevoked informations for each conversation + show why its disabled

* Improve apple redirect view

* Fix apple icon on group task registration page

* WIP(adventure): prereqs

* Block / Unblock - correct disabled states - $gray-200 instead of 300/400

* canReceive not checking chatRevoked

* fix: faceAvatar / userLink open the selected conversation user

* check if the target user is blocking the logged-in user

* fix(subs): style tweaks

* fix(profiles): short circuit contributor
Attempted fix for #11830

* chore(sprites): compile

* fix(content): missing potion data

* fix(content): missing string

* WIP(drops): new modal

* fix(subs): moar style tweaks

* check if blocks is undefined

* max-height instead of height

* fix "no messages" state + canReceive on a new conversation

* WIP(adventure): analytics fixes etc

* Improve apple signin handling

* fixed conversations width (280px on max 768 width page)

* feat(adventure): random egg+potion on 2nd task

* fix(lint): noworkies

* fix(modal): correctly construct classes

* fix(tests): expectations and escape

* Fix typo

* use base url from env variables

* fix lint

* call autosize after message is sent

* fix urls

* always verify token

* throw error when social auth could not retrieve id

* Store emails correctly for apple auth

* Retrieve name when authenticating through apple

* Fix lint errors

* fix all lint errors

* fix(content): missing strings

* Revert "always verify token"

This reverts commit 8ac40c76bf.

# Conflicts:
#	website/server/libs/auth/social.js

* Correctly load name

* remove extra changes

* remove extra logger call

* reset package and package-lock

* add back missing packages

* use name from apple

* add support for multiple apple public keys

* add some unit and integration tests

* add apple auth integration test

* tweak social signup buttons

* pixel pushing

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
Co-authored-by: negue <eugen.bolz@gmail.com>
Co-authored-by: Phillip Thelen <phillip@habitica.com>
2020-04-08 18:44:30 +02:00

238 lines
8.0 KiB
JavaScript

/* eslint-disable global-require */
import got from 'got';
import nconf from 'nconf';
import requireAgain from 'require-again';
import { TAVERN_ID } from '../../../../website/server/models/group';
import { defer } from '../../../helpers/api-unit.helper';
function getUser () {
return {
_id: 'random _id',
auth: {
local: {
username: 'username',
email: 'email@email',
},
facebook: {
emails: [{
value: 'email@facebook',
}],
},
google: {
emails: [{
value: 'email@google',
}],
},
apple: {
emails: [{
value: 'email@apple',
}],
},
},
profile: {
name: 'profile name',
},
preferences: {
emailNotifications: {
unsubscribeFromAll: false,
},
},
};
}
describe('emails', () => {
const pathToEmailLib = '../../../../website/server/libs/email';
describe('getUserInfo', () => {
it('returns an empty object if no field request', () => {
const attachEmail = requireAgain(pathToEmailLib);
const { getUserInfo } = attachEmail;
expect(getUserInfo({}, [])).to.be.empty;
});
it('returns correct user data', () => {
const attachEmail = requireAgain(pathToEmailLib);
const { getUserInfo } = attachEmail;
const user = getUser();
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.local.username);
expect(data).to.have.property('email', user.auth.local.email);
expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true);
});
it('returns correct user data [facebook users]', () => {
const attachEmail = requireAgain(pathToEmailLib);
const { getUserInfo } = attachEmail;
const user = getUser();
delete user.profile.name;
delete user.auth.local.email;
delete user.auth.google.emails;
delete user.auth.apple.emails;
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.local.username);
expect(data).to.have.property('email', user.auth.facebook.emails[0].value);
expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true);
});
it('returns correct user data [google users]', () => {
const attachEmail = requireAgain(pathToEmailLib);
const { getUserInfo } = attachEmail;
const user = getUser();
delete user.profile.name;
delete user.auth.local.email;
delete user.auth.facebook.emails;
delete user.auth.apple.emails;
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.local.username);
expect(data).to.have.property('email', user.auth.google.emails[0].value);
expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true);
});
it('returns correct user data [apple users]', () => {
const attachEmail = requireAgain(pathToEmailLib);
const { getUserInfo } = attachEmail;
const user = getUser();
delete user.profile.name;
delete user.auth.local.email;
delete user.auth.google.emails;
delete user.auth.facebook.emails;
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.local.username);
expect(data).to.have.property('email', user.auth.apple.emails[0].value);
expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true);
});
it('has fallbacks for missing data', () => {
const attachEmail = requireAgain(pathToEmailLib);
const { getUserInfo } = attachEmail;
const user = getUser();
delete user.auth.local.email;
delete user.auth.facebook;
delete user.auth.google;
delete user.auth.apple;
const data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
expect(data).to.have.property('name', user.auth.local.username);
expect(data).not.to.have.property('email');
expect(data).to.have.property('_id', user._id);
expect(data).to.have.property('canSend', true);
});
});
describe('getGroupUrl', () => {
it('returns correct url if group is the tavern', () => {
const { getGroupUrl } = require(pathToEmailLib); // eslint-disable-line import/no-dynamic-require, max-len
expect(getGroupUrl({ _id: TAVERN_ID, type: 'guild' })).to.eql('/groups/tavern');
});
it('returns correct url if group is a guild', () => {
const { getGroupUrl } = require(pathToEmailLib); // eslint-disable-line import/no-dynamic-require, max-len
expect(getGroupUrl({ _id: 'random _id', type: 'guild' })).to.eql('/groups/guild/random _id');
});
it('returns correct url if group is a party', () => {
const { getGroupUrl } = require(pathToEmailLib); // eslint-disable-line import/no-dynamic-require, max-len
expect(getGroupUrl({ _id: 'random _id', type: 'party' })).to.eql('party');
});
});
describe('sendTxnEmail', () => {
beforeEach(() => {
sandbox.stub(got, 'post').returns(defer().promise);
});
afterEach(() => {
sandbox.restore();
});
it('can send a txn email to one recipient', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
const attachEmail = requireAgain(pathToEmailLib);
const sendTxnEmail = attachEmail.sendTxn;
const emailType = 'an email type';
const mailingInfo = {
name: 'my name',
email: 'my@email',
};
sendTxnEmail(mailingInfo, emailType);
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
json: {
data: {
emailType: sinon.match.same(emailType),
to: sinon.match(value => Array.isArray(value) && value[0].name === mailingInfo.name, 'matches mailing info array'),
},
},
}));
});
it('does not send email if address is missing', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
const attachEmail = requireAgain(pathToEmailLib);
const sendTxnEmail = attachEmail.sendTxn;
const emailType = 'an email type';
const mailingInfo = {
name: 'my name',
// email: 'my@email',
};
sendTxnEmail(mailingInfo, emailType);
expect(got.post).not.to.be.called;
});
it('uses getUserInfo in case of user data', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
const attachEmail = requireAgain(pathToEmailLib);
const sendTxnEmail = attachEmail.sendTxn;
const emailType = 'an email type';
const mailingInfo = getUser();
sendTxnEmail(mailingInfo, emailType);
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
json: {
data: {
emailType: sinon.match.same(emailType),
to: sinon.match(val => val[0]._id === mailingInfo._id),
},
},
}));
});
it('sends email with some default variables', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
const attachEmail = requireAgain(pathToEmailLib);
const sendTxnEmail = attachEmail.sendTxn;
const emailType = 'an email type';
const mailingInfo = {
name: 'my name',
email: 'my@email',
};
const variables = [1, 2, 3];
sendTxnEmail(mailingInfo, emailType, variables);
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
json: {
data: {
variables: sinon.match(value => value[0].name === 'BASE_URL', 'matches variables'),
personalVariables: sinon.match(value => value[0].rcpt === mailingInfo.email
&& value[0].vars[0].name === 'RECIPIENT_NAME'
&& value[0].vars[1].name === 'RECIPIENT_UNSUB_URL', 'matches personal variables'),
},
},
}));
});
});
});