Skip to content

Commit 911b372

Browse files
test(timePresets): add utility tests
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent b0242d0 commit 911b372

1 file changed

Lines changed: 153 additions & 0 deletions

File tree

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 LibreSign contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7+
8+
import { getTimePresetRange, getTimePresets } from '../../utils/timePresets.js'
9+
10+
vi.mock('@nextcloud/l10n', () => ({
11+
t: (_app: string, text: string) => text,
12+
}))
13+
14+
describe('getTimePresets', () => {
15+
describe('business rule: should return all 5 presets with correct structure', () => {
16+
it('returns exactly 5 presets', () => {
17+
expect(getTimePresets()).toHaveLength(5)
18+
})
19+
20+
it('each preset has id, label, start, end', () => {
21+
getTimePresets().forEach(preset => {
22+
expect(preset).toHaveProperty('id')
23+
expect(preset).toHaveProperty('label')
24+
expect(preset).toHaveProperty('start')
25+
expect(preset).toHaveProperty('end')
26+
})
27+
})
28+
29+
it('returns presets with the expected ids in order', () => {
30+
const ids = getTimePresets().map(p => p.id)
31+
expect(ids).toEqual(['today', 'last-7', 'last-30', 'this-year', 'last-year'])
32+
})
33+
34+
it('each preset start is before its end', () => {
35+
getTimePresets().forEach(preset => {
36+
expect(preset.start).toBeLessThan(preset.end)
37+
})
38+
})
39+
})
40+
41+
describe('business rule: today preset should span the current day', () => {
42+
it('start is midnight of today', () => {
43+
const preset = getTimePresets().find(p => p.id === 'today')!
44+
const d = new Date(preset.start)
45+
expect(d.getHours()).toBe(0)
46+
expect(d.getMinutes()).toBe(0)
47+
expect(d.getSeconds()).toBe(0)
48+
})
49+
50+
it('end is 23:59:59.999 of today', () => {
51+
const preset = getTimePresets().find(p => p.id === 'today')!
52+
const d = new Date(preset.end)
53+
expect(d.getHours()).toBe(23)
54+
expect(d.getMinutes()).toBe(59)
55+
expect(d.getSeconds()).toBe(59)
56+
})
57+
})
58+
59+
describe('business rule: range widths should match their names', () => {
60+
const MS_PER_DAY = 24 * 60 * 60 * 1000
61+
62+
it('last-7 spans approximately 7 days', () => {
63+
const preset = getTimePresets().find(p => p.id === 'last-7')!
64+
const days = (preset.end - preset.start) / MS_PER_DAY
65+
expect(days).toBeGreaterThanOrEqual(7)
66+
expect(days).toBeLessThan(8)
67+
})
68+
69+
it('last-30 spans approximately 30 days', () => {
70+
const preset = getTimePresets().find(p => p.id === 'last-30')!
71+
const days = (preset.end - preset.start) / MS_PER_DAY
72+
expect(days).toBeGreaterThanOrEqual(30)
73+
expect(days).toBeLessThan(31)
74+
})
75+
76+
it('this-year starts on January 1st', () => {
77+
const preset = getTimePresets().find(p => p.id === 'this-year')!
78+
const d = new Date(preset.start)
79+
expect(d.getMonth()).toBe(0)
80+
expect(d.getDate()).toBe(1)
81+
expect(d.getFullYear()).toBe(new Date().getFullYear())
82+
})
83+
84+
it('last-year starts on January 1st of the previous year', () => {
85+
const preset = getTimePresets().find(p => p.id === 'last-year')!
86+
const d = new Date(preset.start)
87+
expect(d.getMonth()).toBe(0)
88+
expect(d.getDate()).toBe(1)
89+
expect(d.getFullYear()).toBe(new Date().getFullYear() - 1)
90+
})
91+
})
92+
93+
describe('business rule: dates are computed fresh on each call', () => {
94+
beforeEach(() => {
95+
vi.useFakeTimers()
96+
})
97+
98+
afterEach(() => {
99+
vi.useRealTimers()
100+
})
101+
102+
it('returns different start for today when the date changes', () => {
103+
vi.setSystemTime(new Date('2026-01-01T00:00:00'))
104+
const presets1 = getTimePresets()
105+
106+
vi.setSystemTime(new Date('2026-02-15T00:00:00'))
107+
const presets2 = getTimePresets()
108+
109+
expect(presets1[0].start).not.toBe(presets2[0].start)
110+
})
111+
112+
it('always uses the fake current date, not a cached value', () => {
113+
vi.setSystemTime(new Date('2026-06-15T12:00:00'))
114+
const preset = getTimePresets().find(p => p.id === 'this-year')!
115+
expect(new Date(preset.start).getFullYear()).toBe(2026)
116+
})
117+
})
118+
})
119+
120+
describe('getTimePresetRange', () => {
121+
describe('business rule: should return null for missing or unknown ids', () => {
122+
it('returns null when presetId is empty string', () => {
123+
expect(getTimePresetRange('')).toBeNull()
124+
})
125+
126+
it('returns null when presetId is null/undefined', () => {
127+
expect(getTimePresetRange(null as unknown as string)).toBeNull()
128+
expect(getTimePresetRange(undefined as unknown as string)).toBeNull()
129+
})
130+
131+
it('returns null for unknown preset id', () => {
132+
expect(getTimePresetRange('unknown')).toBeNull()
133+
expect(getTimePresetRange('weekly')).toBeNull()
134+
})
135+
})
136+
137+
describe('business rule: should return { start, end } for known ids', () => {
138+
it.each(['today', 'last-7', 'last-30', 'this-year', 'last-year'])('returns range for "%s"', (id) => {
139+
const range = getTimePresetRange(id)
140+
expect(range).not.toBeNull()
141+
expect(range!.start).toBeTypeOf('number')
142+
expect(range!.end).toBeTypeOf('number')
143+
expect(range!.start).toBeLessThan(range!.end)
144+
})
145+
146+
it('range values match getTimePresets output', () => {
147+
const preset = getTimePresets().find(p => p.id === 'last-7')!
148+
const range = getTimePresetRange('last-7')!
149+
expect(range.start).toBe(preset.start)
150+
expect(range.end).toBe(preset.end)
151+
})
152+
})
153+
})

0 commit comments

Comments
 (0)