@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.
Files changed (68) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/chartjs.js +1 -1
  3. package/date_time.js +25 -16
  4. package/draw.js +3 -2
  5. package/duration.js +176 -130
  6. package/event_bus.js +2 -2
  7. package/file.js +20 -5
  8. package/form_helper.js +1 -1
  9. package/google_charts.js +2 -1
  10. package/http_client.js +2 -0
  11. package/jwt.js +18 -6
  12. package/location.js +5 -1
  13. package/media.js +7 -7
  14. package/multi_files_input.js +3 -1
  15. package/number.js +2 -3
  16. package/package.json +4 -2
  17. package/paging.js +2 -2
  18. package/social_network.js +5 -0
  19. package/string.js +11 -2
  20. package/tests/__mocks__/socket.io-client.js +13 -0
  21. package/tests/chartjs.test.js +273 -0
  22. package/tests/count_down.test.js +580 -0
  23. package/tests/date_time/DatePeriod.test.js +179 -0
  24. package/tests/date_time/DateTime.test.js +492 -0
  25. package/tests/date_time/SqlDate.test.js +205 -0
  26. package/tests/date_time/SqlDateTime.test.js +326 -0
  27. package/tests/date_time/SqlTime.test.js +162 -0
  28. package/tests/date_time/TimestampUnix.test.js +262 -0
  29. package/tests/details_sub_array.test.js +367 -0
  30. package/tests/draw.test.js +271 -0
  31. package/tests/duration.test.js +365 -0
  32. package/tests/event_bus.test.js +268 -0
  33. package/tests/file.test.js +568 -0
  34. package/tests/flash_message.test.js +297 -0
  35. package/tests/form_date.test.js +1559 -0
  36. package/tests/form_helper.test.js +1065 -0
  37. package/tests/google_charts.test.js +768 -0
  38. package/tests/google_maps.test.js +655 -0
  39. package/tests/google_recaptcha.test.js +441 -0
  40. package/tests/http_client.test.js +570 -0
  41. package/tests/import_from_csv.test.js +797 -0
  42. package/tests/jwt.test.js +804 -0
  43. package/tests/list_box.test.js +255 -0
  44. package/tests/location.test.js +86 -0
  45. package/tests/media.test.js +473 -0
  46. package/tests/multi_files_input.test.js +1015 -0
  47. package/tests/multiple_action_in_table.test.js +477 -0
  48. package/tests/network.test.js +489 -0
  49. package/tests/number.test.js +448 -0
  50. package/tests/open_street_map.test.js +388 -0
  51. package/tests/paging.test.js +646 -0
  52. package/tests/select_all.test.js +360 -0
  53. package/tests/shopping_cart.test.js +355 -0
  54. package/tests/social_network.test.js +333 -0
  55. package/tests/sortable_list.test.js +602 -0
  56. package/tests/string.test.js +489 -0
  57. package/tests/user.test.js +204 -0
  58. package/tests/util.test.js +99 -0
  59. package/tests/visitor.test.js +508 -0
  60. package/tests/web_rtc.test.js +458 -0
  61. package/tests/web_socket.test.js +538 -0
  62. package/visitor.js +2 -2
  63. package/tmpclaude-0fa4-cwd +0 -1
  64. package/tmpclaude-104f-cwd +0 -1
  65. package/tmpclaude-1468-cwd +0 -1
  66. package/tmpclaude-324b-cwd +0 -1
  67. package/tmpclaude-35d3-cwd +0 -1
  68. package/tmpclaude-4aa8-cwd +0 -1
@@ -0,0 +1,473 @@
1
+ // Mock bowser module before requiring media.js (bowser is used inside requestMediaPermissions)
2
+ jest.mock('bowser', () => ({
3
+ getParser: jest.fn(() => ({
4
+ getBrowserName: jest.fn(() => 'Chrome')
5
+ }))
6
+ }), { virtual: true });
7
+
8
+ const { AudioMedia, VideoMedia, UserMedia } = require('../media');
9
+
10
+ describe('media.js', () => {
11
+ describe('AudioMedia', () => {
12
+ describe('getPlayer', () => {
13
+ test('should return audio element HTML string', () => {
14
+ const result = AudioMedia.getPlayer('http://example.com/audio.wav');
15
+ expect(typeof result).toBe('string');
16
+ expect(result).toContain('<audio');
17
+ expect(result).toContain('</audio>');
18
+ });
19
+
20
+ test('should include the playUrl in source src', () => {
21
+ const playUrl = 'http://example.com/test.wav';
22
+ const result = AudioMedia.getPlayer(playUrl);
23
+ expect(result).toContain(`src="${playUrl}"`);
24
+ });
25
+
26
+ test('should include controls attribute', () => {
27
+ const result = AudioMedia.getPlayer('http://example.com/audio.wav');
28
+ expect(result).toContain('controls');
29
+ });
30
+
31
+ test('should include preload="none" attribute', () => {
32
+ const result = AudioMedia.getPlayer('http://example.com/audio.wav');
33
+ expect(result).toContain('preload="none"');
34
+ });
35
+
36
+ test('should set audio type to audio/x-wav', () => {
37
+ const result = AudioMedia.getPlayer('http://example.com/audio.wav');
38
+ expect(result).toContain('type="audio/x-wav"');
39
+ });
40
+
41
+ test('should handle URLs with special characters', () => {
42
+ const playUrl = 'http://example.com/audio file with spaces.wav';
43
+ const result = AudioMedia.getPlayer(playUrl);
44
+ expect(result).toContain(playUrl);
45
+ });
46
+ });
47
+ });
48
+
49
+ describe('VideoMedia', () => {
50
+ describe('class structure', () => {
51
+ test('should have initPlayPauseClick method', () => {
52
+ expect(typeof VideoMedia.initPlayPauseClick).toBe('function');
53
+ });
54
+ });
55
+ });
56
+
57
+ describe('UserMedia', () => {
58
+ let originalNavigator;
59
+
60
+ beforeEach(() => {
61
+ // Save original navigator
62
+ originalNavigator = global.navigator;
63
+ });
64
+
65
+ afterEach(() => {
66
+ // Restore original navigator
67
+ global.navigator = originalNavigator;
68
+ jest.clearAllMocks();
69
+ });
70
+
71
+ describe('hasGetUserMedia', () => {
72
+ test('should return true when navigator.getUserMedia exists', () => {
73
+ global.navigator = { getUserMedia: jest.fn() };
74
+ expect(UserMedia.hasGetUserMedia()).toBe(true);
75
+ });
76
+
77
+ test('should return true when navigator.webkitGetUserMedia exists', () => {
78
+ global.navigator = { webkitGetUserMedia: jest.fn() };
79
+ expect(UserMedia.hasGetUserMedia()).toBe(true);
80
+ });
81
+
82
+ test('should return true when navigator.mozGetUserMedia exists', () => {
83
+ global.navigator = { mozGetUserMedia: jest.fn() };
84
+ expect(UserMedia.hasGetUserMedia()).toBe(true);
85
+ });
86
+
87
+ test('should return true when navigator.msGetUserMedia exists', () => {
88
+ global.navigator = { msGetUserMedia: jest.fn() };
89
+ expect(UserMedia.hasGetUserMedia()).toBe(true);
90
+ });
91
+
92
+ test('should return false when no getUserMedia available', () => {
93
+ global.navigator = {};
94
+ expect(UserMedia.hasGetUserMedia()).toBe(false);
95
+ });
96
+
97
+ test('should return false when navigator is undefined', () => {
98
+ global.navigator = undefined;
99
+ expect(UserMedia.hasGetUserMedia()).toBe(false);
100
+ });
101
+ });
102
+
103
+ describe('requestMediaPermissions', () => {
104
+ const bowser = require('bowser');
105
+
106
+ beforeEach(() => {
107
+ global.navigator = {
108
+ mediaDevices: {
109
+ getUserMedia: jest.fn()
110
+ }
111
+ };
112
+ global.window = {
113
+ navigator: {
114
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
115
+ }
116
+ };
117
+ });
118
+
119
+ test('should resolve with stream on success', async () => {
120
+ const mockStream = { id: 'test-stream' };
121
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
122
+ bowser.getParser.mockReturnValue({
123
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
124
+ });
125
+
126
+ const result = await UserMedia.requestMediaPermissions({ audio: true, video: true });
127
+
128
+ expect(result).toBe(mockStream);
129
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({ audio: true, video: true });
130
+ });
131
+
132
+ test('should use default constraints when not provided', async () => {
133
+ const mockStream = { id: 'test-stream' };
134
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
135
+ bowser.getParser.mockReturnValue({
136
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
137
+ });
138
+
139
+ await UserMedia.requestMediaPermissions();
140
+
141
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({ audio: true, video: true });
142
+ });
143
+
144
+ test('should handle Chrome NotAllowedError with system permission denied', async () => {
145
+ const error = new Error('Permission denied by system');
146
+ error.name = 'NotAllowedError';
147
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
148
+ bowser.getParser.mockReturnValue({
149
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
150
+ });
151
+
152
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
153
+ .rejects.toEqual({
154
+ type: 'SystemPermissionDenied',
155
+ name: 'NotAllowedError',
156
+ message: 'Permission denied by system'
157
+ });
158
+ });
159
+
160
+ test('should handle Chrome NotAllowedError with user permission denied', async () => {
161
+ const error = new Error('Permission denied');
162
+ error.name = 'NotAllowedError';
163
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
164
+ bowser.getParser.mockReturnValue({
165
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
166
+ });
167
+
168
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
169
+ .rejects.toEqual({
170
+ type: 'UserPermissionDenied',
171
+ name: 'NotAllowedError',
172
+ message: 'Permission denied'
173
+ });
174
+ });
175
+
176
+ test('should handle Chrome NotReadableError', async () => {
177
+ const error = new Error('Could not start video source');
178
+ error.name = 'NotReadableError';
179
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
180
+ bowser.getParser.mockReturnValue({
181
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
182
+ });
183
+
184
+ await expect(UserMedia.requestMediaPermissions({ video: true }))
185
+ .rejects.toEqual({
186
+ type: 'CouldNotStartVideoSource',
187
+ name: 'NotReadableError',
188
+ message: 'Could not start video source'
189
+ });
190
+ });
191
+
192
+ test('should handle Safari NotAllowedError', async () => {
193
+ const error = new Error('Permission denied');
194
+ error.name = 'NotAllowedError';
195
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
196
+ bowser.getParser.mockReturnValue({
197
+ getBrowserName: jest.fn().mockReturnValue('Safari')
198
+ });
199
+
200
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
201
+ .rejects.toEqual({
202
+ type: 'UserPermissionDenied',
203
+ name: 'NotAllowedError',
204
+ message: 'Permission denied'
205
+ });
206
+ });
207
+
208
+ test('should handle Microsoft Edge NotAllowedError', async () => {
209
+ const error = new Error('Permission denied');
210
+ error.name = 'NotAllowedError';
211
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
212
+ bowser.getParser.mockReturnValue({
213
+ getBrowserName: jest.fn().mockReturnValue('Microsoft Edge')
214
+ });
215
+
216
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
217
+ .rejects.toEqual({
218
+ type: 'UserPermissionDenied',
219
+ name: 'NotAllowedError',
220
+ message: 'Permission denied'
221
+ });
222
+ });
223
+
224
+ test('should handle Microsoft Edge NotReadableError', async () => {
225
+ const error = new Error('Could not start video source');
226
+ error.name = 'NotReadableError';
227
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
228
+ bowser.getParser.mockReturnValue({
229
+ getBrowserName: jest.fn().mockReturnValue('Microsoft Edge')
230
+ });
231
+
232
+ await expect(UserMedia.requestMediaPermissions({ video: true }))
233
+ .rejects.toEqual({
234
+ type: 'CouldNotStartVideoSource',
235
+ name: 'NotReadableError',
236
+ message: 'Could not start video source'
237
+ });
238
+ });
239
+
240
+ test('should handle Firefox NotFoundError', async () => {
241
+ const error = new Error('Requested device not found');
242
+ error.name = 'NotFoundError';
243
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
244
+ bowser.getParser.mockReturnValue({
245
+ getBrowserName: jest.fn().mockReturnValue('Firefox')
246
+ });
247
+
248
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
249
+ .rejects.toEqual({
250
+ type: 'SystemPermissionDenied',
251
+ name: 'NotFoundError',
252
+ message: 'Requested device not found'
253
+ });
254
+ });
255
+
256
+ test('should handle Firefox NotReadableError', async () => {
257
+ const error = new Error('Media device not readable');
258
+ error.name = 'NotReadableError';
259
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
260
+ bowser.getParser.mockReturnValue({
261
+ getBrowserName: jest.fn().mockReturnValue('Firefox')
262
+ });
263
+
264
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
265
+ .rejects.toEqual({
266
+ type: 'SystemPermissionDenied',
267
+ name: 'NotReadableError',
268
+ message: 'Media device not readable'
269
+ });
270
+ });
271
+
272
+ test('should handle Firefox NotAllowedError', async () => {
273
+ const error = new Error('Permission denied');
274
+ error.name = 'NotAllowedError';
275
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
276
+ bowser.getParser.mockReturnValue({
277
+ getBrowserName: jest.fn().mockReturnValue('Firefox')
278
+ });
279
+
280
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
281
+ .rejects.toEqual({
282
+ type: 'UserPermissionDenied',
283
+ name: 'NotAllowedError',
284
+ message: 'Permission denied'
285
+ });
286
+ });
287
+
288
+ test('should handle Firefox AbortError', async () => {
289
+ const error = new Error('Operation aborted');
290
+ error.name = 'AbortError';
291
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
292
+ bowser.getParser.mockReturnValue({
293
+ getBrowserName: jest.fn().mockReturnValue('Firefox')
294
+ });
295
+
296
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
297
+ .rejects.toEqual({
298
+ type: 'CouldNotStartVideoSource',
299
+ name: 'AbortError',
300
+ message: 'Operation aborted'
301
+ });
302
+ });
303
+
304
+ test('should handle generic error for unknown browser', async () => {
305
+ const error = new Error('Unknown error');
306
+ error.name = 'UnknownError';
307
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
308
+ bowser.getParser.mockReturnValue({
309
+ getBrowserName: jest.fn().mockReturnValue('Opera')
310
+ });
311
+
312
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
313
+ .rejects.toEqual({
314
+ type: 'Generic',
315
+ name: 'UnknownError',
316
+ message: 'Unknown error'
317
+ });
318
+ });
319
+
320
+ test('should handle generic error for unknown error type', async () => {
321
+ const error = new Error('Weird error');
322
+ error.name = 'WeirdError';
323
+ global.navigator.mediaDevices.getUserMedia.mockRejectedValue(error);
324
+ bowser.getParser.mockReturnValue({
325
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
326
+ });
327
+
328
+ await expect(UserMedia.requestMediaPermissions({ audio: true }))
329
+ .rejects.toEqual({
330
+ type: 'Generic',
331
+ name: 'WeirdError',
332
+ message: 'Weird error'
333
+ });
334
+ });
335
+ });
336
+
337
+ describe('requestAudioPermissions', () => {
338
+ beforeEach(() => {
339
+ global.navigator = {
340
+ mediaDevices: {
341
+ getUserMedia: jest.fn()
342
+ }
343
+ };
344
+ global.window = {
345
+ navigator: {
346
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
347
+ }
348
+ };
349
+ const bowser = require('bowser');
350
+ bowser.getParser.mockReturnValue({
351
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
352
+ });
353
+ });
354
+
355
+ test('should call requestMediaPermissions with audio:true, video:false', async () => {
356
+ const mockStream = { id: 'audio-stream' };
357
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
358
+
359
+ const result = await UserMedia.requestAudioPermissions();
360
+
361
+ expect(result).toBe(mockStream);
362
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
363
+ audio: true,
364
+ video: false
365
+ });
366
+ });
367
+
368
+ test('should pass audio constraints when provided', async () => {
369
+ const mockStream = { id: 'audio-stream' };
370
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
371
+ const audioConstraints = { echoCancellation: true };
372
+
373
+ await UserMedia.requestAudioPermissions(audioConstraints);
374
+
375
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
376
+ audio: audioConstraints,
377
+ video: false
378
+ });
379
+ });
380
+ });
381
+
382
+ describe('requestVideoPermissions', () => {
383
+ beforeEach(() => {
384
+ global.navigator = {
385
+ mediaDevices: {
386
+ getUserMedia: jest.fn()
387
+ }
388
+ };
389
+ global.window = {
390
+ navigator: {
391
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
392
+ }
393
+ };
394
+ const bowser = require('bowser');
395
+ bowser.getParser.mockReturnValue({
396
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
397
+ });
398
+ });
399
+
400
+ test('should call requestMediaPermissions with audio and video', async () => {
401
+ const mockStream = { id: 'video-stream' };
402
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
403
+
404
+ const result = await UserMedia.requestVideoPermissions();
405
+
406
+ expect(result).toBe(mockStream);
407
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
408
+ audio: true,
409
+ video: true
410
+ });
411
+ });
412
+
413
+ test('should pass audio and video constraints when provided', async () => {
414
+ const mockStream = { id: 'video-stream' };
415
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
416
+ const audioConstraints = { echoCancellation: true };
417
+ const videoConstraints = { width: 1280, height: 720 };
418
+
419
+ await UserMedia.requestVideoPermissions(audioConstraints, videoConstraints);
420
+
421
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
422
+ audio: audioConstraints,
423
+ video: videoConstraints
424
+ });
425
+ });
426
+ });
427
+
428
+ describe('requestMutedVideoPermissions', () => {
429
+ beforeEach(() => {
430
+ global.navigator = {
431
+ mediaDevices: {
432
+ getUserMedia: jest.fn()
433
+ }
434
+ };
435
+ global.window = {
436
+ navigator: {
437
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
438
+ }
439
+ };
440
+ const bowser = require('bowser');
441
+ bowser.getParser.mockReturnValue({
442
+ getBrowserName: jest.fn().mockReturnValue('Chrome')
443
+ });
444
+ });
445
+
446
+ test('should call requestMediaPermissions with audio:false, video:true', async () => {
447
+ const mockStream = { id: 'muted-video-stream' };
448
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
449
+
450
+ const result = await UserMedia.requestMutedVideoPermissions();
451
+
452
+ expect(result).toBe(mockStream);
453
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
454
+ audio: false,
455
+ video: true
456
+ });
457
+ });
458
+
459
+ test('should pass video constraints when provided', async () => {
460
+ const mockStream = { id: 'muted-video-stream' };
461
+ global.navigator.mediaDevices.getUserMedia.mockResolvedValue(mockStream);
462
+ const videoConstraints = { facingMode: 'user' };
463
+
464
+ await UserMedia.requestMutedVideoPermissions(videoConstraints);
465
+
466
+ expect(global.navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
467
+ audio: false,
468
+ video: videoConstraints
469
+ });
470
+ });
471
+ });
472
+ });
473
+ });