Skip to content

Commit 2fd8524

Browse files
refactor: Append tests, refactor constants
1 parent f0a3e1f commit 2fd8524

File tree

6 files changed

+146
-5
lines changed

6 files changed

+146
-5
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const LANDING_COMPANY = {
2+
BVI: 'bvi',
3+
LABUAN: 'labuan',
4+
MALTAINVEST: 'maltainvest',
5+
SVG: 'svg',
6+
VANUATU: 'vanuatu',
7+
} as const;

packages/account-v2/src/modules/AddressFields/AddressFields.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { useAuthorize, useSettings, useStatesList } from '@deriv/api';
33
import FormDropDownField from '../../components/FormFields/FormDropDownField';
44
import FormInputField from '../../components/FormFields/FormInputField';
5+
import { LANDING_COMPANY } from '../../constants/constants';
56
import { addressDetailValidations } from './validations';
67

78
export const AddressFields = () => {
@@ -11,7 +12,8 @@ export const AddressFields = () => {
1112
const { landing_company_name: landingCompanyName, upgradeable_landing_companies: upgradableLandingCompanies } =
1213
activeAccount;
1314

14-
const isSvg = landingCompanyName === 'svg' || !!upgradableLandingCompanies?.includes('svg');
15+
const isSvg =
16+
landingCompanyName === LANDING_COMPANY.SVG || !!upgradableLandingCompanies?.includes(LANDING_COMPANY.SVG);
1517
const { data: statesList, isFetched: statesListFetched } = useStatesList(settings.country_code || '', {
1618
enabled: !!settings.country_code,
1719
});
@@ -22,7 +24,7 @@ export const AddressFields = () => {
2224
addressLine2: addressLine2Schema,
2325
addressPostcode: addressPostcodeSchema,
2426
addressState: addressStateSchema,
25-
} = addressDetailValidations(settings.country_code || '', isSvg);
27+
} = addressDetailValidations(settings.country_code ?? '', isSvg);
2628

2729
return (
2830
<div className='space-y-600'>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { addressDetailValidations as validations, addressPermittedSpecialCharactersMessage } from '../validations';
2+
3+
describe('validations', () => {
4+
const maxCharsMessage = 'Only 70 characters, please.';
5+
it('validates addressLine1 correctly without svg flag', async () => {
6+
const { addressLine1 } = validations('id', false);
7+
8+
await expect(addressLine1.validate('123 Main St')).resolves.toBe('123 Main St');
9+
await expect(addressLine1.validate('')).rejects.toThrow('First line of address is required');
10+
await expect(addressLine1.validate('a$^&')).rejects.toThrow(
11+
`Use only the following special characters: ${addressPermittedSpecialCharactersMessage}`
12+
);
13+
await expect(addressLine1.validate('a'.repeat(71))).rejects.toThrow(maxCharsMessage);
14+
await expect(addressLine1.validate('P.O. Box 121')).resolves.toBe('P.O. Box 121');
15+
});
16+
17+
it('validates addressLine1 correctly with svg flag', async () => {
18+
const { addressLine1 } = validations('id', true);
19+
20+
await expect(addressLine1.validate('123 Main St1')).resolves.toBe('123 Main St1');
21+
await expect(addressLine1.validate('')).rejects.toThrow('First line of address is required');
22+
await expect(addressLine1.validate('a'.repeat(71))).rejects.toThrow(maxCharsMessage);
23+
await expect(addressLine1.validate('P.O. Box 123')).rejects.toThrow('P.O. Box is not accepted in address');
24+
});
25+
26+
it('validates addressLine2 correctly', async () => {
27+
const { addressLine2 } = validations('id', false);
28+
29+
await expect(addressLine2.validate('Apt 4B')).resolves.toBe('Apt 4B');
30+
await expect(addressLine2.validate('a$^&')).rejects.toThrow(
31+
`Use only the following special characters: ${addressPermittedSpecialCharactersMessage}`
32+
);
33+
await expect(addressLine2.validate('a'.repeat(71))).rejects.toThrow(maxCharsMessage);
34+
await expect(addressLine2.validate('P.O. Box 120')).resolves.toBe('P.O. Box 120');
35+
});
36+
37+
it('validates addressLine2 correctly with svg flag', async () => {
38+
const { addressLine2 } = validations('id', true);
39+
40+
await expect(addressLine2.validate('Apt 4B')).resolves.toBe('Apt 4B');
41+
await expect(addressLine2.validate('a'.repeat(71))).rejects.toThrow(maxCharsMessage);
42+
await expect(addressLine2.validate('P.O. Box 122')).rejects.toThrow('P.O. Box is not accepted in address');
43+
});
44+
45+
it('validates addressPostcode correctly with country gb', async () => {
46+
const { addressPostcode } = validations('gb', false);
47+
48+
await expect(addressPostcode.validate('12345')).resolves.toBe('12345');
49+
await expect(addressPostcode.validate('$%&')).rejects.toThrow('Letters, numbers, spaces, hyphens only');
50+
await expect(addressPostcode.validate('a'.repeat(21))).rejects.toThrow(
51+
'Please enter a postal/ZIP code under 20 characters.'
52+
);
53+
await expect(addressPostcode.validate('JE1 1AA')).rejects.toThrow(
54+
'Our accounts and services are unavailable for the Jersey postal code.'
55+
);
56+
});
57+
58+
it('validates addressPostcode correctly with country id', async () => {
59+
const { addressPostcode } = validations('id', false);
60+
61+
await expect(addressPostcode.validate('12345')).resolves.toBe('12345');
62+
await expect(addressPostcode.validate('$%&')).rejects.toThrow('Letters, numbers, spaces, hyphens only');
63+
await expect(addressPostcode.validate('a'.repeat(21))).rejects.toThrow(
64+
'Please enter a postal/ZIP code under 20 characters.'
65+
);
66+
await expect(addressPostcode.validate('JE1 1AA')).resolves.toBe('JE1 1AA');
67+
});
68+
69+
it('validates addressState correctly', async () => {
70+
const { addressState } = validations('id', false);
71+
72+
await expect(addressState.validate('NY')).resolves.toBe('NY');
73+
await expect(addressState.validate('')).rejects.toThrow('State is required');
74+
await expect(addressState.validate('a'.repeat(100))).rejects.toThrow('State is not in a proper format');
75+
await expect(addressState.validate('%_ASD')).rejects.toThrow('State is not in a proper format');
76+
});
77+
78+
it('validates addressCity correctly', async () => {
79+
const { addressCity } = validations('id', false);
80+
81+
await expect(addressCity.validate('New York')).resolves.toBe('New York');
82+
await expect(addressCity.validate('')).rejects.toThrow('City is required');
83+
await expect(addressCity.validate('a'.repeat(100))).rejects.toThrow('Only 99 characters, please.');
84+
await expect(addressCity.validate('%_ASD')).rejects.toThrow(
85+
'Only letters, periods, hyphens, apostrophes, and spaces, please.'
86+
);
87+
});
88+
});

packages/account-v2/src/modules/AddressFields/validations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ const regexChecks = {
66
address_line_1: /^[\p{L}\p{Nd}\s'.,:;()\u00b0@#/-]{1,70}$/u,
77
address_line_2: /^[\p{L}\p{Nd}\s'.,:;()\u00b0@#/-]{0,70}$/u,
88
address_postcode: /^[a-zA-Z0-9\s-]{0,20}$/,
9-
address_state: /^[\w\s\W'.;,-]{0,99}$/,
9+
address_state: /^[\w\s'.;,-]{0,99}$/,
1010
non_jersey_postcode: /^(?!\s*je.*)[a-zA-Z0-9\s-]*/i,
1111
},
1212
};
1313

14-
const addressPermittedSpecialCharactersMessage = ". , ' : ; ( ) ° @ # / -";
14+
export const addressPermittedSpecialCharactersMessage = ". , ' : ; ( ) ° @ # / -";
1515

1616
export const addressDetailValidations = (countryCode: string, isSvg: boolean) => ({
1717
addressCity: Yup.string()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import useQuery from '../../useQuery';
3+
import useStatesList from '../useStatesList';
4+
5+
jest.mock('../../useQuery');
6+
7+
const mockUseQuery = useQuery as jest.MockedFunction<typeof useQuery<'states_list'>>;
8+
9+
describe('useStatesList', () => {
10+
it('should return an empty array when the store is not ready', () => {
11+
// @ts-expect-error need to come up with a way to mock the return type of useFetch
12+
mockUseQuery.mockReturnValue({
13+
data: {
14+
states_list: [],
15+
},
16+
});
17+
const { result } = renderHook(() => useStatesList('in'));
18+
19+
expect(result.current.data).toHaveLength(0);
20+
});
21+
22+
it('should return data fetched along with correct status', () => {
23+
// @ts-expect-error need to come up with a way to mock the return type of useFetch
24+
mockUseQuery.mockReturnValue({
25+
data: {
26+
states_list: [
27+
{ text: 'state 1', value: 's1' },
28+
{ text: 'state 2', value: 's2' },
29+
],
30+
},
31+
isFetched: true,
32+
});
33+
const { result } = renderHook(() => useStatesList('in'));
34+
expect(result.current.isFetched).toBeTruthy();
35+
});
36+
37+
it('should call the useQuery with options if passed', () => {
38+
renderHook(() => useStatesList('in', { enabled: false }));
39+
expect(mockUseQuery).toHaveBeenCalledWith('states_list', {
40+
payload: { states_list: 'in' },
41+
options: { enabled: false },
42+
});
43+
});
44+
});

packages/api/src/hooks/useStatesList.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const useStatesList = (country: TStatesList, options?: TSocketRequestQueryOption
1414
options,
1515
});
1616

17-
const modified_states_list = useMemo(() => [...(data?.states_list || [])], [data?.states_list]);
17+
const modified_states_list = useMemo(() => [...(data?.states_list ?? [])], [data?.states_list]);
1818

1919
return {
2020
/** The states list for the given country. */

0 commit comments

Comments
 (0)