Merge branch 'staging' of https://github.com/freecodecamp/freecodecamp into staging

This commit is contained in:
Quincy Larson
2016-02-09 15:50:04 -08:00
15 changed files with 239 additions and 113 deletions

View File

@@ -1,6 +1,5 @@
.challenge-step-description {
font-size: 1.5em;
text-align: center;
}
.challenge-step-counter {
font-size: 20px;

View File

@@ -289,7 +289,7 @@
// Medium screen / desktop
//** Deprecated `@screen-md` as of v3.0.1
@screen-md: 992px;
@screen-md: 1031px;
@screen-md-min: @screen-md;
//** Deprecated `@screen-desktop` as of v3.0.1
@screen-desktop: @screen-md-min;

View File

@@ -96,7 +96,7 @@ main = (function(main, global) {
});
$('#nav-chat-btn').on('click', showMainChat);
$('#nav-chat-btn').on('click', toggleMainChat);
function showMainChat() {
if (!main.chat.isOpen) {
@@ -106,10 +106,10 @@ main = (function(main, global) {
function collapseMainChat() {
$('#chat-embed-main').addClass('is-collapsed');
document.activeElement.blur();
}
// keyboard shortcuts: open main chat
Mousetrap.bind('g c', function() {
function toggleMainChat() {
var isCollapsed = $('#chat-embed-main').hasClass('is-collapsed');
if (isCollapsed) {
@@ -117,7 +117,10 @@ main = (function(main, global) {
} else {
collapseMainChat();
}
});
}
// keyboard shortcuts: open main chat
Mousetrap.bind('g c', toggleMainChat);
});
return main;
@@ -344,7 +347,7 @@ $(document).ready(function() {
var mapFilter = $('#map-filter');
var mapShowAll = $('#showAll');
$('#nav-map-btn').on('click', showMap);
$('#nav-map-btn').on('click', toggleMap);
$('.map-aside-action-collapse').on('click', collapseMap);
@@ -360,6 +363,17 @@ $(document).ready(function() {
function collapseMap() {
$('.map-aside').addClass('is-collapsed');
document.activeElement.blur();
}
function toggleMap() {
var isCollapsed = $('.map-aside').hasClass('is-collapsed');
if (isCollapsed) {
showMap();
} else {
collapseMap();
}
}
$('#accordion').on('show.bs.collapse', function(e) {
@@ -480,13 +494,5 @@ $(document).ready(function() {
window.Mousetrap.bind('esc', clearMapFilter);
// keyboard shortcuts: open map
window.Mousetrap.bind('g m', function() {
var isCollapsed = $('.map-aside').hasClass('is-collapsed');
if (isCollapsed) {
showMap();
} else {
collapseMap();
}
});
window.Mousetrap.bind('g m', toggleMap);
});

View File

@@ -17,6 +17,10 @@
"content": "Jobs",
"link": "/jobs",
"react": true
},{
"content": "Shop",
"link": "/shop",
"target": "_blank"
},{
"content": "About",
"link": "/about"

View File

@@ -148,6 +148,7 @@
"loopback-component-explorer": "^2.1.1",
"loopback-testing": "^1.1.0",
"mocha": "^2.3.3",
"sinon": "^1.17.3",
"tap-spec": "^4.1.1",
"tape": "^4.2.2"
}

View File

@@ -81,8 +81,8 @@
"id": "a3f503de51cf954ede28891d",
"title": "Symmetric Difference",
"description": [
"Create a function that takes two or more arrays and returns an array of the symmetric difference of the provided arrays.",
"The mathematical term symmetric difference refers to the elements in two sets that are in either the first or second set, but not in both.",
"Create a function that takes two or more arrays and returns an array of the <dfn>symmetric difference</dfn> (<code>&xutri;</code> or <code>&oplus;</code>) of the provided arrays.",
"Given two sets (for example set <code>A = {1, 2, 3}</code> and set <code>B = {2, 3, 4}</code>), the mathematical term \"symmetric difference\" of two sets is the set of elements which are in either of the two sets, but not in both (<code>A &xutri; B = C = {1, 4}</code>). For every additional symmetric difference you take (say on a set <code>D = {2, 3}</code>), you should get the set with elements which are in either of the two the sets but not both (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>).",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
@@ -225,8 +225,8 @@
"id": "a7bf700cd123b9a54eef01d5",
"title": "No repeats please",
"description": [
"Return the number of total permutations of the provided string that don't have repeated consecutive letters.",
"For example, 'aab' should return 2 because it has 6 total permutations, but only 2 of them don't have the same letter (in this case 'a') repeating.",
"Return the number of total permutations of the provided string that don't have repeated consecutive letters. Assume that duplicate characters are each unique.",
"For example, <code>aab</code> should return 2 because it has 6 total permutations (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), but only 2 of them (<code>aba</code> and <code>aba</code>) don't have the same letter (in this case <code>a</code>) repeating.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [

View File

@@ -950,7 +950,7 @@
"id": "bad87fee1348bd9aede08845",
"title": "Create a Custom Heading",
"description": [
"We will make a simple heading for our Cat Photo App by putting them in the same row.",
"We will make a simple heading for our Cat Photo App by putting the title and relaxing cat image in the same row.",
"Remember, Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a <code>div</code> element.",
"Here's a diagram of how Bootstrap's 12-column grid layout works:",
"<a href=\"http://i.imgur.com/FaYuui8.png\" data-lightbox=\"img-enlarge\"><img class=\"img-responsive\" src=\"http://i.imgur.com/FaYuui8.png\" title=\"Click to enlarge\" alt=\"an image illustrating Bootstrap's grid system\"></a>",

View File

@@ -48,7 +48,7 @@
"id": "a5de63ebea8dbee56860f4f2",
"title": "Diff Two Arrays",
"description": [
"Compare two arrays and return a new array with any items only found in one of the original arrays.",
"Compare two arrays and return a new array with any items only found in one of the two given arrays, but not both. In other words, return the symmetric difference of the two arrays.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [

View File

@@ -14,7 +14,11 @@ import certTypes from '../utils/certTypes.json';
import { ifNoUser401, ifNoUserRedirectTo } from '../utils/middleware';
import { observeQuery } from '../utils/rx';
import { calcCurrentStreak, calcLongestStreak } from '../utils/user-stats';
import {
prepUniqueDays,
calcCurrentStreak,
calcLongestStreak
} from '../utils/user-stats';
const debug = debugFactory('freecc:boot:user');
const sendNonUserToMap = ifNoUserRedirectTo('/map');
@@ -192,17 +196,18 @@ module.exports = function(app) {
const timezone = req.user &&
req.user.timezone ? req.user.timezone : 'UTC';
var cals = profileUser
const timestamps = profileUser
.progressTimestamps
.map(objOrNum => {
return typeof objOrNum === 'number' ?
objOrNum :
objOrNum.timestamp;
})
.sort();
});
profileUser.currentStreak = calcCurrentStreak(cals, timezone);
profileUser.longestStreak = calcLongestStreak(cals, timezone);
const uniqueDays = prepUniqueDays(timestamps, timezone);
profileUser.currentStreak = calcCurrentStreak(uniqueDays, timezone);
profileUser.longestStreak = calcLongestStreak(uniqueDays, timezone);
const data = profileUser
.progressTimestamps

View File

@@ -26,6 +26,6 @@ var timeoutHandler = setTimeout(function() {
// purposely shutdown server
// pm2 should restart this in production
throw new Error(message);
}, 5000);
}, 15000);
app.dataSources.db.on('connected', onConnect);

View File

@@ -3,7 +3,7 @@ import moment from 'moment-timezone';
// day count between two epochs (inclusive)
export function dayCount([head, tail], timezone = 'UTC') {
return Math.ceil(
moment(moment(head).tz(timezone).endOf('day')).tz(timezone).diff(
moment(moment(head).tz(timezone).endOf('day')).diff(
moment(tail).tz(timezone).startOf('day'),
'days',
true)

View File

@@ -1,46 +1,54 @@
import _ from 'lodash';
import moment from 'moment-timezone';
import { dayCount } from '../utils/date-utils';
const daysBetween = 1.5;
export function calcCurrentStreak(cals, timezone = 'UTC') {
const revCals = cals.slice().reverse();
export function prepUniqueDays(cals, tz = 'UTC') {
if (dayCount([moment().tz(timezone), revCals[0]], timezone) > daysBetween) {
return 0;
}
let streakBroken = false;
const lastDayInStreak = revCals
.reduce((current, cal, index) => {
const before = revCals[index === 0 ? 0 : index - 1];
if (
!streakBroken &&
moment(before).tz(timezone).diff(cal, 'days', true) < daysBetween
) {
return index;
}
streakBroken = true;
return current;
}, 0);
const lastTimestamp = revCals[lastDayInStreak];
return dayCount([moment().tz(timezone), lastTimestamp], timezone);
return _(cals)
.map(ts => moment(ts).tz(tz).startOf('day').valueOf())
.uniq()
.sort()
.value();
}
export function calcLongestStreak(cals, timezone = 'UTC') {
export function calcCurrentStreak(cals, tz = 'UTC') {
let prev = _.last(cals);
if (moment().tz(tz).startOf('day').diff(prev, 'days') > daysBetween) {
return 0;
}
let currentStreak = 0;
let streakContinues = true;
_.forEachRight(cals, cur => {
if (moment(prev).diff(cur, 'days') < daysBetween) {
prev = cur;
currentStreak++;
} else {
// current streak found
streakContinues = false;
}
return streakContinues;
});
return currentStreak;
}
export function calcLongestStreak(cals, tz = 'UTC') {
let tail = cals[0];
const longest = cals.reduce((longest, head, index) => {
const last = cals[index === 0 ? 0 : index - 1];
// is streak broken
if (moment(head).tz(timezone).diff(last, 'days', true) > daysBetween) {
if (moment(head).tz(tz).diff(moment(last).tz(tz), 'days') > daysBetween) {
tail = head;
}
if (dayCount(longest, timezone) < dayCount([head, tail], timezone)) {
if (dayCount(longest, tz) < dayCount([head, tail], tz)) {
return [head, tail];
}
return longest;
}, [cals[0], cals[0]]);
return dayCount(longest, timezone);
return dayCount(longest, tz);
}

View File

@@ -12,5 +12,5 @@ block content
h4 100% Cotton. Unisex. $20 shipped.
h4 Only available until February 15.
h5 Are you outside the US? Ships from the EU &thinsp;
a(href='#') here
a(href='https://teespring.com/free-code-camp-t-shirt-eu-shop' target='_blank') here
| .

View File

@@ -3,6 +3,7 @@ import moment from 'moment-timezone';
import { dayCount } from '../../../server/utils/date-utils';
let test = require('tape');
const PST = 'America/Los_Angeles';
test('Day count between two epochs (inclusive) calculation', function (t) {
t.plan(7);
@@ -25,18 +26,18 @@ test('Day count between two epochs (inclusive) calculation', function (t) {
t.equal(dayCount([
moment.utc("8/4/2015 1:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 23:00", "M/D/YYYY H:mm").valueOf()
]), 2, "should return 2 days when the diff is less than 24h but days are different in default timezone UTC");
]), 2, "should return 2 days when the diff is less than 24h but days are different in UTC");
t.equal(dayCount([
moment.utc("8/4/2015 1:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 23:00", "M/D/YYYY H:mm").valueOf()
], 'America/Los_Angeles'), 1, "should return 1 day when the diff is less than 24h and days are different in UTC, but given 'America/Los_Angeles' timezone");
], PST), 1, "should return 1 day when the diff is less than 24h and days are different in UTC, but given PST");
t.equal(dayCount([
moment.utc("10/27/2015 1:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("5/12/1982 1:00", "M/D/YYYY H:mm").valueOf()
]), 12222, "should return correct count when there is very big period");
t.equal(dayCount([
moment.utc("8/4/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf()

View File

@@ -1,31 +1,78 @@
import moment from 'moment-timezone';
import sinon from 'sinon';
import { calcCurrentStreak, calcLongestStreak } from '../../../server/utils/user-stats';
import {
prepUniqueDays,
calcCurrentStreak,
calcLongestStreak
} from '../../../server/utils/user-stats';
let test = require('tape');
let clock = sinon.useFakeTimers(1454526000000); // setting now to 2016-02-03T11:00:00 (PST)
const PST = 'America/Los_Angeles';
test('Prepare calendar items', function (t) {
t.plan(5);
t.deepEqual(prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 14:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 20:00", "M/D/YYYY H:mm").valueOf()
]), [1438560000000], "should return correct epoch when all entries fall into one day in UTC");
t.deepEqual(prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf()
]), [1438560000000], "should return correct epoch when given two identical dates");
t.deepEqual(prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(), // 8/2/2015 in America/Los_Angeles
moment.utc("8/3/2015 14:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("8/3/2015 20:00", "M/D/YYYY H:mm").valueOf()
], PST), [1438498800000, 1438585200000], "should return 2 epochs when dates fall into two days in PST");
t.deepEqual(prepUniqueDays([
moment.utc("8/1/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("3/3/2015 14:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/30/2014 20:00", "M/D/YYYY H:mm").valueOf()
]), [1412035200000, 1425340800000, 1438387200000], "should return 3 epochs when dates fall into three days");
t.deepEqual(prepUniqueDays([
1438387200000, 1425340800000, 1412035200000
]), [1412035200000, 1425340800000, 1438387200000], "should return same but sorted array if all input dates are start of day");
});
test('Current streak calculation', function (t) {
t.plan(9);
t.equal(calcCurrentStreak([
t.plan(11);
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 1, "should return 1 day when today one challenge was completed");
])), 1, "should return 1 day when today one challenge was completed");
t.equal(calcCurrentStreak([
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'hours')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 1, "should return 1 day when today more than one challenge was completed");
])), 1, "should return 1 day when today more than one challenge was completed");
t.equal(calcCurrentStreak([
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf()
]), 0, "should return 0 day when today 0 challenges were completed");
])), 0, "should return 0 day when today 0 challenges were completed");
t.equal(calcCurrentStreak([
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 2, "should return 2 days when today and yesterday challenges were completed");
])), 2, "should return 2 days when today and yesterday challenges were completed");
t.equal(calcCurrentStreak([
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 1:00", "M/D/YYYY H:mm").valueOf(),
@@ -37,54 +84,81 @@ test('Current streak calculation', function (t) {
moment.utc(moment.utc().subtract(2, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 3, "should return 3 when today and for two days before user was activity");
])), 3, "should return 3 when today and for two days before user was activity");
t.equal(calcCurrentStreak([
moment.utc(moment.utc().subtract(37, 'hours')).valueOf(),
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(47, 'hours')).valueOf(),
moment.utc(moment.utc().subtract(11, 'hours')).valueOf()
])), 1, "should return 1 when there is 1.5 days long break and dates fall into two days separated by third");
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(40, 'hours')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 1, "should return 1 when between todays challenge completion and yesterdays there is a 1.5 day (36 hours) long break");
])), 2, "should return 2 when the break is more than 1.5 days but dates fall into two consecutive days");
t.ok(calcCurrentStreak([
moment.utc(moment.utc().subtract(35, 'hours')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]) >= 2, "should return not less than 2 days when between todays challenge completion and yesterdays there is less than 1.5 day (36 hours) long break");
t.equal(calcCurrentStreak([
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'hours')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
], undefined), 1, "should return correct count in default timezone UTC given 'undefined' timezone");
t.equal(calcCurrentStreak([
]), undefined), 1, "should return correct count in default timezone UTC given 'undefined' timezone");
t.equal(calcCurrentStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
], 'America/Los_Angeles'), 2, "should return 2 days when today and yesterday challenges were completed given 'America/Los_Angeles' timezone");
], PST), PST), 2, "should return 2 days when today and yesterday challenges were completed given PST");
t.equal(calcCurrentStreak(
prepUniqueDays([
1453174506164, 1453175436725, 1453252466853, 1453294968225, 1453383782844,
1453431903117, 1453471373080, 1453594733026, 1453645014058, 1453746762747,
1453747659197, 1453748029416, 1453818029213, 1453951796007, 1453988570615,
1454069704441, 1454203673979, 1454294055498, 1454333545125, 1454415163903,
1454519128123, moment.tz(PST).valueOf()
], PST), PST), 17, "should return 17 when there is no break in given timezone (but would be the break if in UTC)");
t.equal(calcCurrentStreak(
prepUniqueDays([
1453174506164, 1453175436725, 1453252466853, 1453294968225, 1453383782844,
1453431903117, 1453471373080, 1453594733026, 1453645014058, 1453746762747,
1453747659197, 1453748029416, 1453818029213, 1453951796007, 1453988570615,
1454069704441, 1454203673979, 1454294055498, 1454333545125, 1454415163903,
1454519128123, moment.utc().valueOf()
])), 4, "should return 4 when there is a break in UTC (but would be no break in PST)");
});
test('Longest streak calculation', function (t) {
t.plan(12);
t.plan(14);
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("9/12/2015 4:00", "M/D/YYYY H:mm").valueOf()
]), 1, "should return 1 when there is the only one one-day-long streak available");
])), 1, "should return 1 when there is the only one one-day-long streak available");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/13/2015 3:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/14/2015 1:00", "M/D/YYYY H:mm").valueOf()
]), 4, "should return 4 when there is the only one more-than-one-days-long streak available");
])), 4, "should return 4 when there is the only one more-than-one-days-long streak available");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 1, "should return 1 when there is only one one-day-long streak and it is today");
])), 1, "should return 1 when there is only one one-day-long streak and it is today");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
]), 2, "should return 2 when yesterday and today makes longest streak");
])), 2, "should return 2 when yesterday and today makes longest streak");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 2:00", "M/D/YYYY H:mm").valueOf(),
@@ -93,19 +167,21 @@ test('Longest streak calculation', function (t) {
moment.utc("10/6/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("10/7/2015 5:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("11/3/2015 2:00", "M/D/YYYY H:mm").valueOf()
]), 4, "should return 4 when there is a month long break");
])), 4, "should return 4 when there is a month long break");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 1:00", "M/D/YYYY H:mm").valueOf(),
moment.utc(moment.utc("9/12/2015 1:00", "M/D/YYYY H:mm").add(37, 'hours')).valueOf(),
moment.utc("9/12/2015 15:30", "M/D/YYYY H:mm").valueOf(),
moment.utc(moment.utc("9/12/2015 15:30", "M/D/YYYY H:mm").add(37, 'hours')).valueOf(),
moment.utc("9/14/2015 22:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/15/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("10/3/2015 2:00", "M/D/YYYY H:mm").valueOf()
]), 3, "should return 3 when there is a more than 1.5 days long break of (36 hours)");
])), 2, "should return 2 when there is a more than 1.5 days long break of (36 hours)");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 1:00", "M/D/YYYY H:mm").valueOf(),
@@ -117,9 +193,10 @@ test('Longest streak calculation', function (t) {
moment.utc(moment.utc().subtract(2, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'days')).valueOf(),
moment.utc().valueOf()
]), 4, "should return 4 when the longest streak consist of several same day timestamps");
])), 4, "should return 4 when the longest streak consist of several same day timestamps");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("8/3/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 1:00", "M/D/YYYY H:mm").valueOf(),
@@ -129,32 +206,57 @@ test('Longest streak calculation', function (t) {
moment.utc("10/12/2015 1:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("10/13/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("10/14/2015 5:00", "M/D/YYYY H:mm").valueOf()
]), 4, "should return 4 when there are several longest streaks (same length)");
])), 4, "should return 4 when there are several longest streaks (same length)");
let cals = [];
const n = 100;
for (var i = 0; i < n; i++) {
cals.push(moment.utc(moment.utc().subtract(i, 'days')).valueOf());
}
cals.sort();
t.equal(calcLongestStreak(cals), n, "should return correct longest streak when there is a very long period");
t.equal(calcLongestStreak(prepUniqueDays(cals)), n, "should return correct longest streak when there is a very long period");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc(moment.utc().subtract(1, 'days')).valueOf(),
moment.utc(moment.utc().subtract(1, 'hours')).valueOf()
], undefined), 2, "should return correct longest streak in default timezone UTC given 'undefined' timezone");
]), undefined), 2, "should return correct longest streak in default timezone UTC given 'undefined' timezone");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("9/11/2015 4:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/13/2015 3:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/14/2015 1:00", "M/D/YYYY H:mm").valueOf()
], 'America/Los_Angeles'), 4, "should return 4 when there is the only one more-than-one-days-long streak available given 'America/Los_Angeles' timezone");
]), PST), 4, "should return 4 when there is the only one more-than-one-days-long streak available given PST");
t.equal(calcLongestStreak([
t.equal(calcLongestStreak(
prepUniqueDays([
moment.utc("9/11/2015 23:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/12/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/13/2015 2:00", "M/D/YYYY H:mm").valueOf(),
moment.utc("9/14/2015 1:00", "M/D/YYYY H:mm").valueOf()
], 'America/Los_Angeles'), 3, "should return 3 when longest streak is 3 in given 'America/Los_Angeles' timezone (but would be different in default timezone UTC)");
moment.utc("9/14/2015 6:00", "M/D/YYYY H:mm").valueOf()
], PST), PST), 3, "should return 3 when longest streak is 3 in PST (but would be different in default timezone UTC)");
t.equal(calcLongestStreak(
prepUniqueDays([
1453174506164, 1453175436725, 1453252466853, 1453294968225, 1453383782844,
1453431903117, 1453471373080, 1453594733026, 1453645014058, 1453746762747,
1453747659197, 1453748029416, 1453818029213, 1453951796007, 1453988570615,
1454069704441, 1454203673979, 1454294055498, 1454333545125, 1454415163903,
1454519128123, moment.tz(PST).valueOf()
], PST), PST), 17, "should return 17 when there is no break in PST (but would be break in UTC) and it is current");
t.equal(calcLongestStreak(
prepUniqueDays([
1453174506164, 1453175436725, 1453252466853, 1453294968225, 1453383782844,
1453431903117, 1453471373080, 1453594733026, 1453645014058, 1453746762747,
1453747659197, 1453748029416, 1453818029213, 1453951796007, 1453988570615,
1454069704441, 1454203673979, 1454294055498, 1454333545125, 1454415163903,
1454519128123, moment.utc().valueOf()
])), 4, "should return 4 when there is a break in UTC (but no break in PST)");
});
test.onFinish(() => {
clock.restore();
});