-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from xsolla/PAYMENTS-15244
feat(PAYMENTS-15244): add payment-form component
- Loading branch information
Showing
17 changed files
with
523 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
...s/headless-checkout/web-components/payment-form/get-invalid-fields-names.function.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { getInvalidFieldsNames } from './get-invalid-fields-names.function'; | ||
|
||
const expectedFieldsNames = ['zip', 'email']; | ||
|
||
describe('getInvalidFieldsNames', () => { | ||
it('Should return invalid names', () => { | ||
const exists = ['zip', 'card']; | ||
expect(getInvalidFieldsNames(expectedFieldsNames, exists)).toEqual([ | ||
'card', | ||
]); | ||
}); | ||
|
||
it('Should return invalid names if duplicates', () => { | ||
const exists = ['zip', 'zip']; | ||
expect(getInvalidFieldsNames(expectedFieldsNames, exists)).toEqual(['zip']); | ||
}); | ||
|
||
it('Should not filter empty name fields', () => { | ||
const exists = ['zip', '']; | ||
expect(getInvalidFieldsNames(expectedFieldsNames, exists)).toEqual([]); | ||
}); | ||
}); |
32 changes: 32 additions & 0 deletions
32
...atures/headless-checkout/web-components/payment-form/get-invalid-fields-names.function.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export function getInvalidFieldsNames( | ||
expectedFieldsNames: string[], | ||
existsControlsNames: Array<string | null> | ||
): string[] { | ||
const fieldsExistsCountMap: { [k: string]: number } = {}; | ||
for (const name of existsControlsNames) { | ||
if (name) { | ||
const count = fieldsExistsCountMap[name]; | ||
if (!count) { | ||
fieldsExistsCountMap[name] = 1; | ||
} else { | ||
fieldsExistsCountMap[name] = count + 1; | ||
} | ||
} | ||
} | ||
|
||
const invalidFieldNames = []; | ||
|
||
// eslint-disable-next-line prefer-const | ||
for (let [name, count] of Object.entries(fieldsExistsCountMap)) { | ||
if (!expectedFieldsNames.some((value) => value === name)) { | ||
invalidFieldNames.push(name); | ||
} else if (count > 1) { | ||
while (count > 1) { | ||
invalidFieldNames.push(name); | ||
count--; | ||
} | ||
} | ||
} | ||
|
||
return invalidFieldNames; | ||
} |
12 changes: 12 additions & 0 deletions
12
...es/headless-checkout/web-components/payment-form/get-missed-fields-names.function.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { getMissedFieldsNames } from './get-missed-fields-names.function'; | ||
|
||
const expectedFieldsNames = ['zip', 'email']; | ||
|
||
describe('getMissedFieldsNames', () => { | ||
it('Should return missed names', () => { | ||
const exists = ['zip', 'card', '']; | ||
expect(getMissedFieldsNames(expectedFieldsNames, exists)).toEqual([ | ||
'email', | ||
]); | ||
}); | ||
}); |
20 changes: 20 additions & 0 deletions
20
...eatures/headless-checkout/web-components/payment-form/get-missed-fields-names.function.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
export function getMissedFieldsNames( | ||
expectedFieldsNames: string[], | ||
existsControlsNames: Array<string | null> | ||
): string[] { | ||
const fieldsExistsMap: { [k: string]: boolean } = {}; | ||
|
||
for (const name of existsControlsNames) { | ||
if (name) { | ||
fieldsExistsMap[name] = true; | ||
} | ||
} | ||
|
||
const missedFieldsNames = []; | ||
for (const name of expectedFieldsNames) { | ||
if (!fieldsExistsMap[name]) { | ||
missedFieldsNames.push(name); | ||
} | ||
} | ||
return missedFieldsNames; | ||
} |
75 changes: 75 additions & 0 deletions
75
...eatures/headless-checkout/web-components/payment-form/payment-form-fields.service.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import 'reflect-metadata'; | ||
import { container } from 'tsyringe'; | ||
import { PaymentFormFieldsService } from './payment-form-fields.service'; | ||
import { WebComponentTagName } from '../../../../core/web-components/web-component-tag-name.enum'; | ||
import { noopStub } from '../../../../tests/stubs/noop.stub'; | ||
|
||
const getTextInputElements = (names: string[]): NodeListOf<Element> => { | ||
const mockContainer = document.createElement('div'); | ||
for (const name of names) { | ||
const mockElement = document.createElement( | ||
WebComponentTagName.TextComponent | ||
); | ||
mockElement.setAttribute('name', name); | ||
mockContainer.appendChild(mockElement); | ||
} | ||
|
||
return mockContainer.querySelectorAll(WebComponentTagName.TextComponent); | ||
}; | ||
|
||
describe('PaymentFormFieldsManager', () => { | ||
let paymentFormFieldsManager: PaymentFormFieldsService; | ||
let windowService: Window; | ||
|
||
beforeEach(() => { | ||
windowService = window; | ||
|
||
container.register<Window>(Window, { useValue: windowService }); | ||
paymentFormFieldsManager = container | ||
.createChildContainer() | ||
.resolve(PaymentFormFieldsService); | ||
}); | ||
|
||
it('Should create missed fields and append them into body', () => { | ||
const textInputElements = getTextInputElements([]); | ||
spyOn(windowService.document, 'querySelectorAll').and.returnValue( | ||
textInputElements | ||
); | ||
const missedFields = ['card']; | ||
const mockBody = { | ||
appendChild: noopStub, | ||
} as unknown as HTMLElement; | ||
spyOn(windowService.document, 'querySelector').and.returnValue( | ||
mockBody as unknown as Element | ||
); | ||
const spy = spyOn(mockBody, 'appendChild'); | ||
paymentFormFieldsManager.createMissedFields(missedFields, mockBody); | ||
expect(spy).toHaveBeenCalled(); | ||
}); | ||
|
||
it('Should remove extra field', () => { | ||
const extraFields = ['card', null]; | ||
const mockElement = { | ||
remove: noopStub, | ||
}; | ||
spyOn(windowService.document, 'querySelector').and.returnValue( | ||
mockElement as unknown as Element | ||
); | ||
const spy = spyOn(mockElement, 'remove'); | ||
paymentFormFieldsManager.removeExtraFields(extraFields); | ||
expect(spy).toHaveBeenCalled(); | ||
}); | ||
|
||
it('Should remove fields with empty name', () => { | ||
const textInputElements = getTextInputElements(['zip']); | ||
textInputElements.forEach((element) => { | ||
element.removeAttribute('name'); | ||
}); | ||
spyOn(windowService.document, 'querySelectorAll').and.returnValue( | ||
textInputElements | ||
); | ||
const spy = spyOn(textInputElements[0], 'remove'); | ||
paymentFormFieldsManager.removeEmptyNameFields(); | ||
expect(spy).toHaveBeenCalled(); | ||
}); | ||
}); |
45 changes: 45 additions & 0 deletions
45
src/features/headless-checkout/web-components/payment-form/payment-form-fields.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { injectable } from 'tsyringe'; | ||
import { WebComponentTagName } from '../../../../core/web-components/web-component-tag-name.enum'; | ||
|
||
@injectable() | ||
export class PaymentFormFieldsService { | ||
public constructor(private readonly window: Window) {} | ||
|
||
public createMissedFields( | ||
missedFieldsNames: string[], | ||
container: HTMLElement | ||
): void { | ||
const documentFragment = this.window.document.createDocumentFragment(); | ||
|
||
for (const name of missedFieldsNames) { | ||
const formElement = this.window.document.createElement( | ||
WebComponentTagName.TextComponent | ||
); | ||
formElement.setAttribute('name', name); | ||
documentFragment.append(formElement); | ||
} | ||
|
||
container.appendChild(documentFragment); | ||
} | ||
|
||
public removeExtraFields(extraFieldsNames: Array<string | null>): void { | ||
for (const name of extraFieldsNames) { | ||
if (!name) { | ||
continue; | ||
} | ||
const formElement = this.window.document.querySelector(`[name=${name}]`); | ||
formElement?.remove(); | ||
} | ||
} | ||
|
||
public removeEmptyNameFields(): void { | ||
const formInputs = this.window.document.querySelectorAll( | ||
WebComponentTagName.TextComponent | ||
); | ||
Array.from(formInputs).forEach((formInput) => { | ||
if (!formInput.getAttribute('name')) { | ||
formInput.remove(); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.