Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby): add support for microsecond and alternative iso datetime formats #12533

Merged
merged 6 commits into from
Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
383 changes: 383 additions & 0 deletions packages/gatsby/src/schema/types/__tests__/date.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,383 @@
const { store } = require(`../../../redux`)
const { build } = require(`../..`)
const { isDate } = require(`../date`)
require(`../../../db/__tests__/fixtures/ensure-loki`)()

// Timestamps grabbed from https://github.com/moment/moment/blob/2e2a5b35439665d4b0200143d808a7c26d6cd30f/src/test/moment/is_valid.js

describe(`isDate`, () => {
it.each([
`1970`,
`2019`,
`1970-01`,
`2019-01`,
`1970-01-01`,
`2010-01-01`,
`2010-01-30`,
`19700101`,
`20100101`,
`20100130`,
`2010-01-30T23+00:00`,
`2010-01-30T23:59+00:00`,
`2010-01-30T23:59:59+00:00`,
`2010-01-30T23:59:59.999+00:00`,
`2010-01-30T23:59:59.999-07:00`,
`2010-01-30T00:00:00.000+07:00`,
`2010-01-30T23:59:59.999-07`,
`2010-01-30T00:00:00.000+07`,
`2010-01-30T23Z`,
`2010-01-30T23:59Z`,
`2010-01-30T23:59:59Z`,
`2010-01-30T23:59:59.999Z`,
`2010-01-30T00:00:00.000Z`,
`1970-01-01T00:00:00.000001Z`,
`2012-04-01T00:00:00-05:00`,
`2012-11-12T00:00:00+01:00`,
])(`should return true for valid ISO 8601: %s`, dateString => {
expect(isDate(dateString)).toBeTruthy()
})

it.each([
`2010-01-30 23+00:00`,
`2010-01-30 23:59+00:00`,
`2010-01-30 23:59:59+00:00`,
`2010-01-30 23:59:59.999+00:00`,
`2010-01-30 23:59:59.999-07:00`,
`2010-01-30 00:00:00.000+07:00`,
`2010-01-30 23:59:59.999-07`,
`2010-01-30 00:00:00.000+07`,
`1970-01-01 00:00:00.000Z`,
`2012-04-01 00:00:00-05:00`,
`2012-11-12 00:00:00+01:00`,
`1970-01-01 00:00:00.0000001 Z`,
`1970-01-01 00:00:00.000 Z`,
`1970-01-01 00:00:00 Z`,
`1970-01-01 000000 Z`,
`1970-01-01 00:00 Z`,
`1970-01-01 00 Z`,
])(`should return true for ISO 8601 (no T, extra space): %s`, dateString => {
expect(isDate(dateString)).toBeTruthy()
})

it.each([`1970-W31`, `2006-W01`, `1970W31`, `2009-W53-7`, `2009W537`])(
`should return true for ISO 8601 week dates: %s`,
dateString => {
expect(isDate(dateString)).toBeTruthy()
}
)

it.each([`1970-334`, `1970334`, `2090-001`, `2090001`])(
`should return true for ISO 8601 ordinal dates: %s`,
dateString => {
expect(isDate(dateString)).toBeTruthy()
}
)

it.each([`2018-08-31T23:25:16.019345+02:00`, `2018-08-31T23:25:16.019345Z`])(
`should return true for microsecond precision: %s`,
dateString => {
expect(isDate(dateString)).toBeTruthy()
}
)

it.skip.each([
`2018-08-31T23:25:16.019345123+02:00`,
`2018-08-31T23:25:16.019345123Z`,
])(`should return true for nanosecond precision: %s`, dateString => {
expect(isDate(dateString)).toBeTruthy()
})

it.skip.each([`2018-08-31T23:25:16.012345678901+02:00`])(
`should return false for precision beyond 9 digits: %s`,
dateString => {
expect(isDate(dateString)).toBeFalsy()
}
)

it.each([
`2010-00-00`,
`2010-01-00`,
`2010-01-40`,
`2010-01-01T24:01`, // 24:00:00 is actually valid
`2010-01-01T23:60`,
`2010-01-01T23:59:60`,
`2010-01-40T23:59:59.9999`,
`2010-00-00T+00:00`,
`2010-01-00T+00:00`,
`2010-01-40T+00:00`,
`2010-01-40T24:01+00:00`,
`2010-01-40T23:60+00:00`,
`2010-01-40T23:59:60+00:00`,
`2010-01-40T23:59:59.9999+00:00`,
`2010-01-40T23:59:59,9999+00:00`,
`2012-04-01T00:00:00-5:00`, // should be -05:00
`2012-04-01T00:00:00+1:00`, // should be +01:00
undefined,
`undefined`,
null,
`null`,
[],
{},
``,
` `,
`2012-04-01T00:basketball`,
])(`should return false for invalid ISO 8601: %s`, dateString => {
expect(isDate(dateString)).toBeFalsy()
})

it.skip.each([
1371065286,
1379066897.0,
1379066897.7,
1379066897.0,
1379066897.07,
1379066897.17,
1379066897.0,
1379066897.007,
1379066897.017,
1379066897.157,
`1371065286`,
`1379066897.`,
`1379066897.0`,
`1379066897.7`,
`1379066897.00`,
`1379066897.07`,
`1379066897.17`,
`1379066897.000`,
`1379066897.007`,
`1379066897.017`,
`1379066897.157`,
])(`should return true for unix timestamps: %s`, dateString => {
expect(isDate(dateString)).toBeTruthy()
})
})

const nodes = [
{
id: `id1`,
internal: { type: `Test` },
testDate: new Date(),
explicitValidDate: `2010-01-30T23:59:59.999-07:00`,
inferredValidDate: `1970-01-01T00:00:00.000Z`,
validYYYY: `1970`,
validYYMM: `2019-01`,
validYYMMDD: `2010-01-30`,
validYYMMDDNoDash: `20100101`,
validISO1: `2010-01-30T23:59:59.999+00:00`,
validISO2: `2010-01-30T23:59:59.999-07:00`,
validISO3: `2010-01-30T00:00:00.000+07:00`,
validISO4: `2010-01-30T23:59:59.999-07`,
validISO5: `2010-01-30T00:00:00.000+07`,
validISO6: `2010-01-30 00:00:00.000Z`,
validISO7: `1970-01-01T00:00:00.000Z`,
validISO8: `2012-04-01T00:00:00-05:00`,
validISO9: `2012-11-12T00:00:00+01:00`,

validOrdinal1: `1970-334`,
validOrdinal2: `1970334`,
validOrdinal3: `2090-001`,
validOrdinal4: `2090001`,

validWeek1: `1970-W31`,
validWeek2: `2006-W01`,
validWeek3: `1970W31`,
validWeek4: `2009-W53-7`,
validWeek5: `2009W537`,

validMicrosecond1: `2018-08-31T23:25:16.019345+02:00`,
validMicrosecond2: `2018-08-31T23:25:16.019345Z`,

validNanosecond1: `2018-08-31T23:25:16.019345123+02:00`,
validNanosecond2: `2018-08-31T23:25:16.019345123Z`,

invalidHighPrecision: `2018-08-31T23:25:16.01234567899993+02:00`,

invalidDate1: `2010-00-00`,
invalidDate2: `2010-01-00`,
invalidDate3: `2010-01-40`,
invalidDate4: `2010-01-01T24:01`, // 24:00:00 is actually valid
invalidDate5: `2010-01-01T23:60`,
invalidDate6: `2010-01-01T23:59:60`,
invalidDate7: `2010-01-40T23:59:59.9999`,

invalidDate8: undefined,
invalidDate9: `undefined`,
invalidDate10: null,
invalidDate11: `null`,
invalidDate12: [],
invalidDate13: {},
invalidDate14: ``,
invalidDate15: ` `,
invalidDate16: `2012-04-01T00:basketball`,
},
]

describe(`dateResolver`, () => {
beforeEach(() => {
store.dispatch({ type: `DELETE_CACHE` })
nodes.forEach(node =>
store.dispatch({ type: `CREATE_NODE`, payload: { ...node } })
)
})

const buildTestSchema = async ({
infer = true,
addDefaultResolvers = true,
}) => {
const inferDirective = infer ? `@infer` : `@dontInfer`
const noDefaultResolvers = addDefaultResolvers ? `false` : `true`
const typeDefs = [
`
type Test implements Node ${inferDirective}(noDefaultResolvers: ${noDefaultResolvers}) {
testDate: Date
explicitValidDate: Date
invalidHighPrecision: Date
invalidDate8: Date
invalidDate9: Date
invalidDate10: Date
invalidDate11: Date
invalidDate12: Date
invalidDate13: Date
invalidDate14: Date
invalidDate15: Date
invalidDate16: Date
}`,
]
typeDefs.forEach(def =>
store.dispatch({ type: `CREATE_TYPES`, payload: def })
)

await build({})
return store.getState().schema
}

it(`can properly resolve datetimes`, async () => {
const schema = await buildTestSchema({})
const fields = schema.getType(`Test`).getFields()

expect(fields.testDate.resolve).toBeDefined()
expect(fields.explicitValidDate.resolve).toBeDefined()
expect(fields.inferredValidDate.resolve).toBeDefined()
expect(fields.validYYYY.resolve).toBeDefined()
expect(fields.validYYMM.resolve).toBeDefined()
expect(fields.validYYMMDD.resolve).toBeDefined()
expect(fields.validYYMMDDNoDash.resolve).toBeDefined()

expect(fields.validISO1.resolve).toBeDefined()
expect(fields.validISO2.resolve).toBeDefined()
expect(fields.validISO3.resolve).toBeDefined()
expect(fields.validISO4.resolve).toBeDefined()
expect(fields.validISO5.resolve).toBeDefined()
expect(fields.validISO6.resolve).toBeDefined()
expect(fields.validISO7.resolve).toBeDefined()
expect(fields.validISO8.resolve).toBeDefined()
expect(fields.validISO9.resolve).toBeDefined()

expect(fields.validOrdinal1.resolve).toBeDefined()
expect(fields.validOrdinal2.resolve).toBeDefined()
expect(fields.validOrdinal3.resolve).toBeDefined()
expect(fields.validOrdinal4.resolve).toBeDefined()

expect(fields.validWeek1.resolve).toBeDefined()
expect(fields.validWeek2.resolve).toBeDefined()
expect(fields.validWeek3.resolve).toBeDefined()
expect(fields.validWeek4.resolve).toBeDefined()
expect(fields.validWeek5.resolve).toBeDefined()

expect(fields.validMicrosecond1.resolve).toBeDefined()
expect(fields.validMicrosecond2.resolve).toBeDefined()

expect(fields.validNanosecond1.resolve).toBeDefined()
expect(fields.validNanosecond2.resolve).toBeDefined()
// expect(fields.invalidHighPrecision.resolve).toBeDefined()
expect(fields.invalidDate1.resolve).toBeUndefined()
expect(fields.invalidDate2.resolve).toBeUndefined()
expect(fields.invalidDate3.resolve).toBeUndefined()
expect(fields.invalidDate4.resolve).toBeUndefined()
expect(fields.invalidDate5.resolve).toBeUndefined()
expect(fields.invalidDate6.resolve).toBeUndefined()
expect(fields.invalidDate7.resolve).toBeUndefined()
expect(fields.invalidDate8.resolve).toBeUndefined()
expect(fields.invalidDate9.resolve).toBeUndefined()
expect(fields.invalidDate10.resolve).toBeUndefined()
expect(fields.invalidDate11.resolve).toBeUndefined()
expect(fields.invalidDate12.resolve).toBeUndefined()
expect(fields.invalidDate13.resolve).toBeUndefined()
expect(fields.invalidDate14.resolve).toBeUndefined()
expect(fields.invalidDate15.resolve).toBeUndefined()
expect(fields.invalidDate16.resolve).toBeUndefined()
})

it.each([
`2018-01-28T23:59:59.999-07:00`,
`2018-01-29T00:00:00.000Z`,
`2018-01-29`,
`20180129`,
`2018-01-29T23:59:59.999+00:00`,
`2018-01-28T19:59:59.999-07:00`,
`2018-01-30T06:00:00.001+07:00`,
`2018-01-28 17:00:00.001-07`,
`2018-01-30 04:00:00.001+07`,
`2018-01-29 04:00:00.001Z`,
`2018-01-29 04:00:00.001 Z`,
`2018-01-29 04:00:00 Z`,
`2018-01-29 04:00 Z`,
`2018-01-29 04 Z`,
`2018-01-28T17:00:00.001-07`,
`2018-01-30T04:00:00.001+07`,
`2018-01-29 00:00:00.001Z`,
`2018-01-29T00:00:00.001Z`,
`2018-01-28 23:00:00-05:00`,
`2018-01-29 23:00:00+01:00`,
`2018-01-28T23:00:00-05:00`,
`2018-01-29T23:00:00+01:00`,
`2018-029`,
`2018029`,
`2018-W05`,
`2018W05`,
`2018-W05-1`,
`2018-01-29T23:25:16.019345+02:00`,
`2018-01-29T23:25:16.019345Z`,
// Seems to not require nanosecond definition to not fail
`2018-01-29T23:25:16.019345123+02:00`,
`2018-01-29T23:25:16.019345123Z`,
])(`should return "Jan 29, 2018": %s`, async dateString => {
const schema = await buildTestSchema({})
const fields = schema.getType(`Test`).getFields()
expect(
fields[`testDate`].resolve(
{ date: dateString },
{ formatString: `MMM DD, YYYY` },
{},
{
fieldName: `date`,
}
)
).toEqual(`Jan 29, 2018`)
})

it.each([
`2010-00-00`,
`2010-01-00`,
`2010-01-40`,
`2010-01-01T24:01`,
`2010-01-01T23:60`,
`2010-01-01T23:59:60`,
`2010-01-40T23:59:59.9999`,
// Combine with above statement once we figure out why it passes
// `2018-08-31T23:25:16.01234567899993+02:00`,
])(`should return "Invalid Date": %s`, async dateString => {
const schema = await buildTestSchema({})
const fields = schema.getType(`Test`).getFields()
expect(
fields[`testDate`].resolve(
{ date: dateString },
{ formatString: `MMM DD, YYYY` },
{},
{
fieldName: `date`,
}
)
).toEqual(`Invalid date`)
})
})
Loading