Skip to content

Commit 677f6d1

Browse files
authored
Refine timestamp tests and update user transformer (#264)
1 parent 50b2b49 commit 677f6d1

File tree

4 files changed

+157
-4
lines changed

4 files changed

+157
-4
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import alertReducer from './alertReducer';
2+
3+
import { ALERT_CLEAR_ALL, ALERT_CREATE, ALERT_DISMISS } from 'Constants';
4+
5+
import type { Alert } from 'components/AlertZone/types';
6+
7+
describe('alertReducer', () => {
8+
it('creates alerts with generated ids', () => {
9+
const state = alertReducer([], {
10+
type: ALERT_CREATE,
11+
payload: { message: 'Hello world' },
12+
});
13+
expect(state).toHaveLength(1);
14+
expect(state[0]).toMatchObject({ message: 'Hello world', persistent: false });
15+
expect(state[0].id).toBeDefined();
16+
});
17+
18+
it('dismisses alerts matching payload properties', () => {
19+
const initial: Alert[] = [
20+
{ id: '1', message: 'a', title: '', type: 'info', persistent: false },
21+
{ id: '2', message: 'b', title: '', type: 'info', persistent: false },
22+
];
23+
const state = alertReducer(initial, {
24+
type: ALERT_DISMISS,
25+
payload: { id: '1' },
26+
});
27+
expect(state).toEqual([{ id: '2', message: 'b', title: '', type: 'info', persistent: false }]);
28+
});
29+
30+
it('clears non persistent alerts', () => {
31+
const initial: Alert[] = [
32+
{ id: '1', message: 'a', title: '', type: 'info', persistent: false },
33+
{ id: '2', message: 'b', title: '', type: 'info', persistent: true },
34+
];
35+
const state = alertReducer(initial, { type: ALERT_CLEAR_ALL });
36+
expect(state).toEqual([{ id: '2', message: 'b', title: '', type: 'info', persistent: true }]);
37+
});
38+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { settingsTransformer } from './settings.transformer';
2+
3+
describe('settingsTransformer', () => {
4+
it('applies defaults when values are missing', () => {
5+
expect(settingsTransformer(undefined)).toEqual({
6+
lang: 'auto',
7+
use12Hours: false,
8+
catchPaste: true,
9+
showTrackNumbers: false,
10+
hasActiveSubscription: false,
11+
keepOriginalTimestamp: true,
12+
patreonId: '',
13+
});
14+
});
15+
16+
it('transforms provided settings correctly', () => {
17+
const raw = {
18+
lang: 'es',
19+
use12Hours: true,
20+
catchPaste: false,
21+
showTrackNumbers: true,
22+
activeSubscription: true,
23+
keepOriginalTimestamp: false,
24+
patreonId: '12345',
25+
};
26+
27+
expect(settingsTransformer(raw)).toEqual({
28+
lang: 'es',
29+
use12Hours: true,
30+
catchPaste: false,
31+
showTrackNumbers: true,
32+
hasActiveSubscription: true,
33+
keepOriginalTimestamp: false,
34+
patreonId: '12345',
35+
});
36+
});
37+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { userTransformer } from './user.transformer';
2+
3+
describe('userTransformer', () => {
4+
it('transforms a full response correctly', () => {
5+
const raw = {
6+
token: 'abc123',
7+
user: {
8+
id: '42',
9+
name: 'Sufjan',
10+
url: 'https://example.com/sufjan',
11+
image: [
12+
{ size: 'small', '#text': 'sm.jpg' },
13+
{ size: 'medium', '#text': 'md.jpg' },
14+
],
15+
},
16+
isLoggedIn: true,
17+
};
18+
19+
expect(userTransformer(raw)).toEqual({
20+
token: 'abc123',
21+
user: {
22+
id: '42',
23+
name: 'Sufjan',
24+
avatar: { sm: 'sm.jpg', md: 'md.jpg' },
25+
url: 'https://example.com/sufjan',
26+
},
27+
isLoggedIn: true,
28+
});
29+
});
30+
31+
it('infers logged in state when missing flag', () => {
32+
const raw = {
33+
user: {
34+
name: 'Kurt Cobain',
35+
},
36+
};
37+
38+
expect(userTransformer(raw).isLoggedIn).toBe(true);
39+
});
40+
});

src/utils/datetime.test.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,50 @@
1-
import { formatDuration } from './datetime';
1+
import { formatDuration, formatScrobbleTimestamp } from './datetime';
22

33
describe('`formatDuration` helper', () => {
44
it('is correct', () => {
55
expect(formatDuration(45)).toEqual('0:45');
66
expect(formatDuration(150)).toEqual('2:30');
7-
expect(formatDuration(187)).toEqual('3:07');
8-
expect(formatDuration(777)).toEqual('12:57');
97
expect(formatDuration(3801)).toEqual('1:03:21');
10-
expect(formatDuration(4202)).toEqual('1:10:02');
8+
});
9+
10+
it('handles durations over 13 hours', () => {
11+
expect(formatDuration(13 * 3600 + 5)).toEqual('13:00:05');
12+
});
13+
14+
it('handles durations over 25 hours', () => {
15+
expect(formatDuration(25 * 3600 + 3)).toEqual('1:00:03');
16+
});
17+
});
18+
19+
describe('`formatScrobbleTimestamp` helper', () => {
20+
beforeEach(() => {
21+
vi.useFakeTimers();
22+
vi.setSystemTime(new Date('2025-06-15T12:00:00Z'));
23+
});
24+
25+
afterEach(() => {
26+
vi.useRealTimers();
27+
});
28+
29+
describe('24-hour format', () => {
30+
it('formats today, same year and previous year timestamps', () => {
31+
const today = new Date('2025-06-15T09:30:00');
32+
const sameYear = new Date('2025-02-01T17:05:00');
33+
const prevYear = new Date('2024-12-31T23:59:00');
34+
35+
expect(formatScrobbleTimestamp(today, false)).toBe('09:30');
36+
expect(formatScrobbleTimestamp(sameYear, false)).toBe('1/02 17:05');
37+
expect(formatScrobbleTimestamp(prevYear, false)).toBe('31/12/2024 23:59');
38+
});
39+
});
40+
41+
describe('12-hour format', () => {
42+
it('formats same year and previous year timestamps', () => {
43+
const sameYear = new Date('2025-02-01T17:05:00');
44+
const prevYear = new Date('2024-12-31T17:05:00');
45+
46+
expect(formatScrobbleTimestamp(sameYear, true)).toBe('2/1 05:05 PM');
47+
expect(formatScrobbleTimestamp(prevYear, true)).toBe('12/31/2024 05:05 PM');
48+
});
1149
});
1250
});

0 commit comments

Comments
 (0)