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:
Jan Aagaard
2024-06-18 00:35:37 +02:00
committed by GitHub
parent 077da08309
commit 69a9b2ecc5
2 changed files with 108 additions and 90 deletions
+79 -70
View File
@@ -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
View File
@@ -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()
}
}
}