@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.
@@ -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 const defaults = {
6
- countryCode: 'US',
7
- locale: 'auto',
8
- theme: {
9
- labels: 'stacked'
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 validateOptions(options) {
61
- // TODO: validate more options
62
- const purchaseData = [
63
- options.items,
64
- options.invoiceId,
65
- options.money,
66
- options.transactionId,
67
- ].filter(v => v);
68
-
69
- if (!options.jwt && purchaseData.length === 0) {
70
- throw new Error('Must provide purchase data');
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 (purchaseData.length > 1) {
74
- throw new Error('Must provide only one purchase data type');
34
+ if (options.items) {
35
+ options.items = options.items.map(item => ({
36
+ ...item,
37
+ quantity: parseQuantity(item)
38
+ }));
75
39
  }
76
40
 
77
- if (!options.jwt && (options.invoiceId || options.transactionId)) {
78
- throw new Error('Must provide a jwt');
79
- }
41
+ return options;
80
42
  }
81
43
 
82
- export default ({
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(combinedOptions.jwt);
126
-
127
- combinedOptions.organizationId = organizationId;
128
-
129
- if (transactionId) {
130
- combinedOptions.transactionId = transactionId;
131
- }
132
-
133
- if (invoiceId) {
134
- combinedOptions.invoiceId = invoiceId;
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
- // only add "addons" or "bumpOffer" if items are available
163
- if (combinedOptions.items) {
164
- if (options.addons) {
165
- combinedOptions.addons = options.addons;
166
- }
66
+ return options;
67
+ }
167
68
 
168
- if (options.bumpOffer) {
169
- combinedOptions.bumpOffer = options.bumpOffer;
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 { RenderMockRebillyInstruments } from 'tests/mocks/rebilly-instruments-mock';
2
- import setupOptions, {validateOptions, defaults, sanitizeOptions} from './setup-options';
3
-
4
- describe('Setup mount options', () => {
5
- it("should fill with default options", () => {
6
- const options = setupOptions({
7
- options: {
8
- items: [
9
- {
10
- planId: "test-plan-id",
11
- quantity: 1
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
- expect(options).toMatchObject(defaults);
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("should setup options from mount", async () => {
39
+ it.only('should validate and inject default values', () => {
40
+ const testJwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfVEVTVC1BIiwiZXhwIjoxNzE0ODQwNDg5LCJpYXQiOjE2ODMyMTY1ODkuNTYwMjU2LCJhY2wiOlt7InNjb3BlIjp7Im9yZ2FuaXphdGlvbklkIjpbIm9yZ19URVNULUEiXSwiaW52b2ljZUlkIjpbImluX1RFU1QtQSJdLCJjdXN0b21GaWVsZE5hbWUiOlsiU0lOTGFzdDQiXX0sInBlcm1pc3Npb25zIjpbMjg0LDI4Niw0MTQsNDE1LDQzNCw0MTIsNDI0LDQyNSw0MjYsNDI3LDQyOCw0MjksNDA5LDQxMCw0MDEsNDAyLDQzMyw0MzFdfV0sImNsYWltcyI6eyJ3ZWJzaXRlSWQiOiJ3ZWJfVEVTVC1BIiwiaW52b2ljZUlkIjoiaW5fVEVTVC1BIiwicGF5bWVudE1ldGhvZHMiOltdfSwibWVyY2hhbnQiOiJNRVJDSEFOVC1URVNULUlELUEiLCJjdXN0b21lciI6eyJpZCI6ImN1c19URVNULUEiLCJuYW1lIjoiQ2FyZCBIb2xkZXIgTmFtZSIsImNyZWF0ZWRUaW1lIjoiMjAyMi0wOS0yMVQxODo1MDoyMiswMDowMCJ9fQ.tm33uioGUSpEedHeYufDGm-p1YW40eufNovppcU6-xg';
20
41
  const options = {
21
- publishableKey: 'test-publishable-key',
22
- organizationId: 'test-organization-id',
23
- websiteId: 'test-website-id',
24
- jwt: 'test-jwt'
42
+ jwt: testJwt,
43
+ apiMode: 'sandbox',
44
+ items: [{
45
+ planId: 'plan_TEST',
46
+ quantity: {},
47
+ }]
25
48
  }
26
- const rebillyInstruments = await RenderMockRebillyInstruments(options);
27
- expect(rebillyInstruments.state.options).toMatchObject(options);
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('Validate mount options', () => {
32
- it("should throw an error with no purchase data", async () => {
33
- let error = null;
34
- try {
35
- const options = {};
36
- validateOptions(options);
37
- } catch (e) {
38
- error = e;
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
- expect(error.message).toBe('Must provide purchase data');
189
+ const result = handleComputedProperty(options);
190
+
191
+ expect(result._computed.paymentMethodsUrl).toEqual('https://www.example.com');
41
192
  });
42
193
 
43
- it("should throw error if there are more than one purchase property", () => {
44
- let error = null;
45
- try {
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
- expect(error.message).toBe('Must provide only one purchase data type');
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('sanitize mount options', () => {
62
- it('should make into object', () => {
63
- class options {
64
- constructor() {
65
- this.items = [
66
- {
67
- planId: "test-plan-id",
68
- quantity: 1
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
- expect(setupOptions({
75
- options: new options()
76
- })).toMatchObject(defaults);
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 merge class and default object', () => {
80
- class options {
81
- constructor() {
82
- this.items = [
83
- {
84
- planId: "test-plan-id",
85
- quantity: 1
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
- this.features = {
90
- showCoupons: ['summary'],
91
- other: 'key'
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
- expect(setupOptions({
97
- options: new options()
98
- })).toMatchObject(
99
- expect.objectContaining({
100
- features: expect.objectContaining({
101
- ...defaults.features,
102
- showCoupons: ['summary'],
103
- other: 'key'
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 ('should sanitize class to object', () => {
110
- class OptionsClass {
111
- constructor() {
112
- this.key = "value"
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
- const newOptions = new OptionsClass();
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
- expect(sanitizeOptions(newOptions)).toMatchObject({
119
- key: 'value'
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
- expect(sanitizeOptions(newOptions)).toBeInstanceOf(Object);
122
- expect(sanitizeOptions(newOptions)).not.toBeInstanceOf(OptionsClass);
123
- })
316
+ });
124
317
  });
@@ -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 oldOptions = {
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');