Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91b6d3db02 | ||
|
|
d16ce1ce48 | ||
|
|
564c366bfb | ||
|
|
c8c65a4f4f | ||
|
|
a4feae4dbb | ||
|
|
d8620e1636 | ||
|
|
46d96b444b | ||
|
|
60c9434b14 | ||
|
|
c3901e8615 | ||
|
|
d166de8ad0 | ||
|
|
82e9afe9ce | ||
|
|
999202a8a5 | ||
|
|
8b53adfcb1 | ||
|
|
c23062f87e | ||
|
|
ec98541df6 | ||
|
|
4fed13afdd | ||
|
|
866b28ec15 | ||
|
|
bdf4a69eaf | ||
|
|
4c121fba19 | ||
|
|
0ecb95a294 | ||
|
|
ea7c07e21d | ||
|
|
c4463f991b | ||
|
|
96ce948e1a | ||
|
|
6d06685dfa | ||
|
|
32b6566e37 | ||
|
|
ca3b4cd8ae | ||
|
|
c90b4b488e | ||
|
|
8c203637d7 | ||
|
|
58f72b7eaa | ||
|
|
f0bbe84bd1 | ||
|
|
038e3f3235 | ||
|
|
1a7c8c1f87 | ||
|
|
c73d6154a8 | ||
|
|
e8b77ad2b2 | ||
|
|
ea18489991 | ||
|
|
5eb1b6684e | ||
|
|
a2f77eeba2 | ||
|
|
d4198f8913 | ||
|
|
565d50dd99 | ||
|
|
be1754ab07 | ||
|
|
831b122ce2 | ||
|
|
03088f1d9f | ||
|
|
1d7b733759 | ||
|
|
d170f0b1bd | ||
|
|
4846bc5769 | ||
|
|
30f514e46f | ||
|
|
6aad018eb2 | ||
|
|
daf9421f4f | ||
|
|
b2225f05e5 | ||
|
|
842fbe42a8 | ||
|
|
5eadf9e486 | ||
|
|
68ad3e2d4a | ||
|
|
de947f8069 | ||
|
|
d541e3aa31 | ||
|
|
b0eda344f1 | ||
|
|
02708a7b10 | ||
|
|
fd9f3a32c4 | ||
|
|
6e0341a4ff | ||
|
|
625077fc1a | ||
|
|
9d456e934c | ||
|
|
771d8f492a | ||
|
|
f3fab88f0b | ||
|
|
207e3476e6 | ||
|
|
0ec293bd15 | ||
|
|
cb00ecc0be | ||
|
|
94ef4f80cc | ||
|
|
814b163e1a | ||
|
|
421bdce38b | ||
|
|
624566ecec | ||
|
|
77ff91868e | ||
|
|
59f490d178 | ||
|
|
ae64ef94ae | ||
|
|
2335e22a0c | ||
|
|
910154b3ed | ||
|
|
31e36339c4 | ||
|
|
07fe1df024 | ||
|
|
258742f6b7 | ||
|
|
d9d7c69432 | ||
|
|
03d6c459bf | ||
|
|
12cefe4e9f | ||
|
|
21ad808cc1 | ||
|
|
db9befde17 | ||
|
|
cc9bca5f63 | ||
|
|
05d75a4d5c | ||
|
|
164177f010 |
16
.travis.yml
@@ -16,18 +16,18 @@ before_script:
|
||||
- npm run test:build
|
||||
- cp config.json.example config.json
|
||||
- if [ $REQUIRES_SERVER ]; then until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done; export DISPLAY=:99; fi
|
||||
after_script:
|
||||
- ./node_modules/.bin/lcov-result-merger 'coverage/**/*.info' | ./node_modules/coveralls/bin/coveralls.js
|
||||
script: npm run $TEST
|
||||
script:
|
||||
- npm run $TEST
|
||||
- if [ $COVERAGE ]; then ./node_modules/.bin/lcov-result-merger 'coverage/**/*.info' | ./node_modules/coveralls/bin/coveralls.js; fi
|
||||
env:
|
||||
global:
|
||||
- CXX=g++-4.8
|
||||
- DISABLE_REQUEST_LOGGING=true
|
||||
matrix:
|
||||
- TEST="lint"
|
||||
- TEST="test:api-v3" REQUIRES_SERVER=true
|
||||
- TEST="test:api-v3" REQUIRES_SERVER=true COVERAGE=true
|
||||
- TEST="test:sanity"
|
||||
- TEST="test:content"
|
||||
- TEST="test:common"
|
||||
- TEST="test:karma"
|
||||
- TEST="client:unit"
|
||||
- TEST="test:content" COVERAGE=true
|
||||
- TEST="test:common" COVERAGE=true
|
||||
- TEST="test:karma" COVERAGE=true
|
||||
- TEST="client:unit" COVERAGE=true
|
||||
|
||||
@@ -76,6 +76,11 @@
|
||||
"APN_ENABLED": "false",
|
||||
"FCM_SERVER_API_KEY": ""
|
||||
},
|
||||
"SITE_HTTP_AUTH": {
|
||||
"ENABLED": "false",
|
||||
"USERNAME": "admin",
|
||||
"PASSWORD": "password"
|
||||
},
|
||||
"PUSHER": {
|
||||
"ENABLED": "false",
|
||||
"APP_ID": "appId",
|
||||
@@ -87,5 +92,10 @@
|
||||
"FLAGGING_FOOTER_LINK": "https://habitrpg.github.io/flag-o-rama/",
|
||||
"SUBSCRIPTIONS_URL": "https://hooks.slack.com/services/id/id/id"
|
||||
},
|
||||
"ITUNES_SHARED_SECRET": "aaaabbbbccccddddeeeeffff00001111"
|
||||
"ITUNES_SHARED_SECRET": "aaaabbbbccccddddeeeeffff00001111",
|
||||
"EMAILS" : {
|
||||
"COMMUNITY_MANAGER_EMAIL" : "leslie@habitica.com",
|
||||
"TECH_ASSISTANCE_EMAIL" : "admin@habitica.com",
|
||||
"PRESS_ENQUIRY_EMAIL" : "leslie@habitica.com"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ gulp.task('test:e2e:safe', ['test:prepare', 'test:prepare:server'], (cb) => {
|
||||
|
||||
gulp.task('test:api-v3:unit', (done) => {
|
||||
let runner = exec(
|
||||
testBin('mocha test/api/v3/unit --recursive --require ./test/helpers/start-server'),
|
||||
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-unit --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/unit --recursive --require ./test/helpers/start-server'),
|
||||
(err, stdout, stderr) => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
@@ -298,7 +298,7 @@ gulp.task('test:api-v3:unit:watch', () => {
|
||||
|
||||
gulp.task('test:api-v3:integration', (done) => {
|
||||
let runner = exec(
|
||||
testBin('mocha test/api/v3/integration --recursive --require ./test/helpers/start-server'),
|
||||
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/integration --recursive --require ./test/helpers/start-server'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err, stdout, stderr) => {
|
||||
if (err) {
|
||||
|
||||
47
migrations/challenges/sync-all-challenges.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import Bluebird from 'Bluebird';
|
||||
|
||||
import { model as Challenges } from '../../website/server/models/challenge';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
async function syncChallengeToMembers (challenges) {
|
||||
let challengSyncPromises = challenges.map(async function (challenge) {
|
||||
let users = await User.find({
|
||||
// _id: '',
|
||||
challenges: challenge._id,
|
||||
}).exec();
|
||||
|
||||
let promises = [];
|
||||
users.forEach(function (user) {
|
||||
promises.push(challenge.syncToUser(user));
|
||||
promises.push(challenge.save());
|
||||
promises.push(user.save());
|
||||
});
|
||||
|
||||
return Bluebird.all(promises);
|
||||
});
|
||||
|
||||
return await Bluebird.all(challengSyncPromises);
|
||||
}
|
||||
|
||||
async function syncChallenges (lastChallengeDate) {
|
||||
let query = {
|
||||
// _id: '',
|
||||
};
|
||||
|
||||
if (lastChallengeDate) {
|
||||
query.createdOn = { $lte: lastChallengeDate };
|
||||
}
|
||||
|
||||
let challengesFound = await Challenges.find(query)
|
||||
.limit(10)
|
||||
.sort('-createdAt')
|
||||
.exec();
|
||||
|
||||
let syncedChallenges = await syncChallengeToMembers(challengesFound)
|
||||
.catch(reason => console.error(reason));
|
||||
let lastChallenge = challengesFound[challengesFound.length - 1];
|
||||
if (lastChallenge) syncChallenges(lastChallenge.createdAt);
|
||||
return syncedChallenges;
|
||||
};
|
||||
|
||||
module.exports = syncChallenges;
|
||||
@@ -5,11 +5,12 @@ var authorUuid = ''; //... own data is done
|
||||
/*
|
||||
* This migrations will add a free subscription to a specified group
|
||||
*/
|
||||
import moment from 'moment';
|
||||
|
||||
import { model as Group } from '../../website/server/models/group';
|
||||
|
||||
// @TODO: this should probably be a GroupManager library method
|
||||
async function addUnlimitedSubscription (groupId) {
|
||||
async function addUnlimitedSubscription (groupId, dateTerminated) {
|
||||
let group = await Group.findById(groupId);
|
||||
|
||||
group.purchased.plan.customerId = "group-unlimited";
|
||||
@@ -18,6 +19,10 @@ async function addUnlimitedSubscription (groupId) {
|
||||
group.purchased.plan.paymentMethod = "Group Unlimited";
|
||||
group.purchased.plan.planId = "group_monthly";
|
||||
group.purchased.plan.dateTerminated = null;
|
||||
if (dateTerminated) {
|
||||
let dateToEnd = moment(dateTerminated).toDate();
|
||||
group.purchased.plan.dateTerminated = dateToEnd;
|
||||
}
|
||||
// group.purchased.plan.owner = ObjectId();
|
||||
group.purchased.plan.subscriptionId = "";
|
||||
|
||||
@@ -29,5 +34,7 @@ module.exports = async function addUnlimitedSubscriptionCreator () {
|
||||
|
||||
if (!groupId) throw Error('Group ID is required');
|
||||
|
||||
let result = await addUnlimitedSubscription(groupId)
|
||||
let dateTerminated = process.argv[3];
|
||||
|
||||
let result = await addUnlimitedSubscription(groupId, dateTerminated);
|
||||
};
|
||||
|
||||
@@ -21,4 +21,4 @@ var processUsers = require('./groups/update-groups-with-group-plans');
|
||||
processUsers()
|
||||
.catch(function (err) {
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
@@ -2,7 +2,7 @@ var _id = '';
|
||||
var update = {
|
||||
$addToSet: {
|
||||
'purchased.plan.mysteryItems':{
|
||||
$each:['head_mystery_201702','back_mystery_201702']
|
||||
$each:['head_mystery_201703','armor_mystery_201703']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var migrationName = '20170201_takeThis.js'; // Update per month
|
||||
var migrationName = '20170404_takeThis.js'; // Update per month
|
||||
var authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
var authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
||||
|
||||
@@ -14,7 +14,7 @@ function processUsers(lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
var query = {
|
||||
'migration':{$ne:migrationName},
|
||||
'challenges':{$in:['b1d436b5-c784-42e3-9b07-7072479a6f8e']} // Update per month
|
||||
'challenges':{$in:['630018a7-49ab-4e95-ac26-12417b746e1c']} // Update per month
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
|
||||
1979
npm-shrinkwrap.json
generated
15
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "3.80.1",
|
||||
"version": "3.84.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@slack/client": "^3.8.1",
|
||||
@@ -41,6 +41,7 @@
|
||||
"domain-middleware": "~0.1.0",
|
||||
"estraverse": "^4.1.1",
|
||||
"express": "~4.14.0",
|
||||
"express-basic-auth": "^1.0.1",
|
||||
"express-csv": "~0.6.0",
|
||||
"express-validator": "^2.18.0",
|
||||
"extract-text-webpack-plugin": "^2.0.0-rc.3",
|
||||
@@ -55,7 +56,7 @@
|
||||
"grunt-contrib-stylus": "~0.20.0",
|
||||
"grunt-contrib-uglify": "~0.6.0",
|
||||
"grunt-contrib-watch": "~0.6.1",
|
||||
"grunt-hashres": "~0.4.1",
|
||||
"grunt-hashres": "habitrpg/grunt-hashres#v0.4.2",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-babel": "^6.1.2",
|
||||
"gulp-grunt": "^0.5.2",
|
||||
@@ -138,9 +139,9 @@
|
||||
"test:api-v3:unit": "gulp test:api-v3:unit",
|
||||
"test:api-v3:integration": "gulp test:api-v3:integration",
|
||||
"test:api-v3:integration:separate-server": "NODE_ENV=test gulp test:api-v3:integration:separate-server",
|
||||
"test:sanity": "mocha test/sanity --recursive",
|
||||
"test:common": "mocha test/common --recursive",
|
||||
"test:content": "mocha test/content --recursive",
|
||||
"test:sanity": "istanbul cover --dir coverage/sanity --report lcovonly node_modules/mocha/bin/_mocha -- test/sanity --recursive",
|
||||
"test:common": "istanbul cover --dir coverage/common --report lcovonly node_modules/mocha/bin/_mocha -- test/common --recursive",
|
||||
"test:content": "istanbul cover --dir coverage/content --report lcovonly node_modules/mocha/bin/_mocha -- test/content --recursive",
|
||||
"test:karma": "karma start test/client-old/spec/karma.conf.js --single-run",
|
||||
"test:karma:watch": "karma start test/client-old/spec/karma.conf.js",
|
||||
"test:prepare:webdriver": "webdriver-manager update",
|
||||
@@ -182,7 +183,7 @@
|
||||
"grunt-karma": "~0.12.1",
|
||||
"http-proxy-middleware": "^0.17.0",
|
||||
"inject-loader": "^3.0.0-beta4",
|
||||
"istanbul": "^0.3.14",
|
||||
"istanbul": "^1.1.0-alpha.1",
|
||||
"karma": "^1.3.0",
|
||||
"karma-babel-preprocessor": "^6.0.1",
|
||||
"karma-chai-plugins": "~0.6.0",
|
||||
@@ -197,7 +198,7 @@
|
||||
"karma-webpack": "^2.0.2",
|
||||
"lcov-result-merger": "^1.0.2",
|
||||
"lolex": "^1.4.0",
|
||||
"mocha": "^2.3.3",
|
||||
"mocha": "^3.2.0",
|
||||
"mongodb": "^2.0.46",
|
||||
"mongoskin": "~2.1.0",
|
||||
"monk": "^4.0.0",
|
||||
|
||||
@@ -63,15 +63,17 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
});
|
||||
|
||||
it('returns only first 30 invites', async () => {
|
||||
let group = await generateGroup(user, {type: 'party', name: generateUUID()});
|
||||
let leader = await generateUser({balance: 4});
|
||||
let group = await generateGroup(leader, {type: 'guild', privacy: 'public', name: generateUUID()});
|
||||
|
||||
let invitesToGenerate = [];
|
||||
for (let i = 0; i < 31; i++) {
|
||||
invitesToGenerate.push(generateUser());
|
||||
}
|
||||
let generatedInvites = await Promise.all(invitesToGenerate);
|
||||
await user.post(`/groups/${group._id}/invite`, {uuids: generatedInvites.map(invite => invite._id)});
|
||||
await leader.post(`/groups/${group._id}/invite`, {uuids: generatedInvites.map(invite => invite._id)});
|
||||
|
||||
let res = await user.get('/groups/party/invites');
|
||||
let res = await leader.get(`/groups/${group._id}/invites`);
|
||||
expect(res.length).to.equal(30);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
const INVITES_LIMIT = 100;
|
||||
const PARTY_LIMIT_MEMBERS = 30;
|
||||
|
||||
describe('Post /groups/:groupId/invite', () => {
|
||||
let inviter;
|
||||
@@ -321,6 +322,19 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('allows 30+ members in a guild', async () => {
|
||||
let invitesToGenerate = [];
|
||||
// Generate 30 users to invite (30 + leader = 31 members)
|
||||
for (let i = 0; i < PARTY_LIMIT_MEMBERS; i++) {
|
||||
invitesToGenerate.push(generateUser());
|
||||
}
|
||||
let generatedInvites = await Promise.all(invitesToGenerate);
|
||||
// Invite users
|
||||
expect(await inviter.post(`/groups/${group._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
})).to.be.an('array');
|
||||
});
|
||||
|
||||
// @TODO: Add this after we are able to mock the group plan route
|
||||
xit('returns an error when a non-leader invites to a group plan', async () => {
|
||||
let userToInvite = await generateUser();
|
||||
@@ -410,5 +424,36 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
expect((await userToInvite.get('/user')).invitations.party.id).to.equal(party._id);
|
||||
});
|
||||
|
||||
it('allows 30 members in a party', async () => {
|
||||
let invitesToGenerate = [];
|
||||
// Generate 29 users to invite (29 + leader = 30 members)
|
||||
for (let i = 0; i < PARTY_LIMIT_MEMBERS - 1; i++) {
|
||||
invitesToGenerate.push(generateUser());
|
||||
}
|
||||
let generatedInvites = await Promise.all(invitesToGenerate);
|
||||
// Invite users
|
||||
expect(await inviter.post(`/groups/${party._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
})).to.be.an('array');
|
||||
});
|
||||
|
||||
xit('does not allow 30+ members in a party', async () => {
|
||||
let invitesToGenerate = [];
|
||||
// Generate 30 users to invite (30 + leader = 31 members)
|
||||
for (let i = 0; i < PARTY_LIMIT_MEMBERS; i++) {
|
||||
invitesToGenerate.push(generateUser());
|
||||
}
|
||||
let generatedInvites = await Promise.all(invitesToGenerate);
|
||||
// Invite users
|
||||
await expect(inviter.post(`/groups/${party._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
}))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('partyExceedsMembersLimit', {maxMembersParty: PARTY_LIMIT_MEMBERS}),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
sha1Encrypt as sha1EncryptPassword,
|
||||
} from '../../../../../../website/server/libs/password';
|
||||
|
||||
import nconf from 'nconf';
|
||||
|
||||
describe('POST /user/auth/local/login', () => {
|
||||
let api;
|
||||
let user;
|
||||
@@ -43,7 +45,7 @@ describe('POST /user/auth/local/login', () => {
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('accountSuspended', { userId: user._id }),
|
||||
message: t('accountSuspended', { communityManagerEmail: nconf.get('EMAILS:COMMUNITY_MANAGER_EMAIL'), userId: user._id }),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -71,6 +71,23 @@ describe('POST /user/auth/local/register', () => {
|
||||
await expect(getProperty('users', user._id, '_ABtests')).to.eventually.be.a('object');
|
||||
});
|
||||
|
||||
it('includes items awarded by default when creating a new user', async () => {
|
||||
let username = generateRandomUserName();
|
||||
let email = `${username}@example.com`;
|
||||
let password = 'password';
|
||||
|
||||
let 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 () => {
|
||||
let username = generateRandomUserName();
|
||||
let email = `${username}@example.com`;
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
sha1Encrypt as sha1EncryptPassword,
|
||||
} from '../../../../../../website/server/libs/password';
|
||||
|
||||
import nconf from 'nconf';
|
||||
|
||||
const ENDPOINT = '/user/auth/update-email';
|
||||
|
||||
describe('PUT /user/auth/update-email', () => {
|
||||
@@ -68,7 +70,7 @@ describe('PUT /user/auth/update-email', () => {
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('cannotFulfillReq'),
|
||||
message: t('cannotFulfillReq', { techAssistanceEmail: nconf.get('EMAILS:TECH_ASSISTANCE_EMAIL') }),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ import { model as Coupon } from '../../../../../website/server/models/coupon';
|
||||
import stripePayments from '../../../../../website/server/libs/stripePayments';
|
||||
import payments from '../../../../../website/server/libs/payments';
|
||||
import common from '../../../../../website/common';
|
||||
import logger from '../../../../../website/server/libs/logger';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import moment from 'moment';
|
||||
|
||||
const i18n = common.i18n;
|
||||
|
||||
@@ -759,4 +762,245 @@ describe('Stripe Payments', () => {
|
||||
expect(updatedGroup.purchased.plan.quantity).to.eql(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleWebhooks', () => {
|
||||
describe('all events', () => {
|
||||
const eventType = 'account.updated';
|
||||
const event = {id: 123};
|
||||
const eventRetrieved = {type: eventType};
|
||||
|
||||
beforeEach(() => {
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves(eventRetrieved);
|
||||
sinon.stub(logger, 'error');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
stripe.events.retrieve.restore();
|
||||
logger.error.restore();
|
||||
});
|
||||
|
||||
it('logs an error if an unsupported webhook event is passed', async () => {
|
||||
const error = new Error(`Missing handler for Stripe webhook ${eventType}`);
|
||||
await stripePayments.handleWebhooks({requestBody: event}, stripe);
|
||||
expect(logger.error).to.have.been.called.once;
|
||||
expect(logger.error).to.have.been.calledWith(error, {event: eventRetrieved});
|
||||
});
|
||||
|
||||
it('retrieves and validates the event from Stripe', async () => {
|
||||
await stripePayments.handleWebhooks({requestBody: event}, stripe);
|
||||
expect(stripe.events.retrieve).to.have.been.called.once;
|
||||
expect(stripe.events.retrieve).to.have.been.calledWith(event.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('customer.subscription.deleted', () => {
|
||||
const eventType = 'customer.subscription.deleted';
|
||||
|
||||
beforeEach(() => {
|
||||
sinon.stub(stripe.customers, 'del').returnsPromise().resolves({});
|
||||
sinon.stub(payments, 'cancelSubscription').returnsPromise().resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
stripe.customers.del.restore();
|
||||
payments.cancelSubscription.restore();
|
||||
});
|
||||
|
||||
it('does not do anything if event.request is null (subscription cancelled manually)', async () => {
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
request: 123,
|
||||
});
|
||||
|
||||
await stripePayments.handleWebhooks({requestBody: {}}, stripe);
|
||||
|
||||
expect(stripe.events.retrieve).to.have.been.called.once;
|
||||
expect(stripe.customers.del).to.not.have.been.called;
|
||||
expect(payments.cancelSubscription).to.not.have.been.called;
|
||||
stripe.events.retrieve.restore();
|
||||
});
|
||||
|
||||
describe('user subscription', () => {
|
||||
it('throws an error if the user is not found', async () => {
|
||||
const customerId = 456;
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
object: {
|
||||
plan: {
|
||||
id: 'basic_earned',
|
||||
},
|
||||
customer: customerId,
|
||||
},
|
||||
},
|
||||
request: null,
|
||||
});
|
||||
|
||||
await expect(stripePayments.handleWebhooks({requestBody: {}}, stripe)).to.eventually.be.rejectedWith({
|
||||
message: i18n.t('userNotFound'),
|
||||
httpCode: 404,
|
||||
name: 'NotFound',
|
||||
});
|
||||
|
||||
expect(stripe.customers.del).to.not.have.been.called;
|
||||
expect(payments.cancelSubscription).to.not.have.been.called;
|
||||
|
||||
stripe.events.retrieve.restore();
|
||||
});
|
||||
|
||||
it('deletes the customer on Stripe and calls payments.cancelSubscription', async () => {
|
||||
const customerId = '456';
|
||||
|
||||
let subscriber = new User();
|
||||
subscriber.purchased.plan.customerId = customerId;
|
||||
subscriber.purchased.plan.paymentMethod = 'Stripe';
|
||||
await subscriber.save();
|
||||
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
object: {
|
||||
plan: {
|
||||
id: 'basic_earned',
|
||||
},
|
||||
customer: customerId,
|
||||
},
|
||||
},
|
||||
request: null,
|
||||
});
|
||||
|
||||
await stripePayments.handleWebhooks({requestBody: {}}, stripe);
|
||||
|
||||
expect(stripe.customers.del).to.have.been.calledOnce;
|
||||
expect(stripe.customers.del).to.have.been.calledWith(customerId);
|
||||
expect(payments.cancelSubscription).to.have.been.calledOnce;
|
||||
|
||||
let cancelSubscriptionOpts = payments.cancelSubscription.lastCall.args[0];
|
||||
expect(cancelSubscriptionOpts.user._id).to.equal(subscriber._id);
|
||||
expect(cancelSubscriptionOpts.paymentMethod).to.equal('Stripe');
|
||||
expect(Math.round(moment(cancelSubscriptionOpts.nextBill).diff(new Date(), 'days', true))).to.equal(3);
|
||||
expect(cancelSubscriptionOpts.groupId).to.be.undefined;
|
||||
|
||||
stripe.events.retrieve.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('group plan subscription', () => {
|
||||
it('throws an error if the group is not found', async () => {
|
||||
const customerId = 456;
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
object: {
|
||||
plan: {
|
||||
id: 'group_monthly',
|
||||
},
|
||||
customer: customerId,
|
||||
},
|
||||
},
|
||||
request: null,
|
||||
});
|
||||
|
||||
await expect(stripePayments.handleWebhooks({requestBody: {}}, stripe)).to.eventually.be.rejectedWith({
|
||||
message: i18n.t('groupNotFound'),
|
||||
httpCode: 404,
|
||||
name: 'NotFound',
|
||||
});
|
||||
|
||||
expect(stripe.customers.del).to.not.have.been.called;
|
||||
expect(payments.cancelSubscription).to.not.have.been.called;
|
||||
|
||||
stripe.events.retrieve.restore();
|
||||
});
|
||||
|
||||
it('throws an error if the group leader is not found', async () => {
|
||||
const customerId = 456;
|
||||
|
||||
let subscriber = generateGroup({
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: uuid(),
|
||||
});
|
||||
subscriber.purchased.plan.customerId = customerId;
|
||||
subscriber.purchased.plan.paymentMethod = 'Stripe';
|
||||
await subscriber.save();
|
||||
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
object: {
|
||||
plan: {
|
||||
id: 'group_monthly',
|
||||
},
|
||||
customer: customerId,
|
||||
},
|
||||
},
|
||||
request: null,
|
||||
});
|
||||
|
||||
await expect(stripePayments.handleWebhooks({requestBody: {}}, stripe)).to.eventually.be.rejectedWith({
|
||||
message: i18n.t('userNotFound'),
|
||||
httpCode: 404,
|
||||
name: 'NotFound',
|
||||
});
|
||||
|
||||
expect(stripe.customers.del).to.not.have.been.called;
|
||||
expect(payments.cancelSubscription).to.not.have.been.called;
|
||||
|
||||
stripe.events.retrieve.restore();
|
||||
});
|
||||
|
||||
it('deletes the customer on Stripe and calls payments.cancelSubscription', async () => {
|
||||
const customerId = '456';
|
||||
|
||||
let leader = new User();
|
||||
await leader.save();
|
||||
|
||||
let subscriber = generateGroup({
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
leader: leader._id,
|
||||
});
|
||||
subscriber.purchased.plan.customerId = customerId;
|
||||
subscriber.purchased.plan.paymentMethod = 'Stripe';
|
||||
await subscriber.save();
|
||||
|
||||
sinon.stub(stripe.events, 'retrieve').returnsPromise().resolves({
|
||||
id: 123,
|
||||
type: eventType,
|
||||
data: {
|
||||
object: {
|
||||
plan: {
|
||||
id: 'group_monthly',
|
||||
},
|
||||
customer: customerId,
|
||||
},
|
||||
},
|
||||
request: null,
|
||||
});
|
||||
|
||||
await stripePayments.handleWebhooks({requestBody: {}}, stripe);
|
||||
|
||||
expect(stripe.customers.del).to.have.been.calledOnce;
|
||||
expect(stripe.customers.del).to.have.been.calledWith(customerId);
|
||||
expect(payments.cancelSubscription).to.have.been.calledOnce;
|
||||
|
||||
let cancelSubscriptionOpts = payments.cancelSubscription.lastCall.args[0];
|
||||
expect(cancelSubscriptionOpts.user._id).to.equal(leader._id);
|
||||
expect(cancelSubscriptionOpts.paymentMethod).to.equal('Stripe');
|
||||
expect(Math.round(moment(cancelSubscriptionOpts.nextBill).diff(new Date(), 'days', true))).to.equal(3);
|
||||
expect(cancelSubscriptionOpts.groupId).to.equal(subscriber._id);
|
||||
|
||||
stripe.events.retrieve.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
182
test/api/v3/unit/middlewares/redirects.js
Normal file
@@ -0,0 +1,182 @@
|
||||
import {
|
||||
generateRes,
|
||||
generateReq,
|
||||
generateNext,
|
||||
} from '../../../../helpers/api-unit.helper';
|
||||
import nconf from 'nconf';
|
||||
import requireAgain from 'require-again';
|
||||
|
||||
describe('redirects middleware', () => {
|
||||
let res, req, next;
|
||||
let pathToRedirectsMiddleware = '../../../../../website/server/middlewares/redirects';
|
||||
|
||||
beforeEach(() => {
|
||||
res = generateRes();
|
||||
req = generateReq();
|
||||
next = generateNext();
|
||||
});
|
||||
|
||||
context('forceSSL', () => {
|
||||
it('sends http requests to https', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('http');
|
||||
req.originalUrl = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceSSL(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.calledOnce;
|
||||
expect(res.redirect).to.be.calledWith('https://habitica.com/static/front');
|
||||
});
|
||||
|
||||
it('does not redirect https forwarded requests', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('https');
|
||||
req.originalUrl = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceSSL(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
|
||||
it('does not redirect outside of production environments', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IS_PROD').returns(false);
|
||||
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('http');
|
||||
req.originalUrl = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceSSL(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
|
||||
it('does not redirect if base URL is not https', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('http://habitica.com');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.header = sandbox.stub().withArgs('x-forwarded-proto').returns('http');
|
||||
req.originalUrl = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceSSL(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
});
|
||||
|
||||
context('forceHabitica', () => {
|
||||
it('sends requests with differing hostname to base URL host', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.hostname = 'www.habitica.com';
|
||||
req.method = 'GET';
|
||||
req.originalUrl = '/static/front';
|
||||
req.url = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceHabitica(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.calledOnce;
|
||||
expect(res.redirect).to.be.calledWith(301, 'https://habitica.com/static/front');
|
||||
});
|
||||
|
||||
it('does not redirect outside of production environments', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||
nconfStub.withArgs('IS_PROD').returns(false);
|
||||
req.hostname = 'www.habitica.com';
|
||||
req.method = 'GET';
|
||||
req.originalUrl = '/static/front';
|
||||
req.url = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceHabitica(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
|
||||
it('does not redirect if env is set to ignore redirection', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IGNORE_REDIRECT').returns('true');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.hostname = 'www.habitica.com';
|
||||
req.method = 'GET';
|
||||
req.originalUrl = '/static/front';
|
||||
req.url = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceHabitica(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
|
||||
it('does not redirect if request hostname matches base URL host', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.hostname = 'habitica.com';
|
||||
req.method = 'GET';
|
||||
req.originalUrl = '/static/front';
|
||||
req.url = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceHabitica(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
|
||||
it('does not redirect if request is an API URL', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.hostname = 'www.habitica.com';
|
||||
req.method = 'GET';
|
||||
req.originalUrl = '/api/v3/challenges';
|
||||
req.url = '/api/v3/challenges';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceHabitica(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
|
||||
it('does not redirect if request method is not GET', () => {
|
||||
let nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('BASE_URL').returns('https://habitica.com');
|
||||
nconfStub.withArgs('IGNORE_REDIRECT').returns('false');
|
||||
nconfStub.withArgs('IS_PROD').returns(true);
|
||||
req.hostname = 'www.habitica.com';
|
||||
req.method = 'POST';
|
||||
req.originalUrl = '/static/front';
|
||||
req.url = '/static/front';
|
||||
|
||||
let attachRedirects = requireAgain(pathToRedirectsMiddleware);
|
||||
|
||||
attachRedirects.forceHabitica(req, res, next);
|
||||
|
||||
expect(res.redirect).to.be.notCalled;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -104,6 +104,40 @@ describe('Challenge Model', () => {
|
||||
expect(updatedNewMember.tags[7].id).to.equal(challenge._id);
|
||||
expect(updatedNewMember.tags[7].name).to.equal(challenge.shortName);
|
||||
expect(syncedTask).to.exist;
|
||||
expect(syncedTask.attribute).to.eql('str');
|
||||
});
|
||||
|
||||
it('syncs a challenge to a user with the existing task', async () => {
|
||||
await challenge.addTasks([task]);
|
||||
|
||||
let updatedLeader = await User.findOne({_id: leader._id});
|
||||
let updatedLeadersTasks = await Tasks.Task.find({_id: { $in: updatedLeader.tasksOrder[`${taskType}s`]}});
|
||||
let syncedTask = find(updatedLeadersTasks, function findNewTask (updatedLeadersTask) {
|
||||
return updatedLeadersTask.challenge.taskId === task._id;
|
||||
});
|
||||
|
||||
let createdAtBefore = syncedTask.createdAt;
|
||||
let attributeBefore = syncedTask.attribute;
|
||||
|
||||
let newTitle = 'newName';
|
||||
task.text = newTitle;
|
||||
task.attribute = 'int';
|
||||
await task.save();
|
||||
await challenge.syncToUser(leader);
|
||||
|
||||
updatedLeader = await User.findOne({_id: leader._id});
|
||||
updatedLeadersTasks = await Tasks.Task.find({_id: { $in: updatedLeader.tasksOrder[`${taskType}s`]}});
|
||||
|
||||
syncedTask = find(updatedLeadersTasks, function findNewTask (updatedLeadersTask) {
|
||||
return updatedLeadersTask.challenge.taskId === task._id;
|
||||
});
|
||||
|
||||
let createdAtAfter = syncedTask.createdAt;
|
||||
let attributeAfter = syncedTask.attribute;
|
||||
|
||||
expect(createdAtBefore).to.eql(createdAtAfter);
|
||||
expect(attributeBefore).to.eql(attributeAfter);
|
||||
expect(syncedTask.text).to.eql(newTitle);
|
||||
});
|
||||
|
||||
it('updates tasks to challenge and challenge members', async () => {
|
||||
|
||||
@@ -4,9 +4,6 @@ import validator from 'validator';
|
||||
import { sleep } from '../../../../helpers/api-unit.helper';
|
||||
import { model as Group, INVITES_LIMIT } from '../../../../../website/server/models/group';
|
||||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import {
|
||||
BadRequest,
|
||||
} from '../../../../../website/server/libs/errors';
|
||||
import { quests as questScrolls } from '../../../../../website/common/script/content';
|
||||
import { groupChatReceivedWebhook } from '../../../../../website/server/libs/webhook';
|
||||
import * as email from '../../../../../website/server/libs/email';
|
||||
@@ -460,73 +457,67 @@ describe('Group Model', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('throws an error if no uuids or emails are passed in', (done) => {
|
||||
try {
|
||||
Group.validateInvitations(null, null, res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('canOnlyInviteEmailUuid');
|
||||
done();
|
||||
}
|
||||
it('throws an error if no uuids or emails are passed in', async () => {
|
||||
await expect(Group.validateInvitations(null, null, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('canOnlyInviteEmailUuid');
|
||||
});
|
||||
|
||||
it('throws an error if only uuids are passed in, but they are not an array', (done) => {
|
||||
try {
|
||||
Group.validateInvitations({ uuid: 'user-id'}, null, res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('uuidsMustBeAnArray');
|
||||
done();
|
||||
}
|
||||
it('throws an error if only uuids are passed in, but they are not an array', async () => {
|
||||
await expect(Group.validateInvitations({ uuid: 'user-id'}, null, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('uuidsMustBeAnArray');
|
||||
});
|
||||
|
||||
it('throws an error if only emails are passed in, but they are not an array', (done) => {
|
||||
try {
|
||||
Group.validateInvitations(null, { emails: 'user@example.com'}, res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('emailsMustBeAnArray');
|
||||
done();
|
||||
}
|
||||
it('throws an error if only emails are passed in, but they are not an array', async () => {
|
||||
await expect(Group.validateInvitations(null, { emails: 'user@example.com'}, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('emailsMustBeAnArray');
|
||||
});
|
||||
|
||||
it('throws an error if emails are not passed in, and uuid array is empty', (done) => {
|
||||
try {
|
||||
Group.validateInvitations([], null, res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMissingUuid');
|
||||
done();
|
||||
}
|
||||
it('throws an error if emails are not passed in, and uuid array is empty', async () => {
|
||||
await expect(Group.validateInvitations([], null, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMissingUuid');
|
||||
});
|
||||
|
||||
it('throws an error if uuids are not passed in, and email array is empty', (done) => {
|
||||
try {
|
||||
Group.validateInvitations(null, [], res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMissingEmail');
|
||||
done();
|
||||
}
|
||||
it('throws an error if uuids are not passed in, and email array is empty', async () => {
|
||||
await expect(Group.validateInvitations(null, [], res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMissingEmail');
|
||||
});
|
||||
|
||||
it('throws an error if uuids and emails are passed in as empty arrays', (done) => {
|
||||
try {
|
||||
Group.validateInvitations([], [], res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMustNotBeEmpty');
|
||||
done();
|
||||
}
|
||||
it('throws an error if uuids and emails are passed in as empty arrays', async () => {
|
||||
await expect(Group.validateInvitations([], [], res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('inviteMustNotBeEmpty');
|
||||
});
|
||||
|
||||
it('throws an error if total invites exceed max invite constant', (done) => {
|
||||
it('throws an error if total invites exceed max invite constant', async () => {
|
||||
let uuids = [];
|
||||
let emails = [];
|
||||
|
||||
@@ -537,17 +528,16 @@ describe('Group Model', () => {
|
||||
|
||||
uuids.push('one-more-uuid'); // to put it over the limit
|
||||
|
||||
try {
|
||||
Group.validateInvitations(uuids, emails, res);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('canOnlyInviteMaxInvites', {maxInvites: INVITES_LIMIT });
|
||||
done();
|
||||
}
|
||||
await expect(Group.validateInvitations(uuids, emails, res)).to.eventually.be.rejected.and.eql({
|
||||
httpCode: 400,
|
||||
message: 'Bad request.',
|
||||
name: 'BadRequest',
|
||||
});
|
||||
expect(res.t).to.be.calledOnce;
|
||||
expect(res.t).to.be.calledWith('canOnlyInviteMaxInvites', {maxInvites: INVITES_LIMIT });
|
||||
});
|
||||
|
||||
it('does not throw error if number of invites matches max invite limit', () => {
|
||||
it('does not throw error if number of invites matches max invite limit', async () => {
|
||||
let uuids = [];
|
||||
let emails = [];
|
||||
|
||||
@@ -556,49 +546,33 @@ describe('Group Model', () => {
|
||||
emails.push(`user-${i}@example.com`);
|
||||
}
|
||||
|
||||
expect(function () {
|
||||
Group.validateInvitations(uuids, emails, res);
|
||||
}).to.not.throw();
|
||||
});
|
||||
|
||||
|
||||
it('does not throw an error if only user ids are passed in', () => {
|
||||
expect(function () {
|
||||
Group.validateInvitations(['user-id', 'user-id2'], null, res);
|
||||
}).to.not.throw();
|
||||
|
||||
await Group.validateInvitations(uuids, emails, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if only emails are passed in', () => {
|
||||
expect(function () {
|
||||
Group.validateInvitations(null, ['user1@example.com', 'user2@example.com'], res);
|
||||
}).to.not.throw();
|
||||
|
||||
it('does not throw an error if only user ids are passed in', async () => {
|
||||
await Group.validateInvitations(['user-id', 'user-id2'], null, res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if both uuids and emails are passed in', () => {
|
||||
expect(function () {
|
||||
Group.validateInvitations(['user-id', 'user-id2'], ['user1@example.com', 'user2@example.com'], res);
|
||||
}).to.not.throw();
|
||||
|
||||
it('does not throw an error if only emails are passed in', async () => {
|
||||
await Group.validateInvitations(null, ['user1@example.com', 'user2@example.com'], res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if uuids are passed in and emails are an empty array', () => {
|
||||
expect(function () {
|
||||
Group.validateInvitations(['user-id', 'user-id2'], [], res);
|
||||
}).to.not.throw();
|
||||
|
||||
it('does not throw an error if both uuids and emails are passed in', async () => {
|
||||
await Group.validateInvitations(['user-id', 'user-id2'], ['user1@example.com', 'user2@example.com'], res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if emails are passed in and uuids are an empty array', () => {
|
||||
expect(function () {
|
||||
Group.validateInvitations([], ['user1@example.com', 'user2@example.com'], res);
|
||||
}).to.not.throw();
|
||||
it('does not throw an error if uuids are passed in and emails are an empty array', async () => {
|
||||
await Group.validateInvitations(['user-id', 'user-id2'], [], res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
|
||||
it('does not throw an error if emails are passed in and uuids are an empty array', async () => {
|
||||
await Group.validateInvitations([], ['user1@example.com', 'user2@example.com'], res);
|
||||
expect(res.t).to.not.be.called;
|
||||
});
|
||||
});
|
||||
|
||||
35
test/client-old/spec/directives/task.directive.js
Normal file
@@ -0,0 +1,35 @@
|
||||
describe('task Directive', () => {
|
||||
var compile, scope, directiveElem, $modal;
|
||||
|
||||
beforeEach(function(){
|
||||
module(function($provide) {
|
||||
$modal = {
|
||||
open: sandbox.spy(),
|
||||
};
|
||||
$provide.value('$modal', $modal);
|
||||
});
|
||||
|
||||
inject(function($compile, $rootScope, $templateCache) {
|
||||
compile = $compile;
|
||||
scope = $rootScope.$new();
|
||||
|
||||
$templateCache.put('templates/task.html', '<div>Task</div>');
|
||||
});
|
||||
|
||||
|
||||
directiveElem = getCompiledElement();
|
||||
});
|
||||
|
||||
function getCompiledElement(){
|
||||
var element = angular.element('<task></task>');
|
||||
var compiledElement = compile(element)(scope);
|
||||
scope.$digest();
|
||||
return compiledElement;
|
||||
}
|
||||
|
||||
xit('opens task note modal', () => {
|
||||
scope.showNoteDetails();
|
||||
|
||||
expect($modal.open).to.be.calledOnce;
|
||||
});
|
||||
})
|
||||
@@ -81,8 +81,11 @@ module.exports = function karmaConfig (config) {
|
||||
},
|
||||
|
||||
coverageReporter: {
|
||||
type: 'lcov',
|
||||
dir: 'coverage/karma',
|
||||
reporters: [
|
||||
{ type: 'lcov', subdir: '.' },
|
||||
{ type: 'text-summary' },
|
||||
],
|
||||
dir: '../../../coverage/karma',
|
||||
},
|
||||
|
||||
// Enable mocha-style reporting, for better test visibility
|
||||
|
||||
@@ -28,7 +28,7 @@ module.exports = function (config) {
|
||||
noInfo: true,
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: './coverage',
|
||||
dir: '../../../coverage/client-unit',
|
||||
reporters: [
|
||||
{ type: 'lcov', subdir: '.' },
|
||||
{ type: 'text-summary' },
|
||||
|
||||
151
test/client/unit/specs/libs/asyncResource.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import { asyncResourceFactory, loadAsyncResource } from 'client/libs/asyncResource';
|
||||
import axios from 'axios';
|
||||
import generateStore from 'client/store';
|
||||
import { sleep } from '../../../../helpers/sleep';
|
||||
|
||||
describe('async resource', () => {
|
||||
it('asyncResourceFactory', () => {
|
||||
const resource = asyncResourceFactory();
|
||||
expect(resource.loadingStatus).to.equal('NOT_LOADED');
|
||||
expect(resource.data).to.equal(null);
|
||||
expect(resource).to.not.equal(asyncResourceFactory);
|
||||
});
|
||||
|
||||
describe('loadAsyncResource', () => {
|
||||
context('errors', () => {
|
||||
it('store is missing', () => {
|
||||
expect(() => loadAsyncResource({})).to.throw;
|
||||
});
|
||||
it('path is missing', () => {
|
||||
expect(() => loadAsyncResource({
|
||||
store: 'store',
|
||||
})).to.throw;
|
||||
});
|
||||
it('url is missing', () => {
|
||||
expect(() => loadAsyncResource({
|
||||
store: 'store',
|
||||
path: 'path',
|
||||
})).to.throw;
|
||||
});
|
||||
it('deserialize is missing', () => {
|
||||
expect(() => loadAsyncResource({
|
||||
store: 'store',
|
||||
path: 'path',
|
||||
url: 'url',
|
||||
})).to.throw;
|
||||
});
|
||||
it('resource not found', () => {
|
||||
const store = generateStore();
|
||||
|
||||
expect(() => loadAsyncResource({
|
||||
store,
|
||||
path: 'not existing path',
|
||||
url: 'url',
|
||||
deserialize: 'deserialize',
|
||||
})).to.throw;
|
||||
});
|
||||
|
||||
it('invalid loading status', () => {
|
||||
const store = generateStore();
|
||||
store.state.user.loadingStatus = 'INVALID';
|
||||
|
||||
expect(loadAsyncResource({
|
||||
store,
|
||||
path: 'user',
|
||||
url: 'url',
|
||||
deserialize: 'deserialize',
|
||||
})).to.eventually.be.rejected;
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the resource if it is already loaded and forceLoad is false', async () => {
|
||||
const store = generateStore();
|
||||
store.state.user.loadingStatus = 'LOADED';
|
||||
store.state.user.data = {_id: 1};
|
||||
|
||||
sandbox.stub(axios, 'get');
|
||||
|
||||
const resource = await loadAsyncResource({
|
||||
store,
|
||||
path: 'user',
|
||||
url: 'url',
|
||||
deserialize: 'deserialize',
|
||||
});
|
||||
|
||||
expect(resource).to.equal(store.state.user);
|
||||
expect(axios.get).to.not.have.been.called;
|
||||
});
|
||||
|
||||
it('load the resource if it is not loaded', async () => {
|
||||
const store = generateStore();
|
||||
store.state.user = asyncResourceFactory();
|
||||
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: {_id: 1}}}));
|
||||
|
||||
const resource = await loadAsyncResource({
|
||||
store,
|
||||
path: 'user',
|
||||
url: '/api/v3/user',
|
||||
deserialize (response) {
|
||||
return response.data.data;
|
||||
},
|
||||
});
|
||||
|
||||
expect(resource).to.equal(store.state.user);
|
||||
expect(resource.loadingStatus).to.equal('LOADED');
|
||||
expect(resource.data._id).to.equal(1);
|
||||
expect(axios.get).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('load the resource if it is loaded but forceLoad is true', async () => {
|
||||
const store = generateStore();
|
||||
store.state.user.loadingStatus = 'LOADED';
|
||||
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: {_id: 1}}}));
|
||||
|
||||
const resource = await loadAsyncResource({
|
||||
store,
|
||||
path: 'user',
|
||||
url: '/api/v3/user',
|
||||
deserialize (response) {
|
||||
return response.data.data;
|
||||
},
|
||||
forceLoad: true,
|
||||
});
|
||||
|
||||
expect(resource).to.equal(store.state.user);
|
||||
expect(resource.loadingStatus).to.equal('LOADED');
|
||||
expect(resource.data._id).to.equal(1);
|
||||
expect(axios.get).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('does not send multiple requests if the resource is being loaded', async () => {
|
||||
const store = generateStore();
|
||||
store.state.user.loadingStatus = 'LOADING';
|
||||
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: {_id: 1}}}));
|
||||
|
||||
const resourcePromise = loadAsyncResource({
|
||||
store,
|
||||
path: 'user',
|
||||
url: '/api/v3/user',
|
||||
deserialize (response) {
|
||||
return response.data.data;
|
||||
},
|
||||
forceLoad: true,
|
||||
});
|
||||
|
||||
await sleep(0.1);
|
||||
const userData = {_id: 1};
|
||||
|
||||
expect(store.state.user.loadingStatus).to.equal('LOADING');
|
||||
expect(axios.get).to.not.have.been.called;
|
||||
store.state.user.data = userData;
|
||||
store.state.user.loadingStatus = 'LOADED';
|
||||
|
||||
const result = await resourcePromise;
|
||||
expect(axios.get).to.not.have.been.called;
|
||||
expect(result).to.equal(store.state.user);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import deepFreeze from 'client/libs/deepFreeze';
|
||||
|
||||
describe('deepFreeze', () => {
|
||||
it('works as expected', () => {
|
||||
it('deeply freezes an object', () => {
|
||||
let obj = {
|
||||
a: 1,
|
||||
b () {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import i18n from 'client/plugins/i18n';
|
||||
import i18n from 'client/libs/i18n';
|
||||
import commoni18n from 'common/script/i18n';
|
||||
import Vue from 'vue';
|
||||
|
||||
describe('i18n plugin', () => {
|
||||
before(() => {
|
||||
i18n.install(Vue);
|
||||
Vue.use(i18n);
|
||||
});
|
||||
|
||||
it('adds $t to Vue.prototype', () => {
|
||||
178
test/client/unit/specs/libs/store.js
Normal file
@@ -0,0 +1,178 @@
|
||||
import Vue from 'vue';
|
||||
import StoreModule, { mapState, mapGetters, mapActions } from 'client/libs/store';
|
||||
import { flattenAndNamespace } from 'client/libs/store/helpers/internals';
|
||||
|
||||
describe('Store', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = new StoreModule({ // eslint-disable-line babel/new-cap
|
||||
state: {
|
||||
name: 'test',
|
||||
nested: {
|
||||
name: 'nested state test',
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
computedName ({ state }) {
|
||||
return `${state.name} computed!`;
|
||||
},
|
||||
...flattenAndNamespace({
|
||||
nested: {
|
||||
computedName ({ state }) {
|
||||
return `${state.name} computed!`;
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
actions: {
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
...flattenAndNamespace({
|
||||
nested: {
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
Vue.use(StoreModule);
|
||||
});
|
||||
|
||||
it('injects itself in all component', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
store,
|
||||
created () {
|
||||
expect(this.$store).to.equal(store);
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('can watch a function on the state', (done) => {
|
||||
store.watch(state => state.name, (newName) => {
|
||||
expect(newName).to.equal('test updated');
|
||||
done();
|
||||
});
|
||||
|
||||
store.state.name = 'test updated';
|
||||
});
|
||||
|
||||
describe('getters', () => {
|
||||
it('supports getters', () => {
|
||||
expect(store.getters.computedName).to.equal('test computed!');
|
||||
store.state.name = 'test updated';
|
||||
expect(store.getters.computedName).to.equal('test updated computed!');
|
||||
});
|
||||
|
||||
it('supports nested getters', () => {
|
||||
expect(store.getters['nested:computedName']).to.equal('test computed!');
|
||||
store.state.name = 'test updated';
|
||||
expect(store.getters['nested:computedName']).to.equal('test updated computed!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
it('can dispatch an action', () => {
|
||||
expect(store.dispatch('getName', 1, 2, 3)).to.deep.equal(['test', 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('can dispatch a nested action', () => {
|
||||
expect(store.dispatch('nested:getName', 1, 2, 3)).to.deep.equal(['test', 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('throws an error is the action doesn\'t exists', () => {
|
||||
expect(() => store.dispatched('wrong')).to.throw;
|
||||
});
|
||||
});
|
||||
|
||||
describe('helpers', () => {
|
||||
it('mapState', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
store,
|
||||
data: {
|
||||
title: 'internal',
|
||||
},
|
||||
computed: {
|
||||
...mapState(['name']),
|
||||
...mapState({
|
||||
nameComputed (state, getters) {
|
||||
return `${this.title} ${getters.computedName} ${state.name}`;
|
||||
},
|
||||
}),
|
||||
...mapState({nestedTest: 'nested.name'}),
|
||||
},
|
||||
created () {
|
||||
expect(this.name).to.equal('test');
|
||||
expect(this.nameComputed).to.equal('internal test computed! test');
|
||||
expect(this.nestedTest).to.equal('nested state test');
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('mapGetters', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
store,
|
||||
data: {
|
||||
title: 'internal',
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['computedName']),
|
||||
...mapGetters({
|
||||
nameComputedTwice: 'computedName',
|
||||
}),
|
||||
},
|
||||
created () {
|
||||
expect(this.computedName).to.equal('test computed!');
|
||||
expect(this.nameComputedTwice).to.equal('test computed!');
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('mapActions', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
store,
|
||||
data: {
|
||||
title: 'internal',
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['getName']),
|
||||
...mapActions({
|
||||
getNameRenamed: 'getName',
|
||||
}),
|
||||
},
|
||||
created () {
|
||||
expect(this.getName('123')).to.deep.equal(['test', '123']);
|
||||
expect(this.getNameRenamed('123')).to.deep.equal(['test', '123']);
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('flattenAndNamespace', () => {
|
||||
let result = flattenAndNamespace({
|
||||
nested: {
|
||||
computed ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
},
|
||||
nested2: {
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(Object.keys(result).length).to.equal(3);
|
||||
expect(Object.keys(result).sort()).to.deep.equal(['nested2:getName', 'nested:computed', 'nested:getName']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import { fetchAll as fetchAllGuilds } from 'client/store/actions/guilds';
|
||||
import axios from 'axios';
|
||||
import store from 'client/store';
|
||||
|
||||
describe('guilds actions', () => {
|
||||
it('fetchAll', async () => {
|
||||
const guilds = [{_id: 1}];
|
||||
sandbox
|
||||
.stub(axios, 'get')
|
||||
.withArgs('/api/v3/groups?type=publicGuilds')
|
||||
.returns(Promise.resolve({data: {data: guilds}}));
|
||||
|
||||
await fetchAllGuilds(store);
|
||||
|
||||
expect(store.state.guilds).to.equal(guilds);
|
||||
});
|
||||
});
|
||||
@@ -1,14 +1,54 @@
|
||||
import { fetchUserTasks } from 'client/store/actions/tasks';
|
||||
import axios from 'axios';
|
||||
import store from 'client/store';
|
||||
import generateStore from 'client/store';
|
||||
|
||||
describe('tasks actions', () => {
|
||||
it('fetchUserTasks', async () => {
|
||||
const tasks = [{_id: 1}];
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/tasks/user').returns(Promise.resolve({data: {data: tasks}}));
|
||||
let store;
|
||||
|
||||
await fetchUserTasks(store);
|
||||
beforeEach(() => {
|
||||
store = generateStore();
|
||||
});
|
||||
|
||||
expect(store.state.tasks).to.equal(tasks);
|
||||
describe('fetchUserTasks', () => {
|
||||
it('fetches user tasks', async () => {
|
||||
expect(store.state.tasks.loadingStatus).to.equal('NOT_LOADED');
|
||||
const tasks = [{_id: 1}];
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/tasks/user').returns(Promise.resolve({data: {data: tasks}}));
|
||||
|
||||
await store.dispatch('tasks:fetchUserTasks');
|
||||
|
||||
expect(store.state.tasks.data).to.equal(tasks);
|
||||
expect(store.state.tasks.loadingStatus).to.equal('LOADED');
|
||||
});
|
||||
|
||||
it('does not reload tasks by default', async () => {
|
||||
const originalTask = [{_id: 1}];
|
||||
store.state.tasks = {
|
||||
loadingStatus: 'LOADED',
|
||||
data: originalTask,
|
||||
};
|
||||
|
||||
const tasks = [{_id: 2}];
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/tasks/user').returns(Promise.resolve({data: {data: tasks}}));
|
||||
|
||||
await store.dispatch('tasks:fetchUserTasks');
|
||||
|
||||
expect(store.state.tasks.data).to.equal(originalTask);
|
||||
expect(store.state.tasks.loadingStatus).to.equal('LOADED');
|
||||
});
|
||||
|
||||
it('can reload tasks if forceLoad is true', async () => {
|
||||
store.state.tasks = {
|
||||
loadingStatus: 'LOADED',
|
||||
data: [{_id: 1}],
|
||||
};
|
||||
|
||||
const tasks = [{_id: 2}];
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/tasks/user').returns(Promise.resolve({data: {data: tasks}}));
|
||||
|
||||
await store.dispatch('tasks:fetchUserTasks', true);
|
||||
|
||||
expect(store.state.tasks.data).to.equal(tasks);
|
||||
expect(store.state.tasks.loadingStatus).to.equal('LOADED');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,14 +1,54 @@
|
||||
import { fetch as fetchUser } from 'client/store/actions/user';
|
||||
import axios from 'axios';
|
||||
import store from 'client/store';
|
||||
import generateStore from 'client/store';
|
||||
|
||||
describe('user actions', () => {
|
||||
it('fetch', async () => {
|
||||
const user = {_id: 1};
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: user}}));
|
||||
describe('tasks actions', () => {
|
||||
let store;
|
||||
|
||||
await fetchUser(store);
|
||||
beforeEach(() => {
|
||||
store = generateStore();
|
||||
});
|
||||
|
||||
expect(store.state.user).to.equal(user);
|
||||
describe('fetch', () => {
|
||||
it('loads the user', async () => {
|
||||
expect(store.state.user.loadingStatus).to.equal('NOT_LOADED');
|
||||
const user = {_id: 1};
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: user}}));
|
||||
|
||||
await store.dispatch('user:fetch');
|
||||
|
||||
expect(store.state.user.data).to.equal(user);
|
||||
expect(store.state.user.loadingStatus).to.equal('LOADED');
|
||||
});
|
||||
|
||||
it('does not reload user by default', async () => {
|
||||
const originalUser = {_id: 1};
|
||||
store.state.user = {
|
||||
loadingStatus: 'LOADED',
|
||||
data: originalUser,
|
||||
};
|
||||
|
||||
const user = {_id: 2};
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: user}}));
|
||||
|
||||
await store.dispatch('user:fetch');
|
||||
|
||||
expect(store.state.user.data).to.equal(originalUser);
|
||||
expect(store.state.user.loadingStatus).to.equal('LOADED');
|
||||
});
|
||||
|
||||
it('can reload user if forceLoad is true', async () => {
|
||||
store.state.user = {
|
||||
loadingStatus: 'LOADED',
|
||||
data: {_id: 1},
|
||||
};
|
||||
|
||||
const user = {_id: 2};
|
||||
sandbox.stub(axios, 'get').withArgs('/api/v3/user').returns(Promise.resolve({data: {data: user}}));
|
||||
|
||||
await store.dispatch('user:fetch', true);
|
||||
|
||||
expect(store.state.user.data).to.equal(user);
|
||||
expect(store.state.user.loadingStatus).to.equal('LOADED');
|
||||
});
|
||||
});
|
||||
});
|
||||
16
test/client/unit/specs/store/getters/tasks/getTagsFor.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import generateStore from 'client/store';
|
||||
|
||||
describe('getTagsFor getter', () => {
|
||||
it('returns the tags for a task', () => {
|
||||
const store = generateStore();
|
||||
store.state.user.data = {
|
||||
tags: [
|
||||
{id: 1, name: 'tag 1'},
|
||||
{id: 2, name: 'tag 2'},
|
||||
],
|
||||
};
|
||||
|
||||
const task = {tags: [2]};
|
||||
expect(store.getters['tasks:getTagsFor'](task)).to.deep.equal(['tag 2']);
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ describe('userGems getter', () => {
|
||||
expect(userGems({
|
||||
state: {
|
||||
user: {
|
||||
balance: 4.5,
|
||||
data: {balance: 4.5},
|
||||
},
|
||||
},
|
||||
})).to.equal(18);
|
||||
@@ -1,168 +1,8 @@
|
||||
import Vue from 'vue';
|
||||
import storeInjector from 'inject-loader?-vue!client/store';
|
||||
import { mapState, mapGetters, mapActions } from 'client/store';
|
||||
import { flattenAndNamespace } from 'client/store/helpers/internals';
|
||||
import generateStore from 'client/store';
|
||||
import Store from 'client/libs/store';
|
||||
|
||||
describe('Store', () => {
|
||||
let injectedStore;
|
||||
|
||||
beforeEach(() => {
|
||||
injectedStore = storeInjector({ // eslint-disable-line babel/new-cap
|
||||
'./state': {
|
||||
name: 'test',
|
||||
},
|
||||
'./getters': {
|
||||
computedName ({ state }) {
|
||||
return `${state.name} computed!`;
|
||||
},
|
||||
...flattenAndNamespace({
|
||||
nested: {
|
||||
computedName ({ state }) {
|
||||
return `${state.name} computed!`;
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
'./actions': {
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
...flattenAndNamespace({
|
||||
nested: {
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}).default;
|
||||
});
|
||||
|
||||
it('injects itself in all component', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
created () {
|
||||
expect(this.$store).to.equal(injectedStore);
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('can watch a function on the state', (done) => {
|
||||
injectedStore.watch(state => state.name, (newName) => {
|
||||
expect(newName).to.equal('test updated');
|
||||
done();
|
||||
});
|
||||
|
||||
injectedStore.state.name = 'test updated';
|
||||
});
|
||||
|
||||
describe('getters', () => {
|
||||
it('supports getters', () => {
|
||||
expect(injectedStore.getters.computedName).to.equal('test computed!');
|
||||
injectedStore.state.name = 'test updated';
|
||||
expect(injectedStore.getters.computedName).to.equal('test updated computed!');
|
||||
});
|
||||
|
||||
it('supports nested getters', () => {
|
||||
expect(injectedStore.getters['nested:computedName']).to.equal('test computed!');
|
||||
injectedStore.state.name = 'test updated';
|
||||
expect(injectedStore.getters['nested:computedName']).to.equal('test updated computed!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
it('can dispatch an action', () => {
|
||||
expect(injectedStore.dispatch('getName', 1, 2, 3)).to.deep.equal(['test', 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('can dispatch a nested action', () => {
|
||||
expect(injectedStore.dispatch('nested:getName', 1, 2, 3)).to.deep.equal(['test', 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('throws an error is the action doesn\'t exists', () => {
|
||||
expect(() => injectedStore.dispatched('wrong')).to.throw;
|
||||
});
|
||||
});
|
||||
|
||||
describe('helpers', () => {
|
||||
it('mapState', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
data: {
|
||||
title: 'internal',
|
||||
},
|
||||
computed: {
|
||||
...mapState(['name']),
|
||||
...mapState({
|
||||
nameComputed (state, getters) {
|
||||
return `${this.title} ${getters.computedName} ${state.name}`;
|
||||
},
|
||||
}),
|
||||
},
|
||||
created () {
|
||||
expect(this.name).to.equal('test');
|
||||
expect(this.nameComputed).to.equal('internal test computed! test');
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('mapGetters', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
data: {
|
||||
title: 'internal',
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['computedName']),
|
||||
...mapGetters({
|
||||
nameComputedTwice: 'computedName',
|
||||
}),
|
||||
},
|
||||
created () {
|
||||
expect(this.computedName).to.equal('test computed!');
|
||||
expect(this.nameComputedTwice).to.equal('test computed!');
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('mapActions', (done) => {
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
data: {
|
||||
title: 'internal',
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['getName']),
|
||||
...mapActions({
|
||||
getNameRenamed: 'getName',
|
||||
}),
|
||||
},
|
||||
created () {
|
||||
expect(this.getName('123')).to.deep.equal(['test', '123']);
|
||||
expect(this.getNameRenamed('123')).to.deep.equal(['test', '123']);
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('flattenAndNamespace', () => {
|
||||
let result = flattenAndNamespace({
|
||||
nested: {
|
||||
computed ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
},
|
||||
nested2: {
|
||||
getName ({ state }, ...args) {
|
||||
return [state.name, ...args];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(Object.keys(result).length).to.equal(3);
|
||||
expect(Object.keys(result).sort()).to.deep.equal(['nested2:getName', 'nested:computed', 'nested:getName']);
|
||||
});
|
||||
describe('Application store', () => {
|
||||
it('is an instance of Store', () => {
|
||||
expect(generateStore()).to.be.an.instanceof(Store);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import changeClass from '../../../website/common/script/ops/changeClass';
|
||||
import {
|
||||
NotAuthorized,
|
||||
BadRequest,
|
||||
} from '../../../website/common/script/libs/errors';
|
||||
import i18n from '../../../website/common/script/i18n';
|
||||
import {
|
||||
@@ -27,6 +28,19 @@ describe('shared.ops.changeClass', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('req.query.class is an invalid class', (done) => {
|
||||
user.flags.classSelected = false;
|
||||
user.preferences.disableClasses = false;
|
||||
|
||||
try {
|
||||
changeClass(user, {query: {class: 'cellist'}});
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(BadRequest);
|
||||
expect(err.message).to.equal(i18n.t('invalidClass'));
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
context('req.query.class is a valid class', () => {
|
||||
it('errors if user.stats.flagSelected is true and user.balance < 0.75', (done) => {
|
||||
user.flags.classSelected = true;
|
||||
|
||||
@@ -1,310 +1,350 @@
|
||||
// import { shouldDo, DAY_MAPPING } from '../../website/common/script/cron';
|
||||
// import moment from 'moment';
|
||||
import { shouldDo } from '../../website/common/script/cron';
|
||||
import moment from 'moment';
|
||||
// import 'moment-recur';
|
||||
|
||||
// describe('shouldDo', () => {
|
||||
// let day, dailyTask;
|
||||
// let options = {};
|
||||
describe('shouldDo', () => {
|
||||
let day, dailyTask;
|
||||
let options = {};
|
||||
|
||||
// beforeEach(() => {
|
||||
// day = new Date();
|
||||
// dailyTask = {
|
||||
// completed: 'false',
|
||||
// everyX: 1,
|
||||
// frequency: 'weekly',
|
||||
// type: 'daily',
|
||||
// repeat: {
|
||||
// su: true,
|
||||
// s: true,
|
||||
// f: true,
|
||||
// th: true,
|
||||
// w: true,
|
||||
// t: true,
|
||||
// m: true,
|
||||
// },
|
||||
// startDate: new Date(),
|
||||
// };
|
||||
// });
|
||||
beforeEach(() => {
|
||||
day = new Date();
|
||||
dailyTask = {
|
||||
completed: 'false',
|
||||
everyX: 1,
|
||||
frequency: 'weekly',
|
||||
type: 'daily',
|
||||
repeat: {
|
||||
su: true,
|
||||
s: true,
|
||||
f: true,
|
||||
th: true,
|
||||
w: true,
|
||||
t: true,
|
||||
m: true,
|
||||
},
|
||||
startDate: new Date(),
|
||||
};
|
||||
});
|
||||
|
||||
// it('leaves Daily inactive before start date', () => {
|
||||
// dailyTask.startDate = moment().add(1, 'days').toDate();
|
||||
it('returns false if task type is not a daily', () => {
|
||||
expect(shouldDo(day, {type: 'todo'})).to.equal(false);
|
||||
expect(shouldDo(day, {type: 'habit'})).to.equal(false);
|
||||
expect(shouldDo(day, {type: 'reward'})).to.equal(false);
|
||||
});
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
it('returns false if startDate is in the future', () => {
|
||||
dailyTask.startDate = moment().add(1, 'days').toDate();
|
||||
|
||||
// context('Every X Days', () => {
|
||||
// it('leaves Daily inactive in between X Day intervals', () => {
|
||||
// dailyTask.startDate = moment().subtract(1, 'days').toDate();
|
||||
// dailyTask.frequency = 'daily';
|
||||
// dailyTask.everyX = 2;
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
});
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
context('Every X Days', () => {
|
||||
beforeEach(() => {
|
||||
dailyTask.frequency = 'daily';
|
||||
});
|
||||
|
||||
// it('activates Daily on multiples of X Days', () => {
|
||||
// dailyTask.startDate = moment().subtract(7, 'days').toDate();
|
||||
// dailyTask.frequency = 'daily';
|
||||
// dailyTask.everyX = 7;
|
||||
it('returns false if daily does not have an everyX property', () => {
|
||||
delete dailyTask.everyX;
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
});
|
||||
|
||||
// context('Certain Days of the Week', () => {
|
||||
// it('leaves Daily inactive if day of the week does not match', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
it('returns false in between X Day intervals', () => {
|
||||
dailyTask.startDate = moment().subtract(1, 'days').toDate();
|
||||
dailyTask.everyX = 2;
|
||||
|
||||
// for (let weekday of [0, 1, 2, 3, 4, 5, 6]) {
|
||||
// day = moment().day(weekday).toDate();
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
});
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// }
|
||||
// });
|
||||
it('returns true on multiples of x', () => {
|
||||
dailyTask.startDate = moment().subtract(7, 'days').toDate();
|
||||
dailyTask.everyX = 7;
|
||||
|
||||
// it('leaves Daily inactive if day of the week does not match and active on the day it matches', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: true,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
|
||||
// for (let weekday of [0, 1, 2, 3, 4, 5, 6]) {
|
||||
// day = moment().add(1, 'weeks').day(weekday).toDate();
|
||||
day = moment(day).add(7, 'days');
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
|
||||
// if (weekday === 4) {
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// } else {
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
day = moment(day).add(7, 'days');
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
// it('activates Daily on matching days of the week', () => {
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
context('Certain Days of the Week', () => {
|
||||
beforeEach(() => {
|
||||
dailyTask.frequency = 'weekly';
|
||||
|
||||
// context('Every X Weeks', () => {
|
||||
// it('leaves daily inactive if it has not been the specified number of weeks', () => {
|
||||
// dailyTask.everyX = 3;
|
||||
// let tomorrow = moment().add(1, 'day').toDate();
|
||||
dailyTask.repeat = {
|
||||
su: true,
|
||||
s: true,
|
||||
f: true,
|
||||
th: true,
|
||||
w: true,
|
||||
t: true,
|
||||
m: true,
|
||||
};
|
||||
});
|
||||
|
||||
// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
it('returns false if task does not have a repeat property', () => {
|
||||
delete dailyTask.repeat;
|
||||
|
||||
// it('leaves daily inactive if on every (x) week on weekday it is incorrect weekday', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
});
|
||||
|
||||
// day = moment();
|
||||
// dailyTask.repeat[DAY_MAPPING[day.day()]] = true;
|
||||
// dailyTask.everyX = 3;
|
||||
// let threeWeeksFromTodayPlusOne = day.add(1, 'day').add(3, 'weeks').toDate();
|
||||
it('returns false if day of the week does not match', () => {
|
||||
dailyTask.repeat = {
|
||||
su: false,
|
||||
s: false,
|
||||
f: false,
|
||||
th: false,
|
||||
w: false,
|
||||
t: false,
|
||||
m: false,
|
||||
};
|
||||
|
||||
// expect(shouldDo(threeWeeksFromTodayPlusOne, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
for (let weekday of [0, 1, 2, 3, 4, 5, 6]) {
|
||||
day = moment().day(weekday).toDate();
|
||||
|
||||
// it('activates Daily on matching week', () => {
|
||||
// dailyTask.everyX = 3;
|
||||
// let threeWeeksFromToday = moment().add(3, 'weeks').toDate();
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
}
|
||||
});
|
||||
|
||||
// expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
it('returns false if day of the week does not match and active on the day it matches', () => {
|
||||
dailyTask.repeat = {
|
||||
su: false,
|
||||
s: false,
|
||||
f: false,
|
||||
th: true,
|
||||
w: false,
|
||||
t: false,
|
||||
m: false,
|
||||
};
|
||||
|
||||
// it('activates Daily on every (x) week on weekday', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
for (let weekday of [0, 1, 2, 3, 4, 5, 6]) {
|
||||
day = moment().add(1, 'weeks').day(weekday).toDate();
|
||||
|
||||
// day = moment();
|
||||
// dailyTask.repeat[DAY_MAPPING[day.day()]] = true;
|
||||
// dailyTask.everyX = 3;
|
||||
// let threeWeeksFromToday = day.add(6, 'weeks').day(day.day()).toDate();
|
||||
if (weekday === 4) {
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
} else {
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
it('returns true if Daily on matching days of the week', () => {
|
||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
// context('Monthly - Every X Months on a specified date', () => {
|
||||
// it('leaves daily inactive if not day of the month', () => {
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [15];
|
||||
// let tomorrow = moment().add(1, 'day').toDate();// @TODO: make sure this is not the 15
|
||||
|
||||
// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
|
||||
// it('activates Daily on matching day of month', () => {
|
||||
// day = moment();
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [day.date()];
|
||||
// day = day.add(1, 'months').date(day.date()).toDate();
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
|
||||
// it('leaves daily inactive if not on date of the x month', () => {
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [15];
|
||||
// let tomorrow = moment().add(2, 'months').add(1, 'day').toDate();
|
||||
|
||||
// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
|
||||
// it('activates Daily if on date of the x month', () => {
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [15];
|
||||
// day = moment().add(2, 'months').date(15).toDate();
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
|
||||
// context('Monthly - Certain days of the nth Week', () => {
|
||||
// it('leaves daily inactive if not the correct week of the month on the day of the start date', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
|
||||
// let today = moment('01/27/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// day = moment('02/23/2017');
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
|
||||
// it('activates Daily if correct week of the month on the day of the start date', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
|
||||
// let today = moment('01/27/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// day = moment('02/24/2017');
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
|
||||
// it('leaves daily inactive if not day of the month with every x month on weekday', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
|
||||
// let today = moment('01/26/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
|
||||
// day = moment('03/24/2017');
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
|
||||
// it('activates Daily if on nth weekday of the x month', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
|
||||
// let today = moment('01/27/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
|
||||
// day = moment('03/24/2017');
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
|
||||
// context('Every X Years', () => {
|
||||
// it('leaves daily inactive if not the correct year', () => {
|
||||
// day = moment();
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'yearly';
|
||||
// day = day.add(1, 'day').toDate();
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
|
||||
// it('activates Daily on matching year', () => {
|
||||
// day = moment();
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'yearly';
|
||||
// day = day.add(2, 'years').toDate();
|
||||
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// context('Every X Weeks', () => {
|
||||
// it('leaves daily inactive if it has not been the specified number of weeks', () => {
|
||||
// dailyTask.everyX = 3;
|
||||
// let tomorrow = moment().add(1, 'day').toDate();
|
||||
//
|
||||
// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('leaves daily inactive if on every (x) week on weekday it is incorrect weekday', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
//
|
||||
// day = moment();
|
||||
// dailyTask.repeat[DAY_MAPPING[day.day()]] = true;
|
||||
// dailyTask.everyX = 3;
|
||||
// let threeWeeksFromTodayPlusOne = day.add(1, 'day').add(3, 'weeks').toDate();
|
||||
//
|
||||
// expect(shouldDo(threeWeeksFromTodayPlusOne, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily on matching week', () => {
|
||||
// dailyTask.everyX = 3;
|
||||
// let threeWeeksFromToday = moment().add(3, 'weeks').toDate();
|
||||
//
|
||||
// expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily on every (x) week on weekday', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
//
|
||||
// day = moment();
|
||||
// dailyTask.repeat[DAY_MAPPING[day.day()]] = true;
|
||||
// dailyTask.everyX = 3;
|
||||
// let threeWeeksFromToday = day.add(6, 'weeks').day(day.day()).toDate();
|
||||
//
|
||||
// expect(shouldDo(threeWeeksFromToday, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// context('Monthly - Every X Months on a specified date', () => {
|
||||
// it('leaves daily inactive if not day of the month', () => {
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [15];
|
||||
// let tomorrow = moment().add(1, 'day').toDate();// @TODO: make sure this is not the 15
|
||||
//
|
||||
// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily on matching day of month', () => {
|
||||
// day = moment();
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [day.date()];
|
||||
// day = day.add(1, 'months').date(day.date()).toDate();
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
//
|
||||
// it('leaves daily inactive if not on date of the x month', () => {
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [15];
|
||||
// let tomorrow = moment().add(2, 'months').add(1, 'day').toDate();
|
||||
//
|
||||
// expect(shouldDo(tomorrow, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily if on date of the x month', () => {
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// dailyTask.daysOfMonth = [15];
|
||||
// day = moment().add(2, 'months').date(15).toDate();
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// context('Monthly - Certain days of the nth Week', () => {
|
||||
// it('leaves daily inactive if not the correct week of the month on the day of the start date', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
//
|
||||
// let today = moment('01/27/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// day = moment('02/23/2017');
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily if correct week of the month on the day of the start date', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
//
|
||||
// let today = moment('01/27/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 1;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
// day = moment('02/24/2017');
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
//
|
||||
// it('leaves daily inactive if not day of the month with every x month on weekday', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
//
|
||||
// let today = moment('01/26/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
//
|
||||
// day = moment('03/24/2017');
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily if on nth weekday of the x month', () => {
|
||||
// dailyTask.repeat = {
|
||||
// su: false,
|
||||
// s: false,
|
||||
// f: false,
|
||||
// th: false,
|
||||
// w: false,
|
||||
// t: false,
|
||||
// m: false,
|
||||
// };
|
||||
//
|
||||
// let today = moment('01/27/2017');
|
||||
// let week = today.monthWeek();
|
||||
// let dayOfWeek = today.day();
|
||||
// dailyTask.startDate = today.toDate();
|
||||
// dailyTask.weeksOfMonth = [week];
|
||||
// dailyTask.repeat[DAY_MAPPING[dayOfWeek]] = true;
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'monthly';
|
||||
//
|
||||
// day = moment('03/24/2017');
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// context('Every X Years', () => {
|
||||
// it('leaves daily inactive if not the correct year', () => {
|
||||
// day = moment();
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'yearly';
|
||||
// day = day.add(1, 'day').toDate();
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||
// });
|
||||
//
|
||||
// it('activates Daily on matching year', () => {
|
||||
// day = moment();
|
||||
// dailyTask.everyX = 2;
|
||||
// dailyTask.frequency = 'yearly';
|
||||
// day = day.add(2, 'years').toDate();
|
||||
//
|
||||
// expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
@@ -30,16 +30,17 @@ export function generateChallenge (options = {}) {
|
||||
|
||||
export function generateRes (options = {}) {
|
||||
let defaultRes = {
|
||||
render: sandbox.stub(),
|
||||
send: sandbox.stub(),
|
||||
status: sandbox.stub().returnsThis(),
|
||||
sendStatus: sandbox.stub().returnsThis(),
|
||||
json: sandbox.stub(),
|
||||
locals: {
|
||||
user: generateUser(options.localsUser),
|
||||
group: generateGroup(options.localsGroup),
|
||||
},
|
||||
redirect: sandbox.stub(),
|
||||
render: sandbox.stub(),
|
||||
send: sandbox.stub(),
|
||||
sendStatus: sandbox.stub().returnsThis(),
|
||||
set: sandbox.stub(),
|
||||
status: sandbox.stub().returnsThis(),
|
||||
t (string) {
|
||||
return i18n.t(string);
|
||||
},
|
||||
|
||||
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
BIN
website/assets/img/project_files/npcs/spring/npc_bailey.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
website/assets/img/project_files/npcs/spring/npc_daniel.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
BIN
website/assets/img/project_files/npcs/spring/npc_justin.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
website/assets/img/project_files/npcs/spring/npc_matt.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
@@ -1,9 +1,9 @@
|
||||
/* Comment out for holiday events */
|
||||
.npc_ian {
|
||||
/* .npc_ian {
|
||||
background: url("/npc_ian.gif") no-repeat;
|
||||
width: 78px;
|
||||
height: 135px;
|
||||
}
|
||||
} */
|
||||
|
||||
.quest_burnout {
|
||||
background: url("/quest_burnout.gif") no-repeat;
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
.promo_android {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -180px;
|
||||
background-position: -1689px -180px;
|
||||
width: 175px;
|
||||
height: 175px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201602 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -565px -600px;
|
||||
background-position: -849px -600px;
|
||||
width: 141px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201603 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -707px -600px;
|
||||
background-position: -1547px 0px;
|
||||
width: 141px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201604 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -1041px;
|
||||
background-position: -1265px -442px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201605 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -141px -1041px;
|
||||
background-position: -1406px 0px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
@@ -42,49 +42,55 @@
|
||||
}
|
||||
.promo_backgrounds_armoire_201608 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -142px -600px;
|
||||
background-position: -568px -600px;
|
||||
width: 140px;
|
||||
height: 439px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201609 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -283px -600px;
|
||||
background-position: -709px -600px;
|
||||
width: 139px;
|
||||
height: 438px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201610 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1124px -442px;
|
||||
background-position: 0px -1042px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201611 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1265px 0px;
|
||||
background-position: -282px -1042px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201612 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1265px -442px;
|
||||
background-position: -1124px 0px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201701 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1406px 0px;
|
||||
background-position: -1124px -442px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201702 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -840px 0px;
|
||||
background-position: -982px 0px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201703 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -982px 0px;
|
||||
background-position: 0px -600px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_backgrounds_armoire_201704 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -142px -600px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
@@ -96,151 +102,157 @@
|
||||
}
|
||||
.promo_chairs_glasses {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1757px -532px;
|
||||
background-position: -1795px -532px;
|
||||
width: 51px;
|
||||
height: 210px;
|
||||
}
|
||||
.promo_checkin_incentives {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -423px -600px;
|
||||
background-position: -1547px -295px;
|
||||
width: 141px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_classes_fall_2014 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1207px -1337px;
|
||||
background-position: -277px -1484px;
|
||||
width: 321px;
|
||||
height: 100px;
|
||||
}
|
||||
.promo_classes_fall_2015 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -423px -895px;
|
||||
background-position: -703px -1338px;
|
||||
width: 377px;
|
||||
height: 99px;
|
||||
}
|
||||
.promo_classes_fall_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px 0px;
|
||||
background-position: -1547px -590px;
|
||||
width: 103px;
|
||||
height: 348px;
|
||||
}
|
||||
.promo_coffee_mug {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px 0px;
|
||||
background-position: -1689px 0px;
|
||||
width: 200px;
|
||||
height: 179px;
|
||||
}
|
||||
.promo_contrib_spotlight_Keith {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -1118px;
|
||||
background-position: -1406px -884px;
|
||||
width: 87px;
|
||||
height: 111px;
|
||||
}
|
||||
.promo_contrib_spotlight_beffymaroo {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1406px -884px;
|
||||
background-position: -1689px -1102px;
|
||||
width: 114px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_contrib_spotlight_blade {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -1006px;
|
||||
background-position: -1547px -1339px;
|
||||
width: 89px;
|
||||
height: 111px;
|
||||
}
|
||||
.promo_contrib_spotlight_cantras {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -1230px;
|
||||
background-position: -1124px -884px;
|
||||
width: 87px;
|
||||
height: 109px;
|
||||
}
|
||||
.promo_contrib_spotlight_dewines {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1265px -884px;
|
||||
width: 89px;
|
||||
height: 108px;
|
||||
}
|
||||
.promo_contrib_spotlight_megan {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -894px;
|
||||
background-position: -1790px -1341px;
|
||||
width: 90px;
|
||||
height: 111px;
|
||||
}
|
||||
.promo_contrib_spotlight_shanaqui {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -782px;
|
||||
background-position: -1547px -1227px;
|
||||
width: 90px;
|
||||
height: 111px;
|
||||
}
|
||||
.promo_cow {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -282px -1041px;
|
||||
background-position: -141px -1042px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_cupid_potions {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -705px -1041px;
|
||||
background-position: -564px -1042px;
|
||||
width: 138px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_dilatoryDistress {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1286px -1644px;
|
||||
background-position: -903px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_egg_mounts {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -844px -1041px;
|
||||
background-position: -703px -1190px;
|
||||
width: 280px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_enchanted_armoire {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -1483px;
|
||||
background-position: -1081px -1338px;
|
||||
width: 374px;
|
||||
height: 76px;
|
||||
}
|
||||
.promo_enchanted_armoire_201507 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -507px -1644px;
|
||||
background-position: 0px -1632px;
|
||||
width: 217px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_enchanted_armoire_201508 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -1342px;
|
||||
background-position: -1689px -1250px;
|
||||
width: 180px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_enchanted_armoire_201509 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -614px -1735px;
|
||||
background-position: -1540px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_enchanted_armoire_201511 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -982px -442px;
|
||||
background-position: -1547px -1045px;
|
||||
width: 122px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_enchanted_armoire_201601 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -887px -1735px;
|
||||
background-position: -1722px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_floral_potions {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -532px;
|
||||
background-position: -1689px -532px;
|
||||
width: 105px;
|
||||
height: 273px;
|
||||
}
|
||||
.promo_ghost_potions {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1406px -442px;
|
||||
background-position: -1265px 0px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_habitica {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -356px;
|
||||
background-position: -1689px -356px;
|
||||
width: 175px;
|
||||
height: 175px;
|
||||
}
|
||||
@@ -252,217 +264,217 @@
|
||||
}
|
||||
.promo_habitoween_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -423px -1041px;
|
||||
background-position: -1406px -442px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_haunted_hair {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -644px;
|
||||
background-position: -1689px -1341px;
|
||||
width: 100px;
|
||||
height: 137px;
|
||||
}
|
||||
.promo_holly_potions {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -600px;
|
||||
background-position: -426px -600px;
|
||||
width: 141px;
|
||||
height: 440px;
|
||||
}
|
||||
.promo_item_notif {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -1735px;
|
||||
background-position: -849px -895px;
|
||||
width: 249px;
|
||||
height: 102px;
|
||||
}
|
||||
.promo_jackalope {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1124px -1189px;
|
||||
background-position: 0px -1484px;
|
||||
width: 276px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_mystery_201405 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1650px -1644px;
|
||||
background-position: -1267px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201406 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1401px -1189px;
|
||||
background-position: -1341px -1042px;
|
||||
width: 90px;
|
||||
height: 96px;
|
||||
}
|
||||
.promo_mystery_201407 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1809px -669px;
|
||||
background-position: -1847px -669px;
|
||||
width: 42px;
|
||||
height: 62px;
|
||||
}
|
||||
.promo_mystery_201408 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1051px -812px;
|
||||
background-position: -991px -806px;
|
||||
width: 60px;
|
||||
height: 71px;
|
||||
}
|
||||
.promo_mystery_201409 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1195px -1644px;
|
||||
background-position: -1176px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201410 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -982px -533px;
|
||||
background-position: -306px -536px;
|
||||
width: 72px;
|
||||
height: 63px;
|
||||
}
|
||||
.promo_mystery_201411 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1468px -1644px;
|
||||
background-position: -1358px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201412 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1809px -602px;
|
||||
background-position: -1847px -602px;
|
||||
width: 42px;
|
||||
height: 66px;
|
||||
}
|
||||
.promo_mystery_201501 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1792px -806px;
|
||||
background-position: -1830px -806px;
|
||||
width: 48px;
|
||||
height: 63px;
|
||||
}
|
||||
.promo_mystery_201502 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -341px -1735px;
|
||||
background-position: 0px -1723px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201503 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -432px -1735px;
|
||||
background-position: -273px -1723px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201504 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -375px -1483px;
|
||||
background-position: -1052px -806px;
|
||||
width: 60px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_mystery_201505 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -796px -1735px;
|
||||
background-position: -1085px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201506 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1809px -532px;
|
||||
background-position: -1847px -532px;
|
||||
width: 42px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_mystery_201507 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -990px -600px;
|
||||
background-position: -699px -448px;
|
||||
width: 90px;
|
||||
height: 105px;
|
||||
}
|
||||
.promo_mystery_201508 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -819px -1644px;
|
||||
background-position: -624px -1632px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201509 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1377px -1644px;
|
||||
background-position: -1449px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201510 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -725px -1644px;
|
||||
background-position: -718px -1632px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201511 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1559px -1644px;
|
||||
background-position: -1631px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201512 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -990px -812px;
|
||||
background-position: -1803px -1479px;
|
||||
width: 60px;
|
||||
height: 81px;
|
||||
}
|
||||
.promo_mystery_201601 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -840px -442px;
|
||||
background-position: -1547px -1136px;
|
||||
width: 120px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201602 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -250px -1735px;
|
||||
background-position: -91px -1723px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201603 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1741px -1644px;
|
||||
background-position: -182px -1723px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201604 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1101px -1644px;
|
||||
background-position: -1432px -1042px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201605 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -523px -1735px;
|
||||
background-position: -812px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201606 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -699px -448px;
|
||||
background-position: -991px -600px;
|
||||
width: 90px;
|
||||
height: 105px;
|
||||
}
|
||||
.promo_mystery_201607 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -705px -1735px;
|
||||
background-position: -994px -1632px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201608 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -913px -1644px;
|
||||
background-position: -436px -1632px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201609 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1007px -1644px;
|
||||
background-position: -530px -1632px;
|
||||
width: 93px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_mystery_201610 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1771px -1194px;
|
||||
background-position: -1804px -1102px;
|
||||
width: 63px;
|
||||
height: 84px;
|
||||
}
|
||||
.promo_mystery_201611 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1405px -1041px;
|
||||
background-position: -991px -706px;
|
||||
width: 90px;
|
||||
height: 99px;
|
||||
}
|
||||
@@ -474,151 +486,121 @@
|
||||
}
|
||||
.promo_mystery_201701 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -990px -706px;
|
||||
background-position: -840px -442px;
|
||||
width: 90px;
|
||||
height: 105px;
|
||||
}
|
||||
.promo_mystery_201702 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1125px -1041px;
|
||||
background-position: -1264px -1190px;
|
||||
width: 279px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_mystery_201703 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1058px -1042px;
|
||||
width: 282px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_mystery_3014 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -289px -1644px;
|
||||
background-position: -218px -1632px;
|
||||
width: 217px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_new_hair_fall2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -564px -1041px;
|
||||
background-position: -423px -1042px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_orca {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1124px -884px;
|
||||
background-position: -1547px -939px;
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
}
|
||||
.promo_partyhats {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -1433px;
|
||||
background-position: -1265px -993px;
|
||||
width: 115px;
|
||||
height: 47px;
|
||||
}
|
||||
.promo_pastel_skin {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -1560px;
|
||||
background-position: -599px -1484px;
|
||||
width: 330px;
|
||||
height: 83px;
|
||||
}
|
||||
.customize-option.promo_pastel_skin {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -25px -1575px;
|
||||
background-position: -624px -1499px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_pastel_skin_hair {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -703px -1042px;
|
||||
width: 354px;
|
||||
height: 147px;
|
||||
}
|
||||
.customize-option.promo_pastel_skin_hair {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -728px -1057px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_peppermint_flame {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -954px;
|
||||
background-position: -1689px -806px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_pet_skins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -806px;
|
||||
background-position: -1689px -954px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.customize-option.promo_pet_skins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1676px -821px;
|
||||
background-position: -1714px -969px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_pyromancer {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1265px -884px;
|
||||
background-position: -1689px -1479px;
|
||||
width: 113px;
|
||||
height: 113px;
|
||||
}
|
||||
.promo_rainbow_armor {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -1340px;
|
||||
background-position: -982px -442px;
|
||||
width: 92px;
|
||||
height: 103px;
|
||||
}
|
||||
.promo_seasonal_shop_fall_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -844px -1189px;
|
||||
background-position: -984px -1190px;
|
||||
width: 279px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_shimmer_hair {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -331px -1560px;
|
||||
background-position: -930px -1484px;
|
||||
width: 330px;
|
||||
height: 83px;
|
||||
}
|
||||
.promo_splashyskins {
|
||||
.promo_shimmer_potions {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -1102px;
|
||||
width: 198px;
|
||||
height: 91px;
|
||||
}
|
||||
.customize-option.promo_splashyskins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1676px -1117px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_spooky_sparkles_fall_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -849px -600px;
|
||||
width: 140px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_spring_classes_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -844px -1337px;
|
||||
width: 362px;
|
||||
height: 102px;
|
||||
}
|
||||
.promo_springclasses2014 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -801px -895px;
|
||||
width: 288px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_springclasses2015 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: 0px -1644px;
|
||||
width: 288px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_staff_spotlight_Lemoness {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -349px;
|
||||
width: 102px;
|
||||
height: 146px;
|
||||
}
|
||||
.promo_staff_spotlight_Viirus {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1651px -1194px;
|
||||
width: 119px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_staff_spotlight_paglias {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1547px -496px;
|
||||
width: 99px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_steampunk_3017 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -1124px 0px;
|
||||
width: 140px;
|
||||
background-position: -284px -600px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_shinySeeds {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-0.png);
|
||||
background-position: -840px 0px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
@@ -1,198 +1,270 @@
|
||||
.promo_splashyskins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -947px -1191px;
|
||||
width: 198px;
|
||||
height: 91px;
|
||||
}
|
||||
.customize-option.promo_splashyskins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -972px -1206px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_spooky_sparkles_fall_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1215px -196px;
|
||||
width: 140px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_spring_classes_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -301px -1040px;
|
||||
width: 362px;
|
||||
height: 102px;
|
||||
}
|
||||
.promo_spring_classes_2017 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -581px -859px;
|
||||
width: 309px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_springclasses2014 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -891px -859px;
|
||||
width: 288px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_springclasses2015 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1025px -1040px;
|
||||
width: 288px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_staff_spotlight_Lemoness {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -792px -442px;
|
||||
width: 102px;
|
||||
height: 146px;
|
||||
}
|
||||
.promo_staff_spotlight_Viirus {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -933px -442px;
|
||||
width: 119px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_staff_spotlight_paglias {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1356px -196px;
|
||||
width: 99px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_steampunk_3017 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1074px 0px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_summer_classes_2014 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -885px -591px;
|
||||
background-position: -340px -220px;
|
||||
width: 429px;
|
||||
height: 102px;
|
||||
}
|
||||
.promo_summer_classes_2015 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -553px -615px;
|
||||
background-position: -900px -708px;
|
||||
width: 300px;
|
||||
height: 88px;
|
||||
}
|
||||
.promo_summer_classes_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -452px -145px;
|
||||
background-position: 0px -708px;
|
||||
width: 400px;
|
||||
height: 150px;
|
||||
}
|
||||
.promo_takeThis_gear {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -361px -882px;
|
||||
background-position: -1074px -590px;
|
||||
width: 114px;
|
||||
height: 87px;
|
||||
}
|
||||
.promo_takethis_armor {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -476px -882px;
|
||||
background-position: -933px -590px;
|
||||
width: 114px;
|
||||
height: 87px;
|
||||
}
|
||||
.promo_task_planning {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -885px -96px;
|
||||
background-position: -1215px 0px;
|
||||
width: 240px;
|
||||
height: 195px;
|
||||
}
|
||||
.promo_turkey_day_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -141px -440px;
|
||||
background-position: -933px 0px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_unconventional_armor {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1315px -591px;
|
||||
background-position: -1356px -419px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_unconventional_armor2 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1283px -694px;
|
||||
background-position: -1356px -344px;
|
||||
width: 70px;
|
||||
height: 74px;
|
||||
}
|
||||
.promo_updos {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1195px -292px;
|
||||
background-position: -1215px -663px;
|
||||
width: 156px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_veteran_pets {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -706px -704px;
|
||||
background-position: -1146px -1191px;
|
||||
width: 146px;
|
||||
height: 75px;
|
||||
}
|
||||
.promo_winter_classes_2016 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: 0px -882px;
|
||||
background-position: -664px -1040px;
|
||||
width: 360px;
|
||||
height: 90px;
|
||||
}
|
||||
.promo_winter_classes_2017 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -452px 0px;
|
||||
background-position: 0px -563px;
|
||||
width: 432px;
|
||||
height: 144px;
|
||||
}
|
||||
.promo_winter_fireworks {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -302px -973px;
|
||||
background-position: -1074px -442px;
|
||||
width: 138px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_winterclasses2015 {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -452px -296px;
|
||||
background-position: -433px -563px;
|
||||
width: 325px;
|
||||
height: 110px;
|
||||
}
|
||||
.promo_wintery_skins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: 0px -440px;
|
||||
background-position: -792px 0px;
|
||||
width: 140px;
|
||||
height: 441px;
|
||||
}
|
||||
.customize-option.promo_wintery_skins {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -25px -455px;
|
||||
background-position: -817px -15px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_winteryhair {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -553px -704px;
|
||||
background-position: -1215px -962px;
|
||||
width: 152px;
|
||||
height: 75px;
|
||||
}
|
||||
.avatar_variety {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -885px 0px;
|
||||
background-position: -401px -708px;
|
||||
width: 498px;
|
||||
height: 95px;
|
||||
}
|
||||
.npc_viirus {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -441px -973px;
|
||||
background-position: -792px -589px;
|
||||
width: 108px;
|
||||
height: 90px;
|
||||
}
|
||||
.party_preview {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: 0px 0px;
|
||||
background-position: -340px 0px;
|
||||
width: 451px;
|
||||
height: 219px;
|
||||
}
|
||||
.promo_backtoschool {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1186px -440px;
|
||||
background-position: -645px -1191px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.promo_cooking {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: 0px -220px;
|
||||
background-position: 0px -343px;
|
||||
width: 396px;
|
||||
height: 219px;
|
||||
}
|
||||
.promo_startingover {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1132px -694px;
|
||||
background-position: -796px -1191px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.promo_valentines {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -885px -292px;
|
||||
background-position: -271px -859px;
|
||||
width: 309px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_working_out {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -885px -440px;
|
||||
background-position: 0px -1040px;
|
||||
width: 300px;
|
||||
height: 150px;
|
||||
}
|
||||
.scene_coding {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -151px -973px;
|
||||
background-position: -494px -1191px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.scene_eco_friendly {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -589px -440px;
|
||||
background-position: -1215px -491px;
|
||||
width: 222px;
|
||||
height: 171px;
|
||||
}
|
||||
.scene_habits {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -282px -440px;
|
||||
background-position: -397px -343px;
|
||||
width: 306px;
|
||||
height: 174px;
|
||||
}
|
||||
.scene_phone_peek {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: 0px -973px;
|
||||
background-position: -1215px -811px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.scene_video_games {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: 0px 0px;
|
||||
width: 339px;
|
||||
height: 342px;
|
||||
}
|
||||
.welcome_basic_avatars {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -885px -694px;
|
||||
background-position: 0px -1191px;
|
||||
width: 246px;
|
||||
height: 165px;
|
||||
}
|
||||
.welcome_promo_party {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -282px -615px;
|
||||
background-position: 0px -859px;
|
||||
width: 270px;
|
||||
height: 180px;
|
||||
}
|
||||
.welcome_sample_tasks {
|
||||
background-image: url(/static/sprites/spritesmith-largeSprites-1.png);
|
||||
background-position: -1126px -96px;
|
||||
background-position: -247px -1191px;
|
||||
width: 246px;
|
||||
height: 165px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 286 KiB |
1138
website/assets/sprites/dist/spritesmith-main-0.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-0.png
vendored
|
Before Width: | Height: | Size: 478 KiB After Width: | Height: | Size: 497 KiB |
2930
website/assets/sprites/dist/spritesmith-main-1.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-1.png
vendored
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 73 KiB |
2186
website/assets/sprites/dist/spritesmith-main-10.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-10.png
vendored
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 147 KiB |
2062
website/assets/sprites/dist/spritesmith-main-11.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-11.png
vendored
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 152 KiB |
1364
website/assets/sprites/dist/spritesmith-main-12.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-12.png
vendored
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 136 KiB |
1644
website/assets/sprites/dist/spritesmith-main-13.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-13.png
vendored
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 143 KiB |
684
website/assets/sprites/dist/spritesmith-main-14.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-14.png
vendored
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 154 KiB |
1532
website/assets/sprites/dist/spritesmith-main-15.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-15.png
vendored
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 178 KiB |
2568
website/assets/sprites/dist/spritesmith-main-16.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-16.png
vendored
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 161 KiB |
528
website/assets/sprites/dist/spritesmith-main-17.css
vendored
Normal file
@@ -0,0 +1,528 @@
|
||||
.Pet-TRex-Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-TRex-Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-TRex-Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-TRex-Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-TRex-White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-TRex-Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-CottonCandyBlue {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-CottonCandyPink {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Desert {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Triceratops-Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turkey-Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turkey-Gilded {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-CottonCandyBlue {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-CottonCandyPink {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Desert {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-CottonCandyBlue {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-CottonCandyPink {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Desert {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-CottonCandyBlue {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-CottonCandyPink {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Desert {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-CottonCandyBlue {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-CottonCandyPink {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Cupid {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Desert {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Floral {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Ghost {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -82px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Holly {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -164px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Peppermint {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -246px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -328px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-RoyalPurple {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -410px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -492px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Shimmer {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -574px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -656px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Spooky {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Thunderstorm {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Veteran {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet_HatchingPotion_Base {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -552px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_CottonCandyBlue {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -343px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_CottonCandyPink {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -604px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Cupid {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Desert {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -49px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Floral {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -98px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Ghost {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -147px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Golden {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -196px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Holly {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -245px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Peppermint {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -294px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Purple {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -738px -500px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Red {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -392px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_RoyalPurple {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -441px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Shade {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -490px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Shimmer {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -539px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Skeleton {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -588px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Spooky {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -637px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Thunderstorm {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -686px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_White {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: -735px -700px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.Pet_HatchingPotion_Zombie {
|
||||
background-image: url(/static/sprites/spritesmith-main-17.png);
|
||||
background-position: 0px -752px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
BIN
website/assets/sprites/dist/spritesmith-main-17.png
vendored
Normal file
|
After Width: | Height: | Size: 37 KiB |
6686
website/assets/sprites/dist/spritesmith-main-2.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-2.png
vendored
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 66 KiB |
5970
website/assets/sprites/dist/spritesmith-main-3.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-3.png
vendored
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
3114
website/assets/sprites/dist/spritesmith-main-4.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-4.png
vendored
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 111 KiB |
4304
website/assets/sprites/dist/spritesmith-main-5.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-5.png
vendored
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 152 KiB |
2032
website/assets/sprites/dist/spritesmith-main-6.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-6.png
vendored
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 147 KiB |
1046
website/assets/sprites/dist/spritesmith-main-7.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-7.png
vendored
|
Before Width: | Height: | Size: 309 KiB After Width: | Height: | Size: 273 KiB |
1068
website/assets/sprites/dist/spritesmith-main-8.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-8.png
vendored
|
Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 353 KiB |
2582
website/assets/sprites/dist/spritesmith-main-9.css
vendored
BIN
website/assets/sprites/dist/spritesmith-main-9.png
vendored
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 888 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 786 B |