Skip to content

Commit 915c8c9

Browse files
SK-2157 custom input formatting for collect elements (#108)
* SK-2157 custom input formatting for collect elements * SK-2168 input formatting with combination of constants & dynamic input in InputFieldElement
1 parent c040c47 commit 915c8c9

8 files changed

Lines changed: 472 additions & 11 deletions

File tree

__tests__/core/collectElement.test.js

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,11 @@ describe('test Collect Element class', () => {
257257
new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_COLUMN_IN_COLLECT, [], true)
258258
);
259259

260-
collecteElement = new CollectElement({ table: 'cards', column: 'test', skyflowID: '' }, {}, context);
260+
collecteElement = new CollectElement(
261+
{ table: 'cards', column: 'test', skyflowID: '' },
262+
{},
263+
context
264+
);
261265
expect(isValid).toThrow(
262266
new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_SKYFLOW_ID_COLLECT, [], true)
263267
);
@@ -515,8 +519,10 @@ describe('test Collect Element class', () => {
515519
);
516520
cardNumberElement.onDropdownSelect(CardType.DISCOVER);
517521
cardNumberElement.onChangeElement('', true);
518-
expect(cardNumberElement.getClientState().selectedCardScheme).toEqual('DISCOVER');
519-
})
522+
expect(cardNumberElement.getClientState().selectedCardScheme).toEqual(
523+
'DISCOVER'
524+
);
525+
});
520526

521527
it('should remove spaces from value', () => {
522528
const elementInput = {
@@ -529,4 +535,118 @@ describe('test Collect Element class', () => {
529535
collectElement.updateValue('4111 1111 1111 1111');
530536
expect(collectElement.getUnformattedValue()).toBe('4111111111111111');
531537
});
532-
});
538+
539+
it('test format option in card number element', () => {
540+
const formatTestCases = [
541+
// Test different valid formats for the card number
542+
{
543+
format: 'XXXX-XXXX-XXXX-XXXX',
544+
input: '4111111111111111',
545+
expected: '4111-1111-1111-1111',
546+
},
547+
{
548+
format: 'XXXX XXXX XXXX XXXX',
549+
input: '4111111111111111',
550+
expected: '4111 1111 1111 1111',
551+
},
552+
// Test partial input
553+
{
554+
format: 'XXXX-XXXX-XXXX-XXXX',
555+
input: '411111',
556+
expected: '4111-11',
557+
},
558+
{
559+
format: 'XXXX XXXX XXXX XXXX',
560+
input: '411111',
561+
expected: '4111 11',
562+
},
563+
// Test for invalid format, It will fallback to default format
564+
{
565+
format: ' xxxx-xxxx-xxxx ',
566+
input: ' 4111111111111111 ',
567+
expected: '4111 1111 1111 1111',
568+
},
569+
];
570+
571+
formatTestCases.forEach((testCase) => {
572+
const collectElement = new CollectElement(
573+
{
574+
table: 'cards',
575+
column: 'card_number',
576+
type: ElementType.CARD_NUMBER,
577+
containerType: ContainerType.COLLECT,
578+
},
579+
{
580+
format: testCase.format,
581+
},
582+
context
583+
);
584+
585+
collectElement.onChangeElement(testCase.input);
586+
expect(collectElement.getInternalState().value).toBe(testCase.expected);
587+
});
588+
});
589+
590+
it('test format option in input field element', () => {
591+
const formatTestCases = [
592+
{
593+
format: 'XX-XX-XX',
594+
input: '123456',
595+
expected: '12-34-56',
596+
},
597+
{
598+
format: 'XXX XXX',
599+
input: '123456',
600+
expected: '123 456',
601+
},
602+
{
603+
format: 'XX/XX/XX',
604+
input: '123456',
605+
expected: '12/34/56',
606+
},
607+
// Test partial input
608+
{
609+
format: 'XX-XX-XX',
610+
input: '1234',
611+
expected: '12-34',
612+
},
613+
// Test with special characters
614+
{
615+
format: 'XX@XX#XX',
616+
input: '123456',
617+
expected: '12@34#56',
618+
},
619+
// Test input longer than format
620+
{
621+
format: 'XX-XX',
622+
input: '123456',
623+
expected: '12-34',
624+
},
625+
// Test input with leading, trailing spaces & small format
626+
{
627+
format: ' xx-xx-xxx ',
628+
input: ' 1234567 ',
629+
expected: ' xx-xx-xxx ',
630+
},
631+
];
632+
633+
formatTestCases.forEach((testCase) => {
634+
const collectElement = new CollectElement(
635+
{
636+
table: 'table',
637+
column: 'column',
638+
type: ElementType.INPUT_FIELD,
639+
containerType: ContainerType.COLLECT,
640+
},
641+
{
642+
format: testCase.format,
643+
},
644+
context
645+
);
646+
647+
collectElement.onChangeElement(testCase.input);
648+
expect(collectElement.getInternalState().value).toBe(testCase.expected);
649+
expect(collectElement.getInternalState().isValid).toBe(true);
650+
});
651+
});
652+
});

__tests__/utils/helper.test.js

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
getYearAndMonthBasedOnFormat,
1717
getMetaObject,
1818
getDeviceModel,
19+
formatInputFieldValue,
1920
} from '../../src/utils/helpers';
2021
import {
2122
CardType,
@@ -300,4 +301,223 @@ describe('test getYearAndMonthBasedOnFormat function', () => {
300301
year: '2032',
301302
});
302303
});
304+
305+
it('should format expiration date options correctly', () => {
306+
const validFormats = ['MM/YY', 'MM/YYYY', 'YYYY/MM', 'YY/MM'];
307+
validFormats.forEach((format) => {
308+
const result = formatCollectElementOptions(
309+
ElementType.EXPIRATION_DATE,
310+
{ format },
311+
LogLevel.WARN
312+
);
313+
expect(result).toEqual({
314+
format,
315+
required: false,
316+
});
317+
});
318+
});
319+
320+
it('should use default format for invalid expiration date format', () => {
321+
const result = formatCollectElementOptions(
322+
ElementType.EXPIRATION_DATE,
323+
{ format: 'INVALID' },
324+
LogLevel.WARN
325+
);
326+
expect(result).toEqual({
327+
format: DEFAULT_EXPIRATION_DATE_FORMAT,
328+
required: false,
329+
});
330+
expect(printLog).toBeCalled();
331+
});
332+
333+
it('should format expiration year options correctly', () => {
334+
const validFormats = ['YY', 'YYYY'];
335+
validFormats.forEach((format) => {
336+
const result = formatCollectElementOptions(
337+
ElementType.EXPIRATION_YEAR,
338+
{ format },
339+
LogLevel.WARN
340+
);
341+
expect(result).toEqual({
342+
format,
343+
required: false,
344+
});
345+
});
346+
});
347+
348+
it('should use default format for invalid expiration year format', () => {
349+
const result = formatCollectElementOptions(
350+
ElementType.EXPIRATION_YEAR,
351+
{ format: 'INVALID' },
352+
LogLevel.WARN
353+
);
354+
expect(result).toEqual({
355+
format: DEFAULT_EXPIRATION_YEAR_FORMAT,
356+
required: false,
357+
});
358+
expect(printLog).toBeCalled();
359+
});
360+
});
361+
362+
describe('test formatCardNumber with different formats', () => {
363+
const testCases = [
364+
{
365+
input: '4111111111111111',
366+
type: CardType.VISA,
367+
format: 'XXXX-XXXX-XXXX-XXXX',
368+
expected: '4111-1111-1111-1111',
369+
},
370+
{
371+
input: '378282246310005',
372+
type: CardType.AMEX,
373+
format: 'XXXX-XXXX-XXXX-XXXX',
374+
expected: '3782-822463-10005',
375+
},
376+
{
377+
input: '6011111111111117',
378+
type: CardType.DISCOVER,
379+
format: 'XXXX XXXX XXXX XXXX',
380+
expected: '6011 1111 1111 1117',
381+
},
382+
// Test partial inputs
383+
{
384+
input: '411111',
385+
type: CardType.VISA,
386+
format: 'XXXX-XXXX-XXXX-XXXX',
387+
expected: '4111-11',
388+
},
389+
// Test empty input
390+
{
391+
input: '',
392+
type: CardType.DEFAULT,
393+
format: 'XXXX-XXXX-XXXX-XXXX',
394+
expected: '',
395+
},
396+
];
397+
398+
testCases.forEach((testCase) => {
399+
it(`should format ${testCase.type} card number correctly with format ${testCase.format}`, () => {
400+
expect(
401+
formatCardNumber(testCase.input, testCase.type, testCase.format)
402+
).toBe(testCase.expected);
403+
});
404+
});
405+
});
406+
407+
describe('test formatInputFieldValue with different formats', () => {
408+
const testCases = [
409+
{
410+
input: '123456',
411+
format: 'XX-XX-XX',
412+
expected: '12-34-56',
413+
},
414+
{
415+
input: '123456',
416+
format: 'XXX XXX',
417+
expected: '123 456',
418+
},
419+
{
420+
input: '12345',
421+
format: 'XX/XX/X',
422+
expected: '12/34/5',
423+
},
424+
{
425+
input: '1567C89',
426+
format: 'XX/XYX/X',
427+
translation: { X: '[5-9]', Y: '[A-C]' },
428+
expected: '56/7C8/9',
429+
},
430+
// Combination of constants and dynamic inputs
431+
{
432+
input: '1234121234',
433+
format: '+91 XXXX-XX-XXXX',
434+
expected: '+91 1234-12-1234',
435+
},
436+
{
437+
input: 'B5678978C7QAB97',
438+
format: '91 YXX-XZX-XXY-XZYXX',
439+
translation: { X: '[5-9]', Y: '[A-C]' },
440+
expected: '91 B56-7Z8-97C-7ZA97',
441+
},
442+
// Test with special characters in format
443+
{
444+
input: '123456',
445+
format: 'XX@XX#XX',
446+
expected: '12@34#56',
447+
},
448+
// Test partial input
449+
{
450+
input: '123',
451+
format: 'XX-XX-XX',
452+
expected: '12-3',
453+
},
454+
// Test input longer than format
455+
{
456+
input: '1234567',
457+
format: 'XX-XX',
458+
expected: '12-34',
459+
},
460+
// Test empty input
461+
{
462+
input: '',
463+
format: 'XX-XX',
464+
expected: '',
465+
},
466+
// Test with no format
467+
{
468+
input: '123456',
469+
format: '',
470+
expected: '123456',
471+
},
472+
];
473+
474+
testCases.forEach((testCase) => {
475+
const translation = testCase.translation || {
476+
X: '[0-9]',
477+
};
478+
it(`should format input '${testCase.input}' with format '${
479+
testCase.format
480+
}' & translation '${JSON.stringify(translation)}' correctly`, () => {
481+
expect(
482+
formatInputFieldValue(
483+
testCase.input,
484+
testCase.format,
485+
testCase?.translation
486+
)
487+
).toBe(testCase.expected);
488+
});
489+
});
490+
});
491+
492+
describe('test formatCollectElementOptions for different element types', () => {
493+
it('should format card number options correctly', () => {
494+
const options = {
495+
format: 'XXXX-XXXX-XXXX-XXXX',
496+
required: true,
497+
};
498+
const result = formatCollectElementOptions(
499+
ElementType.CARD_NUMBER,
500+
options,
501+
LogLevel.WARN
502+
);
503+
expect(result).toEqual({
504+
format: 'XXXX-XXXX-XXXX-XXXX',
505+
required: true,
506+
});
507+
});
508+
509+
it('should preserve other options while formatting', () => {
510+
const options = {
511+
format: 'XXXX-XXXX-XXXX-XXXX',
512+
required: true,
513+
enableCardIcon: true,
514+
customOption: 'value',
515+
};
516+
const result = formatCollectElementOptions(
517+
ElementType.CARD_NUMBER,
518+
options,
519+
LogLevel.WARN
520+
);
521+
expect(result).toEqual(options);
522+
});
303523
});

0 commit comments

Comments
 (0)