@osimatic/helpers-js 1.4.25 → 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 +1 -1
- package/duration.js +174 -125
- package/file.js +19 -4
- package/google_charts.js +2 -1
- package/location.js +5 -1
- package/media.js +6 -6
- package/multi_files_input.js +3 -1
- package/package.json +2 -1
- package/paging.js +2 -2
- package/tests/__mocks__/socket.io-client.js +13 -0
- package/tests/count_down.test.js +580 -0
- package/tests/details_sub_array.test.js +367 -0
- package/tests/file.test.js +210 -0
- package/tests/flash_message.test.js +297 -0
- package/tests/form_date.test.js +1142 -0
- package/tests/form_helper.test.js +780 -130
- 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/import_from_csv.test.js +797 -0
- package/tests/list_box.test.js +255 -0
- package/tests/location.test.js +86 -0
- package/tests/media.test.js +15 -0
- package/tests/multi_files_input.test.js +1015 -0
- package/tests/multiple_action_in_table.test.js +477 -0
- package/tests/paging.test.js +646 -0
- package/tests/select_all.test.js +360 -0
- package/tests/sortable_list.test.js +602 -0
- package/tests/string.test.js +16 -0
- package/tests/web_rtc.test.js +458 -0
- package/tests/web_socket.test.js +538 -0
- package/tmpclaude-00a6-cwd +0 -1
- package/tmpclaude-0526-cwd +0 -1
- package/tmpclaude-0973-cwd +0 -1
- package/tmpclaude-0b61-cwd +0 -1
- package/tmpclaude-0fa4-cwd +0 -1
- package/tmpclaude-104f-cwd +0 -1
- package/tmpclaude-1468-cwd +0 -1
- package/tmpclaude-146f-cwd +0 -1
- package/tmpclaude-223d-cwd +0 -1
- package/tmpclaude-2330-cwd +0 -1
- package/tmpclaude-282a-cwd +0 -1
- package/tmpclaude-2846-cwd +0 -1
- package/tmpclaude-28a6-cwd +0 -1
- package/tmpclaude-2b5a-cwd +0 -1
- package/tmpclaude-2def-cwd +0 -1
- package/tmpclaude-324b-cwd +0 -1
- package/tmpclaude-35d3-cwd +0 -1
- package/tmpclaude-3906-cwd +0 -1
- package/tmpclaude-3b32-cwd +0 -1
- package/tmpclaude-3da9-cwd +0 -1
- package/tmpclaude-3dc3-cwd +0 -1
- package/tmpclaude-3e3b-cwd +0 -1
- package/tmpclaude-43b6-cwd +0 -1
- package/tmpclaude-4495-cwd +0 -1
- package/tmpclaude-462f-cwd +0 -1
- package/tmpclaude-4aa8-cwd +0 -1
- package/tmpclaude-4b29-cwd +0 -1
- package/tmpclaude-4db5-cwd +0 -1
- package/tmpclaude-4e01-cwd +0 -1
- package/tmpclaude-5101-cwd +0 -1
- package/tmpclaude-524f-cwd +0 -1
- package/tmpclaude-5636-cwd +0 -1
- package/tmpclaude-5cdd-cwd +0 -1
- package/tmpclaude-5f1f-cwd +0 -1
- package/tmpclaude-6078-cwd +0 -1
- package/tmpclaude-622e-cwd +0 -1
- package/tmpclaude-6802-cwd +0 -1
- package/tmpclaude-6e36-cwd +0 -1
- package/tmpclaude-7793-cwd +0 -1
- package/tmpclaude-7f96-cwd +0 -1
- package/tmpclaude-8566-cwd +0 -1
- package/tmpclaude-8874-cwd +0 -1
- package/tmpclaude-8915-cwd +0 -1
- package/tmpclaude-8c8b-cwd +0 -1
- package/tmpclaude-94df-cwd +0 -1
- package/tmpclaude-9859-cwd +0 -1
- package/tmpclaude-9ac5-cwd +0 -1
- package/tmpclaude-9f18-cwd +0 -1
- package/tmpclaude-a202-cwd +0 -1
- package/tmpclaude-a741-cwd +0 -1
- package/tmpclaude-ab5f-cwd +0 -1
- package/tmpclaude-b008-cwd +0 -1
- package/tmpclaude-b0a1-cwd +0 -1
- package/tmpclaude-b63d-cwd +0 -1
- package/tmpclaude-b681-cwd +0 -1
- package/tmpclaude-b72d-cwd +0 -1
- package/tmpclaude-b92f-cwd +0 -1
- package/tmpclaude-bc49-cwd +0 -1
- package/tmpclaude-bc50-cwd +0 -1
- package/tmpclaude-bccf-cwd +0 -1
- package/tmpclaude-be55-cwd +0 -1
- package/tmpclaude-c228-cwd +0 -1
- package/tmpclaude-c717-cwd +0 -1
- package/tmpclaude-c7ce-cwd +0 -1
- package/tmpclaude-cf3e-cwd +0 -1
- package/tmpclaude-d142-cwd +0 -1
- package/tmpclaude-d5bc-cwd +0 -1
- package/tmpclaude-d6ae-cwd +0 -1
- package/tmpclaude-d77a-cwd +0 -1
- package/tmpclaude-d8da-cwd +0 -1
- package/tmpclaude-dbdb-cwd +0 -1
- package/tmpclaude-de61-cwd +0 -1
- package/tmpclaude-de81-cwd +0 -1
- package/tmpclaude-df9d-cwd +0 -1
- package/tmpclaude-e786-cwd +0 -1
- package/tmpclaude-f01d-cwd +0 -1
- package/tmpclaude-f2a9-cwd +0 -1
- package/tmpclaude-fc36-cwd +0 -1
- package/tmpclaude-ffef-cwd +0 -1
|
@@ -1,7 +1,627 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
1
4
|
require('../array'); // For removeEmptyValues method
|
|
2
5
|
const { FormHelper, ArrayField, EditValue } = require('../form_helper');
|
|
3
6
|
|
|
4
7
|
describe('FormHelper', () => {
|
|
8
|
+
let mockForm;
|
|
9
|
+
let mockButton;
|
|
10
|
+
let mockInput;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// Setup common jQuery mocks
|
|
14
|
+
mockInput = {
|
|
15
|
+
val: jest.fn().mockReturnThis(),
|
|
16
|
+
prop: jest.fn().mockReturnThis(),
|
|
17
|
+
attr: jest.fn().mockReturnThis(),
|
|
18
|
+
off: jest.fn().mockReturnThis(),
|
|
19
|
+
click: jest.fn().mockReturnThis(),
|
|
20
|
+
on: jest.fn().mockReturnThis(),
|
|
21
|
+
each: jest.fn().mockReturnThis(),
|
|
22
|
+
filter: jest.fn().mockReturnThis(),
|
|
23
|
+
data: jest.fn().mockReturnThis(),
|
|
24
|
+
parent: jest.fn().mockReturnThis(),
|
|
25
|
+
closest: jest.fn().mockReturnThis(),
|
|
26
|
+
addClass: jest.fn().mockReturnThis(),
|
|
27
|
+
removeClass: jest.fn().mockReturnThis(),
|
|
28
|
+
find: jest.fn().mockReturnThis(),
|
|
29
|
+
remove: jest.fn().mockReturnThis(),
|
|
30
|
+
append: jest.fn().mockReturnThis(),
|
|
31
|
+
prepend: jest.fn().mockReturnThis(),
|
|
32
|
+
before: jest.fn().mockReturnThis(),
|
|
33
|
+
after: jest.fn().mockReturnThis(),
|
|
34
|
+
wrap: jest.fn().mockReturnThis(),
|
|
35
|
+
html: jest.fn().mockReturnThis(),
|
|
36
|
+
text: jest.fn().mockReturnThis(),
|
|
37
|
+
css: jest.fn().mockReturnThis(),
|
|
38
|
+
hasClass: jest.fn(() => false),
|
|
39
|
+
length: 1,
|
|
40
|
+
serialize: jest.fn(() => 'field1=value1&field2=value2'),
|
|
41
|
+
0: document.createElement('form')
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
mockButton = {
|
|
45
|
+
...mockInput,
|
|
46
|
+
attr: jest.fn((key, value) => {
|
|
47
|
+
if (key === 'disabled' && value === undefined) return false;
|
|
48
|
+
return mockButton;
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
mockForm = {
|
|
53
|
+
...mockInput,
|
|
54
|
+
find: jest.fn((selector) => {
|
|
55
|
+
if (selector.includes('button[name="validate"]')) return mockButton;
|
|
56
|
+
if (selector.includes('input[name]:not')) return mockInput;
|
|
57
|
+
if (selector.includes('select.selectpicker')) return mockInput;
|
|
58
|
+
if (selector.includes('div.form_errors')) return mockInput;
|
|
59
|
+
if (selector.includes('.form_errors_content')) return { length: 0 };
|
|
60
|
+
if (selector.includes('.modal-body')) return { length: 0 };
|
|
61
|
+
if (selector.includes('.form-group:first')) return mockInput;
|
|
62
|
+
return mockInput;
|
|
63
|
+
})
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
global.$ = jest.fn((selector) => {
|
|
67
|
+
if (typeof selector === 'function') {
|
|
68
|
+
// Document ready
|
|
69
|
+
return mockInput;
|
|
70
|
+
}
|
|
71
|
+
if (selector === mockButton || selector === mockInput || selector === mockForm) {
|
|
72
|
+
return selector;
|
|
73
|
+
}
|
|
74
|
+
return mockInput;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
global.$.each = jest.fn((obj, callback) => {
|
|
78
|
+
if (Array.isArray(obj)) {
|
|
79
|
+
obj.forEach((item, idx) => callback(idx, item));
|
|
80
|
+
} else {
|
|
81
|
+
Object.keys(obj).forEach(key => callback(key, obj[key]));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
delete global.$;
|
|
88
|
+
jest.clearAllMocks();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('init', () => {
|
|
92
|
+
test('should initialize form with default submit button', () => {
|
|
93
|
+
const onSubmitCallback = jest.fn();
|
|
94
|
+
|
|
95
|
+
const result = FormHelper.init(mockForm, onSubmitCallback);
|
|
96
|
+
|
|
97
|
+
expect(mockForm.find).toHaveBeenCalledWith('button[name="validate"]');
|
|
98
|
+
expect(mockButton.off).toHaveBeenCalledWith('click');
|
|
99
|
+
expect(mockButton.click).toHaveBeenCalled();
|
|
100
|
+
expect(result).toBe(mockForm);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('should initialize form with custom submit button', () => {
|
|
104
|
+
const onSubmitCallback = jest.fn();
|
|
105
|
+
const customButton = { ...mockButton };
|
|
106
|
+
|
|
107
|
+
FormHelper.init(mockForm, onSubmitCallback, customButton);
|
|
108
|
+
|
|
109
|
+
expect(customButton.off).toHaveBeenCalledWith('click');
|
|
110
|
+
expect(customButton.click).toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('should call callback on submit', () => {
|
|
114
|
+
const onSubmitCallback = jest.fn();
|
|
115
|
+
let clickHandler;
|
|
116
|
+
|
|
117
|
+
mockButton.click.mockImplementation((handler) => {
|
|
118
|
+
clickHandler = handler;
|
|
119
|
+
return mockButton;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
FormHelper.init(mockForm, onSubmitCallback);
|
|
123
|
+
|
|
124
|
+
// Simulate button click
|
|
125
|
+
const mockEvent = { preventDefault: jest.fn() };
|
|
126
|
+
clickHandler.call(mockButton, mockEvent);
|
|
127
|
+
|
|
128
|
+
expect(mockButton.data).toHaveBeenCalled();
|
|
129
|
+
expect(onSubmitCallback).toHaveBeenCalledWith(mockForm, mockButton);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('should prevent default on submit', () => {
|
|
133
|
+
const onSubmitCallback = jest.fn();
|
|
134
|
+
let clickHandler;
|
|
135
|
+
const mockEvent = { preventDefault: jest.fn() };
|
|
136
|
+
|
|
137
|
+
mockButton.click.mockImplementation((handler) => {
|
|
138
|
+
clickHandler = handler;
|
|
139
|
+
return mockButton;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
FormHelper.init(mockForm, onSubmitCallback);
|
|
143
|
+
clickHandler.call(mockButton, { preventDefault: () => {} });
|
|
144
|
+
|
|
145
|
+
expect(onSubmitCallback).toHaveBeenCalledWith(mockForm, mockButton);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('reset', () => {
|
|
150
|
+
test('should reset form fields', () => {
|
|
151
|
+
mockInput.each.mockImplementation((callback) => {
|
|
152
|
+
callback(0, {});
|
|
153
|
+
return mockInput;
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const result = FormHelper.reset(mockForm);
|
|
157
|
+
|
|
158
|
+
expect(mockInput.val).toHaveBeenCalledWith('');
|
|
159
|
+
expect(mockInput.off).toHaveBeenCalledWith('change');
|
|
160
|
+
expect(result).toBe(mockForm);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('should reset form with custom submit button', () => {
|
|
164
|
+
const customButton = { ...mockButton };
|
|
165
|
+
|
|
166
|
+
FormHelper.reset(mockForm, customButton);
|
|
167
|
+
|
|
168
|
+
expect(mockForm.find).toHaveBeenCalled();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('populateForm', () => {
|
|
173
|
+
test('should skip null values', () => {
|
|
174
|
+
const data = { field1: 'value1', field2: null };
|
|
175
|
+
|
|
176
|
+
FormHelper.populateForm(mockForm, data);
|
|
177
|
+
|
|
178
|
+
// Should only process non-null values
|
|
179
|
+
expect(mockForm.find).toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('should handle object values as array select', () => {
|
|
183
|
+
const selectMock = {
|
|
184
|
+
find: jest.fn().mockReturnThis(),
|
|
185
|
+
prop: jest.fn().mockReturnThis(),
|
|
186
|
+
data: jest.fn().mockReturnThis()
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
mockForm.find = jest.fn((selector) => {
|
|
190
|
+
if (selector.includes('employees_display_type')) return mockInput;
|
|
191
|
+
if (selector.includes('[]')) return selectMock;
|
|
192
|
+
return mockInput;
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const data = { tags: ['tag1', 'tag2'] };
|
|
196
|
+
|
|
197
|
+
FormHelper.populateForm(mockForm, data);
|
|
198
|
+
|
|
199
|
+
expect(selectMock.find).toHaveBeenCalled();
|
|
200
|
+
expect(selectMock.data).toHaveBeenCalledWith('default_id', 'tag1,tag2');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('should handle radio button values', () => {
|
|
204
|
+
mockInput.prop = jest.fn((key) => {
|
|
205
|
+
if (key === 'type') return 'radio';
|
|
206
|
+
return mockInput;
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const data = { gender: 'male' };
|
|
210
|
+
|
|
211
|
+
FormHelper.populateForm(mockForm, data);
|
|
212
|
+
|
|
213
|
+
expect(mockInput.filter).toHaveBeenCalledWith('[value="male"]');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('should handle checkbox values', () => {
|
|
217
|
+
mockInput.prop = jest.fn((key) => {
|
|
218
|
+
if (key === 'type') return 'checkbox';
|
|
219
|
+
return mockInput;
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const data = { terms: 'accepted' };
|
|
223
|
+
|
|
224
|
+
FormHelper.populateForm(mockForm, data);
|
|
225
|
+
|
|
226
|
+
expect(mockInput.filter).toHaveBeenCalledWith('[value="accepted"]');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('should handle regular input values', () => {
|
|
230
|
+
mockInput.prop = jest.fn(() => 'text');
|
|
231
|
+
|
|
232
|
+
const data = { name: 'John' };
|
|
233
|
+
|
|
234
|
+
FormHelper.populateForm(mockForm, data);
|
|
235
|
+
|
|
236
|
+
expect(mockInput.val).toHaveBeenCalled();
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe('reset', () => {
|
|
241
|
+
test('should reset form fields', () => {
|
|
242
|
+
mockInput.each.mockImplementation((callback) => {
|
|
243
|
+
callback(0, document.createElement('input'));
|
|
244
|
+
return mockInput;
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const result = FormHelper.reset(mockForm);
|
|
248
|
+
|
|
249
|
+
expect(mockForm.find).toHaveBeenCalled();
|
|
250
|
+
expect(mockInput.each).toHaveBeenCalled();
|
|
251
|
+
expect(result).toBe(mockForm);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test('should reset with custom button', () => {
|
|
255
|
+
const customButton = { ...mockButton };
|
|
256
|
+
mockInput.each.mockImplementation(() => mockInput);
|
|
257
|
+
|
|
258
|
+
FormHelper.reset(mockForm, customButton);
|
|
259
|
+
|
|
260
|
+
expect(mockInput.each).toHaveBeenCalled();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe('getFormData', () => {
|
|
265
|
+
test('should return FormData from form element', () => {
|
|
266
|
+
const result = FormHelper.getFormData(mockForm);
|
|
267
|
+
|
|
268
|
+
expect(result).toBeInstanceOf(FormData);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe('getFormDataQueryString', () => {
|
|
273
|
+
test('should return serialized form data', () => {
|
|
274
|
+
const result = FormHelper.getFormDataQueryString(mockForm);
|
|
275
|
+
|
|
276
|
+
expect(result).toBe('field1=value1&field2=value2');
|
|
277
|
+
expect(mockForm.serialize).toHaveBeenCalled();
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe('setOnInputChange', () => {
|
|
282
|
+
beforeEach(() => {
|
|
283
|
+
jest.useFakeTimers();
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
afterEach(() => {
|
|
287
|
+
jest.useRealTimers();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test('should setup keyup handler with timeout', () => {
|
|
291
|
+
const callback = jest.fn();
|
|
292
|
+
let keyupHandler;
|
|
293
|
+
|
|
294
|
+
mockInput.on.mockImplementation((event, handler) => {
|
|
295
|
+
if (event === 'keyup') keyupHandler = handler;
|
|
296
|
+
return mockInput;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
FormHelper.setOnInputChange(mockInput, callback, 500);
|
|
300
|
+
|
|
301
|
+
expect(mockInput.on).toHaveBeenCalledWith('keyup', expect.any(Function));
|
|
302
|
+
|
|
303
|
+
keyupHandler();
|
|
304
|
+
jest.advanceTimersByTime(500);
|
|
305
|
+
|
|
306
|
+
expect(callback).toHaveBeenCalled();
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test('should clear timeout on keydown', () => {
|
|
310
|
+
const callback = jest.fn();
|
|
311
|
+
let keyupHandler, keydownHandler;
|
|
312
|
+
|
|
313
|
+
mockInput.on.mockImplementation((event, handler) => {
|
|
314
|
+
if (event === 'keyup') keyupHandler = handler;
|
|
315
|
+
if (event === 'keydown') keydownHandler = handler;
|
|
316
|
+
return mockInput;
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
FormHelper.setOnInputChange(mockInput, callback, 500);
|
|
320
|
+
|
|
321
|
+
keyupHandler();
|
|
322
|
+
keydownHandler();
|
|
323
|
+
jest.advanceTimersByTime(500);
|
|
324
|
+
|
|
325
|
+
expect(callback).not.toHaveBeenCalled();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('should call callback on focusout', () => {
|
|
329
|
+
const callback = jest.fn();
|
|
330
|
+
let focusoutHandler;
|
|
331
|
+
|
|
332
|
+
mockInput.on.mockImplementation((event, handler) => {
|
|
333
|
+
if (event === 'focusout') focusoutHandler = handler;
|
|
334
|
+
return mockInput;
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
FormHelper.setOnInputChange(mockInput, callback);
|
|
338
|
+
|
|
339
|
+
focusoutHandler();
|
|
340
|
+
|
|
341
|
+
expect(callback).toHaveBeenCalled();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test('should use default interval of 700ms', () => {
|
|
345
|
+
const callback = jest.fn();
|
|
346
|
+
let keyupHandler;
|
|
347
|
+
|
|
348
|
+
mockInput.on.mockImplementation((event, handler) => {
|
|
349
|
+
if (event === 'keyup') keyupHandler = handler;
|
|
350
|
+
return mockInput;
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
FormHelper.setOnInputChange(mockInput, callback);
|
|
354
|
+
|
|
355
|
+
keyupHandler();
|
|
356
|
+
jest.advanceTimersByTime(700);
|
|
357
|
+
|
|
358
|
+
expect(callback).toHaveBeenCalled();
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
describe('Select methods', () => {
|
|
363
|
+
test('resetSelectOption should reset select options', () => {
|
|
364
|
+
const optionMock = {
|
|
365
|
+
prop: jest.fn().mockReturnThis()
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
mockForm.find = jest.fn(() => optionMock);
|
|
369
|
+
|
|
370
|
+
FormHelper.resetSelectOption(mockForm, 'category');
|
|
371
|
+
|
|
372
|
+
expect(mockForm.find).toHaveBeenCalledWith('select[name="category"] option');
|
|
373
|
+
expect(optionMock.prop).toHaveBeenCalledWith('disabled', false);
|
|
374
|
+
expect(optionMock.prop).toHaveBeenCalledWith('selected', false);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('setSelectedSelectOption should select option', () => {
|
|
378
|
+
const optionMock = {
|
|
379
|
+
prop: jest.fn().mockReturnThis()
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
mockForm.find = jest.fn(() => optionMock);
|
|
383
|
+
|
|
384
|
+
FormHelper.setSelectedSelectOption(mockForm, 'category', '5');
|
|
385
|
+
|
|
386
|
+
expect(mockForm.find).toHaveBeenCalledWith('select[name="category"] option[value="5"]');
|
|
387
|
+
expect(optionMock.prop).toHaveBeenCalledWith('selected', true);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test('setSelectedSelectOptions should select multiple options', () => {
|
|
391
|
+
const optionMock = {
|
|
392
|
+
prop: jest.fn().mockReturnThis()
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
mockForm.find = jest.fn(() => optionMock);
|
|
396
|
+
|
|
397
|
+
FormHelper.setSelectedSelectOptions(mockForm, 'tags', ['1', '2', '3']);
|
|
398
|
+
|
|
399
|
+
expect(mockForm.find).toHaveBeenCalledTimes(3);
|
|
400
|
+
expect(optionMock.prop).toHaveBeenCalledWith('selected', true);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test('disableSelectOption should disable option', () => {
|
|
404
|
+
const optionMock = {
|
|
405
|
+
prop: jest.fn().mockReturnThis()
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
mockForm.find = jest.fn(() => optionMock);
|
|
409
|
+
|
|
410
|
+
FormHelper.disableSelectOption(mockForm, 'category', '5');
|
|
411
|
+
|
|
412
|
+
expect(mockForm.find).toHaveBeenCalledWith('select[name="category"] option[value="5"]');
|
|
413
|
+
expect(optionMock.prop).toHaveBeenCalledWith('disabled', true);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test('disableSelectOptions should disable multiple options', () => {
|
|
417
|
+
const optionMock = {
|
|
418
|
+
prop: jest.fn().mockReturnThis()
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
mockForm.find = jest.fn(() => optionMock);
|
|
422
|
+
|
|
423
|
+
FormHelper.disableSelectOptions(mockForm, 'category', ['1', '2']);
|
|
424
|
+
|
|
425
|
+
expect(mockForm.find).toHaveBeenCalledTimes(2);
|
|
426
|
+
expect(optionMock.prop).toHaveBeenCalledWith('disabled', true);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test('countSelectOptions should count non-disabled options', () => {
|
|
430
|
+
const optionMock = {
|
|
431
|
+
length: 5
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
mockForm.find = jest.fn(() => optionMock);
|
|
435
|
+
|
|
436
|
+
const count = FormHelper.countSelectOptions(mockForm, 'category');
|
|
437
|
+
|
|
438
|
+
expect(mockForm.find).toHaveBeenCalledWith('select[name="category"] option:not([disabled])');
|
|
439
|
+
expect(count).toBe(5);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
describe('Checkbox methods', () => {
|
|
444
|
+
test('getCheckedValues should return checked values', () => {
|
|
445
|
+
const mockCheckboxes = {
|
|
446
|
+
map: jest.fn((callback) => {
|
|
447
|
+
const results = [
|
|
448
|
+
callback.call({ checked: true, value: 'option1' }),
|
|
449
|
+
callback.call({ checked: false, value: 'option2' }),
|
|
450
|
+
callback.call({ checked: true, value: 'option3' })
|
|
451
|
+
];
|
|
452
|
+
return { get: () => results.filter(r => r !== undefined) };
|
|
453
|
+
})
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const result = FormHelper.getCheckedValues(mockCheckboxes);
|
|
457
|
+
|
|
458
|
+
expect(result).toEqual(['option1', 'option3']);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test('setCheckedValues should check specified values', () => {
|
|
462
|
+
const parentMock = {
|
|
463
|
+
find: jest.fn().mockReturnThis(),
|
|
464
|
+
prop: jest.fn().mockReturnThis()
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
mockInput.parent = jest.fn(() => parentMock);
|
|
468
|
+
|
|
469
|
+
FormHelper.setCheckedValues(mockInput, ['value1', 'value2']);
|
|
470
|
+
|
|
471
|
+
expect(parentMock.find).toHaveBeenCalledWith('[value="value1"]');
|
|
472
|
+
expect(parentMock.find).toHaveBeenCalledWith('[value="value2"]');
|
|
473
|
+
expect(parentMock.prop).toHaveBeenCalledWith('checked', true);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test('getInputListValues should return all input values', () => {
|
|
477
|
+
const mockInputs = {
|
|
478
|
+
map: jest.fn((callback) => {
|
|
479
|
+
const results = [
|
|
480
|
+
callback.call({ value: 'value1' }),
|
|
481
|
+
callback.call({ value: 'value2' }),
|
|
482
|
+
callback.call({ value: '' })
|
|
483
|
+
];
|
|
484
|
+
return {
|
|
485
|
+
get: () => results.filter(r => r.length > 0)
|
|
486
|
+
};
|
|
487
|
+
})
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const result = FormHelper.getInputListValues(mockInputs);
|
|
491
|
+
|
|
492
|
+
expect(result).toEqual(['value1', 'value2']);
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
describe('initTypeFields', () => {
|
|
497
|
+
test('should wrap password fields with toggle button', () => {
|
|
498
|
+
const passwordInput = {
|
|
499
|
+
wrap: jest.fn().mockReturnThis(),
|
|
500
|
+
after: jest.fn().mockReturnThis()
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
mockForm.find = jest.fn((selector) => {
|
|
504
|
+
if (selector === 'input[type="password"]') return passwordInput;
|
|
505
|
+
if (selector.includes('input[type="date"]')) return { length: 0 };
|
|
506
|
+
if (selector.includes('input[type="time"]')) return { length: 0 };
|
|
507
|
+
return mockInput;
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
FormHelper.initTypeFields(mockForm);
|
|
511
|
+
|
|
512
|
+
expect(passwordInput.wrap).toHaveBeenCalled();
|
|
513
|
+
expect(passwordInput.after).toHaveBeenCalled();
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test('should handle date inputs when Modernizr not available', () => {
|
|
517
|
+
const dateInput = {
|
|
518
|
+
css: jest.fn().mockReturnThis(),
|
|
519
|
+
length: 1
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
const passwordInput = {
|
|
523
|
+
wrap: jest.fn().mockReturnThis(),
|
|
524
|
+
after: jest.fn().mockReturnThis(),
|
|
525
|
+
length: 0
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
mockForm.find = jest.fn((selector) => {
|
|
529
|
+
if (selector.includes('input[type="date"]')) return dateInput;
|
|
530
|
+
if (selector.includes('input[type="time"]')) return { length: 0 };
|
|
531
|
+
if (selector === 'input[type="password"]') return passwordInput;
|
|
532
|
+
return mockInput;
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
global.Modernizr = {
|
|
536
|
+
inputtypes: {
|
|
537
|
+
date: false,
|
|
538
|
+
time: true
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
FormHelper.initTypeFields(mockForm);
|
|
543
|
+
|
|
544
|
+
expect(dateInput.css).toHaveBeenCalledWith('max-width', '120px');
|
|
545
|
+
|
|
546
|
+
delete global.Modernizr;
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
test('should handle time inputs when not supported', () => {
|
|
550
|
+
const timeInput = {
|
|
551
|
+
css: jest.fn().mockReturnThis(),
|
|
552
|
+
attr: jest.fn().mockReturnThis(),
|
|
553
|
+
length: 1
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const passwordInput = {
|
|
557
|
+
wrap: jest.fn().mockReturnThis(),
|
|
558
|
+
after: jest.fn().mockReturnThis(),
|
|
559
|
+
length: 0
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
mockForm.find = jest.fn((selector) => {
|
|
563
|
+
if (selector.includes('input[type="time"]')) return timeInput;
|
|
564
|
+
if (selector.includes('[step="1"]')) return timeInput;
|
|
565
|
+
if (selector.includes('input[type="date"]')) return { length: 0 };
|
|
566
|
+
if (selector === 'input[type="password"]') return passwordInput;
|
|
567
|
+
return mockInput;
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
global.Modernizr = {
|
|
571
|
+
inputtypes: {
|
|
572
|
+
date: true,
|
|
573
|
+
time: false
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
FormHelper.initTypeFields(mockForm);
|
|
578
|
+
|
|
579
|
+
expect(timeInput.css).toHaveBeenCalledWith('max-width', '100px');
|
|
580
|
+
expect(timeInput.attr).toHaveBeenCalledWith('placeholder', 'hh:mm');
|
|
581
|
+
|
|
582
|
+
delete global.Modernizr;
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
test('should skip when Modernizr not defined', () => {
|
|
586
|
+
const passwordInput = {
|
|
587
|
+
wrap: jest.fn().mockReturnThis(),
|
|
588
|
+
after: jest.fn().mockReturnThis(),
|
|
589
|
+
length: 1
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const emptyElement = {
|
|
593
|
+
length: 0,
|
|
594
|
+
css: jest.fn().mockReturnThis(),
|
|
595
|
+
attr: jest.fn().mockReturnThis()
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
mockForm.find = jest.fn((selector) => {
|
|
599
|
+
if (selector === 'input[type="password"]') return passwordInput;
|
|
600
|
+
return emptyElement;
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
FormHelper.initTypeFields(mockForm);
|
|
604
|
+
|
|
605
|
+
// Should still wrap password fields
|
|
606
|
+
expect(passwordInput.wrap).toHaveBeenCalled();
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
describe('hideField', () => {
|
|
611
|
+
test('should hide field form-group', () => {
|
|
612
|
+
const formGroupMock = {
|
|
613
|
+
addClass: jest.fn().mockReturnThis()
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
mockInput.closest = jest.fn(() => formGroupMock);
|
|
617
|
+
|
|
618
|
+
FormHelper.hideField(mockInput);
|
|
619
|
+
|
|
620
|
+
expect(mockInput.closest).toHaveBeenCalledWith('.form-group');
|
|
621
|
+
expect(formGroupMock.addClass).toHaveBeenCalledWith('hide');
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
|
|
5
625
|
describe('extractErrorKeyOfJson', () => {
|
|
6
626
|
test('should return null for undefined', () => {
|
|
7
627
|
expect(FormHelper.extractErrorKeyOfJson(undefined)).toBeNull();
|
|
@@ -86,26 +706,6 @@ describe('FormHelper', () => {
|
|
|
86
706
|
|
|
87
707
|
expect(result).toEqual({});
|
|
88
708
|
});
|
|
89
|
-
|
|
90
|
-
test('should handle multiple values for same key (last value wins)', () => {
|
|
91
|
-
const formData = new FormData();
|
|
92
|
-
formData.append('tag', 'tag1');
|
|
93
|
-
formData.append('tag', 'tag2');
|
|
94
|
-
|
|
95
|
-
const result = FormHelper.getDataFromFormData(formData);
|
|
96
|
-
|
|
97
|
-
// FormData entries() with same key will have last value
|
|
98
|
-
expect(result.tag).toBe('tag2');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
test('should handle special characters', () => {
|
|
102
|
-
const formData = new FormData();
|
|
103
|
-
formData.append('field', 'value with spaces & special!');
|
|
104
|
-
|
|
105
|
-
const result = FormHelper.getDataFromFormData(formData);
|
|
106
|
-
|
|
107
|
-
expect(result.field).toBe('value with spaces & special!');
|
|
108
|
-
});
|
|
109
709
|
});
|
|
110
710
|
|
|
111
711
|
describe('getFormErrorText', () => {
|
|
@@ -152,69 +752,167 @@ describe('FormHelper', () => {
|
|
|
152
752
|
|
|
153
753
|
expect(result).toBe('<span>Error 1</span>');
|
|
154
754
|
});
|
|
755
|
+
});
|
|
155
756
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
757
|
+
describe('displayFormErrors', () => {
|
|
758
|
+
test('should display errors and reset button', () => {
|
|
759
|
+
const errors = { field: 'Error message' };
|
|
760
|
+
const displaySpy = jest.spyOn(FormHelper, 'displayFormErrorsFromText');
|
|
761
|
+
const getTextSpy = jest.spyOn(FormHelper, 'getFormErrorText').mockReturnValue('<span>Error</span>');
|
|
762
|
+
const buttonLoaderSpy = jest.spyOn(FormHelper, 'buttonLoader');
|
|
763
|
+
|
|
764
|
+
FormHelper.displayFormErrors(mockForm, mockButton, errors);
|
|
765
|
+
|
|
766
|
+
expect(getTextSpy).toHaveBeenCalledWith(errors);
|
|
767
|
+
expect(displaySpy).toHaveBeenCalledWith(mockForm, '<span>Error</span>', null);
|
|
768
|
+
expect(buttonLoaderSpy).toHaveBeenCalledWith(mockButton, 'reset');
|
|
769
|
+
|
|
770
|
+
displaySpy.mockRestore();
|
|
771
|
+
getTextSpy.mockRestore();
|
|
772
|
+
buttonLoaderSpy.mockRestore();
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
test('should work without button', () => {
|
|
776
|
+
const errors = { field: 'Error message' };
|
|
777
|
+
const displaySpy = jest.spyOn(FormHelper, 'displayFormErrorsFromText');
|
|
778
|
+
const getTextSpy = jest.spyOn(FormHelper, 'getFormErrorText').mockReturnValue('<span>Error</span>');
|
|
779
|
+
|
|
780
|
+
FormHelper.displayFormErrors(mockForm, null, errors);
|
|
781
|
+
|
|
782
|
+
expect(displaySpy).toHaveBeenCalledWith(mockForm, '<span>Error</span>', null);
|
|
783
|
+
|
|
784
|
+
displaySpy.mockRestore();
|
|
785
|
+
getTextSpy.mockRestore();
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
test('should use custom error wrapper', () => {
|
|
789
|
+
const errors = { field: 'Error message' };
|
|
790
|
+
const wrapper = { append: jest.fn() };
|
|
791
|
+
const displaySpy = jest.spyOn(FormHelper, 'displayFormErrorsFromText');
|
|
792
|
+
const getTextSpy = jest.spyOn(FormHelper, 'getFormErrorText').mockReturnValue('<span>Error</span>');
|
|
793
|
+
|
|
794
|
+
FormHelper.displayFormErrors(mockForm, mockButton, errors, wrapper);
|
|
795
|
+
|
|
796
|
+
expect(displaySpy).toHaveBeenCalledWith(mockForm, '<span>Error</span>', wrapper);
|
|
797
|
+
|
|
798
|
+
displaySpy.mockRestore();
|
|
799
|
+
getTextSpy.mockRestore();
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
describe('displayFormErrorsFromText', () => {
|
|
804
|
+
test('should append to errorWrapperDiv when provided', () => {
|
|
805
|
+
const wrapper = {
|
|
806
|
+
append: jest.fn()
|
|
162
807
|
};
|
|
163
808
|
|
|
164
|
-
|
|
809
|
+
FormHelper.displayFormErrorsFromText(mockForm, 'Error text', wrapper);
|
|
165
810
|
|
|
166
|
-
expect(
|
|
167
|
-
expect(result).toContain('<span>Error 4</span>');
|
|
168
|
-
expect(result).not.toContain('<span></span>');
|
|
811
|
+
expect(wrapper.append).toHaveBeenCalledWith('<div class="alert alert-danger form_errors">Error text</div>');
|
|
169
812
|
});
|
|
170
813
|
|
|
171
|
-
test('should
|
|
172
|
-
const
|
|
814
|
+
test('should append to .form_errors_content when exists', () => {
|
|
815
|
+
const errorContent = {
|
|
816
|
+
append: jest.fn(),
|
|
817
|
+
length: 1
|
|
818
|
+
};
|
|
173
819
|
|
|
174
|
-
|
|
820
|
+
mockForm.find = jest.fn((selector) => {
|
|
821
|
+
if (selector === '.form_errors_content') return errorContent;
|
|
822
|
+
return { length: 0 };
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
FormHelper.displayFormErrorsFromText(mockForm, 'Error text');
|
|
826
|
+
|
|
827
|
+
expect(errorContent.append).toHaveBeenCalled();
|
|
175
828
|
});
|
|
176
829
|
|
|
177
|
-
test('should
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
830
|
+
test('should prepend to modal-body when exists', () => {
|
|
831
|
+
const formGroupMock = {
|
|
832
|
+
parent: jest.fn().mockReturnThis(),
|
|
833
|
+
hasClass: jest.fn(() => false),
|
|
834
|
+
before: jest.fn(),
|
|
835
|
+
length: 1
|
|
182
836
|
};
|
|
183
837
|
|
|
184
|
-
const
|
|
838
|
+
const modalBody = {
|
|
839
|
+
find: jest.fn((selector) => {
|
|
840
|
+
if (selector === '.form-group:first') return formGroupMock;
|
|
841
|
+
return { length: 0 };
|
|
842
|
+
}),
|
|
843
|
+
length: 1
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
mockForm.find = jest.fn((selector) => {
|
|
847
|
+
if (selector === '.form_errors_content') return { length: 0 };
|
|
848
|
+
if (selector === '.modal-body') return modalBody;
|
|
849
|
+
if (selector === '.form-group:first') return { length: 0 };
|
|
850
|
+
return mockInput;
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
FormHelper.displayFormErrorsFromText(mockForm, 'Error text');
|
|
185
854
|
|
|
186
|
-
expect(
|
|
187
|
-
expect(result).toContain('<span>Described error</span>');
|
|
188
|
-
expect(result).toContain('<span>Array error</span>');
|
|
855
|
+
expect(mockForm.find).toHaveBeenCalledWith('.modal-body');
|
|
189
856
|
});
|
|
190
|
-
});
|
|
191
857
|
|
|
192
|
-
|
|
193
|
-
|
|
858
|
+
test('should insert before first form-group when exists', () => {
|
|
859
|
+
const formGroup = {
|
|
860
|
+
parent: jest.fn().mockReturnThis(),
|
|
861
|
+
hasClass: jest.fn(() => false),
|
|
862
|
+
before: jest.fn(),
|
|
863
|
+
length: 1
|
|
864
|
+
};
|
|
194
865
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
866
|
+
mockForm.find = jest.fn((selector) => {
|
|
867
|
+
if (selector === '.form_errors_content') return { length: 0 };
|
|
868
|
+
if (selector === '.modal-body') return { length: 0 };
|
|
869
|
+
if (selector === '.form-group:first') return formGroup;
|
|
870
|
+
return mockInput;
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
FormHelper.displayFormErrorsFromText(mockForm, 'Error text');
|
|
874
|
+
|
|
875
|
+
expect(formGroup.before).toHaveBeenCalled();
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
test('should insert before row parent when form-group is in row', () => {
|
|
879
|
+
const parentRow = {
|
|
880
|
+
parent: jest.fn().mockReturnThis(),
|
|
881
|
+
hasClass: jest.fn(() => true),
|
|
882
|
+
before: jest.fn()
|
|
203
883
|
};
|
|
204
884
|
|
|
205
|
-
|
|
206
|
-
|
|
885
|
+
const formGroup = {
|
|
886
|
+
parent: jest.fn(() => parentRow),
|
|
887
|
+
length: 1
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
mockForm.find = jest.fn((selector) => {
|
|
891
|
+
if (selector === '.form_errors_content') return { length: 0 };
|
|
892
|
+
if (selector === '.modal-body') return { length: 0 };
|
|
893
|
+
if (selector === '.form-group:first') return formGroup;
|
|
894
|
+
return mockInput;
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
FormHelper.displayFormErrorsFromText(mockForm, 'Error text');
|
|
898
|
+
|
|
899
|
+
expect(parentRow.before).toHaveBeenCalled();
|
|
207
900
|
});
|
|
208
901
|
|
|
209
|
-
|
|
210
|
-
|
|
902
|
+
test('should prepend to form when no other location found', () => {
|
|
903
|
+
mockForm.find = jest.fn(() => ({ length: 0 }));
|
|
904
|
+
mockForm.prepend = jest.fn();
|
|
905
|
+
|
|
906
|
+
FormHelper.displayFormErrorsFromText(mockForm, 'Error text');
|
|
907
|
+
|
|
908
|
+
expect(mockForm.prepend).toHaveBeenCalledWith('<div class="alert alert-danger form_errors">Error text</div>');
|
|
211
909
|
});
|
|
910
|
+
});
|
|
212
911
|
|
|
912
|
+
describe('buttonLoader', () => {
|
|
213
913
|
test('should disable button on loading', () => {
|
|
214
914
|
mockButton.attr.mockImplementation((key, value) => {
|
|
215
|
-
if (key === 'disabled' && value === undefined)
|
|
216
|
-
return false; // button not disabled initially
|
|
217
|
-
}
|
|
915
|
+
if (key === 'disabled' && value === undefined) return false;
|
|
218
916
|
return mockButton;
|
|
219
917
|
});
|
|
220
918
|
mockButton.data.mockImplementation((key, value) => {
|
|
@@ -228,6 +926,17 @@ describe('FormHelper', () => {
|
|
|
228
926
|
expect(mockButton.addClass).toHaveBeenCalledWith('disabled');
|
|
229
927
|
});
|
|
230
928
|
|
|
929
|
+
test('should not process if already disabled', () => {
|
|
930
|
+
mockButton.attr.mockImplementation((key) => {
|
|
931
|
+
if (key === 'disabled') return true;
|
|
932
|
+
return mockButton;
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
FormHelper.buttonLoader(mockButton, 'loading');
|
|
936
|
+
|
|
937
|
+
expect(mockButton.html).not.toHaveBeenCalled();
|
|
938
|
+
});
|
|
939
|
+
|
|
231
940
|
test('should enable button on reset', () => {
|
|
232
941
|
mockButton.data.mockReturnValue('Original Text');
|
|
233
942
|
|
|
@@ -238,39 +947,34 @@ describe('FormHelper', () => {
|
|
|
238
947
|
expect(mockButton.attr).toHaveBeenCalledWith('disabled', false);
|
|
239
948
|
});
|
|
240
949
|
|
|
241
|
-
test('should use
|
|
950
|
+
test('should use load-text when provided', () => {
|
|
242
951
|
mockButton.attr.mockImplementation((key) => {
|
|
243
952
|
if (key === 'disabled') return false;
|
|
244
953
|
return mockButton;
|
|
245
954
|
});
|
|
246
955
|
mockButton.data.mockImplementation((key) => {
|
|
247
|
-
if (key === '
|
|
248
|
-
return
|
|
956
|
+
if (key === 'load-text') return 'Loading...';
|
|
957
|
+
return null;
|
|
249
958
|
});
|
|
250
959
|
|
|
251
960
|
FormHelper.buttonLoader(mockButton, 'start');
|
|
252
961
|
|
|
253
|
-
expect(mockButton.html).toHaveBeenCalledWith('
|
|
962
|
+
expect(mockButton.html).toHaveBeenCalledWith('Loading...');
|
|
254
963
|
});
|
|
255
964
|
|
|
256
|
-
test('should
|
|
965
|
+
test('should use loading-text when provided', () => {
|
|
257
966
|
mockButton.attr.mockImplementation((key) => {
|
|
258
967
|
if (key === 'disabled') return false;
|
|
259
968
|
return mockButton;
|
|
260
969
|
});
|
|
261
|
-
mockButton.data.
|
|
970
|
+
mockButton.data.mockImplementation((key) => {
|
|
971
|
+
if (key === 'loading-text') return 'Custom Loading...';
|
|
972
|
+
return null;
|
|
973
|
+
});
|
|
262
974
|
|
|
263
975
|
FormHelper.buttonLoader(mockButton, 'start');
|
|
264
976
|
|
|
265
|
-
expect(mockButton.
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test('should handle "stop" action same as "reset"', () => {
|
|
269
|
-
mockButton.data.mockReturnValue('Original');
|
|
270
|
-
|
|
271
|
-
FormHelper.buttonLoader(mockButton, 'stop');
|
|
272
|
-
|
|
273
|
-
expect(mockButton.attr).toHaveBeenCalledWith('disabled', false);
|
|
977
|
+
expect(mockButton.html).toHaveBeenCalledWith('Custom Loading...');
|
|
274
978
|
});
|
|
275
979
|
|
|
276
980
|
test('should return button object', () => {
|
|
@@ -295,15 +999,6 @@ describe('FormHelper', () => {
|
|
|
295
999
|
delete global.$;
|
|
296
1000
|
});
|
|
297
1001
|
|
|
298
|
-
test('should return null for null value', () => {
|
|
299
|
-
const mockInput = { val: jest.fn(() => null) };
|
|
300
|
-
global.$ = jest.fn(() => mockInput);
|
|
301
|
-
|
|
302
|
-
expect(FormHelper.getInputValue(mockInput)).toBeNull();
|
|
303
|
-
|
|
304
|
-
delete global.$;
|
|
305
|
-
});
|
|
306
|
-
|
|
307
1002
|
test('should return value when present', () => {
|
|
308
1003
|
const mockInput = { val: jest.fn(() => 'test value') };
|
|
309
1004
|
global.$ = jest.fn(() => mockInput);
|
|
@@ -334,59 +1029,14 @@ describe('FormHelper', () => {
|
|
|
334
1029
|
|
|
335
1030
|
expect(result).toEqual(['line1', 'line2', 'line3']);
|
|
336
1031
|
});
|
|
337
|
-
|
|
338
|
-
test('should filter empty lines', () => {
|
|
339
|
-
const mockTextarea = {
|
|
340
|
-
val: jest.fn(() => 'line1\n\nline2\n\n\nline3')
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
const result = FormHelper.getLinesOfTextarea(mockTextarea);
|
|
344
|
-
|
|
345
|
-
expect(result).toEqual(['line1', 'line2', 'line3']);
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
test('should handle Mac line endings', () => {
|
|
349
|
-
const mockTextarea = {
|
|
350
|
-
val: jest.fn(() => 'line1\rline2\rline3')
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const result = FormHelper.getLinesOfTextarea(mockTextarea);
|
|
354
|
-
|
|
355
|
-
expect(result).toEqual(['line1', 'line2', 'line3']);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
test('should handle empty textarea', () => {
|
|
359
|
-
const mockTextarea = {
|
|
360
|
-
val: jest.fn(() => '')
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
const result = FormHelper.getLinesOfTextarea(mockTextarea);
|
|
364
|
-
|
|
365
|
-
expect(result).toEqual([]);
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
test('should handle single line', () => {
|
|
369
|
-
const mockTextarea = {
|
|
370
|
-
val: jest.fn(() => 'single line')
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
const result = FormHelper.getLinesOfTextarea(mockTextarea);
|
|
374
|
-
|
|
375
|
-
expect(result).toEqual(['single line']);
|
|
376
|
-
});
|
|
377
1032
|
});
|
|
378
1033
|
|
|
379
1034
|
describe('hideFormErrors', () => {
|
|
380
1035
|
test('should remove form_errors div', () => {
|
|
381
|
-
const mockForm = {
|
|
382
|
-
find: jest.fn().mockReturnThis(),
|
|
383
|
-
remove: jest.fn().mockReturnThis()
|
|
384
|
-
};
|
|
385
|
-
|
|
386
1036
|
const result = FormHelper.hideFormErrors(mockForm);
|
|
387
1037
|
|
|
388
1038
|
expect(mockForm.find).toHaveBeenCalledWith('div.form_errors');
|
|
389
|
-
expect(
|
|
1039
|
+
expect(mockInput.remove).toHaveBeenCalled();
|
|
390
1040
|
expect(result).toBe(mockForm);
|
|
391
1041
|
});
|
|
392
1042
|
});
|