Create a testable version of ago() and re-enable the disabled test (#4364)
* Enable the test of ago() * Use test cases This puts the input and the expected values next to each other. * Create dateDiff function This is a copy of ago(), but with the ability to specify the second date instead of using Date.now(). * Let ago() use dateDiff() * Move constants close to usage * Test dateDiff instead of ago This makes it possible to test the dates without being forced to rely on what the current date is. The commented out tests do not yet pass. This is fixed in later commits. * Update dateDiff and enable the remaining tests
This commit is contained in:
@@ -6,7 +6,7 @@ import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles'
|
||||
import {enforceLen} from '../../src/lib/strings/helpers'
|
||||
import {detectLinkables} from '../../src/lib/strings/rich-text-detection'
|
||||
import {shortenLinks} from '../../src/lib/strings/rich-text-manip'
|
||||
import {ago} from '../../src/lib/strings/time'
|
||||
import {dateDiff} from '../../src/lib/strings/time'
|
||||
import {
|
||||
makeRecordUri,
|
||||
toNiceDomain,
|
||||
@@ -142,77 +142,86 @@ describe('makeRecordUri', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// FIXME: Reenable after fixing non-deterministic test.
|
||||
describe.skip('ago', () => {
|
||||
const oneYearDate = new Date(
|
||||
new Date().setMonth(new Date().getMonth() - 11),
|
||||
).setDate(new Date().getDate() - 28)
|
||||
|
||||
const inputs = [
|
||||
1671461038,
|
||||
'04 Dec 1995 00:12:00 GMT',
|
||||
new Date(),
|
||||
new Date().setSeconds(new Date().getSeconds() - 10),
|
||||
new Date().setMinutes(new Date().getMinutes() - 10),
|
||||
new Date().setHours(new Date().getHours() - 1),
|
||||
new Date().setDate(new Date().getDate() - 1),
|
||||
new Date().setDate(new Date().getDate() - 20),
|
||||
new Date().setDate(new Date().getDate() - 25),
|
||||
new Date().setDate(new Date().getDate() - 28),
|
||||
new Date().setDate(new Date().getDate() - 29),
|
||||
new Date().setDate(new Date().getDate() - 30),
|
||||
new Date().setMonth(new Date().getMonth() - 1),
|
||||
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
|
||||
new Date().getDate() - 20,
|
||||
),
|
||||
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
|
||||
new Date().getDate() - 25,
|
||||
),
|
||||
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
|
||||
new Date().getDate() - 28,
|
||||
),
|
||||
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
|
||||
new Date().getDate() - 29,
|
||||
),
|
||||
new Date().setMonth(new Date().getMonth() - 11),
|
||||
new Date(new Date().setMonth(new Date().getMonth() - 11)).setDate(
|
||||
new Date().getDate() - 20,
|
||||
),
|
||||
new Date(new Date().setMonth(new Date().getMonth() - 11)).setDate(
|
||||
new Date().getDate() - 25,
|
||||
),
|
||||
oneYearDate,
|
||||
]
|
||||
const outputs = [
|
||||
new Date(1671461038).toLocaleDateString(),
|
||||
new Date('04 Dec 1995 00:12:00 GMT').toLocaleDateString(),
|
||||
'now',
|
||||
'10s',
|
||||
'10m',
|
||||
'1h',
|
||||
'1d',
|
||||
'20d',
|
||||
'25d',
|
||||
'28d',
|
||||
'29d',
|
||||
'1mo',
|
||||
'1mo',
|
||||
'1mo',
|
||||
'1mo',
|
||||
'2mo',
|
||||
'2mo',
|
||||
'11mo',
|
||||
'11mo',
|
||||
'11mo',
|
||||
new Date(oneYearDate).toLocaleDateString(),
|
||||
describe('dateDiff', () => {
|
||||
type Case = [number | string | Date, number | string | Date, string]
|
||||
const cases: Case[] = [
|
||||
[
|
||||
1671461038,
|
||||
new Date('2034-05-31T22:00Z'),
|
||||
new Date(1671461038).toLocaleDateString(),
|
||||
],
|
||||
[
|
||||
'04 Dec 1995 00:12:00 GMT',
|
||||
new Date('2024-05-31T22:00Z'),
|
||||
new Date('04 Dec 1995 00:12:00 GMT').toLocaleDateString(),
|
||||
],
|
||||
[new Date('2010-01-01Z'), new Date('2005-01-01Z'), 'now'],
|
||||
[new Date(), new Date(), 'now'],
|
||||
[
|
||||
new Date('2001-01-01T00:00:00Z'),
|
||||
new Date('2001-01-01T00:00:04.999Z'),
|
||||
'now',
|
||||
],
|
||||
[new Date('2001-01-01T12:00:00Z'), new Date('2001-01-01T12:00:05Z'), '5s'],
|
||||
[
|
||||
new Date('2001-01-01T21:59:55Z'),
|
||||
new Date('2001-01-01T22:00:05.123Z'),
|
||||
'10s',
|
||||
],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-01T00:00:59.999Z'), '59s'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-01T00:01:00.000Z'), '1m'],
|
||||
[new Date('2001-01-01T23:59:50Z'), new Date('2001-01-02T00:09:55Z'), '10m'],
|
||||
[
|
||||
new Date('2001-01-01T23:00:00Z'),
|
||||
new Date('2001-01-01T23:59:59.999Z'),
|
||||
'59m',
|
||||
],
|
||||
[new Date('2001-01-01T23:00:00Z'), new Date('2001-01-02T00:00:00Z'), '1h'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-01T23:59:59.999Z'), '23h'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-02Z'), '1d'],
|
||||
[new Date('2001-01-01T14:00Z'), new Date('2001-01-02T14:00Z'), '1d'],
|
||||
[new Date('2001-02-25Z'), new Date('2001-03-03Z'), '6d'],
|
||||
[new Date('2004-02-25Z'), new Date('2004-03-03Z'), '7d'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-30T00:00Z'), '29d'],
|
||||
[new Date('2004-01-01Z'), new Date('2004-01-30T23:59:59.999Z'), '29d'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-31T00:00Z'), '1mo'],
|
||||
[new Date('2001-02-01Z'), new Date('2001-03-01Z'), '28d'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-01-31Z'), '1mo'],
|
||||
[new Date('2001-02-01Z'), new Date('2001-03-01Z'), '28d'],
|
||||
[new Date('2004-02-01Z'), new Date('2004-03-01Z'), '29d'],
|
||||
[new Date('2001-03-01Z'), new Date('2001-04-01Z'), '1mo'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-03-01Z'), '1mo'], // 31 + 28 = 59 days -> 1 months
|
||||
[new Date('2001-01-01Z'), new Date('2001-04-01Z'), '3mo'], // 31 + 28 + 31 = 90 days -> 3 months
|
||||
[new Date('2001-02-01Z'), new Date('2001-05-01Z'), '2mo'], // 28 + 31 + 30 = 89 days -> 2 months
|
||||
[new Date('2001-01-01Z'), new Date('2001-05-01Z'), '4mo'], // 31 + 28 + 31 + 30 = 120 days -> 4 months
|
||||
[new Date('2001-02-01Z'), new Date('2001-06-01Z'), '4mo'], // 28 + 31 + 30 + 31 = 120 days -> 4 months
|
||||
[new Date('2001-01-01Z'), new Date('2001-12-01Z'), '11mo'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-12-26Z'), '11mo'],
|
||||
[new Date('2001-01-01Z'), new Date('2001-12-26T23:59:59.999Z'), '11mo'],
|
||||
[
|
||||
new Date('2001-01-01Z'),
|
||||
new Date('2001-12-27Z'),
|
||||
new Date('2001-01-01Z').toLocaleDateString(),
|
||||
],
|
||||
[
|
||||
new Date('2001-01-01Z'),
|
||||
new Date('2002-01-01Z'),
|
||||
new Date('2001-01-01Z').toLocaleDateString(),
|
||||
],
|
||||
[
|
||||
new Date('2050-12-31Z'),
|
||||
new Date('2100-01-01Z'),
|
||||
new Date('2050-12-31Z').toLocaleDateString(),
|
||||
],
|
||||
]
|
||||
|
||||
it('correctly calculates how much time passed, in a string', () => {
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
const result = ago(inputs[i])
|
||||
expect(result).toEqual(outputs[i])
|
||||
}
|
||||
})
|
||||
it.each(cases)(
|
||||
'given the dates %p and %p returns %p',
|
||||
(date1, date2, expected) => {
|
||||
const result = dateDiff(date1, date2)
|
||||
expect(result).toEqual(expected)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('makeValidHandle', () => {
|
||||
|
||||
+29
-20
@@ -1,19 +1,34 @@
|
||||
export function ago(date: number | string | Date): string {
|
||||
return dateDiff(date, Date.now())
|
||||
}
|
||||
|
||||
const NOW = 5
|
||||
const MINUTE = 60
|
||||
const HOUR = MINUTE * 60
|
||||
const DAY = HOUR * 24
|
||||
const MONTH_30 = DAY * 30
|
||||
const MONTH = DAY * 30.41675 // This results in 365.001 days in a year, which is close enough for nearly all cases
|
||||
export function ago(date: number | string | Date): string {
|
||||
let ts: number
|
||||
if (typeof date === 'string') {
|
||||
ts = Number(new Date(date))
|
||||
} else if (date instanceof Date) {
|
||||
ts = Number(date)
|
||||
/** Returns the difference between date1 and date2 in full seconds, minutes, hours etc. All month are considered exactly 30 days. Assuming that date1 <= date2. Differences >= 360 days are returned as the "M/D/YYYY" string. */
|
||||
export function dateDiff(
|
||||
date1: number | string | Date,
|
||||
date2: number | string | Date,
|
||||
): string {
|
||||
let ts1: number
|
||||
if (typeof date1 === 'string') {
|
||||
ts1 = Number(new Date(date1))
|
||||
} else if (date1 instanceof Date) {
|
||||
ts1 = Number(date1)
|
||||
} else {
|
||||
ts = date
|
||||
ts1 = date1
|
||||
}
|
||||
const diffSeconds = Math.floor((Date.now() - ts) / 1e3)
|
||||
let ts2: number
|
||||
if (typeof date2 === 'string') {
|
||||
ts2 = Number(new Date(date2))
|
||||
} else if (date2 instanceof Date) {
|
||||
ts2 = Number(date2)
|
||||
} else {
|
||||
ts2 = date2
|
||||
}
|
||||
const diffSeconds = Math.floor((ts2 - ts1) / 1e3)
|
||||
if (diffSeconds < NOW) {
|
||||
return `now`
|
||||
} else if (diffSeconds < MINUTE) {
|
||||
@@ -23,19 +38,13 @@ export function ago(date: number | string | Date): string {
|
||||
} else if (diffSeconds < DAY) {
|
||||
return `${Math.floor(diffSeconds / HOUR)}h`
|
||||
} else if (diffSeconds < MONTH_30) {
|
||||
return `${Math.round(diffSeconds / DAY)}d`
|
||||
return `${Math.floor(diffSeconds / DAY)}d`
|
||||
} else {
|
||||
let months = diffSeconds / MONTH
|
||||
if (months % 1 >= 0.9) {
|
||||
months = Math.ceil(months)
|
||||
const diffMonths30 = Math.floor(diffSeconds / MONTH_30)
|
||||
if (diffMonths30 < 12) {
|
||||
return `${diffMonths30}mo`
|
||||
} else {
|
||||
months = Math.floor(months)
|
||||
}
|
||||
|
||||
if (months < 12) {
|
||||
return `${months}mo`
|
||||
} else {
|
||||
return new Date(ts).toLocaleDateString()
|
||||
return new Date(ts1).toLocaleDateString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user