local_time 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +7 -1
- data/app/assets/javascripts/local-time.es2017-esm.js +1 -1
- data/app/assets/javascripts/local-time.es2017-umd.js +1 -1
- data/lib/local_time/version.rb +1 -1
- data/test/helpers/local_time_helper_test.rb +1 -7
- data/test/javascripts/builds/index.js +23787 -21189
- data/test/javascripts/src/format24_test.js +109 -0
- data/test/javascripts/src/i18n_test.js +55 -0
- data/test/javascripts/src/local_time_test.js +54 -0
- data/test/javascripts/src/relative_date_test.js +121 -0
- data/test/javascripts/src/strftime_test.js +151 -0
- data/test/javascripts/src/test_helpers.js +66 -0
- data/test/javascripts/src/time_ago_test.js +72 -0
- data/test/javascripts/vendor/moment.js +5650 -5647
- data/test/javascripts/vendor/sinon.js +18218 -15475
- metadata +23 -23
- data/test/javascripts/src/format24_test.coffee +0 -94
- data/test/javascripts/src/i18n_test.coffee +0 -49
- data/test/javascripts/src/local_time_test.coffee +0 -43
- data/test/javascripts/src/relative_date_test.coffee +0 -91
- data/test/javascripts/src/strftime_test.coffee +0 -127
- data/test/javascripts/src/test_helpers.coffee +0 -46
- data/test/javascripts/src/time_ago_test.coffee +0 -58
- /data/test/javascripts/src/{index.coffee → index.js} +0 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
const { addTimeEl, assert, defer, getText, testAsync, testGroup, getTitle } = LocalTime.TestHelpers
|
4
|
+
const { config } = LocalTime
|
5
|
+
|
6
|
+
testGroup("format24 (24h time)", () => {
|
7
|
+
testAsync("default behavior", (done) => {
|
8
|
+
const now = moment()
|
9
|
+
|
10
|
+
const el = addTimeEl({ format: "%-l:%M%P", format24: "%H:%M", datetime: now.toISOString() })
|
11
|
+
defer(() => {
|
12
|
+
assert.equal(getText(el), now.format("h:mma"))
|
13
|
+
done()
|
14
|
+
})
|
15
|
+
})
|
16
|
+
|
17
|
+
testAsync("turned off", (done) => {
|
18
|
+
const now = moment()
|
19
|
+
const originalFormat24 = config.useFormat24
|
20
|
+
config.useFormat24 = false
|
21
|
+
|
22
|
+
const el = addTimeEl({ format: "%-l:%M%P", format24: "%H:%M", datetime: now.toISOString() })
|
23
|
+
defer(() => {
|
24
|
+
assert.equal(getText(el), now.format("h:mma"))
|
25
|
+
config.useFormat24 = originalFormat24
|
26
|
+
done()
|
27
|
+
})
|
28
|
+
})
|
29
|
+
|
30
|
+
testAsync("turned on", (done) => {
|
31
|
+
const now = moment()
|
32
|
+
const originalFormat24 = config.useFormat24
|
33
|
+
config.useFormat24 = true
|
34
|
+
|
35
|
+
const el = addTimeEl({ format: "%-l:%M%P", format24: "%H:%M", datetime: now.toISOString() })
|
36
|
+
defer(() => {
|
37
|
+
assert.equal(getText(el), now.format("HH:mm"))
|
38
|
+
config.useFormat24 = originalFormat24
|
39
|
+
done()
|
40
|
+
})
|
41
|
+
})
|
42
|
+
|
43
|
+
testAsync("fallback for missing data-format24 values", (done) => {
|
44
|
+
const now = moment()
|
45
|
+
const originalFormat24 = config.useFormat24
|
46
|
+
config.useFormat24 = true
|
47
|
+
|
48
|
+
const el = addTimeEl({ format: "%-l:%M%P", datetime: now.toISOString() })
|
49
|
+
defer(() => {
|
50
|
+
assert.equal(getText(el), now.format("h:mma"))
|
51
|
+
config.useFormat24 = originalFormat24
|
52
|
+
done()
|
53
|
+
})
|
54
|
+
})
|
55
|
+
|
56
|
+
testAsync("turned off for relative time elements", (done) => {
|
57
|
+
const ago = moment().subtract("days", 5)
|
58
|
+
const originalFormat24 = config.useFormat24
|
59
|
+
config.useFormat24 = false
|
60
|
+
|
61
|
+
const el = addTimeEl({ type: "time-ago", datetime: ago.toISOString() })
|
62
|
+
defer(() => {
|
63
|
+
assert.equal(getText(el), `${ago.format("dddd")} at ${ago.format("h:mma")}`)
|
64
|
+
config.useFormat24 = originalFormat24
|
65
|
+
done()
|
66
|
+
})
|
67
|
+
})
|
68
|
+
|
69
|
+
testAsync("turned on for relative time elements", (done) => {
|
70
|
+
const ago = moment().subtract("days", 5)
|
71
|
+
const originalFormat24 = config.useFormat24
|
72
|
+
config.useFormat24 = true
|
73
|
+
|
74
|
+
const el = addTimeEl({ type: "time-ago", datetime: ago.toISOString() })
|
75
|
+
defer(() => {
|
76
|
+
assert.equal(getText(el), `${ago.format("dddd")} at ${ago.format("HH:mm")}`)
|
77
|
+
config.useFormat24 = originalFormat24
|
78
|
+
done()
|
79
|
+
})
|
80
|
+
})
|
81
|
+
|
82
|
+
testAsync("element title when turned off", (done) => {
|
83
|
+
const ago = moment().subtract("days", 5)
|
84
|
+
const originalFormat24 = config.useFormat24
|
85
|
+
config.useFormat24 = false
|
86
|
+
|
87
|
+
const el = addTimeEl({ type: "time-ago", datetime: ago.toISOString() })
|
88
|
+
defer(() => {
|
89
|
+
const regex = new RegExp(ago.format('MMMM D, YYYY [at] h:mma') + " (\\w{3,4}|UTC[+-]d+)")
|
90
|
+
assert.ok(regex.test(getTitle(el)), `'${getTitle(el)}' doesn't look correct, it should match regex ${regex}`)
|
91
|
+
config.useFormat24 = originalFormat24
|
92
|
+
done()
|
93
|
+
})
|
94
|
+
})
|
95
|
+
|
96
|
+
testAsync("element title when turned on", (done) => {
|
97
|
+
const ago = moment().subtract("days", 5)
|
98
|
+
const originalFormat24 = config.useFormat24
|
99
|
+
config.useFormat24 = true
|
100
|
+
|
101
|
+
const el = addTimeEl({ type: "time-ago", datetime: ago.toISOString() })
|
102
|
+
defer(() => {
|
103
|
+
const regex = new RegExp(ago.format('MMMM D, YYYY [at] HH:mm') + " (\\w{3,4}|UTC[+-]d+)")
|
104
|
+
assert.ok(regex.test(getTitle(el)), `'${getTitle(el)}' doesn't look correct, it should match regex ${regex}`)
|
105
|
+
config.useFormat24 = originalFormat24
|
106
|
+
done()
|
107
|
+
})
|
108
|
+
})
|
109
|
+
})
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
const { addTimeEl, assert, defer, getText, setText, test, testAsync, testGroup, triggerEvent } = LocalTime.TestHelpers
|
4
|
+
const { config } = LocalTime
|
5
|
+
const { i18n } = config
|
6
|
+
|
7
|
+
testGroup("i18n", () => {
|
8
|
+
testAsync("updating a value", (done) => {
|
9
|
+
const now = moment()
|
10
|
+
const values = i18n[config.defaultLocale].date
|
11
|
+
|
12
|
+
const originalValue = values.today
|
13
|
+
values.today = "2day"
|
14
|
+
|
15
|
+
const el = addTimeEl({ type: "weekday", datetime: now.toISOString() })
|
16
|
+
defer(() => {
|
17
|
+
assert.equal(getText(el), "2day")
|
18
|
+
values.today = originalValue
|
19
|
+
done()
|
20
|
+
})
|
21
|
+
})
|
22
|
+
|
23
|
+
testAsync("adding a new locale", (done) => {
|
24
|
+
const now = moment()
|
25
|
+
|
26
|
+
const originalLocale = config.locale
|
27
|
+
config.locale = "es"
|
28
|
+
i18n.es = { date: { today: "hoy" } }
|
29
|
+
|
30
|
+
const el = addTimeEl({ type: "weekday", datetime: now.toISOString() })
|
31
|
+
defer(() => {
|
32
|
+
assert.equal(getText(el), "hoy")
|
33
|
+
config.locale = originalLocale
|
34
|
+
done()
|
35
|
+
})
|
36
|
+
})
|
37
|
+
|
38
|
+
testAsync("falling back to the default locale", (done) => {
|
39
|
+
const now = moment()
|
40
|
+
const yesterday = moment().subtract("days", 1)
|
41
|
+
|
42
|
+
const originalLocale = config.locale
|
43
|
+
config.locale = "es"
|
44
|
+
i18n.es = { date: { yesterday: "ayer" } }
|
45
|
+
|
46
|
+
const elWithTranslation = addTimeEl({ type: "weekday", datetime: yesterday.toISOString() })
|
47
|
+
const elWithoutTranslation = addTimeEl({ type: "weekday", datetime: now.toISOString() })
|
48
|
+
defer(() => {
|
49
|
+
assert.equal(getText(elWithTranslation), "ayer")
|
50
|
+
assert.equal(getText(elWithoutTranslation), "today")
|
51
|
+
config.locale = originalLocale
|
52
|
+
done()
|
53
|
+
})
|
54
|
+
})
|
55
|
+
})
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
const { addTimeEl, assert, defer, getText, setText, test, testAsync, testGroup, triggerEvent } = LocalTime.TestHelpers
|
4
|
+
|
5
|
+
testGroup("localized", () => {
|
6
|
+
for (var id of [ "one", "two", "past", "future" ]) {
|
7
|
+
test(id, () => {
|
8
|
+
assertLocalized(id)
|
9
|
+
})
|
10
|
+
}
|
11
|
+
|
12
|
+
test("date", () => {
|
13
|
+
assertLocalized("date", "date")
|
14
|
+
})
|
15
|
+
|
16
|
+
test("unparseable time", () => {
|
17
|
+
const el = addTimeEl({ format: "%Y", datetime: ":(" })
|
18
|
+
setText(el, "2013")
|
19
|
+
assert.equal(getText(el), "2013")
|
20
|
+
})
|
21
|
+
})
|
22
|
+
|
23
|
+
test("processed timestamp", () => {
|
24
|
+
const el = addTimeEl({ type: "time-or-date", datetime: moment().toISOString() })
|
25
|
+
assert.notOk(el.getAttribute("data-processed-at"))
|
26
|
+
LocalTime.run()
|
27
|
+
assert.ok(el.getAttribute("data-processed-at"))
|
28
|
+
})
|
29
|
+
|
30
|
+
function assertLocalized(id, type = "time") {
|
31
|
+
let compare, datetime, local, momentFormat
|
32
|
+
switch (type) {
|
33
|
+
case "time":
|
34
|
+
momentFormat = "MMMM D, YYYY h:mma"
|
35
|
+
compare = "toString"
|
36
|
+
break
|
37
|
+
case "date":
|
38
|
+
momentFormat = "MMMM D, YYYY"
|
39
|
+
compare = "dayOfYear"
|
40
|
+
break
|
41
|
+
}
|
42
|
+
|
43
|
+
const el = document.getElementById(id)
|
44
|
+
|
45
|
+
assert.ok(datetime = el.getAttribute("datetime"))
|
46
|
+
assert.ok(local = getText(el))
|
47
|
+
|
48
|
+
const datetimeParsed = moment(datetime)
|
49
|
+
const localParsed = moment(local, momentFormat)
|
50
|
+
|
51
|
+
assert.ok(datetimeParsed.isValid())
|
52
|
+
assert.ok(localParsed.isValid())
|
53
|
+
assert.equal(datetimeParsed[compare](), localParsed[compare]())
|
54
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
const { addTimeEl, assert, defer, getText, testAsync, testGroup, stubNow } = LocalTime.TestHelpers
|
4
|
+
|
5
|
+
testGroup("relative date", () => {
|
6
|
+
testAsync("this year", (done) => {
|
7
|
+
const now = moment()
|
8
|
+
const el = addTimeEl({ type: "date", datetime: now.toISOString() })
|
9
|
+
defer(() => {
|
10
|
+
assert.equal(getText(el), now.format("MMM D"))
|
11
|
+
done()
|
12
|
+
})
|
13
|
+
})
|
14
|
+
|
15
|
+
testAsync("last year", (done) => {
|
16
|
+
const before = moment().subtract("years", 1).subtract("days", 1)
|
17
|
+
const el = addTimeEl({ type: "date", datetime: before.toISOString() })
|
18
|
+
defer(() => {
|
19
|
+
assert.equal(getText(el), before.format("MMM D, YYYY"))
|
20
|
+
done()
|
21
|
+
})
|
22
|
+
})
|
23
|
+
})
|
24
|
+
|
25
|
+
testGroup("relative time or date", () => {
|
26
|
+
testAsync("today", (done) => {
|
27
|
+
const now = moment()
|
28
|
+
const el = addTimeEl({ type: "time-or-date", datetime: now.toISOString() })
|
29
|
+
defer(() => {
|
30
|
+
assert.equal(getText(el), now.format("h:mma"))
|
31
|
+
done()
|
32
|
+
})
|
33
|
+
})
|
34
|
+
|
35
|
+
testAsync("before today", (done) => {
|
36
|
+
const before = moment().subtract("days", 1)
|
37
|
+
const el = addTimeEl({ type: "time-or-date", datetime: before.toISOString() })
|
38
|
+
defer(() => {
|
39
|
+
assert.equal(getText(el), before.format("MMM D"))
|
40
|
+
done()
|
41
|
+
})
|
42
|
+
})
|
43
|
+
})
|
44
|
+
|
45
|
+
testGroup("relative weekday", () => {
|
46
|
+
testAsync("today", (done) => {
|
47
|
+
const now = moment()
|
48
|
+
const el = addTimeEl({ type: "weekday", datetime: now.toISOString() })
|
49
|
+
defer(() => {
|
50
|
+
assert.equal(getText(el), "today")
|
51
|
+
done()
|
52
|
+
})
|
53
|
+
})
|
54
|
+
|
55
|
+
testAsync("yesterday", (done) => {
|
56
|
+
const yesterday = moment().subtract("days", 1)
|
57
|
+
const el = addTimeEl({ type: "weekday", datetime: yesterday.toISOString() })
|
58
|
+
defer(() => {
|
59
|
+
assert.equal(getText(el), "yesterday")
|
60
|
+
done()
|
61
|
+
})
|
62
|
+
})
|
63
|
+
|
64
|
+
testAsync("this week", (done) => {
|
65
|
+
const recent = moment().subtract("days", 3)
|
66
|
+
const el = addTimeEl({ type: "weekday", datetime: recent.toISOString() })
|
67
|
+
defer(() => {
|
68
|
+
assert.equal(getText(el), recent.format("dddd"))
|
69
|
+
done()
|
70
|
+
})
|
71
|
+
})
|
72
|
+
|
73
|
+
testAsync("before this week", (done) => {
|
74
|
+
const before = moment().subtract("days", 8)
|
75
|
+
const el = addTimeEl({ type: "weekday", datetime: before.toISOString() })
|
76
|
+
defer(() => {
|
77
|
+
assert.equal(getText(el), "")
|
78
|
+
done()
|
79
|
+
})
|
80
|
+
})
|
81
|
+
})
|
82
|
+
|
83
|
+
testGroup("relative weekday or date", () => {
|
84
|
+
testAsync("today", (done) => {
|
85
|
+
const now = moment()
|
86
|
+
const el = addTimeEl({ type: "weekday-or-date", datetime: now.toISOString() })
|
87
|
+
defer(() => {
|
88
|
+
assert.equal(getText(el), "today")
|
89
|
+
done()
|
90
|
+
})
|
91
|
+
})
|
92
|
+
|
93
|
+
testAsync("yesterday", (done) => {
|
94
|
+
const yesterday = moment().subtract("days", 1)
|
95
|
+
const el = addTimeEl({ type: "weekday-or-date", datetime: yesterday.toISOString() })
|
96
|
+
defer(() => {
|
97
|
+
assert.equal(getText(el), "yesterday")
|
98
|
+
done()
|
99
|
+
})
|
100
|
+
})
|
101
|
+
|
102
|
+
testAsync("this week", (done) => {
|
103
|
+
const recent = moment().subtract("days", 3)
|
104
|
+
const el = addTimeEl({ type: "weekday-or-date", datetime: recent.toISOString() })
|
105
|
+
defer(() => {
|
106
|
+
assert.equal(getText(el), recent.format("dddd"))
|
107
|
+
done()
|
108
|
+
})
|
109
|
+
})
|
110
|
+
|
111
|
+
testAsync("before this week", (done) => {
|
112
|
+
stubNow(`${moment().year()}-03-20`, () => {
|
113
|
+
const before = moment().subtract("days", 8)
|
114
|
+
const el = addTimeEl({ type: "weekday-or-date", datetime: before.toISOString() })
|
115
|
+
defer(() => {
|
116
|
+
assert.equal(getText(el), before.format("MMM D"))
|
117
|
+
done()
|
118
|
+
})
|
119
|
+
})
|
120
|
+
})
|
121
|
+
})
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
const { addTimeEl, assert, defer, getText, setText, test, testAsync, testGroup, triggerEvent } = LocalTime.TestHelpers
|
4
|
+
|
5
|
+
const momentMap = {
|
6
|
+
"%a": "ddd",
|
7
|
+
"%A": "dddd",
|
8
|
+
"%b": "MMM",
|
9
|
+
"%B": "MMMM",
|
10
|
+
"%c": "toString()",
|
11
|
+
"%d": "DD",
|
12
|
+
"%-d": "D",
|
13
|
+
"%e": "D",
|
14
|
+
"%H": "HH",
|
15
|
+
"%-H": "H",
|
16
|
+
"%I": "hh",
|
17
|
+
"%-I": "h",
|
18
|
+
"%l": "h",
|
19
|
+
"%m": "MM",
|
20
|
+
"%-m": "M",
|
21
|
+
"%M": "mm",
|
22
|
+
"%-M": "m",
|
23
|
+
"%p": "A",
|
24
|
+
"%P": "a",
|
25
|
+
"%S": "ss",
|
26
|
+
"%-S": "s",
|
27
|
+
"%w": "e",
|
28
|
+
"%y": "YY",
|
29
|
+
"%Y": "YYYY"
|
30
|
+
}
|
31
|
+
|
32
|
+
function stubDateToLocaleString(stubImplementation, callback) {
|
33
|
+
const original = Date.prototype.toLocaleString
|
34
|
+
Date.prototype.toLocaleString = stubImplementation
|
35
|
+
try {
|
36
|
+
return callback()
|
37
|
+
} finally {
|
38
|
+
Date.prototype.toLocaleString = original
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
function stubDateToString(stubImplementation, callback) {
|
43
|
+
const original = Date.prototype.toString
|
44
|
+
Date.prototype.toString = stubImplementation
|
45
|
+
try {
|
46
|
+
return callback()
|
47
|
+
} finally {
|
48
|
+
Date.prototype.toString = original
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
testGroup("strftime", () => {
|
53
|
+
for (let day = 0; day <= 30; day += 6) {
|
54
|
+
for (let hour = 0; hour <= 24; hour += 6) {
|
55
|
+
for (const format in momentMap) {
|
56
|
+
if (Object.prototype.hasOwnProperty.call(momentMap, format)) {
|
57
|
+
const momentFormat = momentMap[ format ]
|
58
|
+
|
59
|
+
test(`${format} (+${day} days, ${hour} hours)`, () => {
|
60
|
+
const now = moment().add("days", day).add("hours", hour)
|
61
|
+
const el = addTimeEl({ format, datetime: now.toISOString() })
|
62
|
+
LocalTime.process(el)
|
63
|
+
|
64
|
+
if (momentFormat.includes("toString()")) {
|
65
|
+
assert.equal(getText(el), now.toDate().toString())
|
66
|
+
} else {
|
67
|
+
assert.equal(getText(el), now.format(momentFormat))
|
68
|
+
}
|
69
|
+
})
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
test(`%Z Timezone (+${day} days, ${hour} hours)`, () => {
|
74
|
+
const now = moment().add("days", day).add("hours", hour)
|
75
|
+
const el = addTimeEl({ format: "%Z", datetime: now.toISOString() })
|
76
|
+
LocalTime.process(el)
|
77
|
+
|
78
|
+
const text = getText(el)
|
79
|
+
assert.ok(/^(\w{3,4}|UTC[\+\-]\d+)$/.test(text), `'${text}' doesn't look like a timezone. System date: '${new Date}'`)
|
80
|
+
})
|
81
|
+
}
|
82
|
+
}
|
83
|
+
})
|
84
|
+
|
85
|
+
testGroup("strftime time zones", () => {
|
86
|
+
for (var timeZone of Array.from(Object.keys(LocalTime.knownEdgeCaseTimeZones))) {
|
87
|
+
((timeZone => test(`edge-case time zone ${timeZone}`, () => {
|
88
|
+
const stub = () => `Thu Nov 30 2023 14:22:57 GMT-0000 (${timeZone})`
|
89
|
+
|
90
|
+
stubDateToLocaleString(stub, () => {
|
91
|
+
const el = addTimeEl({ format: "%Z", datetime: "2023-11-30T14:22:57Z" })
|
92
|
+
LocalTime.process(el)
|
93
|
+
|
94
|
+
assert.equal(getText(el), LocalTime.knownEdgeCaseTimeZones[timeZone])
|
95
|
+
})
|
96
|
+
})))(timeZone)
|
97
|
+
}
|
98
|
+
|
99
|
+
test("time zones Intl can abbreviate are parsed correctly", () => {
|
100
|
+
const stub = (_, options) => {
|
101
|
+
if (options.timeZoneName === "long") {
|
102
|
+
return "Thu Nov 30 2023 14:22:57 GMT-0800 (Alaska Daylight Time)" // not a known edge-case
|
103
|
+
} else if (options.timeZoneName === "short") {
|
104
|
+
return "11/30/2023, 2:22:57 PM AKDT" // possible to abbreviate
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
stubDateToLocaleString(stub, () => {
|
109
|
+
const el = addTimeEl({ format: "%Z", datetime: "2023-11-30T14:22:57Z" })
|
110
|
+
LocalTime.process(el)
|
111
|
+
|
112
|
+
assert.equal(getText(el), "AKDT")
|
113
|
+
})
|
114
|
+
})
|
115
|
+
|
116
|
+
test("time zones Intl can't abbreviate are parsed by our heuristic", () => {
|
117
|
+
const dateToStringStub = () => "Sat Dec 02 2023 17:20:26 GMT-0600 (Central Standard Time)"
|
118
|
+
const dateToLocaleStringStub = (_, options) => {
|
119
|
+
if (options.timeZoneName === "long") {
|
120
|
+
return "Thu Nov 30 2023 14:22:57 GMT+0700 (Central Twilight Time)" // not a known edge-case
|
121
|
+
} else if (options.timeZoneName === "short") {
|
122
|
+
return "11/30/2023, 2:22:57 PM GMT+7" // not possible to abbreviate
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
stubDateToString(dateToStringStub, () => stubDateToLocaleString(dateToLocaleStringStub, () => {
|
127
|
+
const el = addTimeEl({ format: "%Z", datetime: "2023-11-30T14:22:57Z" })
|
128
|
+
LocalTime.process(el)
|
129
|
+
|
130
|
+
assert.equal(getText(el), "CST")
|
131
|
+
}))
|
132
|
+
})
|
133
|
+
|
134
|
+
test("time zones Intl can't abbreviate and our heuristic can't parse display GMT offset", () => {
|
135
|
+
const dateToStringStub = () => ""
|
136
|
+
const dateToLocaleStringStub = (_, options) => {
|
137
|
+
if (options.timeZoneName === "long") {
|
138
|
+
return "Thu Nov 30 2023 14:22:57 GMT+0700 (Central Twilight Time)" // not a known edge-case
|
139
|
+
} else if (options.timeZoneName === "short") {
|
140
|
+
return "11/30/2023, 2:22:57 PM GMT+7" // not possible to abbreviate
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
stubDateToString(dateToStringStub, () => stubDateToLocaleString(dateToLocaleStringStub, () => {
|
145
|
+
const el = addTimeEl({ format: "%Z", datetime: "2023-11-30T14:22:57Z" })
|
146
|
+
LocalTime.process(el)
|
147
|
+
|
148
|
+
assert.equal(getText(el), "GMT+7")
|
149
|
+
}))
|
150
|
+
})
|
151
|
+
})
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
LocalTime.start()
|
4
|
+
|
5
|
+
LocalTime.TestHelpers = {
|
6
|
+
assert: QUnit.assert,
|
7
|
+
testGroup: QUnit.module,
|
8
|
+
test: QUnit.test,
|
9
|
+
|
10
|
+
testAsync(name, callback) {
|
11
|
+
QUnit.test(name, (assert) => {
|
12
|
+
const done = assert.async()
|
13
|
+
callback(done)
|
14
|
+
})
|
15
|
+
},
|
16
|
+
|
17
|
+
addTimeEl(param = {}) {
|
18
|
+
let { format, type, datetime, format24 } = param
|
19
|
+
if (!format) format = "%Y"
|
20
|
+
if (!type) type = "time"
|
21
|
+
if (!datetime) datetime = "2013-11-12T12:13:00Z"
|
22
|
+
|
23
|
+
const el = document.createElement("time")
|
24
|
+
el.setAttribute("data-local", type)
|
25
|
+
el.setAttribute("data-format", format)
|
26
|
+
el.setAttribute("datetime", datetime)
|
27
|
+
if (format24) el.setAttribute("data-format24", format24)
|
28
|
+
|
29
|
+
document.body.appendChild(el)
|
30
|
+
return el
|
31
|
+
},
|
32
|
+
|
33
|
+
setText(el, text) {
|
34
|
+
el.textContent = text
|
35
|
+
},
|
36
|
+
|
37
|
+
getText(el) {
|
38
|
+
// innerHTML works in all browsers so using it ensures we're
|
39
|
+
// reading the text content, not a potentially arbitrary property.
|
40
|
+
return el.innerHTML
|
41
|
+
},
|
42
|
+
|
43
|
+
getTitle(el) {
|
44
|
+
return el.getAttribute("title")
|
45
|
+
},
|
46
|
+
|
47
|
+
triggerEvent(name, el = document) {
|
48
|
+
const event = document.createEvent("Events")
|
49
|
+
event.initEvent(name, true, true)
|
50
|
+
el.dispatchEvent(event)
|
51
|
+
},
|
52
|
+
|
53
|
+
defer(callback) {
|
54
|
+
setTimeout(callback, 1)
|
55
|
+
},
|
56
|
+
|
57
|
+
stubNow(dateString, callback) {
|
58
|
+
const originalNow = moment.now
|
59
|
+
try {
|
60
|
+
moment.now = () => new Date(dateString).getTime()
|
61
|
+
callback()
|
62
|
+
} finally {
|
63
|
+
moment.now = originalNow
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import LocalTime from "local_time"
|
2
|
+
|
3
|
+
const { addTimeEl, assert, defer, getText, setText, test, testAsync, testGroup, triggerEvent } = LocalTime.TestHelpers
|
4
|
+
|
5
|
+
testGroup("time ago", () => {
|
6
|
+
test("a second ago", () => {
|
7
|
+
assertTimeAgo("a second ago", "seconds", 9)
|
8
|
+
})
|
9
|
+
|
10
|
+
test("seconds ago", () => {
|
11
|
+
assertTimeAgo("44 seconds ago", "seconds", 44)
|
12
|
+
})
|
13
|
+
|
14
|
+
test("a minute ago", () => {
|
15
|
+
assertTimeAgo("a minute ago", "seconds", 89)
|
16
|
+
})
|
17
|
+
|
18
|
+
test("minutes ago", () => {
|
19
|
+
assertTimeAgo("44 minutes ago", "minutes", 44)
|
20
|
+
})
|
21
|
+
|
22
|
+
test("an hour ago", () => {
|
23
|
+
assertTimeAgo("an hour ago", "minutes", 89)
|
24
|
+
})
|
25
|
+
|
26
|
+
test("hours ago", () => {
|
27
|
+
assertTimeAgo("23 hours ago", "hours", 23)
|
28
|
+
})
|
29
|
+
|
30
|
+
test("yesterday", () => {
|
31
|
+
const time = moment().subtract("days", 1).format("h:mma")
|
32
|
+
assertTimeAgo(`yesterday at ${time}`, "days", 1)
|
33
|
+
})
|
34
|
+
|
35
|
+
test("tomorrow", () => {
|
36
|
+
const time = moment().add("days", 1).format("h:mma")
|
37
|
+
assertTimeAgo(`tomorrow at ${time}`, "days", -1)
|
38
|
+
})
|
39
|
+
|
40
|
+
test("last week", () => {
|
41
|
+
const ago = moment().subtract("days", 5)
|
42
|
+
const day = ago.format("dddd")
|
43
|
+
const time = ago.format("h:mma")
|
44
|
+
|
45
|
+
assertTimeAgo(`${day} at ${time}`, "days", 5)
|
46
|
+
})
|
47
|
+
|
48
|
+
test("this year", () => {
|
49
|
+
const clock = sinon.useFakeTimers(new Date(2013, 11, 11, 11, 11).getTime(), "Date")
|
50
|
+
const date = moment().subtract("days", 7).format("MMM D")
|
51
|
+
assertTimeAgo(`on ${date}`, "days", 7)
|
52
|
+
clock.restore()
|
53
|
+
})
|
54
|
+
|
55
|
+
test("last year", () => {
|
56
|
+
const date = moment().subtract("days", 366).format("MMM D, YYYY")
|
57
|
+
assertTimeAgo(`on ${date}`, "days", 366)
|
58
|
+
})
|
59
|
+
|
60
|
+
test("next year", () => {
|
61
|
+
const date = moment().add("days", 366).format("MMM D, YYYY")
|
62
|
+
assertTimeAgo(`on ${date}`, "days", -366)
|
63
|
+
})
|
64
|
+
})
|
65
|
+
|
66
|
+
function assertTimeAgo(string, unit, amount) {
|
67
|
+
const el = document.getElementById("ago")
|
68
|
+
el.setAttribute("data-local", "time-ago")
|
69
|
+
el.setAttribute("datetime", moment().subtract(unit, amount).utc().toISOString())
|
70
|
+
LocalTime.run()
|
71
|
+
assert.equal(getText(el), string)
|
72
|
+
}
|