@financial-times/n-conversion-forms 23.0.5 → 23.0.6
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/__mocks__/@financial-times/o-expander.js +9 -0
- package/__mocks__/@financial-times/o-forms-input.js +11 -0
- package/__mocks__/@financial-times/o-forms.js +40 -0
- package/build-state/npm-shrinkwrap.json +74 -167
- package/components/delivery-security-instructions.spec.js +3 -3
- package/components/graduation-date.spec.js +8 -8
- package/components/payment-term.spec.js +3 -3
- package/helpers/index.spec.js +11 -0
- package/helpers/ncf-common-data.spec.js +34 -0
- package/helpers/ncf-countries.spec.js +136 -0
- package/jest.config.js +3 -0
- package/package.json +2 -1
- package/utils/app-banner.spec.js +68 -0
- package/utils/apple-pay.spec.js +177 -0
- package/utils/billing-country.spec.js +87 -0
- package/utils/billing-postcode.spec.js +138 -0
- package/utils/company-name.spec.js +3 -7
- package/utils/country.spec.js +87 -0
- package/utils/delivery-address-type.spec.js +24 -11
- package/utils/delivery-option-messages.spec.js +3 -3
- package/utils/delivery-option.spec.js +100 -15
- package/utils/delivery-postcode.spec.js +138 -0
- package/utils/delivery-start-date.spec.js +177 -0
- package/utils/email.spec.js +210 -0
- package/utils/event-notifier.spec.js +116 -0
- package/utils/form-element.spec.js +71 -0
- package/utils/loader.spec.js +161 -0
- package/utils/password.spec.js +65 -0
- package/utils/payment-term.spec.js +198 -0
- package/utils/payment-type.spec.js +136 -0
- package/utils/postcode.spec.js +122 -0
- package/utils/salesforce.spec.js +30 -0
- package/utils/submit.spec.js +81 -0
- package/utils/tracking.spec.js +174 -0
- package/utils/validation.spec.js +234 -0
- package/utils/zuora.spec.js +249 -0
|
@@ -104,11 +104,11 @@ describe('DeliverySecurityInstructions', () => {
|
|
|
104
104
|
expect(textAreaProps.name).toBe('inputId');
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
it('
|
|
107
|
+
it('sets maxLength to 10', () => {
|
|
108
108
|
expect(textAreaProps.maxLength).toBe(10);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
it('
|
|
111
|
+
it('sets rows to 3', () => {
|
|
112
112
|
expect(textAreaProps.rows).toBe(3);
|
|
113
113
|
});
|
|
114
114
|
|
|
@@ -120,7 +120,7 @@ describe('DeliverySecurityInstructions', () => {
|
|
|
120
120
|
expect(textAreaProps.disabled).toBeTrue;
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
it('
|
|
123
|
+
it('sets value', () => {
|
|
124
124
|
expect(textAreaProps.defaultValue).toBe('value');
|
|
125
125
|
});
|
|
126
126
|
});
|
|
@@ -24,7 +24,7 @@ describe('GraduationDate', () => {
|
|
|
24
24
|
).toBe(true);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
it('
|
|
27
|
+
it('displays graduationDateMonth options as English month names', () => {
|
|
28
28
|
const wrapper = shallow(<GraduationDate />);
|
|
29
29
|
const values = wrapper
|
|
30
30
|
.find('#graduationDateMonth option')
|
|
@@ -45,7 +45,7 @@ describe('GraduationDate', () => {
|
|
|
45
45
|
]);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
it('
|
|
48
|
+
it('stores graduationDateMonth values as two-digit numbers', () => {
|
|
49
49
|
const wrapper = shallow(<GraduationDate />);
|
|
50
50
|
const values = wrapper
|
|
51
51
|
.find('#graduationDateMonth option')
|
|
@@ -85,13 +85,13 @@ describe('GraduationDate', () => {
|
|
|
85
85
|
describe('given a valid value prop is passed', () => {
|
|
86
86
|
const wrapper = shallow(<GraduationDate value="2020-08-28" />);
|
|
87
87
|
|
|
88
|
-
it('
|
|
88
|
+
it('sets the default month', () => {
|
|
89
89
|
expect(wrapper.find('#graduationDateMonth').prop('defaultValue')).toEqual(
|
|
90
90
|
'08'
|
|
91
91
|
);
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
it('
|
|
94
|
+
it('sets the default year', () => {
|
|
95
95
|
expect(wrapper.find('#graduationDateYear').prop('defaultValue')).toEqual(
|
|
96
96
|
'2020'
|
|
97
97
|
);
|
|
@@ -101,7 +101,7 @@ describe('GraduationDate', () => {
|
|
|
101
101
|
describe('given an invalid value prop is passed', () => {
|
|
102
102
|
const wrapper = shallow(<GraduationDate value="invalid" />);
|
|
103
103
|
|
|
104
|
-
it('
|
|
104
|
+
it('does not set any default values', () => {
|
|
105
105
|
expect(
|
|
106
106
|
wrapper.find('#graduationDateMonth').prop('defaultValue')
|
|
107
107
|
).toBeFalsy();
|
|
@@ -114,7 +114,7 @@ describe('GraduationDate', () => {
|
|
|
114
114
|
describe('given the isDisabled prop is set to true', () => {
|
|
115
115
|
const wrapper = shallow(<GraduationDate isDisabled={true} />);
|
|
116
116
|
|
|
117
|
-
it('
|
|
117
|
+
it('disables both select fields', () => {
|
|
118
118
|
expect(
|
|
119
119
|
wrapper.find('#graduationDateMonth').prop('disabled')
|
|
120
120
|
).toBeTruthy();
|
|
@@ -125,7 +125,7 @@ describe('GraduationDate', () => {
|
|
|
125
125
|
describe('given the isRequired prop is set to true', () => {
|
|
126
126
|
const wrapper = shallow(<GraduationDate isRequired={true} />);
|
|
127
127
|
|
|
128
|
-
it('
|
|
128
|
+
it('makes both fields required', () => {
|
|
129
129
|
expect(
|
|
130
130
|
wrapper.find('#graduationDateMonth').prop('required')
|
|
131
131
|
).toBeTruthy();
|
|
@@ -136,7 +136,7 @@ describe('GraduationDate', () => {
|
|
|
136
136
|
describe('given the hasError prop is set to true', () => {
|
|
137
137
|
const wrapper = shallow(<GraduationDate hasError={true} />);
|
|
138
138
|
|
|
139
|
-
it('
|
|
139
|
+
it('adds an invalid modifier class', () => {
|
|
140
140
|
expect(wrapper.find('div.o-forms-input').prop('className')).toMatch(
|
|
141
141
|
'o-forms-input--invalid'
|
|
142
142
|
);
|
|
@@ -134,19 +134,19 @@ describe('PaymentTerm', () => {
|
|
|
134
134
|
/>
|
|
135
135
|
);
|
|
136
136
|
|
|
137
|
-
it('
|
|
137
|
+
it('does not include renewal text', () => {
|
|
138
138
|
expect(
|
|
139
139
|
wrapper.find('.ncf__payment-term__renews-text').text()
|
|
140
140
|
).not.toMatch(/Renews (annually|monthly|quarterly) unless cancelled/);
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
-
it('
|
|
143
|
+
it('renders fixed term renewal text in English', () => {
|
|
144
144
|
expect(wrapper.find('.ncf__payment-term__renews-text').text()).toMatch(
|
|
145
145
|
/This subscription is for 3 months, charged monthly. You can cancel at anytime/
|
|
146
146
|
);
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
it('
|
|
149
|
+
it('renders offer name on payment term title', () => {
|
|
150
150
|
expect(wrapper.find('.ncf__payment-term__title').text()).toMatch(
|
|
151
151
|
'Mix & Match - Monthly'
|
|
152
152
|
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const helpers = require('.');
|
|
2
|
+
|
|
3
|
+
describe('helpers', () => {
|
|
4
|
+
it('exports a "ncf-common-data" helper', () => {
|
|
5
|
+
expect(helpers).toHaveProperty('ncf-common-data');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('exports a "ncf-countries" helper', () => {
|
|
9
|
+
expect(helpers).toHaveProperty('ncf-countries');
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const mockCommonModule = {
|
|
2
|
+
example: 'example',
|
|
3
|
+
another: 'sample',
|
|
4
|
+
nested: {
|
|
5
|
+
property: 'no-problem',
|
|
6
|
+
},
|
|
7
|
+
};
|
|
8
|
+
jest.mock('n-common-static-data', () => mockCommonModule);
|
|
9
|
+
const helper = require('./ncf-common-data');
|
|
10
|
+
|
|
11
|
+
describe('ncf-common-data', () => {
|
|
12
|
+
let stub;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
stub = jest.fn();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('imports and exports the properties as defined', () => {
|
|
19
|
+
const hash = { import: 'example', export: 'whatever' };
|
|
20
|
+
helper({ hash, fn: stub });
|
|
21
|
+
const context = stub.mock.calls[0][0];
|
|
22
|
+
expect(context).toHaveProperty(hash.export, mockCommonModule[hash.import]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('can import nested properties', () => {
|
|
26
|
+
const hash = { import: 'nested.property', export: 'whatever' };
|
|
27
|
+
helper({ hash, fn: stub });
|
|
28
|
+
const context = stub.mock.calls[0][0];
|
|
29
|
+
expect(context).toHaveProperty(
|
|
30
|
+
hash.export,
|
|
31
|
+
mockCommonModule.nested.property
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
let mockCountries = generateCountryArray(100, { includeAllFrequent: true });
|
|
2
|
+
jest.mock('n-common-static-data', () => {
|
|
3
|
+
return {
|
|
4
|
+
billingCountries: { countries: mockCountries },
|
|
5
|
+
};
|
|
6
|
+
});
|
|
7
|
+
jest.mock('n-common-static-data');
|
|
8
|
+
const helper = require('./ncf-countries');
|
|
9
|
+
|
|
10
|
+
describe('ncf-countries', () => {
|
|
11
|
+
let stub;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
stub = jest.fn();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('filter', () => {
|
|
22
|
+
it('does not filter if not present', () => {
|
|
23
|
+
helper({ hash: {}, fn: stub });
|
|
24
|
+
const context = stub.mock.calls[0][0];
|
|
25
|
+
|
|
26
|
+
expect(context.countries[1].countries).toEqual(mockCountries);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('does not filter if not an array', () => {
|
|
30
|
+
helper({ hash: { filterList: 'C-1' }, fn: stub });
|
|
31
|
+
const context = stub.mock.calls[0][0];
|
|
32
|
+
|
|
33
|
+
expect(context.countries[1].countries).toEqual(mockCountries);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('filters and return only countries in array', () => {
|
|
37
|
+
helper({ hash: { filterList: ['C-1'] }, fn: stub });
|
|
38
|
+
const context = stub.mock.calls[0][0];
|
|
39
|
+
|
|
40
|
+
expect(context.countries).toEqual([{ code: 'C-1' }]);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('select', () => {
|
|
45
|
+
it('does not mark any countries selected if no value passed', () => {
|
|
46
|
+
helper({ hash: {}, fn: stub });
|
|
47
|
+
const context = stub.mock.calls[0][0];
|
|
48
|
+
|
|
49
|
+
expect(
|
|
50
|
+
context.countries.find((country) => country.selected)
|
|
51
|
+
).not.toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('does not mark any countries selected if incorrect value passed', () => {
|
|
55
|
+
helper({ hash: { value: 'Test' }, fn: stub });
|
|
56
|
+
const context = stub.mock.calls[0][0];
|
|
57
|
+
|
|
58
|
+
expect(
|
|
59
|
+
context.countries.find((country) => country.selected)
|
|
60
|
+
).not.toBeDefined();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('marks a country as selected if value matches code', () => {
|
|
64
|
+
const value = 'C-2';
|
|
65
|
+
helper({ hash: { value }, fn: stub });
|
|
66
|
+
const context = stub.mock.calls[0][0];
|
|
67
|
+
|
|
68
|
+
expect(
|
|
69
|
+
context.countries[1].countries.find((country) => country.code === value)
|
|
70
|
+
).toBeDefined();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('group', () => {
|
|
75
|
+
it('does not group if frequently used countries under limit', () => {
|
|
76
|
+
helper({ hash: { filterList: ['CAN', 'FRA', 'JPN', 'USA'] }, fn: stub });
|
|
77
|
+
const context = stub.mock.calls[0][0];
|
|
78
|
+
|
|
79
|
+
expect(context.countries[0]).not.toHaveProperty('label');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('groups countries over limits', () => {
|
|
83
|
+
helper({ hash: {}, fn: stub });
|
|
84
|
+
const context = stub.mock.calls[0][0];
|
|
85
|
+
|
|
86
|
+
expect(context.countries[0]).toHaveProperty('label');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('sorts the group of frequently used countries', () => {
|
|
90
|
+
helper({ hash: {}, fn: stub });
|
|
91
|
+
const context = stub.mock.calls[0][0];
|
|
92
|
+
const correctOrder = ['GBR', 'USA', 'JPN', 'FRA', 'CAN'];
|
|
93
|
+
const frequentlyUsed = context.countries[0].countries;
|
|
94
|
+
|
|
95
|
+
frequentlyUsed.forEach((item, index) => {
|
|
96
|
+
expect(correctOrder[index]).toEqual(item.code);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('selects only one country if it exists in two places', () => {
|
|
101
|
+
const value = 'GBR';
|
|
102
|
+
helper({ hash: { value }, fn: stub });
|
|
103
|
+
const context = stub.mock.calls[0][0];
|
|
104
|
+
const frequentlyUsed = context.countries[0].countries;
|
|
105
|
+
const alphabetical = context.countries[1].countries;
|
|
106
|
+
|
|
107
|
+
expect(frequentlyUsed.find((item) => item.code === value)).toEqual(
|
|
108
|
+
expect.objectContaining({
|
|
109
|
+
selected: true,
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
expect(alphabetical.find((item) => item.code === value)).toEqual(
|
|
113
|
+
expect.objectContaining({
|
|
114
|
+
selected: false,
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
function generateCountryArray (length, { includeAllFrequent = true } = {}) {
|
|
122
|
+
return Array.from(Array(length), (item, index) => ({
|
|
123
|
+
code: `C-${index}`,
|
|
124
|
+
})).concat(
|
|
125
|
+
// prettier-ignore
|
|
126
|
+
includeAllFrequent
|
|
127
|
+
? [
|
|
128
|
+
{ code: 'JPN' },
|
|
129
|
+
{ code: 'FRA' },
|
|
130
|
+
{ code: 'USA' },
|
|
131
|
+
{ code: 'CAN' },
|
|
132
|
+
{ code: 'GBR' },
|
|
133
|
+
]
|
|
134
|
+
: []
|
|
135
|
+
);
|
|
136
|
+
}
|
package/jest.config.js
CHANGED
|
@@ -9,8 +9,11 @@ module.exports = {
|
|
|
9
9
|
},
|
|
10
10
|
testMatch: [
|
|
11
11
|
'**/components/**/?(*.)+(spec|test).[tj]s?(x)',
|
|
12
|
+
'**/helpers/**/?(*.)+(spec|test).[tj]s?(x)',
|
|
12
13
|
'**/utils/**/?(*.)+(spec|test).[tj]s?(x)',
|
|
13
14
|
],
|
|
14
15
|
snapshotSerializers: ['jest-serializer-html'],
|
|
15
16
|
setupFilesAfterEnv: ['<rootDir>/test-jest/helpers/setup.js'],
|
|
17
|
+
resolver: '@financial-times/jest-browser-resolver',
|
|
18
|
+
transformIgnorePatterns: ['/node_modules//(?!(@financial-times)/)'],
|
|
16
19
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/n-conversion-forms",
|
|
3
|
-
"version": "23.0.
|
|
3
|
+
"version": "23.0.6",
|
|
4
4
|
"description": "Containing jsx components and styles for forms included on Accounts and Acqusition apps (next-signup, next-profile, next-retention, etc).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@babel/preset-env": "^7.11.0",
|
|
39
39
|
"@babel/preset-react": "^7.10.4",
|
|
40
40
|
"@financial-times/eslint-config-next": "^3.0.0",
|
|
41
|
+
"@financial-times/jest-browser-resolver": "^1.0.2",
|
|
41
42
|
"@financial-times/n-gage": "^8.2.0",
|
|
42
43
|
"@storybook/addon-a11y": "^6.0.10",
|
|
43
44
|
"@storybook/addon-essentials": "6.0.10",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const AppBanner = require('./app-banner');
|
|
2
|
+
|
|
3
|
+
describe('Apple Pay', () => {
|
|
4
|
+
let window;
|
|
5
|
+
let element;
|
|
6
|
+
let iosAction;
|
|
7
|
+
let androidAction;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
iosAction = { remove: jest.fn() };
|
|
11
|
+
androidAction = { remove: jest.fn() };
|
|
12
|
+
const classNameMap = {
|
|
13
|
+
'.ncf__app-banner-action--android': androidAction,
|
|
14
|
+
'.ncf__app-banner-action--ios': iosAction,
|
|
15
|
+
};
|
|
16
|
+
element = {
|
|
17
|
+
querySelector: jest.fn((className) => {
|
|
18
|
+
return classNameMap[className];
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
window = {
|
|
22
|
+
document: { querySelector: jest.fn(() => element) },
|
|
23
|
+
navigator: { userAgent: '' },
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('constructor', () => {
|
|
32
|
+
it('throws an error if window not provided', () => {
|
|
33
|
+
expect(() => {
|
|
34
|
+
new AppBanner();
|
|
35
|
+
}).toThrow();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('throws an error if banner not found', () => {
|
|
39
|
+
window.document.querySelector = jest.fn(() => false);
|
|
40
|
+
expect(() => {
|
|
41
|
+
new AppBanner(window);
|
|
42
|
+
}).toThrow();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('does not remove any actions if the user agent is not sniffed', () => {
|
|
46
|
+
new AppBanner(window);
|
|
47
|
+
|
|
48
|
+
expect(iosAction.remove).not.toHaveBeenCalled();
|
|
49
|
+
expect(androidAction.remove).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('removes ios action if the user agent is android', () => {
|
|
53
|
+
window.navigator.userAgent = 'android';
|
|
54
|
+
new AppBanner(window);
|
|
55
|
+
|
|
56
|
+
expect(iosAction.remove).toHaveBeenCalled();
|
|
57
|
+
expect(androidAction.remove).not.toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('removes android action if the user agent is ios', () => {
|
|
61
|
+
window.navigator.userAgent = 'iphone';
|
|
62
|
+
new AppBanner(window);
|
|
63
|
+
|
|
64
|
+
expect(iosAction.remove).not.toHaveBeenCalled();
|
|
65
|
+
expect(androidAction.remove).toHaveBeenCalled();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const ApplePay = require('./apple-pay');
|
|
2
|
+
|
|
3
|
+
describe('Apple Pay', () => {
|
|
4
|
+
let request;
|
|
5
|
+
let window;
|
|
6
|
+
let event;
|
|
7
|
+
let applePay;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
request = { canMakePayment: function () {}, show: function () {} };
|
|
11
|
+
window = {
|
|
12
|
+
PaymentRequest: function () {
|
|
13
|
+
return request;
|
|
14
|
+
},
|
|
15
|
+
fetch: function () {
|
|
16
|
+
return Promise.resolve({ json: function () {} });
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
event = { complete: function () {} };
|
|
20
|
+
|
|
21
|
+
jest.spyOn(request, 'canMakePayment');
|
|
22
|
+
jest.spyOn(request, 'show');
|
|
23
|
+
jest.spyOn(window, 'PaymentRequest');
|
|
24
|
+
jest.spyOn(window, 'fetch');
|
|
25
|
+
jest.spyOn(event, 'complete');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
jest.clearAllMocks();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('public methods', () => {
|
|
33
|
+
describe('constructor', () => {
|
|
34
|
+
it('throws an error if PaymentRequest not available', () => {
|
|
35
|
+
window.PaymentRequest = null;
|
|
36
|
+
expect(() => {
|
|
37
|
+
new ApplePay(window);
|
|
38
|
+
}).toThrow();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('creates the PaymentRequest with the defaults', () => {
|
|
42
|
+
new ApplePay(window);
|
|
43
|
+
expect(window.PaymentRequest).toHaveBeenCalledWith(
|
|
44
|
+
ApplePay.PAYMENT_METHODS,
|
|
45
|
+
ApplePay.PAYMENT_DETAILS,
|
|
46
|
+
ApplePay.PAYMENT_OPTIONS
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('canMakePayment', () => {
|
|
52
|
+
it('proxies canMakePayment to the request', () => {
|
|
53
|
+
applePay = new ApplePay(window);
|
|
54
|
+
applePay.canMakePayment();
|
|
55
|
+
expect(request.canMakePayment).toHaveBeenCalled();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('show', () => {
|
|
60
|
+
it('proxies show to the request', () => {
|
|
61
|
+
applePay = new ApplePay(window);
|
|
62
|
+
applePay.show();
|
|
63
|
+
expect(request.show).toHaveBeenCalled();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('does not create new request if no details passed', () => {
|
|
67
|
+
applePay = new ApplePay(window);
|
|
68
|
+
applePay.show();
|
|
69
|
+
expect(window.PaymentRequest).toHaveBeenCalledTimes(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('creates new request if new details passed', () => {
|
|
73
|
+
applePay = new ApplePay(window);
|
|
74
|
+
applePay.show({ total: { label: 'new' } });
|
|
75
|
+
expect(window.PaymentRequest).toHaveBeenCalledTimes(2);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('creates new request with right parameters', () => {
|
|
79
|
+
applePay = new ApplePay(window);
|
|
80
|
+
applePay.show({ total: { label: 'new' } });
|
|
81
|
+
expect(window.PaymentRequest).toHaveBeenCalledWith(
|
|
82
|
+
applePay.methods,
|
|
83
|
+
applePay.details,
|
|
84
|
+
applePay.options
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('setup onmerchantvalidation method', () => {
|
|
89
|
+
delete request.onmerchantvalidation;
|
|
90
|
+
applePay = new ApplePay(window);
|
|
91
|
+
applePay.show();
|
|
92
|
+
expect(request.onmerchantvalidation).toBeInstanceOf(Function);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('handleMerchantValidation', () => {
|
|
97
|
+
it('uses the production merchant validation URL by default', () => {
|
|
98
|
+
applePay = new ApplePay(window);
|
|
99
|
+
applePay.handleMerchantValidation(event);
|
|
100
|
+
expect(window.fetch).toHaveBeenCalledWith(
|
|
101
|
+
ApplePay.MERCHANT_VALIDATION_URL,
|
|
102
|
+
expect.anything()
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('uses the test merchant validation URL', () => {
|
|
107
|
+
applePay = new ApplePay(window, ApplePay.TEST_PAYMENT_METHODS);
|
|
108
|
+
applePay.handleMerchantValidation(event);
|
|
109
|
+
expect(window.fetch).toHaveBeenCalledWith(
|
|
110
|
+
ApplePay.TEST_MERCHANT_VALIDATION_URL,
|
|
111
|
+
expect.anything()
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('calls event.complete with response', async () => {
|
|
116
|
+
applePay = new ApplePay(window);
|
|
117
|
+
await applePay.handleMerchantValidation(event);
|
|
118
|
+
expect(event.complete).toHaveBeenCalled();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('static methods', () => {
|
|
124
|
+
describe('getMerchantId', () => {
|
|
125
|
+
it('returns default merchant id', () => {
|
|
126
|
+
expect(ApplePay.getMerchantId()).toEqual(expect.any(String));
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('returns default merchant id if methods has no data', () => {
|
|
130
|
+
const methods = [{}];
|
|
131
|
+
expect(ApplePay.getMerchantId(methods)).toEqual(expect.any(String));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('returns default merchant id if methods data has not got one', () => {
|
|
135
|
+
const methods = [{ data: {} }];
|
|
136
|
+
expect(ApplePay.getMerchantId(methods)).toEqual(expect.any(String));
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('returns merchant id from methods data', () => {
|
|
140
|
+
const methods = [{ data: { merchantIdentifier: 'test' } }];
|
|
141
|
+
expect(ApplePay.getMerchantId(methods)).toEqual('test');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('getMerchantValidationUrl', () => {
|
|
146
|
+
it('returns production merchant validation url', () => {
|
|
147
|
+
expect(ApplePay.getMerchantValidationUrl(ApplePay.MERCHANT_ID)).toEqual(
|
|
148
|
+
ApplePay.MERCHANT_VALIDATION_URL
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('returns a differnt merchant validation url for test merchant', () => {
|
|
153
|
+
expect(
|
|
154
|
+
ApplePay.getMerchantValidationUrl(ApplePay.TEST_MERCHANT_ID)
|
|
155
|
+
).toEqual(ApplePay.TEST_MERCHANT_VALIDATION_URL);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('defaults to the production merchant validation url', () => {
|
|
159
|
+
expect(ApplePay.getMerchantValidationUrl()).toEqual(
|
|
160
|
+
ApplePay.MERCHANT_VALIDATION_URL
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('getPaymentDetails', () => {
|
|
166
|
+
it('formats given values in payment details object', () => {
|
|
167
|
+
const label = 'test';
|
|
168
|
+
const value = 1.01;
|
|
169
|
+
const currency = 'GBP';
|
|
170
|
+
const details = ApplePay.getPaymentDetails(value, currency, label);
|
|
171
|
+
|
|
172
|
+
expect(details.total.label).toEqual(label);
|
|
173
|
+
expect(details.total.amount).toEqual({ value, currency });
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const BillingCountry = require('./billing-country');
|
|
2
|
+
|
|
3
|
+
describe('BillingCountry', () => {
|
|
4
|
+
let billingCountry;
|
|
5
|
+
let documentStub;
|
|
6
|
+
let elementStub;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
elementStub = {
|
|
10
|
+
addEventListener: jest.fn(),
|
|
11
|
+
selectedIndex: 1,
|
|
12
|
+
options: [{ value: 0 }, { value: 1 }, { value: 2 }],
|
|
13
|
+
};
|
|
14
|
+
documentStub = {
|
|
15
|
+
querySelector: jest.fn(),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
jest.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('constructor', () => {
|
|
24
|
+
it('throws an error if nothing passed', () => {
|
|
25
|
+
expect(() => {
|
|
26
|
+
new BillingCountry();
|
|
27
|
+
}).toThrow();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('throws an error if field not present', () => {
|
|
31
|
+
expect(() => {
|
|
32
|
+
documentStub.querySelector.mockReturnValue(false);
|
|
33
|
+
new BillingCountry(documentStub);
|
|
34
|
+
}).toThrow();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('constructed', () => {
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
documentStub.querySelector.mockReturnValue(elementStub);
|
|
41
|
+
billingCountry = new BillingCountry(documentStub);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('onChange', () => {
|
|
45
|
+
it('adds an event listener on change', () => {
|
|
46
|
+
billingCountry.onChange();
|
|
47
|
+
expect(elementStub.addEventListener).toHaveBeenCalledWith(
|
|
48
|
+
'change',
|
|
49
|
+
expect.anything()
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('calls the callback', () => {
|
|
54
|
+
const callback = jest.fn();
|
|
55
|
+
elementStub.addEventListener = (type, callback) => callback();
|
|
56
|
+
billingCountry.onChange(callback);
|
|
57
|
+
expect(callback).toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('getSelected', () => {
|
|
62
|
+
it('throws an error if nothing selected', () => {
|
|
63
|
+
elementStub.options = [];
|
|
64
|
+
elementStub.selectedIndex = 0;
|
|
65
|
+
expect(() => {
|
|
66
|
+
billingCountry.getSelected();
|
|
67
|
+
}).toThrow();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('throws an error if something selected that is not there', () => {
|
|
71
|
+
elementStub.selectedIndex = 4;
|
|
72
|
+
expect(() => {
|
|
73
|
+
billingCountry.getSelected();
|
|
74
|
+
}).toThrow();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('returns the selected option', () => {
|
|
78
|
+
expect(billingCountry.getSelected()).toBe(1);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('returns the changed selected option', () => {
|
|
82
|
+
elementStub.selectedIndex = 0;
|
|
83
|
+
expect(billingCountry.getSelected()).toBe(0);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|