diff --git a/src/scalars/iso-date/DateTime.ts b/src/scalars/iso-date/DateTime.ts index 83ae0c5cc..9e1dcc812 100644 --- a/src/scalars/iso-date/DateTime.ts +++ b/src/scalars/iso-date/DateTime.ts @@ -10,32 +10,37 @@ import { GraphQLScalarType, Kind } from 'graphql'; import type { GraphQLScalarTypeConfig } from 'graphql'; // eslint-disable-line import { validateJSDate, validateDateTime } from './validator.js'; -import { parseDateTime } from './formatter.js'; +import { + serializeDateTime, + serializeDateTimeString, + serializeTimestamp, + parseDateTime, +} from './formatter.js'; import { createGraphQLError } from '../../error.js'; -export const GraphQLDateTimeConfig: GraphQLScalarTypeConfig = /*#__PURE__*/ { +export const GraphQLDateTimeConfig: GraphQLScalarTypeConfig = /*#__PURE__*/ { name: 'DateTime', description: - 'A date-time string at UTC, such as 2007-12-03T10:15:30Z, ' + + 'A date-time string at UTC, such as 2007-12-03T10:15:30.123Z, ' + 'compliant with the `date-time` format outlined in section 5.6 of ' + 'the RFC 3339 profile of the ISO 8601 standard for representation ' + 'of dates and times using the Gregorian calendar.', serialize(value) { if (value instanceof Date) { if (validateJSDate(value)) { - return value; + return serializeDateTime(value); } throw createGraphQLError('DateTime cannot represent an invalid Date instance'); } else if (typeof value === 'string') { if (validateDateTime(value)) { - return parseDateTime(value); + return serializeDateTimeString(value); } throw createGraphQLError(`DateTime cannot represent an invalid date-time-string ${value}.`); } else if (typeof value === 'number') { try { - return new Date(value); + return serializeTimestamp(value); } catch (e) { - throw createGraphQLError('DateTime cannot represent an invalid Unix timestamp ' + value); + throw createGraphQLError('DateTime cannot represent an invalid timestamp ' + value); } } else { throw createGraphQLError( @@ -88,7 +93,7 @@ export const GraphQLDateTimeConfig: GraphQLScalarTypeConfig = /*#__P * * Output: * This scalar serializes javascript Dates, - * RFC 3339 date-time strings and unix timestamps + * RFC 3339 date-time strings and ECMAScript timestamps (number of milliseconds) * to RFC 3339 UTC date-time strings. */ export const GraphQLDateTime: GraphQLScalarType = /*#__PURE__*/ new GraphQLScalarType(GraphQLDateTimeConfig); diff --git a/src/scalars/iso-date/formatter.ts b/src/scalars/iso-date/formatter.ts index 03fd144b1..0180c93a2 100644 --- a/src/scalars/iso-date/formatter.ts +++ b/src/scalars/iso-date/formatter.ts @@ -88,12 +88,18 @@ export const parseDateTime = (dateTime: string): Date => { return new Date(dateTime); }; +// Serializes a Date into an RFC 3339 compliant date-time-string +// in the format YYYY-MM-DDThh:mm:ss.sssZ. +export const serializeDateTime = (dateTime: Date): string => { + return dateTime.toISOString(); +}; + // Serializes an RFC 3339 compliant date-time-string by shifting // it to UTC. -export const serializeDateTimeString = (dateTime: string): Date => { +export const serializeDateTimeString = (dateTime: string): string => { // If already formatted to UTC then return the time string if (dateTime.indexOf('Z') !== -1) { - return new Date(dateTime); + return dateTime; } else { // These are time-strings with timezone information, // these need to be shifted to UTC. @@ -112,7 +118,7 @@ export const serializeDateTimeString = (dateTime: string): Date => { // The date-time-string has no fractional part, // so we remove it from the dateTimeUTC variable. dateTimeUTC = dateTimeUTC.replace(regexFracSec, ''); - return new Date(dateTimeUTC); + return dateTimeUTC; } else { // These are datetime-string with fractional seconds. // Make sure that we inject the fractional @@ -120,7 +126,13 @@ export const serializeDateTimeString = (dateTime: string): Date => { // has millisecond precision, we may want more or less // depending on the string that was passed. dateTimeUTC = dateTimeUTC.replace(regexFracSec, fractionalPart[0]); - return new Date(dateTimeUTC); + return dateTimeUTC; } } }; + +// Serializes ECMAScript timestamp (number of milliseconds) to an RFC 3339 compliant date-time-string +// in the format YYYY-MM-DDThh:mm:ss.sssZ +export const serializeTimestamp = (timestamp: number): string => { + return new Date(timestamp).toISOString(); +}; diff --git a/src/scalars/iso-date/validator.ts b/src/scalars/iso-date/validator.ts index bb4b66c74..763a8129a 100644 --- a/src/scalars/iso-date/validator.ts +++ b/src/scalars/iso-date/validator.ts @@ -140,17 +140,22 @@ export const validateDateTime = (dateTimeString: string): boolean => { }; // Function that checks whether a given number is a valid -// Unix timestamp. +// ECMAScript timestamp. // -// Unix timestamps are signed 32-bit integers. They are interpreted -// as the number of seconds since 00:00:00 UTC on 1 January 1970. +// ECMAScript are interpreted as the number of milliseconds +// since 00:00:00 UTC on 1 January 1970. // -export const validateUnixTimestamp = (timestamp: number): boolean => { - const MAX_INT = 2147483647; - const MIN_INT = -2147483648; - return ( - timestamp === timestamp && timestamp <= MAX_INT && timestamp >= MIN_INT - ); // eslint-disable-line +// It is defined in ECMA-262 that a maximum of ±100,000,000 days relative to +// January 1, 1970 UTC (that is, April 20, 271821 BCE ~ September 13, 275760 CE) +// can be represented by the standard Date object +// (equivalent to ±8,640,000,000,000,000 milliseconds). +// +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#the_ecmascript_epoch_and_timestamps +// +export const validateTimestamp = (timestamp: number): boolean => { + const MAX = 8640000000000000; + const MIN = -8640000000000000; + return timestamp === timestamp && timestamp <= MAX && timestamp >= MIN; // eslint-disable-line }; // Function that checks whether a javascript Date instance diff --git a/tests/iso-date/DateTime.integration.test.ts b/tests/iso-date/DateTime.integration.test.ts index 6e73208d0..f92951b73 100644 --- a/tests/iso-date/DateTime.integration.test.ts +++ b/tests/iso-date/DateTime.integration.test.ts @@ -26,7 +26,7 @@ const schema = new GraphQLSchema({ type: GraphQLDateTime, resolve: () => '2016-02-01T00:00:00-11:00', }, - validUnixTimestamp: { + validTimestamp: { type: GraphQLDateTime, resolve: () => 854325678000, }, @@ -38,6 +38,10 @@ const schema = new GraphQLSchema({ type: GraphQLDateTime, resolve: () => new Date('wrong'), }, + invalidTimestamp: { + type: GraphQLDateTime, + resolve: () => Number.POSITIVE_INFINITY, + }, invalidType: { type: GraphQLDateTime, resolve: () => [], @@ -61,7 +65,7 @@ it('executes a query that includes a DateTime', async () => { validDate validUTCDateString validDateString - validUnixTimestamp + validTimestamp input(date: $date) inputNull: input } @@ -73,11 +77,11 @@ it('executes a query that includes a DateTime', async () => { expect(response).toEqual({ data: { - validDate: new Date('2016-05-02T10:31:42.200Z'), - validUTCDateString: new Date('1991-12-24T00:00:00Z'), - validDateString: new Date('2016-02-01T11:00:00Z'), - input: new Date('2017-10-01T00:00:00.000Z'), - validUnixTimestamp: new Date('1997-01-27T00:41:18.000Z'), + validDate: '2016-05-02T10:31:42.200Z', + validUTCDateString: '1991-12-24T00:00:00Z', + validDateString: '2016-02-01T11:00:00Z', + input: '2017-10-01T00:00:00.000Z', + validTimestamp: '1997-01-27T00:41:18.000Z', inputNull: null, }, }); @@ -96,7 +100,7 @@ it('shifts an input date-time to UTC', async () => { expect(response).toEqual({ data: { - input: new Date('2016-02-01T11:00:00.000Z'), + input: '2016-02-01T11:00:00.000Z', }, }); }); @@ -141,6 +145,7 @@ it('errors if an invalid date-time is returned from the resolver', async () => { { invalidDateString invalidDate + invalidTimestamp invalidType } `; @@ -152,11 +157,13 @@ it('errors if an invalid date-time is returned from the resolver', async () => { "data": { "invalidDate": null, "invalidDateString": null, + "invalidTimestamp": null, "invalidType": null, }, "errors": [ [GraphQLError: DateTime cannot represent an invalid date-time-string 2017-01-001T00:00:00Z.], [GraphQLError: DateTime cannot represent an invalid Date instance], + [GraphQLError: DateTime cannot represent an invalid timestamp Infinity], [GraphQLError: DateTime cannot be serialized from a non string, non numeric or non Date type []], ], } diff --git a/tests/iso-date/DateTime.test.ts b/tests/iso-date/DateTime.test.ts index 8157e56c9..5d247d11a 100644 --- a/tests/iso-date/DateTime.test.ts +++ b/tests/iso-date/DateTime.test.ts @@ -59,7 +59,7 @@ describe('GraphQLDateTime', () => { [new Date(Date.UTC(2016, 0, 1, 14, 48, 10, 30)), '2016-01-01T14:48:10.030Z'], ].forEach(([value, expected]) => { it(`serializes javascript Date ${stringify(value)} into ${stringify(expected)}`, () => { - expect(GraphQLDateTime.serialize(value).toJSON()).toEqual(expected); + expect(GraphQLDateTime.serialize(value)).toEqual(expected); }); }); @@ -68,13 +68,17 @@ describe('GraphQLDateTime', () => { }); [ + ['2016-02-01T00:00:15Z', '2016-02-01T00:00:15Z'], ['2016-02-01T00:00:15.000Z', '2016-02-01T00:00:15.000Z'], ['2016-02-01T00:00:00.234Z', '2016-02-01T00:00:00.234Z'], - ['2016-02-01T00:00:00-11:00', '2016-02-01T11:00:00.000Z'], - ['2017-01-07T00:00:00.1+01:20', '2017-01-06T22:40:00.100Z'], + ['2016-02-01T00:00:00.23498Z', '2016-02-01T00:00:00.23498Z'], + ['2016-02-01T00:00:00-11:00', '2016-02-01T11:00:00Z'], + ['2016-02-01T00:00:00+11:00', '2016-01-31T13:00:00Z'], + ['2016-02-02T00:00:00.4567+01:30', '2016-02-01T22:30:00.4567Z'], + ['2017-01-07T00:00:00.1+01:20', '2017-01-06T22:40:00.1Z'], ].forEach(([input, output]) => { it(`serializes date-time-string ${input} into UTC date-time-string ${output}`, () => { - expect(GraphQLDateTime.serialize(input).toJSON()).toEqual(output); + expect(GraphQLDateTime.serialize(input)).toEqual(output); }); }); @@ -84,21 +88,28 @@ describe('GraphQLDateTime', () => { }); }); - // Serializes Unix timestamp + // Serializes ECMAScript timestamp [ [854325678000, '1997-01-27T00:41:18.000Z'], + [854325678123, '1997-01-27T00:41:18.123Z'], [876535000, '1970-01-11T03:28:55.000Z'], - // The maximum representable unix timestamp - [2147483647000, '2038-01-19T03:14:07.000Z'], - // The minimum representable unit timestamp - [-2147483648000, '1901-12-13T20:45:52.000Z'], + // The maximum representable ECMAScript timestamp + [8640000000000000, '+275760-09-13T00:00:00.000Z'], + // The minimum representable ECMAScript timestamp + [-8640000000000000, '-271821-04-20T00:00:00.000Z'], ].forEach(([value, expected]) => { - it(`serializes unix timestamp ${stringify(value)} into date-string ${expected}`, () => { - expect(GraphQLDateTime.serialize(value).toJSON()).toEqual(expected); + it(`serializes timestamp ${stringify(value)} into date-time-string ${expected}`, () => { + expect(GraphQLDateTime.serialize(value)).toEqual(expected); }); }); }); + [Number.NaN, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY].forEach(value => { + it(`throws an error serializing the invalid timestamp ${stringify(value)}`, () => { + expect(() => GraphQLDateTime.serialize(value)).toThrowErrorMatchingSnapshot(); + }); + }); + describe('value parsing', () => { validDates.forEach(([value, expected]) => { it(`parses date-string ${stringify(value)} into javascript Date ${stringify(expected)}`, () => { diff --git a/tests/iso-date/__snapshots__/DateTime.test.ts.snap b/tests/iso-date/__snapshots__/DateTime.test.ts.snap index a75c80670..1edb1fa95 100644 --- a/tests/iso-date/__snapshots__/DateTime.test.ts.snap +++ b/tests/iso-date/__snapshots__/DateTime.test.ts.snap @@ -1,65 +1,71 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GraphQLDateTime has a description 1`] = `"A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the \`date-time\` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar."`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "Document"} 1`] = `"DateTime cannot represent non string or Date type false"`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "FloatValue", "value": "5"} 1`] = `"DateTime cannot represent non string or Date type 5"`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2015-02-24T00:00:00.000+0100"} 1`] = `"DateTime cannot represent an invalid date-time-string 2015-02-24T00:00:00.000+0100."`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T00:00:00.Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00:00.Z."`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T00:00Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00Z."`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T000059Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T000059Z."`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T00Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00Z."`; - -exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "Invalid date"} 1`] = `"DateTime cannot represent an invalid date-time-string Invalid date."`; - -exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2015-02-24T00:00:00.000+0100" 1`] = `"DateTime cannot represent an invalid date-time-string 2015-02-24T00:00:00.000+0100."`; - -exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T00:00:00.Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00:00.Z."`; - -exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T00:00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00Z."`; - -exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T000059Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T000059Z."`; - -exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00Z."`; - -exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "Invalid date" 1`] = `"DateTime cannot represent an invalid date-time-string Invalid date."`; - -exports[`GraphQLDateTime serialization throws error when serializing [] 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type []"`; - -exports[`GraphQLDateTime serialization throws error when serializing {} 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type {}"`; - -exports[`GraphQLDateTime serialization throws error when serializing invalid date 1`] = `"DateTime cannot represent an invalid Date instance"`; - -exports[`GraphQLDateTime serialization throws error when serializing null 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type null"`; - -exports[`GraphQLDateTime serialization throws error when serializing true 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type true"`; - -exports[`GraphQLDateTime serialization throws error when serializing undefined 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type undefined"`; - -exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2015-02-24T00:00:00.000+0100" 1`] = `"DateTime cannot represent an invalid date-time-string 2015-02-24T00:00:00.000+0100."`; - -exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T00:00:00.Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00:00.Z."`; - -exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T00:00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00Z."`; - -exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T000059Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T000059Z."`; - -exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00Z."`; - -exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "Invalid date" 1`] = `"DateTime cannot represent an invalid date-time-string Invalid date."`; - -exports[`GraphQLDateTime value parsing throws an error when parsing [] 1`] = `"DateTime cannot represent non string or Date type []"`; - -exports[`GraphQLDateTime value parsing throws an error when parsing {} 1`] = `"DateTime cannot represent non string or Date type {}"`; - -exports[`GraphQLDateTime value parsing throws an error when parsing 4566 1`] = `"DateTime cannot represent non string or Date type 4566"`; - -exports[`GraphQLDateTime value parsing throws an error when parsing null 1`] = `"DateTime cannot represent non string or Date type null"`; - -exports[`GraphQLDateTime value parsing throws an error when parsing true 1`] = `"DateTime cannot represent non string or Date type true"`; +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GraphQLDateTime has a description 1`] = `"A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the \`date-time\` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar."`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "Document"} 1`] = `"DateTime cannot represent non string or Date type false"`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "FloatValue", "value": "5"} 1`] = `"DateTime cannot represent non string or Date type 5"`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2015-02-24T00:00:00.000+0100"} 1`] = `"DateTime cannot represent an invalid date-time-string 2015-02-24T00:00:00.000+0100."`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T00:00:00.Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00:00.Z."`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T00:00Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00Z."`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T000059Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T000059Z."`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "2016-02-01T00Z"} 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00Z."`; + +exports[`GraphQLDateTime literal parsing errors when parsing invalid literal {"kind": "StringValue", "value": "Invalid date"} 1`] = `"DateTime cannot represent an invalid date-time-string Invalid date."`; + +exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2015-02-24T00:00:00.000+0100" 1`] = `"DateTime cannot represent an invalid date-time-string 2015-02-24T00:00:00.000+0100."`; + +exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T00:00:00.Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00:00.Z."`; + +exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T00:00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00Z."`; + +exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T000059Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T000059Z."`; + +exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "2016-02-01T00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00Z."`; + +exports[`GraphQLDateTime serialization throws an error when serializing an invalid date-string "Invalid date" 1`] = `"DateTime cannot represent an invalid date-time-string Invalid date."`; + +exports[`GraphQLDateTime serialization throws error when serializing [] 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type []"`; + +exports[`GraphQLDateTime serialization throws error when serializing {} 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type {}"`; + +exports[`GraphQLDateTime serialization throws error when serializing invalid date 1`] = `"DateTime cannot represent an invalid Date instance"`; + +exports[`GraphQLDateTime serialization throws error when serializing null 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type null"`; + +exports[`GraphQLDateTime serialization throws error when serializing true 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type true"`; + +exports[`GraphQLDateTime serialization throws error when serializing undefined 1`] = `"DateTime cannot be serialized from a non string, non numeric or non Date type undefined"`; + +exports[`GraphQLDateTime throws an error serializing the invalid timestamp Infinity 1`] = `"DateTime cannot represent an invalid timestamp Infinity"`; + +exports[`GraphQLDateTime throws an error serializing the invalid timestamp Infinity 2`] = `"DateTime cannot represent an invalid timestamp Infinity"`; + +exports[`GraphQLDateTime throws an error serializing the invalid timestamp NaN 1`] = `"DateTime cannot represent an invalid timestamp NaN"`; + +exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2015-02-24T00:00:00.000+0100" 1`] = `"DateTime cannot represent an invalid date-time-string 2015-02-24T00:00:00.000+0100."`; + +exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T00:00:00.Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00:00.Z."`; + +exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T00:00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00:00Z."`; + +exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T000059Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T000059Z."`; + +exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "2016-02-01T00Z" 1`] = `"DateTime cannot represent an invalid date-time-string 2016-02-01T00Z."`; + +exports[`GraphQLDateTime value parsing throws an error parsing an invalid date-string "Invalid date" 1`] = `"DateTime cannot represent an invalid date-time-string Invalid date."`; + +exports[`GraphQLDateTime value parsing throws an error when parsing [] 1`] = `"DateTime cannot represent non string or Date type []"`; + +exports[`GraphQLDateTime value parsing throws an error when parsing {} 1`] = `"DateTime cannot represent non string or Date type {}"`; + +exports[`GraphQLDateTime value parsing throws an error when parsing 4566 1`] = `"DateTime cannot represent non string or Date type 4566"`; + +exports[`GraphQLDateTime value parsing throws an error when parsing null 1`] = `"DateTime cannot represent non string or Date type null"`; + +exports[`GraphQLDateTime value parsing throws an error when parsing true 1`] = `"DateTime cannot represent non string or Date type true"`; diff --git a/tests/iso-date/formatter.test.ts b/tests/iso-date/formatter.test.ts index 6f8c0ba5e..837b0eb79 100644 --- a/tests/iso-date/formatter.test.ts +++ b/tests/iso-date/formatter.test.ts @@ -11,7 +11,9 @@ import { serializeTime, serializeTimeString, serializeDate, + serializeDateTime, serializeDateTimeString, + serializeTimestamp, parseTime, parseDate, parseDateTime, @@ -59,6 +61,47 @@ describe('formatting', () => { }); }); + ( + [ + [new Date(Date.UTC(2016, 1, 1)), '2016-02-01T00:00:00.000Z'], + [new Date(Date.UTC(2016, 3, 5, 10, 1, 4, 555)), '2016-04-05T10:01:04.555Z'], + ] as [Date, string][] + ).forEach(([date, dateTimeString]) => { + it(`serializes ${stringify(date)} into date-time-string ${dateTimeString}`, () => { + expect(serializeDateTime(date)).toEqual(dateTimeString); + }); + }); + + ( + [ + [new Date(Date.UTC(2016, 1, 1)), '2016-02-01T00:00:00.000Z'], + [new Date(Date.UTC(2016, 3, 5, 10, 1, 4, 555)), '2016-04-05T10:01:04.555Z'], + ] as [Date, string][] + ).forEach(([date, dateTimeString]) => { + it(`serializes ${stringify(date)} into date-time-string ${dateTimeString}`, () => { + expect(serializeDateTime(date)).toEqual(dateTimeString); + }); + }); + + ( + [ + [854325678000, '1997-01-27T00:41:18.000Z'], + [876535000, '1970-01-11T03:28:55.000Z'], + [876535800, '1970-01-11T03:28:55.800Z'], + [876535832.1, '1970-01-11T03:28:55.832Z'], + [-876535800, '1969-12-21T20:31:04.200Z'], + [0, '1970-01-01T00:00:00.000Z'], + // The maximum representable ECMAScript timestamp + [8640000000000000, '+275760-09-13T00:00:00.000Z'], + // The minimum representable ECMAScript timestamp + [-8640000000000000, '-271821-04-20T00:00:00.000Z'], + ] as [number, string][] + ).forEach(([timestamp, dateTimeString]) => { + it(`serializes timestamp ${stringify(timestamp)} into date-time-string ${dateTimeString}`, () => { + expect(serializeTimestamp(timestamp)).toEqual(dateTimeString); + }); + }); + ( [ ['00:00:59Z', new Date(Date.UTC(2017, 0, 1, 0, 0, 59))], @@ -114,14 +157,14 @@ describe('formatting', () => { }); [ - ['2016-02-01T00:00:00Z', '2016-02-01T00:00:00.000Z'], - ['2016-02-01T12:23:44Z', '2016-02-01T12:23:44.000Z'], - ['2016-02-01T14:38:12-01:00', '2016-02-01T15:38:12.000Z'], - ['2016-02-02T00:00:00.456+01:30', '2016-02-01T22:30:00.456Z'], - ['2016-02-01T14:38:12.1+01:00', '2016-02-01T13:38:12.100Z'], + ['2016-02-01T00:00:00Z', '2016-02-01T00:00:00Z'], + ['2016-02-01T12:23:44Z', '2016-02-01T12:23:44Z'], + ['2016-02-01T14:38:12-01:00', '2016-02-01T15:38:12Z'], + ['2016-02-02T00:00:00.4567+01:30', '2016-02-01T22:30:00.4567Z'], + ['2016-02-01T14:38:12.1+01:00', '2016-02-01T13:38:12.1Z'], ].forEach(([input, output]) => { it(`serializes date-time-string ${input} into UTC date-time-string ${output}`, () => { - expect(serializeDateTimeString(input).toJSON()).toEqual(output); + expect(serializeDateTimeString(input)).toEqual(output); }); }); }); diff --git a/tests/iso-date/validator.test.ts b/tests/iso-date/validator.test.ts index 71f29c322..f0e87b65d 100644 --- a/tests/iso-date/validator.test.ts +++ b/tests/iso-date/validator.test.ts @@ -11,7 +11,7 @@ import { validateTime, validateDate, validateDateTime, - validateUnixTimestamp, + validateTimestamp, validateJSDate, } from '../../src/scalars/iso-date/validator.js'; @@ -117,22 +117,28 @@ describe('validator', () => { }); }); - describe('validateUnixTimestamp', () => { + describe('validateTimestamp', () => { [ - 854325678, 876535, 876535.8, 876535.8321, -876535.8, - // The maximum representable unix timestamp - 2147483647, - // The minimum representable unit timestamp - -2147483648, - ].forEach(timestamp => { - it(`identifies ${timestamp} as a valid Unix timestamp`, () => { - expect(validateUnixTimestamp(timestamp)).toEqual(true); + 854325678000, 876535000, 876535800, 876535832.1, -876535800, + // The maximum representable ECMAScript timestamp + 8640000000000000, + // The minimum representable ECMAScript timestamp + -8640000000000000, + ].forEach((timestamp) => { + it(`identifies ${timestamp} as a valid timestamp`, () => { + expect(validateTimestamp(timestamp)).toEqual(true); }); }); - [Number.NaN, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, 2147483648, -2147483649].forEach(timestamp => { - it(`identifies ${timestamp} as an invalid Unix timestamp`, () => { - expect(validateUnixTimestamp(timestamp)).toEqual(false); + [ + Number.NaN, + Number.POSITIVE_INFINITY, + Number.POSITIVE_INFINITY, + 8640000000000001, + -8640000000000001, + ].forEach((timestamp) => { + it(`identifies ${timestamp} as an invalid ECMAScript timestamp`, () => { + expect(validateTimestamp(timestamp)).toEqual(false); }); }); });