mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-13 20:57:24 +01:00
* 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>
847 lines
25 KiB
JavaScript
847 lines
25 KiB
JavaScript
import { v4 as uuid } from 'uuid';
|
|
import { each } from 'lodash';
|
|
import {
|
|
generateUser,
|
|
requester,
|
|
translate as t,
|
|
createAndPopulateGroup,
|
|
getProperty,
|
|
} from '../../../../../helpers/api-integration/v3';
|
|
import { ApiUser } from '../../../../../helpers/api-integration/api-classes';
|
|
import { encrypt } from '../../../../../../website/server/libs/encryption';
|
|
|
|
function generateRandomUserName () {
|
|
return (Date.now() + uuid()).substring(0, 20);
|
|
}
|
|
|
|
describe('POST /user/auth/local/register', () => {
|
|
context('username and email are free', () => {
|
|
let api;
|
|
|
|
beforeEach(async () => {
|
|
api = requester();
|
|
});
|
|
|
|
it('registers a new user', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user._id).to.exist;
|
|
expect(user.apiToken).to.exist;
|
|
expect(user.auth.local.username).to.eql(username);
|
|
expect(user.profile.name).to.eql(username);
|
|
expect(user.newUser).to.eql(true);
|
|
});
|
|
|
|
it('registers a new user and sets verifiedUsername to true', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user._id).to.exist;
|
|
expect(user.apiToken).to.exist;
|
|
expect(user.flags.verifiedUsername).to.eql(true);
|
|
});
|
|
|
|
xit('remove spaces from username', async () => {
|
|
// TODO can probably delete this test now
|
|
const username = ' usernamewithspaces ';
|
|
const email = 'test@example.com';
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.auth.local.username).to.eql(username.trim());
|
|
expect(user.profile.name).to.eql(username.trim());
|
|
});
|
|
|
|
context('validates username', () => {
|
|
const email = 'test@example.com';
|
|
const password = 'password';
|
|
|
|
it('requires to username to be less than 20', async () => {
|
|
const username = (Date.now() + uuid()).substring(0, 21);
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'Invalid request parameters.',
|
|
});
|
|
});
|
|
|
|
it('rejects chracters not in [-_a-zA-Z0-9]', async () => {
|
|
const username = 'a-zA_Z09*';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'Invalid request parameters.',
|
|
});
|
|
});
|
|
|
|
it('allows only [-_a-zA-Z0-9] characters', async () => {
|
|
const username = 'a-zA_Z09';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.auth.local.username).to.eql(username);
|
|
});
|
|
});
|
|
|
|
context('provides default tags and tasks', async () => {
|
|
it('for a generic API consumer', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
const requests = new ApiUser(user);
|
|
|
|
const habits = await requests.get('/tasks/user?type=habits');
|
|
const dailys = await requests.get('/tasks/user?type=dailys');
|
|
const todos = await requests.get('/tasks/user?type=todos');
|
|
const rewards = await requests.get('/tasks/user?type=rewards');
|
|
const tags = await requests.get('/tags');
|
|
|
|
expect(habits).to.have.a.lengthOf(0);
|
|
expect(dailys).to.have.a.lengthOf(0);
|
|
expect(todos).to.have.a.lengthOf(1);
|
|
expect(rewards).to.have.a.lengthOf(0);
|
|
|
|
expect(tags).to.have.a.lengthOf(7);
|
|
expect(tags[0].name).to.eql(t('defaultTag1'));
|
|
expect(tags[1].name).to.eql(t('defaultTag2'));
|
|
expect(tags[2].name).to.eql(t('defaultTag3'));
|
|
expect(tags[3].name).to.eql(t('defaultTag4'));
|
|
expect(tags[4].name).to.eql(t('defaultTag5'));
|
|
expect(tags[5].name).to.eql(t('defaultTag6'));
|
|
expect(tags[6].name).to.eql(t('defaultTag7'));
|
|
});
|
|
|
|
xit('for Web', async () => {
|
|
api = requester(
|
|
null,
|
|
{ 'x-client': 'habitica-web' },
|
|
);
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
const requests = new ApiUser(user);
|
|
|
|
const habits = await requests.get('/tasks/user?type=habits');
|
|
const dailys = await requests.get('/tasks/user?type=dailys');
|
|
const todos = await requests.get('/tasks/user?type=todos');
|
|
const rewards = await requests.get('/tasks/user?type=rewards');
|
|
const tags = await requests.get('/tags');
|
|
|
|
expect(habits).to.have.a.lengthOf(3);
|
|
expect(habits[0].text).to.eql(t('defaultHabit1Text'));
|
|
expect(habits[0].notes).to.eql('');
|
|
expect(habits[1].text).to.eql(t('defaultHabit2Text'));
|
|
expect(habits[1].notes).to.eql('');
|
|
expect(habits[2].text).to.eql(t('defaultHabit3Text'));
|
|
expect(habits[2].notes).to.eql('');
|
|
|
|
expect(dailys).to.have.a.lengthOf(0);
|
|
|
|
expect(todos).to.have.a.lengthOf(1);
|
|
expect(todos[0].text).to.eql(t('defaultTodo1Text'));
|
|
expect(todos[0].notes).to.eql(t('defaultTodoNotes'));
|
|
|
|
expect(rewards).to.have.a.lengthOf(1);
|
|
expect(rewards[0].text).to.eql(t('defaultReward1Text'));
|
|
expect(rewards[0].notes).to.eql('');
|
|
|
|
expect(tags).to.have.a.lengthOf(7);
|
|
expect(tags[0].name).to.eql(t('defaultTag1'));
|
|
expect(tags[1].name).to.eql(t('defaultTag2'));
|
|
expect(tags[2].name).to.eql(t('defaultTag3'));
|
|
expect(tags[3].name).to.eql(t('defaultTag4'));
|
|
expect(tags[4].name).to.eql(t('defaultTag5'));
|
|
expect(tags[5].name).to.eql(t('defaultTag6'));
|
|
expect(tags[6].name).to.eql(t('defaultTag7'));
|
|
});
|
|
});
|
|
|
|
context('does not provide default tags and tasks', async () => {
|
|
it('for Android', async () => {
|
|
api = requester(
|
|
null,
|
|
{ 'x-client': 'habitica-android' },
|
|
);
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
const requests = new ApiUser(user);
|
|
|
|
const habits = await requests.get('/tasks/user?type=habits');
|
|
const dailys = await requests.get('/tasks/user?type=dailys');
|
|
const todos = await requests.get('/tasks/user?type=todos');
|
|
const rewards = await requests.get('/tasks/user?type=rewards');
|
|
const tags = await requests.get('/tags');
|
|
|
|
expect(habits).to.have.a.lengthOf(0);
|
|
expect(dailys).to.have.a.lengthOf(0);
|
|
expect(todos).to.have.a.lengthOf(0);
|
|
expect(rewards).to.have.a.lengthOf(0);
|
|
expect(tags).to.have.a.lengthOf(0);
|
|
});
|
|
|
|
it('for iOS', async () => {
|
|
api = requester(
|
|
null,
|
|
{ 'x-client': 'habitica-ios' },
|
|
);
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
const requests = new ApiUser(user);
|
|
|
|
const habits = await requests.get('/tasks/user?type=habits');
|
|
const dailys = await requests.get('/tasks/user?type=dailys');
|
|
const todos = await requests.get('/tasks/user?type=todos');
|
|
const rewards = await requests.get('/tasks/user?type=rewards');
|
|
const tags = await requests.get('/tags');
|
|
|
|
expect(habits).to.have.a.lengthOf(0);
|
|
expect(dailys).to.have.a.lengthOf(0);
|
|
expect(todos).to.have.a.lengthOf(0);
|
|
expect(rewards).to.have.a.lengthOf(0);
|
|
expect(tags).to.have.a.lengthOf(0);
|
|
});
|
|
});
|
|
|
|
xit('enrolls new users in an A/B test', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
await expect(getProperty('users', user._id, '_ABtests')).to.eventually.be.a('object');
|
|
});
|
|
|
|
it('includes items awarded by default when creating a new user', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.items.quests.dustbunnies).to.equal(1);
|
|
expect(user.purchased.background.violet).to.be.ok;
|
|
expect(user.preferences.background).to.equal('violet');
|
|
});
|
|
|
|
it('requires password and confirmPassword to match', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = 'password';
|
|
const confirmPassword = 'not password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
it('requires minimum length for the password', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const password = '1234567';
|
|
const confirmPassword = '1234567';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
it('requires a username', async () => {
|
|
const email = `${generateRandomUserName()}@example.com`;
|
|
const password = 'password';
|
|
const confirmPassword = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
email,
|
|
password,
|
|
confirmPassword,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
it('requires an email', async () => {
|
|
const username = generateRandomUserName();
|
|
const password = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
it('requires a valid email', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = 'notanemail@sdf';
|
|
const password = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
|
|
it('sanitizes email params to a lowercase string before creating the user', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = 'ISANEmAiL@ExAmPle.coM';
|
|
const password = 'password';
|
|
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.auth.local.email).to.equal(email.toLowerCase());
|
|
});
|
|
|
|
it('fails on a habitica.com email', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@habitica.com`;
|
|
const password = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'User validation failed',
|
|
});
|
|
});
|
|
|
|
it('fails on a habitrpg.com email', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@habitrpg.com`;
|
|
const password = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: 'User validation failed',
|
|
});
|
|
});
|
|
|
|
it('requires a password', async () => {
|
|
const username = generateRandomUserName();
|
|
const email = `${username}@example.com`;
|
|
const confirmPassword = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
confirmPassword,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 400,
|
|
error: 'BadRequest',
|
|
message: t('invalidReqParams'),
|
|
});
|
|
});
|
|
});
|
|
|
|
context('attach to facebook user', () => {
|
|
let user;
|
|
const email = 'some@email.net';
|
|
const username = 'some-username';
|
|
const password = 'some-password';
|
|
beforeEach(async () => {
|
|
user = await generateUser();
|
|
});
|
|
it('checks onlySocialAttachLocal', async () => {
|
|
await expect(user.post('/user/auth/local/register', {
|
|
email,
|
|
username,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('onlySocialAttachLocal'),
|
|
});
|
|
});
|
|
it('succeeds', async () => {
|
|
await user.update({ 'auth.facebook.id': 'some-fb-id', 'auth.local': { ok: true } });
|
|
await user.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
await user.sync();
|
|
expect(user.auth.local.username).to.eql(username);
|
|
expect(user.auth.local.email).to.eql(email);
|
|
});
|
|
});
|
|
|
|
context('attach to google user', () => {
|
|
let user;
|
|
const email = 'some@email-google.net';
|
|
const username = 'some-username-google';
|
|
const password = 'some-password';
|
|
beforeEach(async () => {
|
|
user = await generateUser();
|
|
});
|
|
it('checks onlySocialAttachLocal', async () => {
|
|
await expect(user.post('/user/auth/local/register', {
|
|
email,
|
|
username,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('onlySocialAttachLocal'),
|
|
});
|
|
});
|
|
it('succeeds', async () => {
|
|
await user.update({ 'auth.google.id': 'some-google-id', 'auth.local': { ok: true } });
|
|
await user.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
await user.sync();
|
|
expect(user.auth.local.username).to.eql(username);
|
|
expect(user.auth.local.email).to.eql(email);
|
|
});
|
|
});
|
|
|
|
context('attach to apple user', () => {
|
|
let user;
|
|
const email = 'some@email-apple.net';
|
|
const username = 'some-username-apple';
|
|
const password = 'some-password';
|
|
beforeEach(async () => {
|
|
user = await generateUser();
|
|
});
|
|
it('checks onlySocialAttachLocal', async () => {
|
|
await expect(user.post('/user/auth/local/register', {
|
|
email,
|
|
username,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('onlySocialAttachLocal'),
|
|
});
|
|
});
|
|
it('succeeds', async () => {
|
|
await user.update({ 'auth.apple.id': 'some-apple-id', 'auth.local': { ok: true } });
|
|
await user.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
await user.sync();
|
|
expect(user.auth.local.username).to.eql(username);
|
|
expect(user.auth.local.email).to.eql(email);
|
|
});
|
|
});
|
|
|
|
context('login is already taken', () => {
|
|
let username; let email; let
|
|
api;
|
|
|
|
beforeEach(async () => {
|
|
api = requester();
|
|
username = generateRandomUserName();
|
|
email = `${username}@example.com`;
|
|
|
|
return generateUser({
|
|
'auth.local.username': username,
|
|
'auth.local.lowerCaseUsername': username,
|
|
'auth.local.email': email,
|
|
});
|
|
});
|
|
|
|
it('rejects if username is already taken', async () => {
|
|
const uniqueEmail = `${generateRandomUserName()}@exampe.com`;
|
|
const password = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username,
|
|
email: uniqueEmail,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('usernameTaken'),
|
|
});
|
|
});
|
|
|
|
it('rejects if email is already taken', async () => {
|
|
const uniqueUsername = generateRandomUserName();
|
|
const password = 'password';
|
|
|
|
await expect(api.post('/user/auth/local/register', {
|
|
username: uniqueUsername,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
})).to.eventually.be.rejected.and.eql({
|
|
code: 401,
|
|
error: 'NotAuthorized',
|
|
message: t('emailTaken'),
|
|
});
|
|
});
|
|
});
|
|
|
|
context('req.query.groupInvite', () => {
|
|
let api; let username; let email; let
|
|
password;
|
|
|
|
beforeEach(() => {
|
|
api = requester();
|
|
username = generateRandomUserName();
|
|
email = `${username}@example.com`;
|
|
password = 'password';
|
|
});
|
|
|
|
it('does not crash the signup process when it\'s invalid', async () => {
|
|
const user = await api.post('/user/auth/local/register?groupInvite=aaaaInvalid', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user._id).to.be.a('string');
|
|
});
|
|
|
|
it('supports invite using req.query.groupInvite', async () => {
|
|
const { group, groupLeader } = await createAndPopulateGroup({
|
|
groupDetails: { type: 'party', privacy: 'private' },
|
|
});
|
|
|
|
const invite = encrypt(JSON.stringify({
|
|
id: group._id,
|
|
inviter: groupLeader._id,
|
|
sentAt: Date.now(), // so we can let it expire
|
|
}));
|
|
|
|
const user = await api.post(`/user/auth/local/register?groupInvite=${invite}`, {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.invitations.parties[0].id).to.eql(group._id);
|
|
expect(user.invitations.parties[0].name).to.eql(group.name);
|
|
expect(user.invitations.parties[0].inviter).to.eql(groupLeader._id);
|
|
});
|
|
|
|
it('awards achievement to inviter', async () => {
|
|
const { group, groupLeader } = await createAndPopulateGroup({
|
|
groupDetails: { type: 'party', privacy: 'private' },
|
|
});
|
|
|
|
const invite = encrypt(JSON.stringify({
|
|
id: group._id,
|
|
inviter: groupLeader._id,
|
|
sentAt: Date.now(),
|
|
}));
|
|
|
|
await api.post(`/user/auth/local/register?groupInvite=${invite}`, {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
await groupLeader.sync();
|
|
expect(groupLeader.achievements.invitedFriend).to.be.true;
|
|
});
|
|
|
|
it('user not added to a party on expired invite', async () => {
|
|
const { group, groupLeader } = await createAndPopulateGroup({
|
|
groupDetails: { type: 'party', privacy: 'private' },
|
|
});
|
|
|
|
const invite = encrypt(JSON.stringify({
|
|
id: group._id,
|
|
inviter: groupLeader._id,
|
|
sentAt: Date.now() - 6.912e8, // 8 days old
|
|
}));
|
|
|
|
const user = await api.post(`/user/auth/local/register?groupInvite=${invite}`, {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.invitations.party).to.eql({});
|
|
});
|
|
|
|
it('adds a user to a guild on an invite of type other than party', async () => {
|
|
const { group, groupLeader } = await createAndPopulateGroup({
|
|
groupDetails: { type: 'guild', privacy: 'private' },
|
|
});
|
|
|
|
const invite = encrypt(JSON.stringify({
|
|
id: group._id,
|
|
inviter: groupLeader._id,
|
|
sentAt: Date.now(),
|
|
}));
|
|
|
|
const user = await api.post(`/user/auth/local/register?groupInvite=${invite}`, {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.invitations.guilds[0]).to.eql({
|
|
id: group._id,
|
|
name: group.name,
|
|
inviter: groupLeader._id,
|
|
});
|
|
});
|
|
});
|
|
|
|
context('successful login via api', () => {
|
|
let api; let username; let email; let
|
|
password;
|
|
|
|
beforeEach(() => {
|
|
api = requester();
|
|
username = generateRandomUserName();
|
|
email = `${username}@example.com`;
|
|
password = 'password';
|
|
});
|
|
|
|
it('sets all site tour values to -2 (already seen)', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.flags.tour).to.not.be.empty;
|
|
|
|
each(user.flags.tour, value => {
|
|
expect(value).to.eql(-2);
|
|
});
|
|
});
|
|
|
|
it('populates user with default todos, not no other task types', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.tasksOrder.todos).to.not.be.empty;
|
|
expect(user.tasksOrder.dailys).to.be.empty;
|
|
expect(user.tasksOrder.habits).to.be.empty;
|
|
expect(user.tasksOrder.rewards).to.be.empty;
|
|
});
|
|
|
|
it('populates user with default tags', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.tags).to.not.be.empty;
|
|
});
|
|
});
|
|
|
|
context('successful login with habitica-web header', () => {
|
|
let api; let username; let email; let
|
|
password;
|
|
|
|
beforeEach(() => {
|
|
api = requester({}, { 'x-client': 'habitica-web' });
|
|
username = generateRandomUserName();
|
|
email = `${username}@example.com`;
|
|
password = 'password';
|
|
});
|
|
|
|
it('sets all common tutorial flags to true', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.flags.tour).to.not.be.empty;
|
|
|
|
each(user.flags.tutorial.common, value => {
|
|
expect(value).to.eql(true);
|
|
});
|
|
});
|
|
|
|
it('populates user with default todos, habits, and rewards', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.tasksOrder.todos).to.be.empty;
|
|
expect(user.tasksOrder.dailys).to.be.empty;
|
|
expect(user.tasksOrder.habits).to.be.empty;
|
|
expect(user.tasksOrder.rewards).to.be.empty;
|
|
});
|
|
|
|
it('populates user with default tags', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
expect(user.tags).to.not.be.empty;
|
|
});
|
|
|
|
it('adds the correct tags to the correct tasks', async () => {
|
|
const user = await api.post('/user/auth/local/register', {
|
|
username,
|
|
email,
|
|
password,
|
|
confirmPassword: password,
|
|
});
|
|
|
|
const requests = new ApiUser(user);
|
|
|
|
const habits = await requests.get('/tasks/user?type=habits');
|
|
const todos = await requests.get('/tasks/user?type=todos');
|
|
|
|
expect(habits).to.have.a.lengthOf(0);
|
|
expect(todos).to.have.a.lengthOf(0);
|
|
});
|
|
});
|
|
});
|