@rebilly/instruments 3.29.2 → 3.30.0
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/CHANGELOG.md +14 -0
- package/dist/index.js +19 -11
- package/dist/index.min.js +19 -11
- package/package.json +4 -2
- package/src/data/options-schema/index.js +93 -0
- package/src/data/options-schema/schemas/options-schema.js +425 -0
- package/src/functions/mount/setup-options.js +56 -151
- package/src/functions/mount/setup-options.spec.js +287 -94
- package/src/functions/update.js +1 -25
- package/src/functions/update.spec.js +1 -0
- package/src/instance.spec.js +5 -1
- package/src/style/base/__snapshots__/theme.spec.js.snap +1 -1
- package/tests/mocks/rebilly-instruments-mock.js +19 -10
|
@@ -1,120 +1,48 @@
|
|
|
1
|
-
import merge from 'lodash.merge';
|
|
2
1
|
import decodeJwt from 'jwt-decode';
|
|
2
|
+
import merge from 'lodash.merge';
|
|
3
3
|
import { parseQuantity } from '../../utils/quantity';
|
|
4
|
+
import { validateOptions } from '../../data/options-schema';
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
addons: [],
|
|
12
|
-
bumpOffer: [],
|
|
13
|
-
paymentInstruments: {
|
|
14
|
-
address: {
|
|
15
|
-
name: 'default',
|
|
16
|
-
region: 'default',
|
|
17
|
-
hide: [],
|
|
18
|
-
show: [],
|
|
19
|
-
require: []
|
|
20
|
-
},
|
|
21
|
-
compactExpressInstruments: false,
|
|
22
|
-
googlePay: {
|
|
23
|
-
displayOptions: {
|
|
24
|
-
buttonColor: 'black',
|
|
25
|
-
buttonType: 'plain',
|
|
26
|
-
buttonHeight: '48px'
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
applePay: {
|
|
30
|
-
displayOptions: {
|
|
31
|
-
buttonColor: 'black',
|
|
32
|
-
buttonType: 'plain',
|
|
33
|
-
buttonHeight: '48px'
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
paymentCard: {
|
|
37
|
-
popup: false
|
|
38
|
-
},
|
|
39
|
-
paypal: {
|
|
40
|
-
buttonHeight: 48,
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
transactionType: 'purchase',
|
|
44
|
-
features: {
|
|
45
|
-
autoConfirmation: true,
|
|
46
|
-
autoResult: true,
|
|
47
|
-
showCoupons: null,
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export function sanitizeOptions(options) {
|
|
52
|
-
// TODO: Additional sanitization
|
|
53
|
-
|
|
54
|
-
// cast options to be only json object
|
|
55
|
-
return JSON.parse(
|
|
56
|
-
JSON.stringify(options)
|
|
57
|
-
)
|
|
6
|
+
export function handleComputedProperty(options) {
|
|
7
|
+
const _computed = {
|
|
8
|
+
paymentMethodsUrl: options._dev?.paymentMethodsUrl ?? 'https://forms.secure-payments.app'
|
|
9
|
+
};
|
|
10
|
+
options._computed = _computed;
|
|
11
|
+
return options
|
|
58
12
|
}
|
|
59
13
|
|
|
60
|
-
export function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
14
|
+
export function handleNestedPropertiesDefaultValues(options) {
|
|
15
|
+
/*
|
|
16
|
+
The JSON Schema default property doesn't work on nested schemas.
|
|
17
|
+
So we'll need to handle the default properties in these instances.
|
|
18
|
+
In most cases default property in schema is sufficient.
|
|
19
|
+
|
|
20
|
+
see https://ajv.js.org/guide/modifying-data.html#assigning-defaults
|
|
21
|
+
*/
|
|
22
|
+
if (options.deposit?.currency) {
|
|
23
|
+
options.deposit = merge({
|
|
24
|
+
editable: true,
|
|
25
|
+
buttons: [],
|
|
26
|
+
customAmount: {
|
|
27
|
+
minimum: 1,
|
|
28
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
29
|
+
increment: 1,
|
|
30
|
+
}
|
|
31
|
+
}, (options.deposit || {}));
|
|
71
32
|
}
|
|
72
33
|
|
|
73
|
-
if (
|
|
74
|
-
|
|
34
|
+
if (options.items) {
|
|
35
|
+
options.items = options.items.map(item => ({
|
|
36
|
+
...item,
|
|
37
|
+
quantity: parseQuantity(item)
|
|
38
|
+
}));
|
|
75
39
|
}
|
|
76
40
|
|
|
77
|
-
|
|
78
|
-
throw new Error('Must provide a jwt');
|
|
79
|
-
}
|
|
41
|
+
return options;
|
|
80
42
|
}
|
|
81
43
|
|
|
82
|
-
export
|
|
83
|
-
options
|
|
84
|
-
} = {}) => {
|
|
85
|
-
const sanitizedOptions = sanitizeOptions(options);
|
|
86
|
-
|
|
87
|
-
validateOptions(sanitizedOptions);
|
|
88
|
-
|
|
89
|
-
const _computed = {
|
|
90
|
-
paymentMethodsUrl: sanitizedOptions._dev
|
|
91
|
-
? sanitizedOptions._dev.paymentMethodsUrl || 'https://forms.local.rebilly.dev:3000'
|
|
92
|
-
: 'https://forms.secure-payments.app'
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const combinedOptions = merge({ ...defaults }, {
|
|
96
|
-
apiMode: sanitizedOptions.apiMode,
|
|
97
|
-
i18n: sanitizedOptions.i18n,
|
|
98
|
-
theme: sanitizedOptions.theme,
|
|
99
|
-
css: sanitizedOptions.css,
|
|
100
|
-
locale: sanitizedOptions.locale,
|
|
101
|
-
countryCode: sanitizedOptions.countryCode,
|
|
102
|
-
features: sanitizedOptions.features,
|
|
103
|
-
paymentInstruments: sanitizedOptions.paymentInstruments,
|
|
104
|
-
transactionType: sanitizedOptions.transactionType,
|
|
105
|
-
_computed
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
if (sanitizedOptions.publishableKey) {
|
|
109
|
-
Object.entries({
|
|
110
|
-
organizationId: sanitizedOptions.organizationId,
|
|
111
|
-
publishableKey: sanitizedOptions.publishableKey,
|
|
112
|
-
websiteId: sanitizedOptions.websiteId,
|
|
113
|
-
}).forEach(([key, value]) => {
|
|
114
|
-
combinedOptions[key] = value;
|
|
115
|
-
});
|
|
116
|
-
} else if (sanitizedOptions.jwt) {
|
|
117
|
-
combinedOptions.jwt = sanitizedOptions.jwt;
|
|
44
|
+
export function handleJwtDestructuring(options) {
|
|
45
|
+
if (options.jwt && !options.publishableKey) {
|
|
118
46
|
const {
|
|
119
47
|
merchant: organizationId,
|
|
120
48
|
claims: {
|
|
@@ -122,53 +50,30 @@ export default ({
|
|
|
122
50
|
invoiceId,
|
|
123
51
|
websiteId,
|
|
124
52
|
}
|
|
125
|
-
} = decodeJwt(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (websiteId) {
|
|
138
|
-
combinedOptions.websiteId = websiteId;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (options.items) {
|
|
143
|
-
combinedOptions.items = options.items.map(item => ({
|
|
144
|
-
...item,
|
|
145
|
-
quantity: parseQuantity(item)
|
|
146
|
-
}));
|
|
53
|
+
} = decodeJwt(options.jwt);
|
|
54
|
+
Object.entries({
|
|
55
|
+
organizationId,
|
|
56
|
+
transactionId,
|
|
57
|
+
invoiceId,
|
|
58
|
+
websiteId
|
|
59
|
+
}).forEach(([key, value]) => {
|
|
60
|
+
if (Boolean(value)) {
|
|
61
|
+
options[key] = value;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
147
64
|
}
|
|
148
|
-
|
|
149
|
-
// Add optional key's
|
|
150
|
-
[
|
|
151
|
-
'money',
|
|
152
|
-
'invoiceId',
|
|
153
|
-
'transactionId',
|
|
154
|
-
'jwt',
|
|
155
|
-
'_dev'
|
|
156
|
-
].forEach(key => {
|
|
157
|
-
if (options[key]) {
|
|
158
|
-
combinedOptions[key] = options[key];
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
65
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (options.addons) {
|
|
165
|
-
combinedOptions.addons = options.addons;
|
|
166
|
-
}
|
|
66
|
+
return options;
|
|
67
|
+
}
|
|
167
68
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
69
|
+
export default ({
|
|
70
|
+
options = {}
|
|
71
|
+
} = {}) => {
|
|
72
|
+
let validOptions = validateOptions(options);
|
|
73
|
+
if (validOptions) {
|
|
74
|
+
validOptions = handleComputedProperty(validOptions);
|
|
75
|
+
validOptions = handleNestedPropertiesDefaultValues(validOptions);
|
|
76
|
+
validOptions = handleJwtDestructuring(validOptions);
|
|
171
77
|
}
|
|
172
|
-
|
|
173
|
-
return combinedOptions;
|
|
78
|
+
return validOptions;
|
|
174
79
|
}
|
|
@@ -1,124 +1,317 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import setupOptions, {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { RebillyInstrumentsConfigError } from '../../data/options-schema';
|
|
2
|
+
import setupOptions, {
|
|
3
|
+
handleComputedProperty,
|
|
4
|
+
handleNestedPropertiesDefaultValues,
|
|
5
|
+
handleJwtDestructuring
|
|
6
|
+
} from './setup-options';
|
|
7
|
+
|
|
8
|
+
describe('Setup options function', () => {
|
|
9
|
+
it('should throw error when options are invalid', () => {
|
|
10
|
+
jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
11
|
+
|
|
12
|
+
expect(() => setupOptions()).toThrow(RebillyInstrumentsConfigError);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it ('should expect only one purchase data', () => {
|
|
16
|
+
const errorLogs = [];
|
|
17
|
+
jest.spyOn(console, 'error').mockImplementation((error) => {
|
|
18
|
+
if (typeof error === 'object') {
|
|
19
|
+
errorLogs.push(error.message);
|
|
14
20
|
}
|
|
15
21
|
});
|
|
16
|
-
|
|
22
|
+
|
|
23
|
+
const options = {
|
|
24
|
+
apiMode: 'sandbox',
|
|
25
|
+
items: [{
|
|
26
|
+
planId: 'plan_TEST',
|
|
27
|
+
quantity: 1
|
|
28
|
+
}],
|
|
29
|
+
money: {
|
|
30
|
+
amount: 1.99,
|
|
31
|
+
currency: 'USD'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
expect(() => setupOptions({options})).toThrow(RebillyInstrumentsConfigError);
|
|
35
|
+
expect(errorLogs.length).toEqual(1);
|
|
36
|
+
expect(errorLogs[0]).toEqual('options must match exactly one schema in oneOf, see schemas below.');
|
|
17
37
|
});
|
|
18
38
|
|
|
19
|
-
it(
|
|
39
|
+
it.only('should validate and inject default values', () => {
|
|
40
|
+
const testJwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfVEVTVC1BIiwiZXhwIjoxNzE0ODQwNDg5LCJpYXQiOjE2ODMyMTY1ODkuNTYwMjU2LCJhY2wiOlt7InNjb3BlIjp7Im9yZ2FuaXphdGlvbklkIjpbIm9yZ19URVNULUEiXSwiaW52b2ljZUlkIjpbImluX1RFU1QtQSJdLCJjdXN0b21GaWVsZE5hbWUiOlsiU0lOTGFzdDQiXX0sInBlcm1pc3Npb25zIjpbMjg0LDI4Niw0MTQsNDE1LDQzNCw0MTIsNDI0LDQyNSw0MjYsNDI3LDQyOCw0MjksNDA5LDQxMCw0MDEsNDAyLDQzMyw0MzFdfV0sImNsYWltcyI6eyJ3ZWJzaXRlSWQiOiJ3ZWJfVEVTVC1BIiwiaW52b2ljZUlkIjoiaW5fVEVTVC1BIiwicGF5bWVudE1ldGhvZHMiOltdfSwibWVyY2hhbnQiOiJNRVJDSEFOVC1URVNULUlELUEiLCJjdXN0b21lciI6eyJpZCI6ImN1c19URVNULUEiLCJuYW1lIjoiQ2FyZCBIb2xkZXIgTmFtZSIsImNyZWF0ZWRUaW1lIjoiMjAyMi0wOS0yMVQxODo1MDoyMiswMDowMCJ9fQ.tm33uioGUSpEedHeYufDGm-p1YW40eufNovppcU6-xg';
|
|
20
41
|
const options = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
42
|
+
jwt: testJwt,
|
|
43
|
+
apiMode: 'sandbox',
|
|
44
|
+
items: [{
|
|
45
|
+
planId: 'plan_TEST',
|
|
46
|
+
quantity: {},
|
|
47
|
+
}]
|
|
25
48
|
}
|
|
26
|
-
|
|
27
|
-
|
|
49
|
+
|
|
50
|
+
const results = setupOptions({options});
|
|
51
|
+
|
|
52
|
+
expect(results).toEqual({
|
|
53
|
+
jwt: testJwt,
|
|
54
|
+
apiMode: 'sandbox',
|
|
55
|
+
items: [{
|
|
56
|
+
planId: 'plan_TEST',
|
|
57
|
+
quantity: {
|
|
58
|
+
minimum: 1,
|
|
59
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
60
|
+
multipleOf: 1
|
|
61
|
+
}
|
|
62
|
+
}],
|
|
63
|
+
form: '.rebilly-instruments',
|
|
64
|
+
summary: '.rebilly-instruments-summary',
|
|
65
|
+
addons: [],
|
|
66
|
+
bumpOffer: [],
|
|
67
|
+
transactionType: 'purchase',
|
|
68
|
+
theme: { labels: 'stacked' },
|
|
69
|
+
countryCode: 'US',
|
|
70
|
+
locale: 'auto',
|
|
71
|
+
paymentInstruments: {
|
|
72
|
+
compactExpressInstruments: false,
|
|
73
|
+
address: {
|
|
74
|
+
name: 'default',
|
|
75
|
+
region: 'default',
|
|
76
|
+
show: [],
|
|
77
|
+
hide: [],
|
|
78
|
+
require: []
|
|
79
|
+
},
|
|
80
|
+
paypal: { buttonHeight: 48 },
|
|
81
|
+
googlePay: {
|
|
82
|
+
displayOptions: {
|
|
83
|
+
buttonColor: 'black',
|
|
84
|
+
buttonHeight: '48px',
|
|
85
|
+
buttonType: 'plain'
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
applePay: {
|
|
89
|
+
displayOptions: {
|
|
90
|
+
buttonColor: 'black',
|
|
91
|
+
buttonHeight: '48px',
|
|
92
|
+
buttonType: 'plain'
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
paymentCard: { popup: false }
|
|
96
|
+
},
|
|
97
|
+
features: { autoConfirmation: true, autoResult: true },
|
|
98
|
+
_computed: { paymentMethodsUrl: 'https://forms.secure-payments.app' },
|
|
99
|
+
organizationId: 'MERCHANT-TEST-ID-A',
|
|
100
|
+
invoiceId: 'in_TEST-A',
|
|
101
|
+
websiteId: 'web_TEST-A'
|
|
102
|
+
});
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
describe ('should throw error for missing purchase data', () => {
|
|
106
|
+
const errorLogs = [];
|
|
107
|
+
jest.spyOn(console, 'error').mockImplementation((error) => {
|
|
108
|
+
if (typeof error === 'string') {
|
|
109
|
+
errorLogs.push(error);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(() => setupOptions()).toThrow(RebillyInstrumentsConfigError);
|
|
114
|
+
expect(errorLogs.length).toEqual(6);
|
|
115
|
+
const expectedResults = [
|
|
116
|
+
'items',
|
|
117
|
+
'money',
|
|
118
|
+
'invoiceId',
|
|
119
|
+
'transactionId',
|
|
120
|
+
'deposit',
|
|
121
|
+
'jwt'
|
|
122
|
+
]
|
|
123
|
+
expectedResults.forEach(result => {
|
|
124
|
+
it (`should expect required oneOf ${result}`, () => {
|
|
125
|
+
expect(errorLogs.some((error) => {
|
|
126
|
+
return (error.includes('required') && error.includes(result));
|
|
127
|
+
})).toEqual(true);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('should ensure purchase data has dependant properties', () => {
|
|
133
|
+
let errorLogs = [];
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
errorLogs = [];
|
|
136
|
+
jest.spyOn(console, 'error').mockImplementation((error) => {
|
|
137
|
+
if (typeof error === 'object') {
|
|
138
|
+
errorLogs.push(error.message);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const expectJwtTests = [
|
|
144
|
+
{
|
|
145
|
+
invoiceId: 'in_TEST'
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
transactionId: 'txn_TEST'
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
deposit: {
|
|
152
|
+
depositRequestId: 'cash_req_TEST'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
expectJwtTests.forEach(test => {
|
|
158
|
+
const key = Object.keys(test)[0];
|
|
159
|
+
it(`should expect jwt with ${key}`, () => {
|
|
160
|
+
const options = {
|
|
161
|
+
apiMode: 'sandbox',
|
|
162
|
+
...test
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
expect(() => setupOptions({options})).toThrow(RebillyInstrumentsConfigError);
|
|
166
|
+
expect(errorLogs.length).toEqual(1);
|
|
167
|
+
expect(errorLogs[0]).toEqual(`options must have property jwt when property ${key} is present`);
|
|
168
|
+
})
|
|
169
|
+
});
|
|
28
170
|
});
|
|
29
171
|
});
|
|
30
172
|
|
|
31
|
-
describe('
|
|
32
|
-
it(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
173
|
+
describe('Setup options handleComputedProperty function', () => {
|
|
174
|
+
it('should populate options with instrument methods url', () => {
|
|
175
|
+
const options = {}
|
|
176
|
+
const result = handleComputedProperty(options);
|
|
177
|
+
|
|
178
|
+
expect(result).toEqual({
|
|
179
|
+
_computed: { paymentMethodsUrl: 'https://forms.secure-payments.app' }
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should set paymentMethodsUrl from _dev configuration', () => {
|
|
184
|
+
const options = {
|
|
185
|
+
_dev: {
|
|
186
|
+
paymentMethodsUrl: 'https://www.example.com'
|
|
187
|
+
}
|
|
39
188
|
}
|
|
40
|
-
|
|
189
|
+
const result = handleComputedProperty(options);
|
|
190
|
+
|
|
191
|
+
expect(result._computed.paymentMethodsUrl).toEqual('https://www.example.com');
|
|
41
192
|
});
|
|
42
193
|
|
|
43
|
-
it(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const options = {
|
|
47
|
-
invoiceId: "test-invoice-id",
|
|
48
|
-
items: [{
|
|
49
|
-
planId: "test-plan-id",
|
|
50
|
-
quantity: 1
|
|
51
|
-
}]
|
|
52
|
-
};
|
|
53
|
-
validateOptions(options);
|
|
54
|
-
} catch (e) {
|
|
55
|
-
error = e;
|
|
194
|
+
it('should default paymentMethodsUrl from empty _dev configuration', () => {
|
|
195
|
+
const options = {
|
|
196
|
+
_dev: {}
|
|
56
197
|
}
|
|
57
|
-
|
|
198
|
+
const result = handleComputedProperty(options);
|
|
199
|
+
|
|
200
|
+
expect(result._computed.paymentMethodsUrl).toEqual('https://forms.secure-payments.app');
|
|
58
201
|
});
|
|
59
202
|
});
|
|
60
203
|
|
|
61
|
-
describe('
|
|
62
|
-
it('should
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
204
|
+
describe('Setup options handleNestedPropertiesDefaultValues function', () => {
|
|
205
|
+
it('should add defaults for deposits with currency configuration', () => {
|
|
206
|
+
const options = {
|
|
207
|
+
deposit: {
|
|
208
|
+
currency: 'USD',
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const result = handleNestedPropertiesDefaultValues(options);
|
|
213
|
+
|
|
214
|
+
expect(result).toEqual({
|
|
215
|
+
deposit: {
|
|
216
|
+
editable: true,
|
|
217
|
+
buttons: [],
|
|
218
|
+
customAmount: {
|
|
219
|
+
minimum: 1,
|
|
220
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
221
|
+
increment: 1,
|
|
222
|
+
},
|
|
223
|
+
currency: 'USD'
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should not inject defaults to deposit without currency', () => {
|
|
229
|
+
const options = {
|
|
230
|
+
deposit: {
|
|
231
|
+
depositRequestId: 'cash_req_TEST'
|
|
71
232
|
}
|
|
72
233
|
}
|
|
73
234
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
235
|
+
const result = handleNestedPropertiesDefaultValues(options);
|
|
236
|
+
expect(result).toEqual({
|
|
237
|
+
deposit: {
|
|
238
|
+
depositRequestId: 'cash_req_TEST'
|
|
239
|
+
}
|
|
240
|
+
});
|
|
77
241
|
});
|
|
78
242
|
|
|
79
|
-
it('should
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
];
|
|
243
|
+
it('should add defaults to items with empty object for quantity', () => {
|
|
244
|
+
const options = {
|
|
245
|
+
items: [{
|
|
246
|
+
planId: 'plan_TEST',
|
|
247
|
+
quantity: {}
|
|
248
|
+
}]
|
|
249
|
+
};
|
|
88
250
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
251
|
+
const result = handleNestedPropertiesDefaultValues(options);
|
|
252
|
+
expect(result).toEqual({
|
|
253
|
+
items: [{
|
|
254
|
+
planId: 'plan_TEST',
|
|
255
|
+
quantity: {
|
|
256
|
+
minimum: 1,
|
|
257
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
258
|
+
multipleOf: 1
|
|
92
259
|
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
260
|
+
}]
|
|
261
|
+
});
|
|
262
|
+
})
|
|
263
|
+
});
|
|
95
264
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
265
|
+
describe('Setup options handleJwtDestructuring function', () => {
|
|
266
|
+
const testJwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfVEVTVC1BIiwiZXhwIjoxNzE0ODQwNDg5LCJpYXQiOjE2ODMyMTY1ODkuNTYwMjU2LCJhY2wiOlt7InNjb3BlIjp7Im9yZ2FuaXphdGlvbklkIjpbIm9yZ19URVNULUEiXSwiaW52b2ljZUlkIjpbImluX1RFU1QtQSJdLCJjdXN0b21GaWVsZE5hbWUiOlsiU0lOTGFzdDQiXX0sInBlcm1pc3Npb25zIjpbMjg0LDI4Niw0MTQsNDE1LDQzNCw0MTIsNDI0LDQyNSw0MjYsNDI3LDQyOCw0MjksNDA5LDQxMCw0MDEsNDAyLDQzMyw0MzFdfV0sImNsYWltcyI6eyJ3ZWJzaXRlSWQiOiJ3ZWJfVEVTVC1BIiwiaW52b2ljZUlkIjoiaW5fVEVTVC1BIiwicGF5bWVudE1ldGhvZHMiOltdfSwibWVyY2hhbnQiOiJNRVJDSEFOVC1URVNULUlELUEiLCJjdXN0b21lciI6eyJpZCI6ImN1c19URVNULUEiLCJuYW1lIjoiQ2FyZCBIb2xkZXIgTmFtZSIsImNyZWF0ZWRUaW1lIjoiMjAyMi0wOS0yMVQxODo1MDoyMiswMDowMCJ9fQ.tm33uioGUSpEedHeYufDGm-p1YW40eufNovppcU6-xg';
|
|
267
|
+
|
|
268
|
+
it('should destructure when jwt is present', () => {
|
|
269
|
+
const options = {
|
|
270
|
+
jwt: testJwt,
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const result = handleJwtDestructuring(options);
|
|
274
|
+
expect(result).toEqual({
|
|
275
|
+
jwt: testJwt,
|
|
276
|
+
organizationId: 'MERCHANT-TEST-ID-A',
|
|
277
|
+
invoiceId: 'in_TEST-A',
|
|
278
|
+
websiteId: 'web_TEST-A'
|
|
279
|
+
});
|
|
107
280
|
});
|
|
108
281
|
|
|
109
|
-
it
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
282
|
+
it('should not destructure when publishableKey is supplied', () => {
|
|
283
|
+
const options = {
|
|
284
|
+
jwt: testJwt,
|
|
285
|
+
publishableKey: 'pk_sandbox_TEST',
|
|
286
|
+
organizationId: 'MERCHANT-TEST-ID-B',
|
|
287
|
+
invoiceId: 'in_TEST-B',
|
|
288
|
+
websiteId: 'web_TEST-B'
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const result = handleJwtDestructuring(options);
|
|
292
|
+
expect(result).toEqual({
|
|
293
|
+
jwt: testJwt,
|
|
294
|
+
publishableKey: 'pk_sandbox_TEST',
|
|
295
|
+
organizationId: 'MERCHANT-TEST-ID-B',
|
|
296
|
+
invoiceId: 'in_TEST-B',
|
|
297
|
+
websiteId: 'web_TEST-B'
|
|
298
|
+
});
|
|
299
|
+
});
|
|
115
300
|
|
|
116
|
-
|
|
301
|
+
it('should use JWT values when publishableKey is missing', () => {
|
|
302
|
+
const options = {
|
|
303
|
+
jwt: testJwt,
|
|
304
|
+
organizationId: 'MERCHANT-TEST-ID-B',
|
|
305
|
+
invoiceId: 'in_TEST-B',
|
|
306
|
+
websiteId: 'web_TEST-B'
|
|
307
|
+
};
|
|
117
308
|
|
|
118
|
-
|
|
119
|
-
|
|
309
|
+
const result = handleJwtDestructuring(options);
|
|
310
|
+
expect(result).toEqual({
|
|
311
|
+
jwt: testJwt,
|
|
312
|
+
organizationId: 'MERCHANT-TEST-ID-A',
|
|
313
|
+
invoiceId: 'in_TEST-A',
|
|
314
|
+
websiteId: 'web_TEST-A'
|
|
120
315
|
});
|
|
121
|
-
|
|
122
|
-
expect(sanitizeOptions(newOptions)).not.toBeInstanceOf(OptionsClass);
|
|
123
|
-
})
|
|
316
|
+
});
|
|
124
317
|
});
|
package/src/functions/update.js
CHANGED
|
@@ -3,25 +3,6 @@ import state from '../state';
|
|
|
3
3
|
import { destroy } from './destroy';
|
|
4
4
|
import { mount } from './mount';
|
|
5
5
|
|
|
6
|
-
function sanitizeOldPurchaseData({newOptions}) {
|
|
7
|
-
let purchaseData = {};
|
|
8
|
-
const hasPurchaseDataKeys = Object.keys(newOptions).some(key => [
|
|
9
|
-
'items',
|
|
10
|
-
'money',
|
|
11
|
-
'invoiceId',
|
|
12
|
-
'transactionId'
|
|
13
|
-
].includes(key));
|
|
14
|
-
|
|
15
|
-
purchaseData = hasPurchaseDataKeys ? {
|
|
16
|
-
items: null,
|
|
17
|
-
money: null,
|
|
18
|
-
invoiceId: null,
|
|
19
|
-
transactionId: null
|
|
20
|
-
} : purchaseData;
|
|
21
|
-
|
|
22
|
-
return purchaseData;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
6
|
export async function update({newOptions = {}}) {
|
|
26
7
|
if (!state.hasMounted) {
|
|
27
8
|
throw Error('Update method cannot be called before mounting instruments');
|
|
@@ -45,12 +26,7 @@ export async function update({newOptions = {}}) {
|
|
|
45
26
|
// return;
|
|
46
27
|
// }
|
|
47
28
|
|
|
48
|
-
const
|
|
49
|
-
...state.options,
|
|
50
|
-
...sanitizeOldPurchaseData({newOptions})
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const updatedOptions = merge({...oldOptions}, newOptions);
|
|
29
|
+
const updatedOptions = merge({...state.options}, newOptions);
|
|
54
30
|
|
|
55
31
|
await destroy();
|
|
56
32
|
|
|
@@ -68,6 +68,7 @@ describe('RebillyInstruments Update', () => {
|
|
|
68
68
|
expect(rebillyInstruments.state.options.countryCode).toEqual('ES');
|
|
69
69
|
await avoidUnhandledPromises();
|
|
70
70
|
});
|
|
71
|
+
|
|
71
72
|
it('should replace the items with different options', async () => {
|
|
72
73
|
const rebillyInstruments = await RenderMockRebillyInstruments();
|
|
73
74
|
const formElement = document.querySelector('.form-selector');
|