Merge branch 'api-v3' into api-v3-client

This commit is contained in:
Matteo Pagliazzi
2016-05-11 16:01:54 +02:00
194 changed files with 19205 additions and 20873 deletions
+2 -2
View File
@@ -8,7 +8,7 @@ import {
find,
map,
} from 'lodash';
import Q from 'q';
import Bluebird from 'bluebird';
describe('DELETE /user', () => {
let user;
@@ -30,7 +30,7 @@ describe('DELETE /user', () => {
await user.del('/user');
await Q.all(map(ids, id => {
await Bluebird.all(map(ids, id => {
return expect(checkExistence('tasks', id)).to.eventually.eql(false);
}));
});
@@ -2,7 +2,9 @@ import {
generateUser,
} from '../../../../helpers/api-v3-integration.helper';
import xml2js from 'xml2js';
import Q from 'q';
import Bluebird from 'bluebird';
let parseStringAsync = Bluebird.promisify(xml2js.parseString, {context: xml2js});
describe('GET /export/userdata.xml', () => {
it('should return a valid XML file with user data', async () => {
@@ -22,7 +24,7 @@ describe('GET /export/userdata.xml', () => {
]);
let response = await user.get('/export/userdata.xml');
let {user: res} = await Q.npost(xml2js, 'parseString', [response, {explicitArray: false}]);
let {user: res} = await parseStringAsync(response, {explicitArray: false});
expect(res._id).to.equal(user._id);
expect(res).to.contain.all.keys(['tasks', 'flags', 'tasksOrder', 'auth']);
@@ -9,7 +9,8 @@ import {
describe('GET /groups', () => {
let user;
const NUMBER_OF_PUBLIC_GUILDS = 3;
const NUMBER_OF_PUBLIC_GUILDS = 3; // 2 + the tavern
const NUMBER_OF_PUBLIC_GUILDS_USER_IS_MEMBER = 1;
const NUMBER_OF_USERS_PRIVATE_GUILDS = 1;
const NUMBER_OF_GROUPS_USER_CAN_VIEW = 5;
@@ -87,6 +88,11 @@ describe('GET /groups', () => {
.to.eventually.have.a.lengthOf(NUMBER_OF_PUBLIC_GUILDS);
});
it('returns all the user\'s guilds when guilds passed in as query', async () => {
await expect(user.get('/groups?type=guilds'))
.to.eventually.have.a.lengthOf(NUMBER_OF_PUBLIC_GUILDS_USER_IS_MEMBER + NUMBER_OF_USERS_PRIVATE_GUILDS);
});
it('returns all private guilds user is a part of when privateGuilds passed in as query', async () => {
await expect(user.get('/groups?type=privateGuilds'))
.to.eventually.have.a.lengthOf(NUMBER_OF_USERS_PRIVATE_GUILDS);
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments : amazon #subscribeCancel', () => {
let endpoint = '/amazon/subscribe/cancel';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies subscription', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingAuthParams'),
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments : paypal #checkout', () => {
let endpoint = '/paypal/checkout';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies subscription', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingAuthParams'),
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments : paypal #checkoutSuccess', () => {
let endpoint = '/paypal/checkout/success';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies subscription', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidCredentials'),
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments : paypal #subscribe', () => {
let endpoint = '/paypal/subscribe';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingAuthParams'),
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments : paypal #subscribeCancel', () => {
let endpoint = '/paypal/subscribe/cancel';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingAuthParams'),
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments : paypal #subscribeSuccess', () => {
let endpoint = '/paypal/subscribe/success';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('invalidCredentials'),
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments - stripe - #subscribeCancel', () => {
let endpoint = '/stripe/subscribe/cancel';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.get(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingAuthParams'),
});
});
});
@@ -0,0 +1,20 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
describe('payments - amazon - #checkout', () => {
let endpoint = '/amazon/checkout';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'Missing req.body.orderReferenceId',
});
});
});
@@ -0,0 +1,22 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
describe('payments - amazon - #createOrderReferenceId', () => {
let endpoint = '/amazon/createOrderReferenceId';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies billingAgreementId', async (done) => {
try {
await user.post(endpoint);
} catch (e) {
// Parameter AWSAccessKeyId cannot be empty.
expect(e.error).to.eql('BadRequest');
done();
}
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments - amazon - #subscribe', () => {
let endpoint = '/amazon/subscribe';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies subscription code', async () => {
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('missingSubscriptionCode'),
});
});
});
@@ -0,0 +1,20 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
describe('payments : amazon', () => {
let endpoint = '/amazon/verifyAccessToken';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies access token', async () => {
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: 'Missing req.body.access_token',
});
});
});
@@ -0,0 +1,17 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
describe('payments - paypal - #ipn', () => {
let endpoint = '/paypal/ipn';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
let result = await user.post(endpoint);
expect(result).to.eql('OK');
});
});
@@ -0,0 +1,20 @@
import {
generateUser,
} from '../../../../helpers/api-integration/v3';
describe('payments - stripe - #checkout', () => {
let endpoint = '/stripe/checkout';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.post(endpoint, {id: 123})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'Error',
message: 'Invalid API Key provided: ****************************1111',
});
});
});
@@ -0,0 +1,21 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
describe('payments - stripe - #subscribeEdit', () => {
let endpoint = '/stripe/subscribe/edit';
let user;
beforeEach(async () => {
user = await generateUser();
});
it('verifies credentials', async () => {
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('missingSubscription'),
});
});
});
@@ -10,7 +10,7 @@ import {
each,
map,
} from 'lodash';
import Q from 'q';
import Bluebird from 'bluebird';
describe('DELETE /user', () => {
let user;
@@ -55,7 +55,7 @@ describe('DELETE /user', () => {
password,
});
await Q.all(map(ids, id => {
await Bluebird.all(map(ids, id => {
return expect(checkExistence('tasks', id)).to.eventually.eql(false);
}));
});
@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
import {
generateUser,
translate as t,
@@ -46,6 +48,15 @@ describe('POST /user/buy/:key', () => {
await user.post(`/user/buy/${key}`);
await user.sync();
expect(user.items.gear.owned).to.eql({ armor_warrior_1: true }); // eslint-disable-line camelcase
expect(user.items.gear.owned).to.eql({
armor_warrior_1: true,
eyewear_special_blackTopFrame: true,
eyewear_special_blueTopFrame: true,
eyewear_special_greenTopFrame: true,
eyewear_special_pinkTopFrame: true,
eyewear_special_redTopFrame: true,
eyewear_special_whiteTopFrame: true,
eyewear_special_yellowTopFrame: true,
});
});
});
@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
import {
generateUser,
translate as t,
@@ -29,6 +31,15 @@ describe('POST /user/buy-gear/:key', () => {
await user.post(`/user/buy-gear/${key}`);
await user.sync();
expect(user.items.gear.owned).to.eql({ armor_warrior_1: true }); // eslint-disable-line camelcase
expect(user.items.gear.owned).to.eql({
armor_warrior_1: true,
eyewear_special_blackTopFrame: true,
eyewear_special_blueTopFrame: true,
eyewear_special_greenTopFrame: true,
eyewear_special_pinkTopFrame: true,
eyewear_special_redTopFrame: true,
eyewear_special_whiteTopFrame: true,
eyewear_special_yellowTopFrame: true,
});
});
});
+4 -4
View File
@@ -298,19 +298,19 @@ describe('cron', () => {
expect(tasksByType.dailys[0].completed).to.be.false;
});
it('should set task checklist to completed for completed dailys', () => {
it('should reset task checklist for completed dailys', () => {
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
tasksByType.dailys[0].completed = true;
cron({user, tasksByType, daysMissed, analytics});
expect(tasksByType.dailys[0].checklist[0].completed).to.be.true;
expect(tasksByType.dailys[0].checklist[0].completed).to.be.false;
});
it('should set task checklist to completed for dailys with scheduled misses', () => {
it('should reset task checklist for dailys with scheduled misses', () => {
daysMissed = 10;
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
cron({user, tasksByType, daysMissed, analytics});
expect(tasksByType.dailys[0].checklist[0].completed).to.be.true;
expect(tasksByType.dailys[0].checklist[0].completed).to.be.false;
});
it('should do damage for missing a daily', () => {
+30 -17
View File
@@ -2,9 +2,26 @@
import request from 'request';
import nconf from 'nconf';
import nodemailer from 'nodemailer';
import Q from 'q';
import Bluebird from 'bluebird';
import requireAgain from 'require-again';
import logger from '../../../../../website/src/libs/api-v3/logger';
function defer () {
let resolve;
let reject;
let promise = new Bluebird((resolveParam, rejectParam) => {
resolve = resolveParam;
reject = rejectParam;
});
return {
resolve,
reject,
promise,
};
}
function getUser () {
return {
_id: 'random _id',
@@ -34,25 +51,21 @@ function getUser () {
describe('emails', () => {
let pathToEmailLib = '../../../../../website/src/libs/api-v3/email';
beforeEach(() => {
delete require.cache[require.resolve(pathToEmailLib)];
});
describe('sendEmail', () => {
it('can send an email using the default transport', () => {
let sendMailSpy = sandbox.stub().returns(Q.defer().promise);
let sendMailSpy = sandbox.stub().returns(defer().promise);
sandbox.stub(nodemailer, 'createTransport').returns({
sendMail: sendMailSpy,
});
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
attachEmail.send();
expect(sendMailSpy).to.be.calledOnce;
});
it('logs errors', (done) => {
let deferred = Q.defer();
let deferred = defer();
let sendMailSpy = sandbox.stub().returns(deferred.promise);
sandbox.stub(nodemailer, 'createTransport').returns({
@@ -60,7 +73,7 @@ describe('emails', () => {
});
sandbox.stub(logger, 'error');
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
attachEmail.send();
expect(sendMailSpy).to.be.calledOnce;
deferred.reject();
@@ -75,13 +88,13 @@ describe('emails', () => {
describe('getUserInfo', () => {
it('returns an empty object if no field request', () => {
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let getUserInfo = attachEmail.getUserInfo;
expect(getUserInfo({}, [])).to.be.empty;
});
it('returns correct user data', () => {
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let getUserInfo = attachEmail.getUserInfo;
let user = getUser();
let data = getUserInfo(user, ['name', 'email', '_id', 'canSend']);
@@ -93,7 +106,7 @@ describe('emails', () => {
});
it('returns correct user data [facebook users]', () => {
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let getUserInfo = attachEmail.getUserInfo;
let user = getUser();
delete user.profile.name;
@@ -108,7 +121,7 @@ describe('emails', () => {
});
it('has fallbacks for missing data', () => {
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let getUserInfo = attachEmail.getUserInfo;
let user = getUser();
delete user.profile.name;
@@ -135,7 +148,7 @@ describe('emails', () => {
it('can send a txn email to one recipient', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let sendTxnEmail = attachEmail.sendTxn;
let emailType = 'an email type';
let mailingInfo = {
@@ -158,7 +171,7 @@ describe('emails', () => {
it('does not send email if address is missing', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let sendTxnEmail = attachEmail.sendTxn;
let emailType = 'an email type';
let mailingInfo = {
@@ -172,7 +185,7 @@ describe('emails', () => {
it('uses getUserInfo in case of user data', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let sendTxnEmail = attachEmail.sendTxn;
let emailType = 'an email type';
let mailingInfo = getUser();
@@ -190,7 +203,7 @@ describe('emails', () => {
it('sends email with some default variables', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
let attachEmail = require(pathToEmailLib);
let attachEmail = requireAgain(pathToEmailLib);
let sendTxnEmail = attachEmail.sendTxn;
let emailType = 'an email type';
let mailingInfo = {
+4 -5
View File
@@ -1,4 +1,5 @@
import winston from 'winston';
import requireAgain from 'require-again';
/* eslint-disable global-require */
describe('logger', () => {
@@ -7,8 +8,6 @@ describe('logger', () => {
let errorSpy;
beforeEach(() => {
delete require.cache[require.resolve(pathToLoggerLib)];
infoSpy = sandbox.stub();
errorSpy = sandbox.stub();
sandbox.stub(winston, 'Logger').returns({
@@ -22,7 +21,7 @@ describe('logger', () => {
});
it('info', () => {
let attachLogger = require(pathToLoggerLib);
let attachLogger = requireAgain(pathToLoggerLib);
attachLogger.info(1, 2, 3);
expect(infoSpy).to.be.calledOnce;
expect(infoSpy).to.be.calledWith(1, 2, 3);
@@ -30,14 +29,14 @@ describe('logger', () => {
describe('error', () => {
it('with custom arguments', () => {
let attachLogger = require(pathToLoggerLib);
let attachLogger = requireAgain(pathToLoggerLib);
attachLogger.error(1, 2, 3, 4);
expect(errorSpy).to.be.calledOnce;
expect(errorSpy).to.be.calledWith(1, 2, 3, 4);
});
it('with error', () => {
let attachLogger = require(pathToLoggerLib);
let attachLogger = requireAgain(pathToLoggerLib);
let errInstance = new Error('An error.');
attachLogger.error(errInstance, {
data: 1,
+72
View File
@@ -0,0 +1,72 @@
import * as sender from '../../../../../website/src/libs/api-v3/email';
import * as api from '../../../../../website/src/libs/api-v3/payments';
import { model as User } from '../../../../../website/src/models/user';
import moment from 'moment';
describe('payments/index', () => {
let fakeSend;
let data;
let user;
describe('#createSubscription', () => {
beforeEach(async () => {
user = new User();
});
it('succeeds', async () => {
data = { user, sub: { key: 'basic_3mo' } };
expect(user.purchased.plan.planId).to.not.exist;
await api.createSubscription(data);
expect(user.purchased.plan.planId).to.exist;
});
});
describe('#cancelSubscription', () => {
beforeEach(() => {
fakeSend = sinon.spy(sender, 'sendTxn');
data = { user: new User() };
});
afterEach(() => {
fakeSend.restore();
});
it('plan.extraMonths is defined', () => {
api.cancelSubscription(data);
let terminated = data.user.purchased.plan.dateTerminated;
data.user.purchased.plan.extraMonths = 2;
api.cancelSubscription(data);
let difference = Math.abs(moment(terminated).diff(data.user.purchased.plan.dateTerminated, 'days'));
expect(difference - 60).to.be.lessThan(3); // the difference is approximately two months, +/- 2 days
});
it('plan.extraMonth is a fraction', () => {
api.cancelSubscription(data);
let terminated = data.user.purchased.plan.dateTerminated;
data.user.purchased.plan.extraMonths = 0.3;
api.cancelSubscription(data);
let difference = Math.abs(moment(terminated).diff(data.user.purchased.plan.dateTerminated, 'days'));
expect(difference - 10).to.be.lessThan(3); // the difference should be 10 days.
});
it('nextBill is defined', () => {
api.cancelSubscription(data);
let terminated = data.user.purchased.plan.dateTerminated;
data.nextBill = moment().add({ days: 25 });
api.cancelSubscription(data);
let difference = Math.abs(moment(terminated).diff(data.user.purchased.plan.dateTerminated, 'days'));
expect(difference - 5).to.be.lessThan(2); // the difference should be 5 days, +/- 1 day
});
it('saves the canceled subscription for the user', () => {
expect(data.user.purchased.plan.dateTerminated).to.not.exist;
api.cancelSubscription(data);
expect(data.user.purchased.plan.dateTerminated).to.exist;
});
it('sends a text', async () => {
await api.cancelSubscription(data);
sinon.assert.called(fakeSend);
});
});
});
+4 -10
View File
@@ -6,6 +6,7 @@ import {
} from '../../../../helpers/api-unit.helper';
import analyticsService from '../../../../../website/src/libs/api-v3/analyticsService';
import nconf from 'nconf';
import requireAgain from 'require-again';
describe('analytics middleware', () => {
let res, req, next;
@@ -17,15 +18,8 @@ describe('analytics middleware', () => {
next = generateNext();
});
afterEach(() => {
// The nconf.get('IS_PROD') occurs when the file is required
// Since node caches IS_PROD, we have to delete it from the cache
// to test prod vs non-prod behaviors
delete require.cache[require.resolve(pathToAnalyticsMiddleware)];
});
it('attaches analytics object res.locals', () => {
let attachAnalytics = require(pathToAnalyticsMiddleware);
let attachAnalytics = requireAgain(pathToAnalyticsMiddleware);
attachAnalytics(req, res, next);
@@ -34,7 +28,7 @@ describe('analytics middleware', () => {
it('attaches stubbed methods for non-prod environments', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(false);
let attachAnalytics = require(pathToAnalyticsMiddleware);
let attachAnalytics = requireAgain(pathToAnalyticsMiddleware);
attachAnalytics(req, res, next);
@@ -45,7 +39,7 @@ describe('analytics middleware', () => {
it('attaches real methods for prod environments', () => {
sandbox.stub(nconf, 'get').withArgs('IS_PROD').returns(true);
let attachAnalytics = require(pathToAnalyticsMiddleware);
let attachAnalytics = requireAgain(pathToAnalyticsMiddleware);
attachAnalytics(req, res, next);
@@ -8,7 +8,7 @@ import {
attachTranslateFunction,
} from '../../../../../website/src/middlewares/api-v3/language';
import common from '../../../../../common';
import Q from 'q';
import Bluebird from 'bluebird';
import { model as User } from '../../../../../website/src/models/user';
const i18n = common.i18n;
@@ -162,7 +162,7 @@ describe('language middleware', () => {
return this;
},
exec () {
return Q.resolve({
return Bluebird.resolve({
preferences: {
language: 'it',
},