mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
* Fix #8585 - Add shouldDo CDS and timezone variation test suite * Fix #8585 - resolve feedback
This commit is contained in:
committed by
Keith Holliday
parent
4f305bd505
commit
4bbebdd237
@@ -7,6 +7,7 @@ describe('shouldDo', () => {
|
|||||||
let options = {};
|
let options = {};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
options = {};
|
||||||
day = new Date();
|
day = new Date();
|
||||||
dailyTask = {
|
dailyTask = {
|
||||||
completed: 'false',
|
completed: 'false',
|
||||||
@@ -38,6 +39,164 @@ describe('shouldDo', () => {
|
|||||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context('Timezone variations', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
dailyTask.frequency = 'daily';
|
||||||
|
});
|
||||||
|
|
||||||
|
context('User timezone is UTC', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.timezoneOffset = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if Start Date is before today', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if Start Date is today', () => {
|
||||||
|
dailyTask.startDate = moment().toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('User timezone is between UTC-12 and UTC (0~720)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.timezoneOffset = 600;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if Start Date is before today', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if Start Date is today', () => {
|
||||||
|
dailyTask.startDate = moment().startOf('day').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if the user\'s current time is after start date and CDS', () => {
|
||||||
|
options.dayStart = 4;
|
||||||
|
day = moment().utcOffset(options.timezoneOffset).startOf('day').add(6, 'hours').toDate();
|
||||||
|
dailyTask.startDate = moment().utcOffset(options.timezoneOffset).subtract(1, 'day').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false if the user\'s current time is before CDS', () => {
|
||||||
|
options.dayStart = 8;
|
||||||
|
day = moment().utcOffset(options.timezoneOffset).startOf('day').add(2, 'hours').toDate();
|
||||||
|
dailyTask.startDate = moment().utcOffset(options.timezoneOffset).startOf('day').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('User timezone is between UTC and GMT+14 (-840~0)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.timezoneOffset = -420;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if Start Date is before today', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if Start Date is today', () => {
|
||||||
|
dailyTask.startDate = moment().startOf('day').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if the user\'s current time is after CDS', () => {
|
||||||
|
options.dayStart = 4;
|
||||||
|
day = moment().utcOffset(options.timezoneOffset).startOf('day').add(6, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false if the user\'s current time is before CDS', () => {
|
||||||
|
options.dayStart = 8;
|
||||||
|
day = moment().utcOffset(options.timezoneOffset).startOf('day').add(2, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('CDS variations', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Daily is due every 2 days, and start today
|
||||||
|
dailyTask.frequency = 'daily';
|
||||||
|
dailyTask.everyX = 2;
|
||||||
|
dailyTask.startDate = new Date();
|
||||||
|
});
|
||||||
|
|
||||||
|
context('CDS is midnight (Default dayStart=0)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.dayStart = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is yesterday', () => {
|
||||||
|
it('should not be due yesterday', () => {
|
||||||
|
day = moment(day).subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is today', () => {
|
||||||
|
it('returns false if current time is before midnight', () => {
|
||||||
|
day = moment(day).startOf('day').subtract(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if current time is after midnight', () => {
|
||||||
|
day = moment(day).startOf('day').add(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is tomorrow', () => {
|
||||||
|
it('should not be due tomorrow', () => {
|
||||||
|
day = moment(day).add(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('CDS is 0 <= n < 24', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.dayStart = 7;
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is yesterday', () => {
|
||||||
|
it('should not be due yesterday', () => {
|
||||||
|
day = moment(day).subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is today', () => {
|
||||||
|
it('returns false if current hour is before CDS', () => {
|
||||||
|
day = moment(day).startOf('day').add(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if current hour is after CDS', () => {
|
||||||
|
day = moment(day).startOf('day').add(9, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is tomorrow', () => {
|
||||||
|
it('returns true if current hour is before CDS', () => {
|
||||||
|
day = moment(day).endOf('day').add(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false if current hour is after CDS', () => {
|
||||||
|
day = moment(day).endOf('day').add(9, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
context('Every X Days', () => {
|
context('Every X Days', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dailyTask.frequency = 'daily';
|
dailyTask.frequency = 'daily';
|
||||||
@@ -56,7 +215,14 @@ describe('shouldDo', () => {
|
|||||||
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true on multiples of x', () => {
|
it('returns true on the Start Date', () => {
|
||||||
|
dailyTask.startDate = moment().toDate();
|
||||||
|
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
context('On multiples of x', () => {
|
||||||
|
it('returns true when CDS is midnight', () => {
|
||||||
dailyTask.startDate = moment().subtract(7, 'days').toDate();
|
dailyTask.startDate = moment().subtract(7, 'days').toDate();
|
||||||
dailyTask.everyX = 7;
|
dailyTask.everyX = 7;
|
||||||
|
|
||||||
@@ -68,6 +234,56 @@ describe('shouldDo', () => {
|
|||||||
day = moment(day).add(7, 'days');
|
day = moment(day).add(7, 'days');
|
||||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns true when current time is after CDS', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(5, 'days').toDate();
|
||||||
|
dailyTask.everyX = 5;
|
||||||
|
|
||||||
|
options.dayStart = 3;
|
||||||
|
day = moment(day).startOf('day').add(8, 'hours').toDate();
|
||||||
|
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when current time is before CDS', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(5, 'days').toDate();
|
||||||
|
dailyTask.everyX = 5;
|
||||||
|
|
||||||
|
options.dayStart = 14;
|
||||||
|
day = moment(day).startOf('day').add(7, 'hours').toDate();
|
||||||
|
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('If number of X days is zero', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
dailyTask.everyX = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false on the Start Date', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(4, 'days').toDate();
|
||||||
|
day = moment().subtract(4, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false on the day before Start Date', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(4, 'days').toDate();
|
||||||
|
day = moment().subtract(5, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false on the day after Start Date', () => {
|
||||||
|
dailyTask.startDate = moment().subtract(4, 'days').toDate();
|
||||||
|
day = moment().subtract(3, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for today', () => {
|
||||||
|
dailyTask.startDate = moment().toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('Certain Days of the Week', () => {
|
context('Certain Days of the Week', () => {
|
||||||
@@ -134,6 +350,135 @@ describe('shouldDo', () => {
|
|||||||
it('returns true if Daily on matching days of the week', () => {
|
it('returns true if Daily on matching days of the week', () => {
|
||||||
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context('Day of the week matches', () => {
|
||||||
|
const weekdayMap = {
|
||||||
|
1: 'm',
|
||||||
|
2: 't',
|
||||||
|
3: 'w',
|
||||||
|
4: 'th',
|
||||||
|
5: 'f',
|
||||||
|
6: 's',
|
||||||
|
7: 'su',
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Set repeat day to current weekday
|
||||||
|
const currentWeekday = moment().isoWeekday();
|
||||||
|
dailyTask.startDate = moment().startOf('day').toDate();
|
||||||
|
dailyTask.repeat = {
|
||||||
|
su: false,
|
||||||
|
s: false,
|
||||||
|
f: false,
|
||||||
|
th: false,
|
||||||
|
w: false,
|
||||||
|
t: false,
|
||||||
|
m: false,
|
||||||
|
};
|
||||||
|
dailyTask.repeat[weekdayMap[currentWeekday]] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
context('CDS is midnight (Default dayStart=0)', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.dayStart = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is one day before the matching day', () => {
|
||||||
|
it('should return false', () => {
|
||||||
|
day = moment(day).subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is on the matching day', () => {
|
||||||
|
it('returns false if current time is before midnight', () => {
|
||||||
|
day = moment(day).startOf('day').subtract(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if current time is after midnight', () => {
|
||||||
|
day = moment(day).startOf('day').add(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is one day after the matching day', () => {
|
||||||
|
it('should not be due tomorrow', () => {
|
||||||
|
day = moment(day).add(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('CDS is 0 <= n < 24', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
options.dayStart = 7;
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is one day before the matching day', () => {
|
||||||
|
it('should not be due', () => {
|
||||||
|
day = moment(day).subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is on the matching day', () => {
|
||||||
|
it('returns false if current hour is before CDS', () => {
|
||||||
|
day = moment(day).startOf('day').add(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true if current hour is after CDS', () => {
|
||||||
|
day = moment(day).startOf('day').add(9, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('Current Date is one day after the matching day', () => {
|
||||||
|
it('returns true if current hour is before CDS', () => {
|
||||||
|
day = moment(day).endOf('day').add(1, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false if current hour is after CDS', () => {
|
||||||
|
day = moment(day).endOf('day').add(9, 'hours').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context('No days of the week is selected', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
dailyTask.repeat = {
|
||||||
|
su: false,
|
||||||
|
s: false,
|
||||||
|
f: false,
|
||||||
|
th: false,
|
||||||
|
w: false,
|
||||||
|
t: false,
|
||||||
|
m: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for a day before the Start Date', () => {
|
||||||
|
day = moment().subtract(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for the Start Date', () => {
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for a day after the Start Date', () => {
|
||||||
|
day = moment().add(1, 'days').toDate();
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for today', () => {
|
||||||
|
expect(shouldDo(day, dailyTask, options)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// context('Every X Weeks', () => {
|
// context('Every X Weeks', () => {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function sanitizeOptions (o) {
|
|||||||
let dayStart = !_.isNaN(ref) && ref >= 0 && ref <= 24 ? ref : 0;
|
let dayStart = !_.isNaN(ref) && ref >= 0 && ref <= 24 ? ref : 0;
|
||||||
|
|
||||||
let timezoneOffset;
|
let timezoneOffset;
|
||||||
let timezoneOffsetDefault = Number(moment().zone());
|
let timezoneOffsetDefault = Number(moment().utcOffset());
|
||||||
if (_.isFinite(o.timezoneOffsetOverride)) {
|
if (_.isFinite(o.timezoneOffsetOverride)) {
|
||||||
timezoneOffset = Number(o.timezoneOffsetOverride);
|
timezoneOffset = Number(o.timezoneOffsetOverride);
|
||||||
} else if (_.isFinite(o.timezoneOffset)) {
|
} else if (_.isFinite(o.timezoneOffset)) {
|
||||||
@@ -41,7 +41,7 @@ function sanitizeOptions (o) {
|
|||||||
timezoneOffset = timezoneOffsetDefault;
|
timezoneOffset = timezoneOffsetDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = o.now ? moment(o.now).zone(timezoneOffset) : moment().zone(timezoneOffset);
|
let now = o.now ? moment(o.now).utcOffset(timezoneOffset) : moment().utcOffset(timezoneOffset);
|
||||||
|
|
||||||
// return a new object, we don't want to add "now" to user object
|
// return a new object, we don't want to add "now" to user object
|
||||||
return {
|
return {
|
||||||
@@ -98,7 +98,7 @@ export function shouldDo (day, dailyTask, options = {}) {
|
|||||||
// The time portion of the Start Date is never visible to or modifiable by the user so we must ignore it.
|
// The time portion of the Start Date is never visible to or modifiable by the user so we must ignore it.
|
||||||
// Therefore, we must also ignore the time portion of the user's day start (startOfDayWithCDSTime), otherwise the date comparison will be wrong for some times.
|
// Therefore, we must also ignore the time portion of the user's day start (startOfDayWithCDSTime), otherwise the date comparison will be wrong for some times.
|
||||||
// NB: The user's day start date has already been converted to the PREVIOUS day's date if the time portion was before CDS.
|
// NB: The user's day start date has already been converted to the PREVIOUS day's date if the time portion was before CDS.
|
||||||
let taskStartDate = moment(dailyTask.startDate).zone(o.timezoneOffset);
|
let taskStartDate = moment(dailyTask.startDate).utcOffset(o.timezoneOffset);
|
||||||
|
|
||||||
taskStartDate = moment(taskStartDate).startOf('day');
|
taskStartDate = moment(taskStartDate).startOf('day');
|
||||||
if (taskStartDate > startOfDayWithCDSTime.startOf('day')) {
|
if (taskStartDate > startOfDayWithCDSTime.startOf('day')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user