Skip to content

Commit acda776

Browse files
committed
Fixes #3817
Correct rounding and carry of minutes in Vue.prototype.$elapsedPrettyExtended -Add cypress tests for Vue.prototype.$elapsedPrettyExtended function
1 parent 7001adb commit acda776

File tree

2 files changed

+198
-5
lines changed

2 files changed

+198
-5
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import Vue from 'vue'
2+
import '@/plugins/utils'
3+
4+
// This is the actual function that is being tested
5+
const elapsedPrettyExtended = Vue.prototype.$elapsedPrettyExtended
6+
7+
// Helper function to convert days, hours, minutes, seconds to total seconds
8+
function DHMStoSeconds(days, hours, minutes, seconds) {
9+
return seconds + minutes * 60 + hours * 3600 + days * 86400
10+
}
11+
12+
describe('$elapsedPrettyExtended', () => {
13+
describe('function is on the Vue Prototype', () => {
14+
it('exists as a function on Vue.prototype', () => {
15+
expect(Vue.prototype.$elapsedPrettyExtended).to.exist
16+
expect(Vue.prototype.$elapsedPrettyExtended).to.be.a('function')
17+
})
18+
})
19+
20+
describe('param default values', () => {
21+
const testSeconds = DHMStoSeconds(0, 25, 1, 5) // 25h 1m 5s = 90065 seconds
22+
23+
it('uses useDays=true showSeconds=true by default', () => {
24+
expect(elapsedPrettyExtended(testSeconds)).to.equal('1d 1h 1m 5s')
25+
})
26+
27+
it('only useDays=false overrides useDays but keeps showSeconds=true', () => {
28+
expect(elapsedPrettyExtended(testSeconds, false)).to.equal('25h 1m 5s')
29+
})
30+
31+
it('explicit useDays=false showSeconds=false overrides both', () => {
32+
expect(elapsedPrettyExtended(testSeconds, false, false)).to.equal('25h 1m')
33+
})
34+
})
35+
36+
describe('useDays=false showSeconds=true', () => {
37+
const useDaysFalse = false
38+
const showSecondsTrue = true
39+
const testCases = [
40+
[[0, 0, 0, 0], '', '0s -> ""'],
41+
[[0, 1, 0, 1], '1h 1s', '1h 1s -> 1h 1s'],
42+
[[0, 25, 0, 1], '25h 1s', '25h 1s -> 25h 1s']
43+
]
44+
45+
testCases.forEach(([dhms, expected, description]) => {
46+
it(description, () => {
47+
expect(elapsedPrettyExtended(DHMStoSeconds(...dhms), useDaysFalse, showSecondsTrue)).to.equal(expected)
48+
})
49+
})
50+
})
51+
52+
describe('useDays=true showSeconds=true', () => {
53+
const useDaysTrue = true
54+
const showSecondsTrue = true
55+
const testCases = [
56+
[[0, 0, 0, 0], '', '0s -> ""'],
57+
[[0, 1, 0, 1], '1h 1s', '1h 1s -> 1h 1s'],
58+
[[0, 25, 0, 1], '1d 1h 1s', '25h 1s -> 1d 1h 1s']
59+
]
60+
61+
testCases.forEach(([dhms, expected, description]) => {
62+
it(description, () => {
63+
expect(elapsedPrettyExtended(DHMStoSeconds(...dhms), useDaysTrue, showSecondsTrue)).to.equal(expected)
64+
})
65+
})
66+
})
67+
68+
describe('useDays=true showSeconds=false', () => {
69+
const useDaysTrue = true
70+
const showSecondsFalse = false
71+
const testCases = [
72+
[[0, 0, 0, 0], '', '0s -> ""'],
73+
[[0, 1, 0, 0], '1h', '1h -> 1h'],
74+
[[0, 1, 0, 1], '1h', '1h 1s -> 1h'],
75+
[[0, 1, 1, 0], '1h 1m', '1h 1m -> 1h 1m'],
76+
[[0, 25, 0, 0], '1d 1h', '25h -> 1d 1h'],
77+
[[0, 25, 0, 1], '1d 1h', '25h 1s -> 1d 1h'],
78+
[[2, 0, 0, 0], '2d', '2d -> 2d']
79+
]
80+
81+
testCases.forEach(([dhms, expected, description]) => {
82+
it(description, () => {
83+
expect(elapsedPrettyExtended(DHMStoSeconds(...dhms), useDaysTrue, showSecondsFalse)).to.equal(expected)
84+
})
85+
})
86+
})
87+
88+
describe('rounding useDays=true showSeconds=true', () => {
89+
const useDaysTrue = true
90+
const showSecondsTrue = true
91+
const testCases = [
92+
// Seconds rounding
93+
[[0, 0, 0, 1], '1s', '1s -> 1s'],
94+
[[0, 0, 0, 29.9], '30s', '29.9s -> 30s'],
95+
[[0, 0, 0, 30], '30s', '30s -> 30s'],
96+
[[0, 0, 0, 30.1], '30s', '30.1s -> 30s'],
97+
[[0, 0, 0, 59.4], '59s', '59.4s -> 59s'],
98+
[[0, 0, 0, 59.5], '1m', '59.5s -> 1m'],
99+
100+
// Minutes rounding
101+
[[0, 0, 59, 29], '59m 29s', '59m 29s -> 59m 29s'],
102+
[[0, 0, 59, 30], '59m 30s', '59m 30s -> 59m 30s'],
103+
[[0, 0, 59, 59.5], '1h', '59m 59.5s -> 1h'],
104+
105+
// Hours rounding
106+
[[0, 23, 59, 29], '23h 59m 29s', '23h 59m 29s -> 23h 59m 29s'],
107+
[[0, 23, 59, 30], '23h 59m 30s', '23h 59m 30s -> 23h 59m 30s'],
108+
[[0, 23, 59, 59.5], '1d', '23h 59m 59.5s -> 1d'],
109+
110+
// The actual bug case
111+
[[44, 23, 59, 30], '44d 23h 59m 30s', '44d 23h 59m 30s -> 44d 23h 59m 30s']
112+
]
113+
114+
testCases.forEach(([dhms, expected, description]) => {
115+
it(description, () => {
116+
expect(elapsedPrettyExtended(DHMStoSeconds(...dhms), useDaysTrue, showSecondsTrue)).to.equal(expected)
117+
})
118+
})
119+
})
120+
121+
describe('rounding useDays=true showSeconds=false', () => {
122+
const useDaysTrue = true
123+
const showSecondsFalse = false
124+
const testCases = [
125+
// Seconds rounding - these cases changed behavior from original
126+
[[0, 0, 0, 1], '', '1s -> ""'],
127+
[[0, 0, 0, 29.9], '', '29.9s -> ""'],
128+
[[0, 0, 0, 30], '', '30s -> ""'],
129+
[[0, 0, 0, 30.1], '', '30.1s -> ""'],
130+
[[0, 0, 0, 59.4], '', '59.4s -> ""'],
131+
[[0, 0, 0, 59.5], '1m', '59.5s -> 1m'],
132+
// This is unexpected behavior, but it's consistent with the original behavior
133+
// We preserved the test case, to document the current behavior
134+
// - with showSeconds=false,
135+
// one might expect: 1m 29.5s --round(1.4901m)-> 1m
136+
// actual implementation: 1h 29.5s --roundSeconds-> 1h 30s --roundMinutes-> 2m
137+
// So because of the separate rounding of seconds, and then minutes, it returns 2m
138+
[[0, 0, 1, 29.5], '2m', '1m 29.5s -> 2m'],
139+
140+
// Minutes carry - actual bug fixes below
141+
[[0, 0, 59, 29], '59m', '59m 29s -> 59m'],
142+
[[0, 0, 59, 30], '1h', '59m 30s -> 1h'], // This was an actual bug, used to return 60m
143+
[[0, 0, 59, 59.5], '1h', '59m 59.5s -> 1h'],
144+
145+
// Hours carry
146+
[[0, 23, 59, 29], '23h 59m', '23h 59m 29s -> 23h 59m'],
147+
[[0, 23, 59, 30], '1d', '23h 59m 30s -> 1d'], // This was an actual bug, used to return 23h 60m
148+
[[0, 23, 59, 59.5], '1d', '23h 59m 59.5s -> 1d'],
149+
150+
// The actual bug case
151+
[[44, 23, 59, 30], '45d', '44d 23h 59m 30s -> 45d'] // This was an actual bug, used to return 44d 23h 60m
152+
]
153+
154+
testCases.forEach(([dhms, expected, description]) => {
155+
it(description, () => {
156+
expect(elapsedPrettyExtended(DHMStoSeconds(...dhms), useDaysTrue, showSecondsFalse)).to.equal(expected)
157+
})
158+
})
159+
})
160+
161+
describe('empty values', () => {
162+
const paramCombos = [
163+
// useDays, showSeconds, description
164+
[true, true, 'with days and seconds'],
165+
[true, false, 'with days, no seconds'],
166+
[false, true, 'no days, with seconds'],
167+
[false, false, 'no days, no seconds']
168+
]
169+
170+
const emptyInputs = [
171+
// input, description
172+
[null, 'null input'],
173+
[undefined, 'undefined input'],
174+
[0, 'zero'],
175+
[0.49, 'rounds to zero'] // Just under rounding threshold
176+
]
177+
178+
paramCombos.forEach(([useDays, showSeconds, paramDesc]) => {
179+
describe(paramDesc, () => {
180+
emptyInputs.forEach(([input, desc]) => {
181+
it(desc, () => {
182+
expect(elapsedPrettyExtended(input, useDays, showSeconds)).to.equal('')
183+
})
184+
})
185+
})
186+
})
187+
})
188+
})

client/plugins/utils.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,22 @@ Vue.prototype.$elapsedPrettyExtended = (seconds, useDays = true, showSeconds = t
6969
let hours = Math.floor(minutes / 60)
7070
minutes -= hours * 60
7171

72+
// Handle rollovers before days calculation
73+
if (minutes && seconds && !showSeconds) {
74+
if (seconds >= 30) minutes++
75+
if (minutes >= 60) {
76+
hours++ // Increment hours if minutes roll over
77+
minutes -= 60 // adjust minutes
78+
}
79+
}
80+
81+
// Now calculate days with the final hours value
7282
let days = 0
7383
if (useDays || Math.floor(hours / 24) >= 100) {
7484
days = Math.floor(hours / 24)
7585
hours -= days * 24
7686
}
7787

78-
// If not showing seconds then round minutes up
79-
if (minutes && seconds && !showSeconds) {
80-
if (seconds >= 30) minutes++
81-
}
82-
8388
const strs = []
8489
if (days) strs.push(`${days}d`)
8590
if (hours) strs.push(`${hours}h`)

0 commit comments

Comments
 (0)