UNPKG

@villedemontreal/general-utils

Version:
333 lines 16.9 kB
"use strict"; 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