mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-10-28 19:59:24 +01:00
* refactor(content): split quests file * feat(purchases): sell bundled quests * fix(style): address linting errors * test(bundles): shop and purchase tests * fix(test): remove only * test(bundles): check balance deduction * docs(content): comment bundle structure * fix(test): account for cumulative balance
436 lines
13 KiB
JavaScript
436 lines
13 KiB
JavaScript
'use strict';
|
|
|
|
describe('Quests Service', function() {
|
|
var groupsService, quest, questsService, user, content, resolveSpy, rejectSpy, state;
|
|
|
|
beforeEach(function() {
|
|
user = specHelper.newUser();
|
|
user.ops = {
|
|
buyQuest: sandbox.spy()
|
|
};
|
|
user.party._id = 'unique-party-id';
|
|
|
|
user.achievements.quests = {};
|
|
quest = {lvl:20};
|
|
|
|
module(function($provide) {
|
|
$provide.value('User', {sync: sinon.stub(), user: user});
|
|
});
|
|
|
|
inject(function(Quests, Groups, Content, _$state_) {
|
|
questsService = Quests;
|
|
groupsService = Groups;
|
|
content = Content;
|
|
state = _$state_;
|
|
});
|
|
|
|
sandbox.stub(groupsService, 'inviteOrStartParty');
|
|
sandbox.stub(window,'confirm');
|
|
sandbox.stub(window,'alert');
|
|
resolveSpy = sandbox.spy();
|
|
rejectSpy = sandbox.spy();
|
|
});
|
|
|
|
describe('#lockQuest', function() {
|
|
|
|
it('locks quest when user does not meet level requirement', function() {
|
|
user.stats.lvl = 15;
|
|
|
|
expect(questsService.lockQuest(quest)).to.be.ok;
|
|
});
|
|
|
|
it('does not lock quest if we ignore level requirement', function() {
|
|
user.stats.lvl = 15;
|
|
|
|
expect(questsService.lockQuest(quest,true)).to.not.be.ok;
|
|
});
|
|
|
|
it('does not lock quest if user meets level requirement', function() {
|
|
user.stats.lvl = 20;
|
|
|
|
expect(questsService.lockQuest(quest)).to.not.be.ok;
|
|
});
|
|
|
|
it('locks quest if user has not completed previous quest in series', function() {
|
|
quest.previous = 'priorQuest';
|
|
user.stats.lvl = 25;
|
|
|
|
expect(questsService.lockQuest(quest)).to.be.ok;
|
|
});
|
|
|
|
it('does not lock quest if user has completed previous quest in series', function() {
|
|
quest.previous = 'priorQuest';
|
|
user.stats.lvl = 25;
|
|
user.achievements.quests.priorQuest = 1;
|
|
|
|
expect(questsService.lockQuest(quest)).to.not.be.ok;
|
|
});
|
|
});
|
|
|
|
describe('#buyQuest', function() {
|
|
var scope;
|
|
|
|
beforeEach(inject(function($rootScope) {
|
|
scope = $rootScope.$new();
|
|
}));
|
|
|
|
//@TODO: This is fixed in a Quest Service PR port
|
|
xit('returns a promise', function() {
|
|
var promise = questsService.buyQuest('whale');
|
|
expect(promise).to.respondTo('then');
|
|
});
|
|
|
|
context('Quest key does not exist', function() {
|
|
it('rejects with message that quest is not found', function(done) {
|
|
questsService.buyQuest('foo')
|
|
.then(resolveSpy, function(rej) {
|
|
expect(rej).to.eql('No quest with that key found');
|
|
expect(resolveSpy).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('invite friends', function() {
|
|
it('prompts user to invite friends to party for invite reward quests', function() {
|
|
questsService.buyQuest('basilist');
|
|
|
|
expect(window.confirm).to.be.calledOnce;
|
|
expect(window.confirm).to.be.calledWith(env.t('mustInviteFriend'));
|
|
});
|
|
|
|
it('rejects promise if confirm is cancelled', function(done) {
|
|
window.confirm.returns(false);
|
|
|
|
questsService.buyQuest('basilist')
|
|
.then(resolveSpy, function(rej) {
|
|
expect(rej).to.eql('Did not want to invite friends');
|
|
expect(window.confirm).to.be.calledOnce;
|
|
expect(groupsService.inviteOrStartParty).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
|
|
it('rejects promise if confirm is cofirmed and calls groups service', function(done) {
|
|
window.confirm.returns(true);
|
|
|
|
questsService.buyQuest('basilist')
|
|
.then(resolveSpy, function(rej) {
|
|
expect(rej).to.eql('Invite or start party');
|
|
expect(window.confirm).to.be.calledOnce;
|
|
expect(groupsService.inviteOrStartParty).to.be.calledOnce;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('quests in a series', function() {
|
|
it('does not allow user to buy subsquent quests in a series if user has no quest achievements', function(done) {
|
|
user.stats.lvl = 100;
|
|
user.achievements.quests = undefined;
|
|
|
|
questsService.buyQuest('goldenknight2')
|
|
.then(resolveSpy, function(res) {
|
|
expect(window.alert).to.have.been.calledOnce;
|
|
expect(res).to.eql('unlockByQuesting');
|
|
expect(resolveSpy).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
|
|
it('does not allow user to buy quests whose previous quests are incomplete', function(done) {
|
|
user.stats.lvl = 100;
|
|
user.achievements.quests = {
|
|
'atom1': 1
|
|
};
|
|
|
|
questsService.buyQuest('goldenknight2')
|
|
.then(resolveSpy, function(res) {
|
|
expect(window.alert).to.have.been.calledOnce;
|
|
expect(resolveSpy).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('quests with level requirement', function() {
|
|
it('does not allow user to buy quests beyond their level', function(done) {
|
|
user.stats.lvl = 1;
|
|
|
|
questsService.buyQuest('vice1')
|
|
.then(resolveSpy, function(res) {
|
|
expect(window.alert).to.have.been.calledOnce;
|
|
expect(res).to.eql('mustLvlQuest');
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
|
|
it('allows user to buy quest if they meet level requirement', function(done) {
|
|
user.stats.lvl = 30;
|
|
|
|
questsService.buyQuest('vice1')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.quests.vice1);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('gold purchasable quests', function() {
|
|
it('sends quest object', function(done) {
|
|
questsService.buyQuest('dilatoryDistress1')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.quests.dilatoryDistress1);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('quest bundles', function() {
|
|
it('sends bundle object', function(done) {
|
|
questsService.buyQuest('featheredFriends')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.bundles.featheredFriends);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('all other quests', function() {
|
|
it('sends quest object', function(done) {
|
|
questsService.buyQuest('whale')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.quests.whale);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#showQuest', function() {
|
|
var scope;
|
|
|
|
beforeEach(inject(function($rootScope) {
|
|
scope = $rootScope.$new();
|
|
}));
|
|
|
|
xit('returns a promise', function() {
|
|
var promise = questsService.showQuest('whale');
|
|
expect(promise).to.respondTo('then');
|
|
});
|
|
|
|
context('Quest key does not exist', function() {
|
|
it('rejects with message that quest is not found', function(done) {
|
|
questsService.showQuest('foo')
|
|
.then(resolveSpy, function(rej) {
|
|
expect(rej).to.eql('No quest with that key found');
|
|
expect(resolveSpy).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('quests in a series', function() {
|
|
it('does not allow user to buy subsquent quests in a series if user has no quest achievements', function(done) {
|
|
user.stats.lvl = 100;
|
|
user.achievements.quests = undefined;
|
|
|
|
questsService.showQuest('goldenknight2')
|
|
.then(resolveSpy, function(res) {
|
|
expect(window.alert).to.have.been.calledOnce;
|
|
expect(res).to.eql('unlockByQuesting');
|
|
expect(resolveSpy).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
|
|
it('does not allow user to buy quests whose previous quests are incomplete', function(done) {
|
|
user.stats.lvl = 100;
|
|
user.achievements.quests = {
|
|
'atom1': 1
|
|
};
|
|
|
|
questsService.showQuest('goldenknight2')
|
|
.then(resolveSpy, function(res) {
|
|
expect(window.alert).to.have.been.calledOnce;
|
|
expect(resolveSpy).to.not.be.called;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('quests with level requirement', function() {
|
|
it('does not allow user to buy quests beyond their level', function(done) {
|
|
user.stats.lvl = 1;
|
|
|
|
questsService.showQuest('vice1')
|
|
.then(resolveSpy, function(res) {
|
|
expect(window.alert).to.have.been.calledOnce;
|
|
expect(res).to.eql('mustLvlQuest');
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
|
|
it('allows user to buy quest if they meet level requirement', function(done) {
|
|
user.stats.lvl = 30;
|
|
|
|
questsService.showQuest('vice1')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.quests.vice1);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('gold purchasable quests', function() {
|
|
it('sends quest object', function(done) {
|
|
questsService.showQuest('dilatoryDistress1')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.quests.dilatoryDistress1);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
|
|
context('all other quests', function() {
|
|
it('sends quest object', function(done) {
|
|
questsService.showQuest('whale')
|
|
.then(function(res) {
|
|
expect(res).to.eql(content.quests.whale);
|
|
expect(window.alert).to.not.be.called;
|
|
expect(rejectSpy).to.not.be.called;
|
|
done();
|
|
}, rejectSpy);
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#initQuest', function() {
|
|
var fakeBackend, scope, key = 'whale';
|
|
|
|
beforeEach(inject(function($httpBackend, $rootScope) {
|
|
scope = $rootScope.$new();
|
|
fakeBackend = $httpBackend;
|
|
var partyResponse = {data:{_id: 'party-id'}};
|
|
|
|
fakeBackend.when('GET', 'partials/main.html').respond({});
|
|
fakeBackend.when('GET', 'partials/main.html').respond({});
|
|
fakeBackend.when('GET', '/api/v3/groups/party').respond(partyResponse);
|
|
fakeBackend.when('GET', '/api/v3/groups/party-id/members?includeAllPublicFields=true').respond({});
|
|
fakeBackend.when('GET', '/api/v3/groups/party-id/invites').respond({});
|
|
fakeBackend.when('GET', '/api/v3/challenges/groups/party-id').respond({});
|
|
fakeBackend.when('POST', '/api/v3/groups/party-id/quests/invite/' + key).respond({quest: { key: 'whale' } });
|
|
fakeBackend.flush();
|
|
}));
|
|
|
|
it('returns a promise', function() {
|
|
var promise = questsService.initQuest(key);
|
|
expect(promise).to.respondTo('then');
|
|
});
|
|
|
|
it('starts a quest', function(done) {
|
|
fakeBackend.expectPOST( '/api/v3/groups/party-id/quests/invite/' + key);
|
|
|
|
questsService.initQuest(key)
|
|
.then(function(res) {
|
|
done();
|
|
});
|
|
|
|
fakeBackend.flush();
|
|
scope.$apply();
|
|
});
|
|
|
|
it('brings user to party page');
|
|
});
|
|
|
|
//@TODO: This is fixed in a Quest Service PR port
|
|
xdescribe('#sendAction', function() {
|
|
var fakeBackend, scope;
|
|
|
|
beforeEach(inject(function($httpBackend, $rootScope) {
|
|
scope = $rootScope.$new();
|
|
fakeBackend = $httpBackend;
|
|
var partyResponse = {data:{_id: 'party-id'}};
|
|
|
|
fakeBackend.when('GET', 'partials/main.html').respond({});
|
|
fakeBackend.when('GET', '/api/v3/groups/party').respond(partyResponse);
|
|
fakeBackend.when('POST', '/api/v3/groups/party-id/quests/reject').respond({quest: { key: 'whale' } });
|
|
fakeBackend.flush();
|
|
}));
|
|
|
|
it('returns a promise', function() {
|
|
var promise = questsService.sendAction('quests/reject');
|
|
expect(promise).to.respondTo('then');
|
|
});
|
|
|
|
it('calls specified quest endpoint', function(done) {
|
|
fakeBackend.expectPOST('/api/v3/groups/party-id/quests/reject');
|
|
|
|
questsService.sendAction('quests/reject')
|
|
.then(function(res) {
|
|
expect(res.key).to.eql('whale');
|
|
done();
|
|
});
|
|
|
|
fakeBackend.flush();
|
|
scope.$apply();
|
|
});
|
|
|
|
it('syncs User', function() {
|
|
questsService.sendAction('quests/reject')
|
|
.then(function(res) {
|
|
expect(User.sync).to.be.calledOnce;
|
|
done();
|
|
});
|
|
|
|
scope.$apply();
|
|
});
|
|
});
|
|
});
|