@osimatic/helpers-js 1.4.24 → 1.4.26
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.
- package/.claude/settings.local.json +2 -1
- package/chartjs.js +1 -1
- package/date_time.js +25 -16
- package/draw.js +3 -2
- package/duration.js +176 -130
- package/event_bus.js +2 -2
- package/file.js +20 -5
- package/form_helper.js +1 -1
- package/google_charts.js +2 -1
- package/http_client.js +2 -0
- package/jwt.js +18 -6
- package/location.js +5 -1
- package/media.js +7 -7
- package/multi_files_input.js +3 -1
- package/number.js +2 -3
- package/package.json +4 -2
- package/paging.js +2 -2
- package/social_network.js +5 -0
- package/string.js +11 -2
- package/tests/__mocks__/socket.io-client.js +13 -0
- package/tests/chartjs.test.js +273 -0
- package/tests/count_down.test.js +580 -0
- package/tests/date_time/DatePeriod.test.js +179 -0
- package/tests/date_time/DateTime.test.js +492 -0
- package/tests/date_time/SqlDate.test.js +205 -0
- package/tests/date_time/SqlDateTime.test.js +326 -0
- package/tests/date_time/SqlTime.test.js +162 -0
- package/tests/date_time/TimestampUnix.test.js +262 -0
- package/tests/details_sub_array.test.js +367 -0
- package/tests/draw.test.js +271 -0
- package/tests/duration.test.js +365 -0
- package/tests/event_bus.test.js +268 -0
- package/tests/file.test.js +568 -0
- package/tests/flash_message.test.js +297 -0
- package/tests/form_date.test.js +1559 -0
- package/tests/form_helper.test.js +1065 -0
- package/tests/google_charts.test.js +768 -0
- package/tests/google_maps.test.js +655 -0
- package/tests/google_recaptcha.test.js +441 -0
- package/tests/http_client.test.js +570 -0
- package/tests/import_from_csv.test.js +797 -0
- package/tests/jwt.test.js +804 -0
- package/tests/list_box.test.js +255 -0
- package/tests/location.test.js +86 -0
- package/tests/media.test.js +473 -0
- package/tests/multi_files_input.test.js +1015 -0
- package/tests/multiple_action_in_table.test.js +477 -0
- package/tests/network.test.js +489 -0
- package/tests/number.test.js +448 -0
- package/tests/open_street_map.test.js +388 -0
- package/tests/paging.test.js +646 -0
- package/tests/select_all.test.js +360 -0
- package/tests/shopping_cart.test.js +355 -0
- package/tests/social_network.test.js +333 -0
- package/tests/sortable_list.test.js +602 -0
- package/tests/string.test.js +489 -0
- package/tests/user.test.js +204 -0
- package/tests/util.test.js +99 -0
- package/tests/visitor.test.js +508 -0
- package/tests/web_rtc.test.js +458 -0
- package/tests/web_socket.test.js +538 -0
- package/visitor.js +2 -2
- package/tmpclaude-0fa4-cwd +0 -1
- package/tmpclaude-104f-cwd +0 -1
- package/tmpclaude-1468-cwd +0 -1
- package/tmpclaude-324b-cwd +0 -1
- package/tmpclaude-35d3-cwd +0 -1
- package/tmpclaude-4aa8-cwd +0 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
const { TimestampUnix } = require('../../date_time');
|
|
2
|
+
|
|
3
|
+
describe('TimestampUnix', () => {
|
|
4
|
+
describe('parse', () => {
|
|
5
|
+
test('should parse Unix timestamp to Date', () => {
|
|
6
|
+
const timestamp = 1705314600; // 2024-01-15 10:30:00 UTC
|
|
7
|
+
const result = TimestampUnix.parse(timestamp);
|
|
8
|
+
expect(result instanceof Date).toBe(true);
|
|
9
|
+
expect(result.getTime()).toBe(1705314600000);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('should return null for null input', () => {
|
|
13
|
+
expect(TimestampUnix.parse(null)).toBeNull();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should handle timestamp 0', () => {
|
|
17
|
+
const result = TimestampUnix.parse(0);
|
|
18
|
+
expect(result.getTime()).toBe(0);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('getCurrent', () => {
|
|
23
|
+
test('should return current Unix timestamp', () => {
|
|
24
|
+
const result = TimestampUnix.getCurrent();
|
|
25
|
+
const now = Math.trunc(Date.now() / 1000);
|
|
26
|
+
expect(result).toBeCloseTo(now, 0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('should return an integer', () => {
|
|
30
|
+
const result = TimestampUnix.getCurrent();
|
|
31
|
+
expect(Number.isInteger(result)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('getDateDigitalDisplay', () => {
|
|
36
|
+
test('should format timestamp date in digital format', () => {
|
|
37
|
+
const timestamp = 1705314600;
|
|
38
|
+
const result = TimestampUnix.getDateDigitalDisplay(timestamp, 'fr-FR', 'UTC');
|
|
39
|
+
expect(result).toContain('15');
|
|
40
|
+
expect(result).toContain('01');
|
|
41
|
+
expect(result).toContain('2024');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('getDateTextDisplay', () => {
|
|
46
|
+
test('should format timestamp date in text format', () => {
|
|
47
|
+
const timestamp = 1705314600;
|
|
48
|
+
const result = TimestampUnix.getDateTextDisplay(timestamp, 'fr-FR', 'UTC');
|
|
49
|
+
expect(typeof result).toBe('string');
|
|
50
|
+
expect(result.length).toBeGreaterThan(10);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('getTimeDisplay', () => {
|
|
55
|
+
test('should format timestamp time', () => {
|
|
56
|
+
const timestamp = 1705314600;
|
|
57
|
+
const result = TimestampUnix.getTimeDisplay(timestamp, 'fr-FR', 'UTC');
|
|
58
|
+
expect(result).toContain('10');
|
|
59
|
+
expect(result).toContain('30');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('getTimeDisplayWithNbDays', () => {
|
|
64
|
+
test('should display time without days difference', () => {
|
|
65
|
+
const timestamp = 1705314600;
|
|
66
|
+
const result = TimestampUnix.getTimeDisplayWithNbDays(timestamp, 0, 'fr-FR', 'UTC');
|
|
67
|
+
expect(result).toContain('10');
|
|
68
|
+
expect(result).toContain('30');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should display time with days difference', () => {
|
|
72
|
+
const timestamp1 = 1705315800; // 2024-01-15 10:30:00
|
|
73
|
+
const timestamp2 = 1705574400; // 2024-01-18 10:00:00
|
|
74
|
+
const result = TimestampUnix.getTimeDisplayWithNbDays(timestamp2, timestamp1, 'fr-FR', 'UTC');
|
|
75
|
+
expect(result).toContain('J+');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('getTimeDigitalDisplay', () => {
|
|
80
|
+
test('should format timestamp time in digital format', () => {
|
|
81
|
+
const timestamp = 1705314600;
|
|
82
|
+
const result = TimestampUnix.getTimeDigitalDisplay(timestamp, 'fr-FR', 'UTC');
|
|
83
|
+
expect(result).toMatch(/\d{2}:\d{2}:\d{2}/);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('getYear', () => {
|
|
88
|
+
test('should return year from timestamp', () => {
|
|
89
|
+
const timestamp = 1705314600;
|
|
90
|
+
const result = TimestampUnix.getYear(timestamp, 'UTC');
|
|
91
|
+
expect(result).toBe(2024);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('getMonth', () => {
|
|
96
|
+
test('should return month from timestamp', () => {
|
|
97
|
+
const timestamp = 1705314600;
|
|
98
|
+
const result = TimestampUnix.getMonth(timestamp, 'UTC');
|
|
99
|
+
expect(result).toBe(1);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('getDayOfMonth', () => {
|
|
104
|
+
test('should return day of month from timestamp', () => {
|
|
105
|
+
const timestamp = 1705314600;
|
|
106
|
+
const result = TimestampUnix.getDayOfMonth(timestamp, 'UTC');
|
|
107
|
+
expect(result).toBe(15);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('getHour', () => {
|
|
112
|
+
test('should return hour from timestamp', () => {
|
|
113
|
+
const timestamp = 1705314600;
|
|
114
|
+
const result = TimestampUnix.getHour(timestamp, 'UTC');
|
|
115
|
+
expect(result).toBe(10);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('getMinute', () => {
|
|
120
|
+
test('should return minute from timestamp', () => {
|
|
121
|
+
const timestamp = 1705314600;
|
|
122
|
+
const result = TimestampUnix.getMinute(timestamp, 'UTC');
|
|
123
|
+
expect(result).toBe(30);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('getSecond', () => {
|
|
128
|
+
test('should return second from timestamp', () => {
|
|
129
|
+
const timestamp = 1705314600;
|
|
130
|
+
const result = TimestampUnix.getSecond(timestamp, 'UTC');
|
|
131
|
+
expect(result).toBe(0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('should return 45 seconds', () => {
|
|
135
|
+
const timestamp = 1705315845;
|
|
136
|
+
const result = TimestampUnix.getSecond(timestamp, 'UTC');
|
|
137
|
+
expect(result).toBe(45);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('getSqlDateTime', () => {
|
|
142
|
+
test('should convert timestamp to SQL datetime', () => {
|
|
143
|
+
const timestamp = 1705314600;
|
|
144
|
+
const result = TimestampUnix.getSqlDateTime(timestamp, 'UTC');
|
|
145
|
+
expect(result).toMatch(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('getSqlDate', () => {
|
|
150
|
+
test('should convert timestamp to SQL date', () => {
|
|
151
|
+
const timestamp = 1705314600;
|
|
152
|
+
const result = TimestampUnix.getSqlDate(timestamp, 'UTC');
|
|
153
|
+
expect(result).toBe('2024-01-15');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('getSqlTime', () => {
|
|
158
|
+
test('should convert timestamp to SQL time', () => {
|
|
159
|
+
const timestamp = 1705314600;
|
|
160
|
+
const result = TimestampUnix.getSqlTime(timestamp, 'UTC');
|
|
161
|
+
expect(result).toBe('10:30:00');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('getDateForInputDate', () => {
|
|
166
|
+
test('should return date for input field', () => {
|
|
167
|
+
const timestamp = 1705314600;
|
|
168
|
+
const result = TimestampUnix.getDateForInputDate(timestamp, 'UTC');
|
|
169
|
+
expect(result).toBe('2024-01-15');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('getTimeForInputTime', () => {
|
|
174
|
+
test('should return time for input field without seconds', () => {
|
|
175
|
+
const timestamp = 1705314600;
|
|
176
|
+
const result = TimestampUnix.getTimeForInputTime(timestamp, 'UTC', false);
|
|
177
|
+
expect(result).toMatch(/^\d{2}:\d{2}$/);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('should return time for input field with seconds', () => {
|
|
181
|
+
const timestamp = 1705314600;
|
|
182
|
+
const result = TimestampUnix.getTimeForInputTime(timestamp, 'UTC', true);
|
|
183
|
+
expect(result).toMatch(/^\d{2}:\d{2}:\d{2}$/);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('isDateEqual', () => {
|
|
188
|
+
test('should return true for timestamps on same date', () => {
|
|
189
|
+
const timestamp1 = 1705315800; // 2024-01-15 10:30:00
|
|
190
|
+
const timestamp2 = 1705329600; // 2024-01-15 14:20:00
|
|
191
|
+
expect(TimestampUnix.isDateEqual(timestamp1, timestamp2)).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('should return false for timestamps on different dates', () => {
|
|
195
|
+
const timestamp1 = 1705315800; // 2024-01-15
|
|
196
|
+
const timestamp2 = 1705402200; // 2024-01-16
|
|
197
|
+
expect(TimestampUnix.isDateEqual(timestamp1, timestamp2)).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('getNbDayBetweenTwo', () => {
|
|
202
|
+
test('should calculate days between two timestamps', () => {
|
|
203
|
+
const timestamp1 = 1705315800; // 2024-01-15 10:30:00
|
|
204
|
+
const timestamp2 = 1705747800; // 2024-01-20 10:30:00
|
|
205
|
+
expect(TimestampUnix.getNbDayBetweenTwo(timestamp1, timestamp2, true, 'UTC')).toBe(5);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('should return 0 for same day', () => {
|
|
209
|
+
const timestamp1 = 1705315800; // 2024-01-15 10:30:00
|
|
210
|
+
const timestamp2 = 1705329600; // 2024-01-15 14:20:00
|
|
211
|
+
expect(TimestampUnix.getNbDayBetweenTwo(timestamp1, timestamp2, false, 'UTC')).toBe(0);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('isDateInThePast', () => {
|
|
216
|
+
test('should return true for past timestamp', () => {
|
|
217
|
+
const timestamp = 1577836800; // 2020-01-01
|
|
218
|
+
expect(TimestampUnix.isDateInThePast(timestamp)).toBe(true);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test('should return false for future timestamp', () => {
|
|
222
|
+
const timestamp = 1893456000; // 2030-01-01
|
|
223
|
+
expect(TimestampUnix.isDateInThePast(timestamp)).toBe(false);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe('isDateTimeInThePast', () => {
|
|
228
|
+
test('should return true for past timestamp', () => {
|
|
229
|
+
const timestamp = 1577836800; // 2020-01-01
|
|
230
|
+
expect(TimestampUnix.isDateTimeInThePast(timestamp)).toBe(true);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test('should return false for future timestamp', () => {
|
|
234
|
+
const timestamp = 1893456000; // 2030-01-01
|
|
235
|
+
expect(TimestampUnix.isDateTimeInThePast(timestamp)).toBe(false);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('isDateInTheFuture', () => {
|
|
240
|
+
test('should return true for future timestamp', () => {
|
|
241
|
+
const timestamp = 1893456000; // 2030-01-01
|
|
242
|
+
expect(TimestampUnix.isDateInTheFuture(timestamp)).toBe(true);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test('should return false for past timestamp', () => {
|
|
246
|
+
const timestamp = 1577836800; // 2020-01-01
|
|
247
|
+
expect(TimestampUnix.isDateInTheFuture(timestamp)).toBe(false);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('isDateTimeInTheFuture', () => {
|
|
252
|
+
test('should return true for future timestamp', () => {
|
|
253
|
+
const timestamp = 1893456000; // 2030-01-01
|
|
254
|
+
expect(TimestampUnix.isDateTimeInTheFuture(timestamp)).toBe(true);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('should return false for past timestamp', () => {
|
|
258
|
+
const timestamp = 1577836800; // 2020-01-01
|
|
259
|
+
expect(TimestampUnix.isDateTimeInTheFuture(timestamp)).toBe(false);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
const { DetailsSubArray } = require('../details_sub_array');
|
|
5
|
+
|
|
6
|
+
// Mock HTTPClient
|
|
7
|
+
jest.mock('../http_client', () => ({
|
|
8
|
+
HTTPClient: {
|
|
9
|
+
request: jest.fn()
|
|
10
|
+
}
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const { HTTPClient } = require('../http_client');
|
|
14
|
+
|
|
15
|
+
describe('DetailsSubArray', () => {
|
|
16
|
+
let mockTable;
|
|
17
|
+
let mockLink;
|
|
18
|
+
let mockTr;
|
|
19
|
+
let mockThead;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
// Clear all mocks
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
|
|
25
|
+
// Define global labels used by the code
|
|
26
|
+
global.showDetailsLabel = 'Show details';
|
|
27
|
+
global.hideDetailsLabel = 'Hide details';
|
|
28
|
+
global.labelErrorOccured = 'An error occurred';
|
|
29
|
+
|
|
30
|
+
// Make HTTPClient available globally
|
|
31
|
+
global.HTTPClient = HTTPClient;
|
|
32
|
+
|
|
33
|
+
// Create mock DOM structure
|
|
34
|
+
mockThead = {
|
|
35
|
+
find: jest.fn((selector) => {
|
|
36
|
+
if (selector === 'thead tr') {
|
|
37
|
+
return {
|
|
38
|
+
children: jest.fn(() => ({ length: 5 }))
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
children: jest.fn(() => ({ length: 5 }))
|
|
43
|
+
};
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
mockTr = {
|
|
48
|
+
closest: jest.fn((selector) => {
|
|
49
|
+
if (selector === 'table') {
|
|
50
|
+
return {
|
|
51
|
+
find: jest.fn((sel) => {
|
|
52
|
+
if (sel === 'thead tr') {
|
|
53
|
+
return {
|
|
54
|
+
children: jest.fn(() => ({ length: 5 }))
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return mockThead;
|
|
58
|
+
})
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return mockTr;
|
|
62
|
+
}),
|
|
63
|
+
after: jest.fn(),
|
|
64
|
+
addClass: jest.fn().mockReturnThis(),
|
|
65
|
+
next: jest.fn(() => ({
|
|
66
|
+
hasClass: jest.fn(() => false),
|
|
67
|
+
remove: jest.fn()
|
|
68
|
+
}))
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
mockLink = {
|
|
72
|
+
data: jest.fn((key) => {
|
|
73
|
+
if (key === 'url_details') return 'http://example.com/details';
|
|
74
|
+
return null;
|
|
75
|
+
}),
|
|
76
|
+
closest: jest.fn(() => mockTr),
|
|
77
|
+
prop: jest.fn().mockReturnThis(),
|
|
78
|
+
attr: jest.fn().mockReturnThis(),
|
|
79
|
+
html: jest.fn().mockReturnThis(),
|
|
80
|
+
click: jest.fn().mockReturnThis(),
|
|
81
|
+
stop: jest.fn().mockReturnThis(),
|
|
82
|
+
off: jest.fn().mockReturnThis(),
|
|
83
|
+
removeClass: jest.fn().mockReturnThis()
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
mockTable = {
|
|
87
|
+
find: jest.fn(() => ({
|
|
88
|
+
each: jest.fn((callback) => {
|
|
89
|
+
// Simulate one link found
|
|
90
|
+
callback(0, mockLink);
|
|
91
|
+
})
|
|
92
|
+
}))
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Mock jQuery
|
|
96
|
+
global.$ = jest.fn((selector) => {
|
|
97
|
+
if (typeof selector === 'string') {
|
|
98
|
+
if (selector.includes('<tr')) {
|
|
99
|
+
return {
|
|
100
|
+
find: jest.fn().mockReturnThis(),
|
|
101
|
+
append: jest.fn().mockReturnThis(),
|
|
102
|
+
after: jest.fn().mockReturnThis()
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (selector.includes('<span')) {
|
|
106
|
+
return selector; // Return the HTML string for glyphicon
|
|
107
|
+
}
|
|
108
|
+
if (selector.includes('<i')) {
|
|
109
|
+
return selector; // Return the HTML string for fa icons
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
length: 0,
|
|
113
|
+
remove: jest.fn()
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Wrap element
|
|
117
|
+
return selector;
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
afterEach(() => {
|
|
122
|
+
delete global.$;
|
|
123
|
+
delete global.showDetailsLabel;
|
|
124
|
+
delete global.hideDetailsLabel;
|
|
125
|
+
delete global.labelErrorOccured;
|
|
126
|
+
delete global.HTTPClient;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('initDetailsLink', () => {
|
|
130
|
+
test('should initialize details links', () => {
|
|
131
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
132
|
+
|
|
133
|
+
expect(mockTable.find).toHaveBeenCalledWith('a.details_link');
|
|
134
|
+
expect(mockLink.removeClass).toHaveBeenCalledWith('hide');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('should set up click handlers on links', () => {
|
|
138
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
139
|
+
|
|
140
|
+
expect(mockLink.click).toHaveBeenCalled();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('should show plus button initially', () => {
|
|
144
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
145
|
+
|
|
146
|
+
expect(mockLink.html).toHaveBeenCalled();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('should handle callback before send', () => {
|
|
150
|
+
const beforeSendCallback = jest.fn(() => '<div>Custom content</div>');
|
|
151
|
+
|
|
152
|
+
DetailsSubArray.initDetailsLink(mockTable, null, null, beforeSendCallback);
|
|
153
|
+
|
|
154
|
+
// Trigger the click
|
|
155
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
156
|
+
if (clickHandler) {
|
|
157
|
+
clickHandler.call(mockLink);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// beforeSendCallback should be called when clicking
|
|
161
|
+
// (This tests that the callback is properly wired up)
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('should handle success callback', () => {
|
|
165
|
+
const successCallback = jest.fn((jsonObj, link) => '<div>Success</div>');
|
|
166
|
+
|
|
167
|
+
DetailsSubArray.initDetailsLink(mockTable, successCallback);
|
|
168
|
+
|
|
169
|
+
// Verify the callback is passed through
|
|
170
|
+
expect(mockTable.find).toHaveBeenCalled();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('should handle error callback', () => {
|
|
174
|
+
const errorCallback = jest.fn();
|
|
175
|
+
|
|
176
|
+
DetailsSubArray.initDetailsLink(mockTable, null, errorCallback);
|
|
177
|
+
|
|
178
|
+
// Verify the callback is passed through
|
|
179
|
+
expect(mockTable.find).toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('should make HTTP request when link is clicked', () => {
|
|
183
|
+
HTTPClient.request.mockImplementation((method, url, data, successCb, errorCb) => {
|
|
184
|
+
successCb({ data: 'test' });
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const successCallback = jest.fn(() => '<div>Details</div>');
|
|
188
|
+
DetailsSubArray.initDetailsLink(mockTable, successCallback);
|
|
189
|
+
|
|
190
|
+
// Simulate click
|
|
191
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
192
|
+
if (clickHandler) {
|
|
193
|
+
clickHandler.call(mockLink);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// HTTPClient.request should be called
|
|
197
|
+
expect(HTTPClient.request).toHaveBeenCalledWith(
|
|
198
|
+
'GET',
|
|
199
|
+
'http://example.com/details',
|
|
200
|
+
null,
|
|
201
|
+
expect.any(Function),
|
|
202
|
+
expect.any(Function)
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('should handle HTTP request success with null response', () => {
|
|
207
|
+
HTTPClient.request.mockImplementation((method, url, data, successCb) => {
|
|
208
|
+
successCb(null);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
212
|
+
|
|
213
|
+
// Simulate click
|
|
214
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
215
|
+
if (clickHandler) {
|
|
216
|
+
clickHandler.call(mockLink);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Should display error row
|
|
220
|
+
expect(mockTr.after).toHaveBeenCalled();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('should handle HTTP request error', () => {
|
|
224
|
+
HTTPClient.request.mockImplementation((method, url, data, successCb, errorCb) => {
|
|
225
|
+
errorCb();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
229
|
+
|
|
230
|
+
// Simulate click
|
|
231
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
232
|
+
if (clickHandler) {
|
|
233
|
+
clickHandler.call(mockLink);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Should display error row
|
|
237
|
+
expect(mockTr.after).toHaveBeenCalled();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test('should call success callback with JSON response', () => {
|
|
241
|
+
const jsonResponse = { items: ['item1', 'item2'] };
|
|
242
|
+
const successCallback = jest.fn(() => '<div>Details</div>');
|
|
243
|
+
|
|
244
|
+
HTTPClient.request.mockImplementation((method, url, data, successCb) => {
|
|
245
|
+
successCb(jsonResponse);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
DetailsSubArray.initDetailsLink(mockTable, successCallback);
|
|
249
|
+
|
|
250
|
+
// Simulate click
|
|
251
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
252
|
+
if (clickHandler) {
|
|
253
|
+
clickHandler.call(mockLink);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Success callback should be called with JSON response
|
|
257
|
+
expect(successCallback).toHaveBeenCalledWith(jsonResponse, mockLink);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('should call error callback on HTTP error', () => {
|
|
261
|
+
const errorCallback = jest.fn();
|
|
262
|
+
|
|
263
|
+
HTTPClient.request.mockImplementation((method, url, data, successCb, errorCb) => {
|
|
264
|
+
errorCb();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
DetailsSubArray.initDetailsLink(mockTable, null, errorCallback);
|
|
268
|
+
|
|
269
|
+
// Simulate click
|
|
270
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
271
|
+
if (clickHandler) {
|
|
272
|
+
clickHandler.call(mockLink);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Error callback should be called
|
|
276
|
+
expect(errorCallback).toHaveBeenCalledWith(mockLink);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test('should call error callback when response is null', () => {
|
|
280
|
+
const errorCallback = jest.fn();
|
|
281
|
+
|
|
282
|
+
HTTPClient.request.mockImplementation((method, url, data, successCb) => {
|
|
283
|
+
successCb(null);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
DetailsSubArray.initDetailsLink(mockTable, null, errorCallback);
|
|
287
|
+
|
|
288
|
+
// Simulate click
|
|
289
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
290
|
+
if (clickHandler) {
|
|
291
|
+
clickHandler.call(mockLink);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Error callback should be called
|
|
295
|
+
expect(errorCallback).toHaveBeenCalledWith(mockLink);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test('should use before send callback instead of HTTP request', () => {
|
|
299
|
+
const beforeSendCallback = jest.fn(() => '<div>Immediate content</div>');
|
|
300
|
+
|
|
301
|
+
DetailsSubArray.initDetailsLink(mockTable, null, null, beforeSendCallback);
|
|
302
|
+
|
|
303
|
+
// Simulate click
|
|
304
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
305
|
+
if (clickHandler) {
|
|
306
|
+
clickHandler.call(mockLink);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Before send callback should be called
|
|
310
|
+
expect(beforeSendCallback).toHaveBeenCalledWith(mockLink);
|
|
311
|
+
|
|
312
|
+
// HTTP request should NOT be made
|
|
313
|
+
expect(HTTPClient.request).not.toHaveBeenCalled();
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test('should handle multiple links', () => {
|
|
317
|
+
const mockLink2 = { ...mockLink };
|
|
318
|
+
|
|
319
|
+
mockTable.find = jest.fn(() => ({
|
|
320
|
+
each: jest.fn((callback) => {
|
|
321
|
+
callback(0, mockLink);
|
|
322
|
+
callback(1, mockLink2);
|
|
323
|
+
})
|
|
324
|
+
}));
|
|
325
|
+
|
|
326
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
327
|
+
|
|
328
|
+
// Both links should be initialized
|
|
329
|
+
expect(mockLink.removeClass).toHaveBeenCalled();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test('should disable link while loading', () => {
|
|
333
|
+
HTTPClient.request.mockImplementation(() => {
|
|
334
|
+
// Don't call callbacks, simulate loading state
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
338
|
+
|
|
339
|
+
// Simulate click
|
|
340
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
341
|
+
if (clickHandler) {
|
|
342
|
+
clickHandler.call(mockLink);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Link should be disabled during loading
|
|
346
|
+
expect(mockLink.attr).toHaveBeenCalledWith('disabled', true);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
test('should show loading icon', () => {
|
|
350
|
+
HTTPClient.request.mockImplementation(() => {
|
|
351
|
+
// Loading state
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
DetailsSubArray.initDetailsLink(mockTable);
|
|
355
|
+
|
|
356
|
+
// Simulate click
|
|
357
|
+
const clickHandler = mockLink.click.mock.calls[0][0];
|
|
358
|
+
if (clickHandler) {
|
|
359
|
+
clickHandler.call(mockLink);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Should display loading icon
|
|
363
|
+
expect(mockLink.html).toHaveBeenCalled();
|
|
364
|
+
expect(mockTr.after).toHaveBeenCalled();
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
});
|