Skip to content

Commit

Permalink
Chore cherry-pick 6.1.1 to v5 (#2827)
Browse files Browse the repository at this point in the history
* Improves accessibility by removing region on payment method item and button loading state (#2816)

* small a11y improvement

* go back to disabled

* make it visually hidden

* fix mixin import

(cherry picked from commit 18172bb)

* Fixes LT postal code (#2822)

* fix LT postal code

also add AddressElement to storybook
adds some test to validate

* add changeset

(cherry picked from commit 9d005c3)

* change for v5
  • Loading branch information
m1aw authored Sep 2, 2024
1 parent ec09e95 commit 90b4b31
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-kings-call.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@adyen/adyen-web': patch
---

Fixes Lithuanian postal code to support 4-5 digits and LT prefix
5 changes: 5 additions & 0 deletions .changeset/yellow-crabs-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@adyen/adyen-web': patch
---

Improves acessibility removing region on payment method item and button loading state
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,7 @@ class PaymentMethodItem extends Component<PaymentMethodItemProps> {
)}
</div>

<div
className={`adyen-checkout__payment-method__details ${styles['adyen-checkout__payment-method__details']}`}
id={containerId}
role="region"
>
<div className={`adyen-checkout__payment-method__details ${styles['adyen-checkout__payment-method__details']}`} id={containerId}>
{showRemovePaymentMethodButton && (
<DisableOneClickConfirmation
id={disableConfirmationId}
Expand Down
140 changes: 140 additions & 0 deletions packages/lib/src/components/internal/Address/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { validatePostalCode } from './validate';
import { ValidatorRules } from '../../../utils/Validator/types';

describe('validatePostalCode', () => {
const validatorRules: ValidatorRules = {
postalCode: {
modes: ['blur'],
validate: jest.fn(),
errorMessage: ''
}
};

// LT
it('should return true for a valid LT postal code without the LT prefix', () => {
const result = validatePostalCode('12345', 'LT', validatorRules);
expect(result).toBe(true);
});

it('should return true for a valid LT postal code without the LT prefix (4-digits)', () => {
const result = validatePostalCode('1234', 'LT', validatorRules);
expect(result).toBe(true);
});

it('should return true for a valid LT postal code with the LT prefix', () => {
const result = validatePostalCode('LT-12345', 'LT', validatorRules);
expect(result).toBe(true);
});

it('should return false for a valid LT postal code with the LT prefix but only 4 digits', () => {
const result = validatePostalCode('LT-1235', 'LT', validatorRules);
expect(result).toBe(false);
});

it('should return false for an invalid LT postal code with fewer than 4 digits', () => {
const result = validatePostalCode('123', 'LT', validatorRules);
expect(result).toBe(false);
});

it('should return false for an invalid LT postal code with fewer than 6 digits', () => {
const result = validatePostalCode('1234567', 'LT', validatorRules);
expect(result).toBe(false);
});

// BR
it('should return true for a valid BR postal code with hyphen', () => {
const result = validatePostalCode('12345-678', 'BR', validatorRules);
expect(result).toBe(true);
});

it('should return true for a valid BR postal code without hyphen', () => {
const result = validatePostalCode('12345678', 'BR', validatorRules);
expect(result).toBe(true);
});

it('should return false for an invalid BR postal code', () => {
const result = validatePostalCode('1234-5678', 'BR', validatorRules);
expect(result).toBe(false);
});

// US and the ones using createPatternByDigits
it('should return true for a valid US postal code with 5 digits', () => {
const result = validatePostalCode('12345', 'US', validatorRules);
expect(result).toBe(true);
});

// It fails because createPatternByDigits actually just check if there's at least X amount of digits
// it('should return false for an invalid US postal code with more than 5 digits without a hyphen', () => {
// const result = validatePostalCode('1234567', 'US', validatorRules);
// expect(result).toBe(false);
// });

// General
it('should return null if the postal code is empty', () => {
const result = validatePostalCode('', 'AT', validatorRules);
expect(result).toBeNull();
});

it('should return true for a valid AT postal code', () => {
const result = validatePostalCode('1234', 'AT', validatorRules);
expect(result).toBe(true);
});

// PT
it('should return true for a valid PT postal code without hyphen', () => {
const result = validatePostalCode('1234567', 'PT', validatorRules);
expect(result).toBe(true);
});

it('should return true for a valid PT postal code with hyphen', () => {
const result = validatePostalCode('1234-567', 'PT', validatorRules);
expect(result).toBe(true);
});

it('should return false for an invalid PT postal code with incorrect format', () => {
const result = validatePostalCode('123-4567', 'PT', validatorRules);
expect(result).toBe(false);
});

// it('should return true for an PT postal code with just the part before the hyphen', () => {
// const result = validatePostalCode('1234', 'PT', validatorRules);
// expect(result).toBe(true);
// });

// NL
it('should return true for a valid NL postal code without NL prefix', () => {
const result = validatePostalCode('1234AB', 'NL', validatorRules);
expect(result).toBe(true);
});

it('should return true for a valid NL postal code with space between digits and letters', () => {
const result = validatePostalCode('1234 AB', 'NL', validatorRules);
expect(result).toBe(true);
});

it('should return true for a valid NL postal code with NL prefix', () => {
const result = validatePostalCode('NL-1234AB', 'NL', validatorRules);
expect(result).toBe(true);
});

it('should return false for an invalid NL postal code with missing letters', () => {
const result = validatePostalCode('1234', 'NL', validatorRules);
expect(result).toBe(false);
});

// Againt it seems like it's missing begining and end ^ $ symbols in the regex (same as US)
// it('should return false for an invalid NL postal code with incorrect letter combination', () => {
// const result = validatePostalCode('1234AA1', 'NL', validatorRules);
// expect(result).toBe(false);
// });

it('should return false for an invalid NL postal code with fewer digits', () => {
const result = validatePostalCode('123AB', 'NL', validatorRules);
expect(result).toBe(false);
});

// it('should return false for an invalid NL postal code with too many digits', () => {
// const result = validatePostalCode('12345AB', 'NL', validatorRules);
// expect(result).toBe(false);
// });
});
4 changes: 2 additions & 2 deletions packages/lib/src/components/internal/Address/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const createPatternByDigits = (digits: number) => {
};
};

const validatePostalCode = (val: string, countryCode: string, validatorRules: ValidatorRules) => {
export const validatePostalCode = (val: string, countryCode: string, validatorRules: ValidatorRules) => {
if (countryCode) {
// Dynamically create errorMessage
(validatorRules.postalCode as ValidatorRule).errorMessage = {
Expand Down Expand Up @@ -55,7 +55,7 @@ const postalCodePatterns = {
IS: createPatternByDigits(3),
IT: createPatternByDigits(5),
LI: createPatternByDigits(4),
LT: { pattern: /^(LT-\d{5})$/ },
LT: { pattern: /^(LT-\d{5}|\d{4,5})$/ },
LU: createPatternByDigits(4),
LV: { pattern: /^(LV-)[0-9]{4}$/ },
MC: { pattern: /^980\d{2}$/ },
Expand Down
11 changes: 11 additions & 0 deletions packages/lib/src/components/internal/Button/Button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

&--sr-only {
border: 0;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
overflow: hidden;
margin: -1px;
padding: 0;
position: absolute;
}
}

.adyen-checkout__spinner {
Expand Down
7 changes: 6 additions & 1 deletion packages/lib/src/components/internal/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ class Button extends Component<ButtonProps, ButtonState> {
const buttonClasses = classNames(['adyen-checkout__button', ...modifiers.map(m => `adyen-checkout__button--${m}`)]);

const buttonStates = {
loading: <Spinner size="medium" />,
loading: (
<span className="adyen-checkout__button__content">
<Spinner size="medium" inline />
<span className={'adyen-checkout__button__text--sr-only'}>{i18n.get('loading')}</span>
</span>
),
redirect: (
<span className="adyen-checkout__button__content">
<Spinner size="medium" inline />
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/storybook/helpers/checkout-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export async function handleResponse(response, component, checkout?, paymentData
}

export function handleChange(state: any, component: UIElement) {
console.groupCollapsed(`onChange - ${state.data.paymentMethod.type}`);
console.groupCollapsed(`onChange - ${state.data.paymentMethod?.type}`);
console.log('isValid', state.isValid);
console.log('data', state.data);
console.log('node', component._node);
Expand Down
38 changes: 38 additions & 0 deletions packages/lib/storybook/stories/internals/Address.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Meta } from '@storybook/preact';
import Address from '../../../src/components/internal/Address';
import { getStoryContextCheckout } from '../../utils/get-story-context-checkout';
import { Container } from '../Container';
import AddressElement from '../../../src/components/Address/Address';

const meta: Meta = {
title: 'Internals/Address',
component: Address,
argTypes: {
size: {
options: ['small', 'medium', 'large'],
control: { type: 'radio' }
}
},
args: {
size: 'large'
}
};

export const Default = {
render: (args, context) => {
const { componentConfiguration } = args;
const checkout = getStoryContextCheckout(context);
const address = new AddressElement(checkout, componentConfiguration);
return <Container element={address} />;
},
args: {
countryCode: 'NL',
amount: 2000,
useSessions: false
},
parameters: {
controls: { exclude: ['useSessions', 'countryCode', 'shopperLocale', 'amount', 'showPayButton'] }
}
};

export default meta;

0 comments on commit 90b4b31

Please sign in to comment.