@villedemontreal/general-utils
Version:
General utilities library
333 lines • 16.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const _ = require("lodash");
const moment = require("moment");
const _1 = require(".");
const collectionUtils_1 = require("./collectionUtils");
const dateUtils_1 = require("./dateUtils");
const VALID_DATE_UTC_REPRESENTATION = '2018-07-31T12:34:56.789Z';
const VALID_DATE = new Date(VALID_DATE_UTC_REPRESENTATION);
// tslint:disable:max-func-body-length
describe('Date Utility', () => {
describe('#isDateBetween', () => {
it('should support open ranges', () => {
chai_1.assert.isTrue((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', ['2018-01-01T12:34:56', undefined]));
chai_1.assert.isTrue((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', ['2018-01-01T12:34:56', null]));
chai_1.assert.isFalse((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', ['2018-01-01T12:34:56.123', undefined]));
chai_1.assert.isFalse((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', ['2018-01-01T12:34:56.123', null]));
chai_1.assert.isTrue((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', [undefined, '2018-01-01T12:34:56']));
chai_1.assert.isTrue((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', [null, '2018-01-01T12:34:56']));
chai_1.assert.isFalse((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', [undefined, '2018-01-01T12:34:55.999']));
chai_1.assert.isFalse((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', [null, '2018-01-01T12:34:55.999']));
chai_1.assert.isTrue((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', [undefined, undefined]));
chai_1.assert.isTrue((0, dateUtils_1.isDateBetween)('2018-01-01T12:34:56', [null, null]));
});
});
describe('#isDateCompatible', () => {
const dateRepr = '2018-09-12T21:45:12.243Z';
const dateValues = [dateRepr, new Date(dateRepr), moment(dateRepr)];
(0, collectionUtils_1.getCartesianProduct)(dateValues, dateValues).forEach((dateParameters) => {
const parameter1 = dateParameters[0];
const parameter2 = dateParameters[1];
const parameter1TypeName = parameter1.constructor.name;
const parameter2TypeName = parameter2.constructor.name;
it(`should support \`${parameter1TypeName}\` & \`${parameter2TypeName}\` parameters`, () => {
chai_1.assert.isTrue((0, dateUtils_1.isDateCompatible)(parameter1, parameter2));
});
});
const date1Repr = '2018-09-12T12:34:56.789Z';
const date1Values = [date1Repr, new Date(date1Repr), moment(date1Repr)];
const date2Repr = '2018-09-12T21:45:12.243Z';
const date2Values = [date2Repr, new Date(date2Repr), moment(date2Repr)];
(0, collectionUtils_1.getCartesianProduct)(date1Values, date2Values).forEach((dateRangeParameter) => {
const dateRangeLowBoundary = dateRangeParameter[0];
const dateRangeHighBoundary = dateRangeParameter[1];
const dateRangeLowBoundaryTypeName = dateRangeLowBoundary.constructor.name;
const dateRangeHighBoundaryTypeName = dateRangeHighBoundary.constructor.name;
dateValues.forEach((dateValue) => {
const dateValueParameterType = dateValue.constructor.name;
it(`should support \`${dateValueParameterType}\` & [\`${dateRangeLowBoundaryTypeName}\`:\`${dateRangeHighBoundaryTypeName}\`] parameters`, () => {
chai_1.assert.isTrue((0, dateUtils_1.isDateCompatible)(dateValue, dateRangeParameter));
});
});
});
});
const INVALID_DATE_VALUES = [
undefined,
null,
true,
false,
123,
NaN,
'pouet',
_.noop,
/^$/,
{},
[],
];
const VALID_DATE_VALUES = [
new Date(2018, 7, 31, 23, 59, 59, 999),
new Date(2019, 0, 1, 0, 0, 0, 0),
];
describe('#isDate', () => {
INVALID_DATE_VALUES.forEach((value) => {
const valueDescription = (0, _1.getValueDescriptionWithType)(value);
it(`should return \`false\` for ${valueDescription}`, () => {
chai_1.assert.isFalse(_1.utils.isValidDate(value));
});
});
VALID_DATE_VALUES.forEach((value) => {
const valueDescription = (0, _1.getValueDescription)(value);
it(`should return \`true\` for ${valueDescription}`, () => {
chai_1.assert.isTrue(_1.utils.isValidDate(value));
});
});
});
const INVALID_DATE_RANGE_VALUES = (0, collectionUtils_1.getCartesianProduct)(INVALID_DATE_VALUES, INVALID_DATE_VALUES);
const VALID_DATE_RANGE_VALUES = (0, collectionUtils_1.getCartesianProduct)(VALID_DATE_VALUES, VALID_DATE_VALUES);
// Append open ranges in valid date range values:
VALID_DATE_VALUES.forEach((date) => {
VALID_DATE_RANGE_VALUES.push([date, null]);
VALID_DATE_RANGE_VALUES.push([null, date]);
});
// Append 3-value items into the invalid date range values:
VALID_DATE_RANGE_VALUES.forEach((dateRange) => INVALID_DATE_RANGE_VALUES.push(dateRange.concat(null)));
describe('#isDateRange', () => {
INVALID_DATE_RANGE_VALUES.forEach((value) => {
const valueDescription = value.map((item) => (0, _1.getValueDescriptionWithType)(item));
it(`should return \`false\` for [${valueDescription}]`, () => {
chai_1.assert.isFalse((0, dateUtils_1.isDateRange)(value));
});
});
VALID_DATE_RANGE_VALUES.forEach((value) => {
const valueDescription = (0, _1.getValueDescription)(value);
it(`should return \`true\` for ${valueDescription}`, () => {
chai_1.assert.isTrue((0, dateUtils_1.isDateRange)(value));
});
});
});
describe('#getSafeDate', () => {
// Cf. http://momentjs.com/docs/#/parsing/string/
const expectations = {
'2018-12-07T12:34:56.789': new Date(Date.UTC(2018, 11, 7, 12, 34, 56, 789)),
'20181207T123456.789': new Date(Date.UTC(2018, 11, 7, 12, 34, 56, 789)),
'2018-12-07': new Date(Date.UTC(2018, 11, 7, 0, 0, 0, 0)),
};
_.forEach(expectations, (expectedResult, value) => {
const valueDescription = (0, _1.getValueDescription)(value);
it(`should support ${valueDescription}`, () => {
chai_1.assert.deepEqual((0, dateUtils_1.getSafeDate)(value), expectedResult);
});
});
const expectedlyFailingValues = [null, undefined, 'true', 'false', '???'];
expectedlyFailingValues.forEach((value) => {
const valueDescription = (0, _1.getValueDescription)(value);
it(`should fail with ${valueDescription}`, () => {
let failed = false;
try {
(0, dateUtils_1.getSafeDate)(value);
}
catch (error) {
failed = true;
}
chai_1.assert.isTrue(failed);
});
});
});
describe('#getSafeDateRange', () => {
const expectations = new Map();
expectations.set([VALID_DATE_UTC_REPRESENTATION, undefined], [VALID_DATE, undefined]);
expectations.set([null, VALID_DATE_UTC_REPRESENTATION], [null, VALID_DATE]);
expectations.set([undefined, null], [undefined, null]);
expectations.set([VALID_DATE_UTC_REPRESENTATION, VALID_DATE], [VALID_DATE, VALID_DATE]);
expectations.set([VALID_DATE, VALID_DATE], [VALID_DATE, VALID_DATE]);
for (const entry of expectations) {
const value = entry[0];
const expectedResult = entry[1];
const valueDescription = `[${(0, _1.getValueDescriptionWithType)(value[0])}, ${(0, _1.getValueDescriptionWithType)(value[1])}]`;
it(`should support ${valueDescription}`, () => {
chai_1.assert.deepEqual((0, dateUtils_1.getSafeDateRange)(value), expectedResult);
});
}
});
describe('#parseDate', () => {
it('should parse date representations properly', () => {
chai_1.assert.deepStrictEqual((0, dateUtils_1.parseDate)(VALID_DATE_UTC_REPRESENTATION), VALID_DATE);
chai_1.assert.deepStrictEqual((0, dateUtils_1.parseDate)(VALID_DATE_UTC_REPRESENTATION, dateUtils_1.DEFAULT_DATE_FORMAT), VALID_DATE);
const FUNKY_FORMAT = 'YYYY/MM/DD@HH:mm:ss.SSS';
let result = (0, dateUtils_1.parseDate)('2018/07/31@12:34:56.789', [FUNKY_FORMAT]);
chai_1.assert.deepStrictEqual(result.getDate(), VALID_DATE.getDate());
result = (0, dateUtils_1.parseDate)('2018/07/31@12:34:56.789', [dateUtils_1.DEFAULT_DATE_FORMAT, FUNKY_FORMAT]);
chai_1.assert.deepStrictEqual(result.getDate(), VALID_DATE.getDate());
});
});
describe('#formatDate', () => {
it('should format dates properly', () => {
chai_1.assert.equal((0, dateUtils_1.formatUtcDate)(VALID_DATE), VALID_DATE_UTC_REPRESENTATION);
});
});
describe('ISO_DATE_PATTERN', () => {
const expectations = {
'2018-07-31': ['2018-07-31', '-', undefined, undefined, undefined, undefined],
'20180731': ['20180731', '', undefined, undefined, undefined, undefined],
'2018-07-31 00:00:59': ['2018-07-31', '-', '00:00:59', ':', undefined, undefined],
'2018-07-31T00:59:59': ['2018-07-31', '-', '00:59:59', ':', undefined, undefined],
'2018-07-31 23:59:59': ['2018-07-31', '-', '23:59:59', ':', undefined, undefined],
'2018-07-31T12:34:56.789+06': ['2018-07-31', '-', '12:34:56', ':', '789', '+06'],
'2018-07-31T12:34:56.789+10:11': ['2018-07-31', '-', '12:34:56', ':', '789', '+10:11'],
'20180731T123456,789+1011': ['20180731', '', '123456', '', '789', '+1011'],
'20180731 123456,789-1011': ['20180731', '', '123456', '', '789', '-1011'],
'20180731T123456,789+10:11': ['20180731', '', '123456', '', '789', '+10:11'],
'20180731 12:34:56,789-1011': ['20180731', '', '12:34:56', ':', '789', '-1011'],
'2018-07-31 12:34:56.789Z': ['2018-07-31', '-', '12:34:56', ':', '789', 'Z'],
};
_.forEach(expectations, (expectation, value) => {
it(`should match « ${value} »`, () => {
chai_1.assert.deepEqual(dateUtils_1.ISO_DATE_PATTERN.exec(value).slice(1), expectation);
chai_1.assert.isTrue((0, dateUtils_1.isValidIso8601Date)(value));
});
});
const invalidDateValues = [
'201807-31', // mismatching date separator
'2018/07/31', // bad date separator
'2018-07-31T1234:56', // mismatching time separator
'20180731123456', // missing date-time separator
'2018-13-31', // month overflow
'2018-07-32', // day overflow
'2018-07-31 24:00:00', // hour overflow
'2018-07-31 00:60:00', // minute overflow
'2018-07-31 00:00:60', // second overflow
'2018-07-31 12', // incomplete time representation
'2018-07-31 12:34', // incomplete time representation
'2018-07-31T12:34:56789', // bad second format
'20180731 123456 789', // bad split second separator
'2018-07-31 12:34:56.', // bad split second format
'2018-07-31 12:34:56.7', // bad split second format
'2018-07-31 12:34:56.78', // bad split second format
'2018-07-31 01:23:45.6789', // bad split second format
'20180731T123456.7891011', // missing time-offset separator
'2018-07-31 01:23:45.678+1', // bad offset format
'2018-07-31 12:34:56.789+1011Z', // bad offset format
'2018-07-31 01:23:45.678+2400', // offset overflow
];
invalidDateValues.forEach((value) => {
it(`should *NOT* match « ${value} »`, () => {
chai_1.assert.isNull(dateUtils_1.ISO_DATE_PATTERN.exec(value));
chai_1.assert.isFalse((0, dateUtils_1.isValidIso8601Date)(value));
});
});
});
describe('#endOfDay', () => {
it('Nil', () => {
let result = (0, dateUtils_1.endOfDay)(null);
chai_1.assert.deepEqual(result, null);
result = (0, dateUtils_1.endOfDay)(undefined);
chai_1.assert.deepEqual(result, undefined);
});
it('Invalid', () => {
let error;
try {
(0, dateUtils_1.endOfDay)(``);
}
catch (err) {
error = err;
}
if (!error) {
chai_1.assert.fail();
}
try {
(0, dateUtils_1.endOfDay)(`nope`);
}
catch (err) {
error = err;
}
if (!error) {
chai_1.assert.fail();
}
});
it('As a date - UTC', () => {
const testDate = new Date(`2017-11-02T02:07:11.123Z`);
const result = (0, dateUtils_1.endOfDay)(testDate, 'UTC');
chai_1.assert.deepEqual(result.toISOString(), `2017-11-02T23:59:59.999Z`);
});
// ==========================================
// This test shows how timezone sensitive is the
// `endOfDay()` function!
// The specified date is "2017-11-02T02:07:11" but
// *UTC*. If we are in a timezone with a current offset.
// like "-4" (Montreal is -4 or -5, depending of if
// we are Daylight Time or not), then the local
// date is actually "2017-11-01T22:07:11"...
//
// When calling `endOfDay()` we need to tell it in
// which timezone we want the computation to be made
// otherwise it will use the timezone local to the
// server. If the server runs on a "UTC" timezone,
// the end of the day will be "2017-11-02T23:59:59".
// But on a "UTC-4" timezone, the end of the day would
// actually be "2017-11-01T23:59:59"!
//
// Because of this, we can't have reliable tests
// using "America/Monteal" as the timezone, because
// this timezone can be either "UTC-4" or "UTC-5".
// Tests using such timezone may succeed one day
// and fail the other!
// ==========================================
it('As a date - UTC-4', () => {
const testDate = new Date(`2017-11-02T02:07:11.123Z`);
const result = (0, dateUtils_1.endOfDay)(testDate, 'UTC-4');
chai_1.assert.deepEqual(result.toISOString(), `2017-11-02T03:59:59.999Z`);
});
it('As a string', () => {
const date = `2017-11-02T02:07:11.123Z`;
const result = (0, dateUtils_1.endOfDay)(date, 'UTC');
chai_1.assert.deepEqual(result.toISOString(), `2017-11-02T23:59:59.999Z`);
});
});
describe('#startOfDay', () => {
it('Nil', () => {
let result = (0, dateUtils_1.startOfDay)(null);
chai_1.assert.deepEqual(result, null);
result = (0, dateUtils_1.startOfDay)(undefined);
chai_1.assert.deepEqual(result, undefined);
});
it('Invalid', () => {
let error;
try {
(0, dateUtils_1.startOfDay)(``);
}
catch (err) {
error = err;
}
if (!error) {
chai_1.assert.fail();
}
try {
(0, dateUtils_1.startOfDay)(`nope`);
}
catch (err) {
error = err;
}
if (!error) {
chai_1.assert.fail();
}
});
it('As a date - UTC', () => {
const date = new Date(`2017-11-02T02:07:11.123Z`);
const result = (0, dateUtils_1.startOfDay)(date, 'UTC');
chai_1.assert.deepEqual(result.toISOString(), `2017-11-02T00:00:00.000Z`);
});
it('As a date - UTC-4', () => {
const testDate = new Date(`2017-11-02T02:07:11.123Z`);
const result = (0, dateUtils_1.startOfDay)(testDate, 'UTC-4');
chai_1.assert.deepEqual(result.toISOString(), `2017-11-01T04:00:00.000Z`);
});
it('As a string', () => {
const date = `2017-11-02T02:07:11.123Z`;
const result = (0, dateUtils_1.startOfDay)(date, 'UTC');
chai_1.assert.deepEqual(result.toISOString(), `2017-11-02T00:00:00.000Z`);
});
});
});
//# sourceMappingURL=dateUtils.test.js.map