@rebilly/instruments 3.21.1-beta.0 → 3.23.0-beta.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.
Files changed (54) hide show
  1. package/dist/index.js +10 -17
  2. package/dist/index.min.js +49 -56
  3. package/package.json +3 -1
  4. package/src/functions/destroy.js +11 -9
  5. package/src/functions/mount/fetch-data.js +20 -21
  6. package/src/functions/mount/fetch-data.spec.js +140 -93
  7. package/src/functions/mount/index.js +9 -10
  8. package/src/functions/mount/mount.spec.js +5 -7
  9. package/src/functions/mount/setup-framepay-theme.js +2 -1
  10. package/src/functions/mount/setup-framepay.js +3 -1
  11. package/src/functions/mount/setup-i18n.js +4 -2
  12. package/src/functions/mount/setup-options.js +6 -4
  13. package/src/functions/on.spec.js +3 -2
  14. package/src/functions/purchase.js +16 -5
  15. package/src/functions/setup.js +3 -4
  16. package/src/functions/show.js +7 -6
  17. package/src/functions/show.spec.js +11 -7
  18. package/src/functions/update.js +3 -3
  19. package/src/functions/update.spec.js +4 -3
  20. package/src/instance.js +11 -31
  21. package/src/state/iframes.js +23 -0
  22. package/src/state/index.js +61 -0
  23. package/src/storefront/account-and-website.js +3 -2
  24. package/src/storefront/{fetch-plans-from-addons-bumpOffers.js → fetch-plans-from-addons-bumpOffer.js} +5 -4
  25. package/src/storefront/fetch-products-from-plans.js +5 -4
  26. package/src/storefront/index.js +3 -4
  27. package/src/storefront/invoices.js +6 -4
  28. package/src/storefront/payment-instruments.js +5 -4
  29. package/src/storefront/purchase.js +5 -4
  30. package/src/storefront/ready-to-pay.js +5 -13
  31. package/src/storefront/summary.js +8 -3
  32. package/src/storefront/transactions.js +3 -2
  33. package/src/style/base/index.js +243 -0
  34. package/src/views/common/iframe/base-iframe.js +0 -2
  35. package/src/views/common/iframe/events/update-addons-handler.js +8 -13
  36. package/src/views/common/iframe/events/update-coupons-handler.js +5 -11
  37. package/src/views/confirmation.js +16 -6
  38. package/src/views/method-selector/__snapshots__/method-selector.spec.js.snap +182 -1
  39. package/src/views/method-selector/generate-digital-wallet.js +2 -1
  40. package/src/views/method-selector/generate-digital-wallet.spec.js +32 -37
  41. package/src/views/method-selector/generate-framepay-config.js +1 -1
  42. package/src/views/method-selector/generate-framepay-config.spec.js +9 -12
  43. package/src/views/method-selector/get-payment-methods.js +3 -1
  44. package/src/views/method-selector/get-payment-methods.spec.js +25 -34
  45. package/src/views/method-selector/index.js +39 -20
  46. package/src/views/method-selector/method-selector.spec.js +9 -109
  47. package/src/views/method-selector/mount-bump-offer.js +99 -0
  48. package/src/views/method-selector/mount-express-methods.js +1 -2
  49. package/src/views/modal.js +3 -3
  50. package/src/views/result.js +7 -5
  51. package/src/views/summary.js +12 -16
  52. package/tests/mocks/rebilly-instruments-mock.js +17 -19
  53. package/tests/mocks/storefront-mock.js +10 -9
  54. package/tests/setup-jest.js +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebilly/instruments",
3
- "version": "3.21.1-beta.0",
3
+ "version": "3.23.0-beta.0",
4
4
  "author": "Rebilly",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -17,6 +17,8 @@
17
17
  "@babel/core": "^7.14.6",
18
18
  "@babel/preset-env": "^7.14.7",
19
19
  "@rebilly/risk-data-collector": "^2.3.0",
20
+ "@vue-reactivity/watch": "^0.2.0",
21
+ "@vue/reactivity": "^3.2.39",
20
22
  "jwt-decode": "^3.1.2",
21
23
  "lodash.camelcase": "^4.3.0",
22
24
  "lodash.isequal": "^4.5.0",
@@ -1,21 +1,23 @@
1
1
  import { cancellation } from 'rebilly-js-sdk';
2
2
  import { registeredListeners } from '../events/base-event';
3
3
  import { sleep } from '../utils';
4
+ import state from '../state';
5
+ import iframes from '../state/iframes';
4
6
 
5
- export async function destroy({ state }) {
7
+ export async function destroy() {
6
8
  // wait to allow for cancellation to catch any pending api requests
7
9
  const sleepMilliseconds = 1000;
8
10
  await sleep(sleepMilliseconds);
9
-
10
- Object.values(state.iframeComponents)
11
- .forEach(iframe => iframe?.destroy())
11
+
12
+ Object.keys(iframes).forEach(frame => {
13
+ if (iframes.hasFrame(frame)) {
14
+ iframes[frame].destroy();
15
+ iframes[frame] = null;
16
+ }
17
+ });
12
18
 
13
19
  registeredListeners.removeAll(document);
14
-
15
- state.iframeComponents = {
16
- summary: null,
17
- form: null,
18
- };
20
+
19
21
  state.hasMounted = false;
20
22
 
21
23
  if (state.summary) {
@@ -1,6 +1,7 @@
1
1
  import { collectData } from '@rebilly/risk-data-collector';
2
+ import state from '../../state';
2
3
  import { fetchProductsFromPlans } from '../../storefront/fetch-products-from-plans';
3
- import { fetchPlansFromAddonsBumpOffers } from '../../storefront/fetch-plans-from-addons-bumpOffers';
4
+ import { fetchPlansFromAddonsBumpOffer } from '../../storefront/fetch-plans-from-addons-bumpOffer';
4
5
  import { fetchReadyToPay } from '../../storefront/ready-to-pay';
5
6
  import { fetchSummary } from '../../storefront/summary';
6
7
  import { fetchInvoiceAndProducts as FetchInvoiceAndProducts } from '../../storefront/invoices';
@@ -10,7 +11,6 @@ import { fetchPaymentInstrument as FetchInstruments } from '../../storefront/pay
10
11
 
11
12
  export class DataInstance {
12
13
  constructor({
13
- state = {},
14
14
  ...fields
15
15
  } = {}) {
16
16
  Object.entries({
@@ -23,12 +23,14 @@ export class DataInstance {
23
23
  this.money = state.options?.money || null;
24
24
  this.couponIds = [];
25
25
  this.addons = [];
26
+ this.acceptBumpOffer = false;
26
27
  }
27
28
 
28
29
  get amountAndCurrency() {
29
30
  let currency;
30
31
  let amount;
31
32
  let amountDue;
33
+
32
34
  if (this.previewPurchase) {
33
35
  currency = this.previewPurchase.currency;
34
36
  amount = this.previewPurchase.total;
@@ -118,7 +120,6 @@ export class DataInstance {
118
120
  }
119
121
 
120
122
  export async function fetchData({
121
- state = null,
122
123
  riskMetadata = null,
123
124
 
124
125
  // Dependency injectable functions
@@ -126,20 +127,22 @@ export async function fetchData({
126
127
  fetchTransaction = FetchTransaction,
127
128
  fetchAccountAndWebsite = FetchAccountAndWebsite,
128
129
  fetchInstruments = FetchInstruments
129
- }) {
130
+ } = {}) {
130
131
  try {
131
- state.data = new DataInstance({
132
- state
133
- });
132
+ state.data = new DataInstance();
133
+
134
+ let readyToPayPromise = Promise.resolve(null);
134
135
 
135
- let accountPromise = Promise.resolve(null);
136
136
  let availableInstrumentsPromise = null;
137
137
  if (state.options?.jwt) {
138
- accountPromise = fetchAccountAndWebsite({state}).then(({account, website}) => {
138
+ fetchAccountAndWebsite({state}).then(({account, website}) => {
139
139
  state.data.account = account;
140
140
  state.data.website = website;
141
141
  });
142
+ readyToPayPromise = fetchReadyToPay({riskMetadata, state});
142
143
  availableInstrumentsPromise = fetchInstruments({state});
144
+ } else {
145
+ readyToPayPromise = fetchReadyToPay({riskMetadata, state});
143
146
  }
144
147
 
145
148
  if (state.options?.transactionId) {
@@ -149,12 +152,12 @@ export async function fetchData({
149
152
  }
150
153
 
151
154
  let productsPromise;
152
- if (state.options?.invoiceId || state.data?.transaction?.hasInvoice) {
155
+ const invoiceId = state.options?.invoiceId || state.data?.transaction?.invoiceId;
156
+ if (invoiceId) {
153
157
  const { invoice, products } = await fetchInvoiceAndProducts({
154
158
  data: {
155
- id: state.options?.invoiceId || state.data?.transaction?.invoiceId
156
- },
157
- state,
159
+ id: invoiceId
160
+ }
158
161
  });
159
162
  productsPromise = Promise.resolve(products);
160
163
  state.data.invoice = invoice;
@@ -165,21 +168,18 @@ export async function fetchData({
165
168
  state.data.riskMetadata = riskMetadata;
166
169
  }
167
170
 
168
- const readyToPayPromise = state.data?.readyToPay ??
169
- accountPromise.then(() => fetchReadyToPay({riskMetadata, state}));
170
-
171
171
  const previewPurchasePromise = state.options.items ?
172
- fetchSummary({ state }) : null;
172
+ fetchSummary() : null;
173
173
 
174
174
  if (!state.options?.jwt) {
175
- // There is no invoice, only plans through the static options,
175
+ // There is no invoice, only pla ns through the static options,
176
176
  // so we should fetch the products from the provided plan names.
177
177
  productsPromise = fetchProductsFromPlans({ state });
178
178
  }
179
179
 
180
180
  let plansPromise = new Promise((resolve) => resolve([]));
181
- if (state.options?.addons || state.options?.bumpOffers) {
182
- plansPromise = fetchPlansFromAddonsBumpOffers({ state });
181
+ if (state.options?.addons || state.options?.bumpOffer) {
182
+ plansPromise = fetchPlansFromAddonsBumpOffer({ state });
183
183
  }
184
184
 
185
185
  const [
@@ -197,7 +197,6 @@ export async function fetchData({
197
197
  ]);
198
198
 
199
199
  return new DataInstance({
200
- state,
201
200
  readyToPay,
202
201
  previewPurchase,
203
202
  products,
@@ -3,17 +3,16 @@ import { fetchData, DataInstance } from './fetch-data';
3
3
  import TransactionModel from '../../storefront/models/transaction-model';
4
4
 
5
5
  describe('fetchData function', () => {
6
- it('Should use correct invoice id for invoiceId', async () => {
6
+ it ('Should use correct invoice id for invoiceId', async () => {
7
7
  const mockFetchInvoiceAndProducts = jest.fn();
8
8
  const invoiceId = 'test-invoice-id';
9
- const state = new StorefontTestingInstance({
9
+ StorefontTestingInstance({
10
10
  options: {
11
11
  invoiceId
12
12
  }
13
- })
13
+ });
14
14
 
15
15
  await fetchData({
16
- state,
17
16
  fetchInvoiceAndProducts: mockFetchInvoiceAndProducts
18
17
  });
19
18
 
@@ -27,11 +26,10 @@ describe('fetchData function', () => {
27
26
  );
28
27
  });
29
28
 
30
- it('Should use correct invoice id for transaction with invoiceIds', async () => {
29
+ it ('Should use correct invoice id for transaction with invoiceIds', async () => {
31
30
  const mockFetchInvoiceAndProducts = jest.fn();
32
31
  const invoiceId = 'test-invoice-id';
33
- const state = new StorefontTestingInstance({
34
- options: {},
32
+ StorefontTestingInstance({
35
33
  data: {
36
34
  transaction: new TransactionModel({
37
35
  invoiceIds: [invoiceId]
@@ -40,7 +38,6 @@ describe('fetchData function', () => {
40
38
  });
41
39
 
42
40
  await fetchData({
43
- state,
44
41
  fetchInvoiceAndProducts: mockFetchInvoiceAndProducts
45
42
  });
46
43
 
@@ -54,19 +51,18 @@ describe('fetchData function', () => {
54
51
  );
55
52
  });
56
53
 
57
- it('Should not fetch invoice for transaction with no invoice Ids', async () => {
54
+ it ('Should not fetch invoice for transaction with no invoice Ids', async () => {
58
55
  const mockFetchInvoiceAndProducts = jest.fn();
59
- const invoiceState = {
56
+ StorefontTestingInstance({
60
57
  options: {},
61
58
  data: {
62
59
  transaction: new TransactionModel({
63
60
  invoiceIds: []
64
61
  }),
65
62
  }
66
- }
63
+ });
67
64
 
68
65
  fetchData({
69
- state: invoiceState,
70
66
  fetchInvoiceAndProducts: mockFetchInvoiceAndProducts
71
67
  });
72
68
 
@@ -74,29 +70,28 @@ describe('fetchData function', () => {
74
70
 
75
71
  });
76
72
 
77
- it('Should fetch account when JWT is supplied', async () => {
73
+ it ('Should fetch account when JWT is supplied', async () => {
78
74
  const mockFetchAccountAndWebsite = jest.fn();
79
- const accountState = {
75
+ StorefontTestingInstance({
80
76
  options: {
81
77
  jwt: 'TEST_JWT'
82
78
  }
83
- }
79
+ });
84
80
 
85
81
  await fetchData({
86
- state: accountState,
87
82
  fetchAccountAndWebsite: mockFetchAccountAndWebsite,
88
83
  });
89
84
 
90
85
  expect(mockFetchAccountAndWebsite).toBeCalledTimes(1);
91
86
  });
92
87
 
93
- it('Should not fetch account when there JWT is not supplied', async () => {
88
+ it ('Should not fetch account when there JWT is not supplied', async () => {
94
89
  const mockFetchAccountAndWebsite = jest.fn();
90
+ StorefontTestingInstance({
91
+ options: {}
92
+ });
95
93
 
96
94
  await fetchData({
97
- state: {
98
- options: {}
99
- },
100
95
  fetchAccountAndWebsite: mockFetchAccountAndWebsite,
101
96
  });
102
97
 
@@ -105,117 +100,169 @@ describe('fetchData function', () => {
105
100
  });
106
101
 
107
102
  describe('DataInstance', () => {
108
- it ('Should correctly determine amountAndCurrency', () => {
109
- const expectedAmountAndCurrency = {
110
- amount: 10,
111
- currency: 'USD'
112
- }
113
- let fetchedData = new DataInstance({
114
- state: {
103
+ describe('Determining amountAndCurrency', () => {
104
+ it ('should use money option', () => {
105
+ const expectedAmountAndCurrency = {
106
+ amount: 10,
107
+ currency: 'USD'
108
+ }
109
+ StorefontTestingInstance({
115
110
  options: {
116
- money: {
117
- ...expectedAmountAndCurrency
118
- }
111
+ money: expectedAmountAndCurrency
119
112
  }
120
- }
113
+ });
114
+ const fetchedData = new DataInstance();
115
+
116
+ expect(fetchedData.amountAndCurrency).toEqual(expectedAmountAndCurrency);
121
117
  });
122
- expect(fetchedData.amountAndCurrency).toEqual(
123
- expect.objectContaining(expectedAmountAndCurrency)
124
- );
125
118
 
126
- fetchedData = new DataInstance({
127
- previewPurchase: {
128
- total: expectedAmountAndCurrency.amount,
129
- currency: expectedAmountAndCurrency.currency
119
+ it ('should use preview Purchase', () => {
120
+ const expectedAmountAndCurrency = {
121
+ amount: 10,
122
+ currency: 'USD'
130
123
  }
124
+ StorefontTestingInstance();
125
+
126
+ const fetchedData = new DataInstance({
127
+ previewPurchase: {
128
+ total: expectedAmountAndCurrency.amount,
129
+ currency: expectedAmountAndCurrency.currency
130
+ }
131
+ });
132
+ expect(fetchedData.amountAndCurrency).toEqual(
133
+ expect.objectContaining(expectedAmountAndCurrency)
134
+ );
131
135
  });
132
- expect(fetchedData.amountAndCurrency).toEqual(
133
- expect.objectContaining(expectedAmountAndCurrency)
134
- );
135
136
 
136
- fetchedData = new DataInstance({
137
- invoice: {
138
- ...expectedAmountAndCurrency
137
+ it ('should use invoice', () => {
138
+ const expectedAmountAndCurrency = {
139
+ amount: 10,
140
+ currency: 'USD'
139
141
  }
142
+ StorefontTestingInstance();
143
+
144
+ const fetchedData = new DataInstance({
145
+ invoice: {
146
+ ...expectedAmountAndCurrency
147
+ }
148
+ });
149
+ expect(fetchedData.amountAndCurrency).toEqual(
150
+ expect.objectContaining(expectedAmountAndCurrency)
151
+ );
140
152
  });
141
- expect(fetchedData.amountAndCurrency).toEqual(
142
- expect.objectContaining(expectedAmountAndCurrency)
143
- );
144
153
 
145
- fetchedData = new DataInstance({
146
- transaction: {
147
- ...expectedAmountAndCurrency
154
+ it ('should use transaction', () => {
155
+ const expectedAmountAndCurrency = {
156
+ amount: 10,
157
+ currency: 'USD'
148
158
  }
159
+ StorefontTestingInstance();
160
+
161
+ const fetchedData = new DataInstance({
162
+ transaction: {
163
+ ...expectedAmountAndCurrency
164
+ }
165
+ });
166
+ expect(fetchedData.amountAndCurrency).toEqual(
167
+ expect.objectContaining(expectedAmountAndCurrency)
168
+ );
149
169
  });
150
- expect(fetchedData.amountAndCurrency).toEqual(
151
- expect.objectContaining(expectedAmountAndCurrency)
152
- );
153
170
 
154
- fetchedData = new DataInstance();
155
- expect(fetchedData.amountAndCurrency).toEqual(
156
- expect.objectContaining({
157
- amount: undefined,
158
- currency: undefined
159
- })
160
- );
171
+ it ('should handle empty value', () => {
172
+ StorefontTestingInstance();
173
+
174
+ const fetchedData = new DataInstance();
175
+ expect(fetchedData.amountAndCurrency).toEqual(
176
+ expect.objectContaining({
177
+ amount: undefined,
178
+ currency: undefined
179
+ })
180
+ );
181
+ })
161
182
  });
162
183
 
163
- it ('Should correctly determine isPayment', () => {
164
- let fetchedData = new DataInstance({
165
- state: {
184
+ describe('isPayment', () => {
185
+ it ('money is truthy', () => {
186
+ StorefontTestingInstance({
166
187
  options: {
167
188
  money: true
168
189
  }
169
- }
190
+ });
191
+ const fetchedData = new DataInstance();
192
+ expect(fetchedData.isPayment).toBeTruthy();
170
193
  });
171
- expect(fetchedData.isPayment).toBeTruthy();
172
194
 
173
- fetchedData = new DataInstance({
174
- invoice: true
195
+ it ('invoice is truthy', () => {
196
+ StorefontTestingInstance();
197
+ const fetchedData = new DataInstance({
198
+ invoice: true
199
+ });
200
+ expect(fetchedData.isPayment).toBeTruthy();
175
201
  });
176
- expect(fetchedData.isPayment).toBeTruthy();
177
202
 
178
- fetchedData = new DataInstance({
179
- transaction: true
203
+ it ('transaction is truthy', () => {
204
+ StorefontTestingInstance();
205
+ const fetchedData = new DataInstance({
206
+ transaction: true
207
+ });
208
+ expect(fetchedData.isPayment).toBeTruthy();
180
209
  });
181
- expect(fetchedData.isPayment).toBeTruthy();
182
210
 
183
- fetchedData = new DataInstance({
184
- previewPurchase: true
211
+ it ('previewPurchase is falsy', () => {
212
+ StorefontTestingInstance();
213
+ const fetchedData = new DataInstance({
214
+ previewPurchase: true
215
+ });
216
+ expect(fetchedData.isPayment).toBeFalsy();
185
217
  });
186
- expect(fetchedData.isPayment).toBeFalsy();
187
218
 
188
- fetchedData = new DataInstance({});
189
- expect(fetchedData.isPayment).toBeFalsy();
219
+ it ('empty is falsy', () => {
220
+ StorefontTestingInstance();
221
+ const fetchedData = new DataInstance({});
222
+ expect(fetchedData.isPayment).toBeFalsy();
223
+ });
190
224
  });
191
225
 
192
- it ('Should correctly determine isPurchase', () => {
193
- let fetchedData = new DataInstance({
194
- previewPurchase: true
226
+ describe('isPurchase', () => {
227
+ it ('previewPurchase is truthy', () => {
228
+ StorefontTestingInstance();
229
+ const fetchedData = new DataInstance({
230
+ previewPurchase: true
231
+ });
232
+ expect(fetchedData.isPurchase).toBeTruthy();
195
233
  });
196
- expect(fetchedData.isPurchase).toBeTruthy();
197
-
198
- fetchedData = new DataInstance({
199
- state: {
234
+
235
+ it ('money is falsy', () => {
236
+ StorefontTestingInstance({
200
237
  options: {
201
238
  money: true
202
239
  }
203
- }
240
+ });
241
+ const fetchedData = new DataInstance();
242
+ expect(fetchedData.isPurchase).toBeFalsy();
204
243
  });
205
- expect(fetchedData.isPurchase).toBeFalsy();
206
244
 
207
- fetchedData = new DataInstance({
208
- invoice: true
245
+ it ('invoice is falsy', () => {
246
+ StorefontTestingInstance();
247
+ const fetchedData = new DataInstance({
248
+ invoice: true
249
+ });
250
+ expect(fetchedData.isPurchase).toBeFalsy();
209
251
  });
210
- expect(fetchedData.isPurchase).toBeFalsy();
211
252
 
212
- fetchedData = new DataInstance({
213
- transaction: true
253
+ it ('transaction is falsy', () => {
254
+ StorefontTestingInstance();
255
+ const fetchedData = new DataInstance({
256
+ transaction: true
257
+ });
258
+ expect(fetchedData.isPurchase).toBeFalsy();
214
259
  });
215
- expect(fetchedData.isPurchase).toBeFalsy();
216
260
 
217
- fetchedData = new DataInstance({});
218
- expect(fetchedData.isPurchase).toBeFalsy();
261
+ it ('empty is falsy', () => {
262
+ StorefontTestingInstance();
263
+ const fetchedData = new DataInstance({});
264
+ expect(fetchedData.isPurchase).toBeFalsy();
265
+ });
219
266
  });
220
267
 
221
268
  it ('Should get summaryItems', () => {
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable max-len */
2
+ import state from '../../state';
2
3
  import { mountSummary } from '../../views/summary';
3
4
  import { mountMethodSelector } from '../../views/method-selector';
4
5
  import { fetchData } from './fetch-data';
@@ -64,7 +65,6 @@ import { showError } from '../../views/errors';
64
65
  /**
65
66
  * Mount library with configurations.
66
67
  * @param {object} options - The options object
67
- * @param {object} options.state - Global state
68
68
  * @param {function} options.setupFramepayInstance - Helper for adding FramePay scripts to the DOM
69
69
  * @param {string | HTMLElement} options.form - The CSS class or HTML element were the form will be mounted.
70
70
  * @param {string | HTMLElement} options.summary - The CSS class or HTML element were the summary will be mounted.
@@ -77,7 +77,6 @@ import { showError } from '../../views/errors';
77
77
  * @param {string} options.locale - default: auto. Language to render component text
78
78
  */
79
79
  export async function mount({
80
- state,
81
80
  setupFramepay = setupFramepayInstance,
82
81
  ...options
83
82
  } = {}) {
@@ -99,22 +98,22 @@ export async function mount({
99
98
  state.options = setupOptions({ options });
100
99
  state.storefront = setupStorefront({ options });
101
100
  state.mainStyleVars = setupStylesVars({ options });
102
- state.options.themeFramepay = setupFramepayTheme({ state, options });
101
+ state.options.themeFramepay = setupFramepayTheme({ options });
103
102
 
104
103
  // Setup loader
105
104
  state.loader.addDOMElement({ el: state.form });
106
105
  state.loader.addDOMElement({ section: 'summary', el: state.summary });
107
- state.loader.startLoading({ state, section: 'summary', id: 'rebilly-instruments-summary' });
108
- state.loader.startLoading({ state, id: 'rebilly-instruments-form' });
106
+ state.loader.startLoading({ section: 'summary', id: 'rebilly-instruments-summary' });
107
+ state.loader.startLoading({ id: 'rebilly-instruments-form' });
109
108
 
110
109
  const [data] = await Promise.all([
111
- fetchData({ state }),
112
- setupFramepay(state)
110
+ fetchData(),
111
+ setupFramepay()
113
112
  ]);
114
113
  state.data = data;
115
114
  Events.dataReady.dispatch(state.data);
116
115
 
117
- state.i18n = setupI18n({ state });
116
+ state.i18n = setupI18n();
118
117
 
119
118
  // Update state options from data
120
119
  if ((!state.options.websiteId) && state.data.transaction?.websiteId) {
@@ -128,10 +127,10 @@ export async function mount({
128
127
 
129
128
  // Mount content
130
129
  if (state.form) {
131
- mountMethodSelector({ state });
130
+ mountMethodSelector();
132
131
  }
133
132
  if (state.summary) {
134
- mountSummary({ state });
133
+ mountSummary();
135
134
  }
136
135
  state.i18n({state});
137
136
  state.hasMounted = true;
@@ -1,4 +1,5 @@
1
1
  import {RenderMockRebillyInstruments} from 'tests/mocks/rebilly-instruments-mock';
2
+ import { sleep } from '@/utils';
2
3
 
3
4
  describe('RebillyInstruments instance', () => {
4
5
  it('should inject HTML to the merchant\'s website', async () => {
@@ -28,16 +29,13 @@ describe('RebillyInstruments instance', () => {
28
29
  },
29
30
  };
30
31
  await RenderMockRebillyInstruments(options);
31
-
32
- await new Promise((resolve) => {
33
- setTimeout(() => {
34
- resolve();
35
- }, 100);
36
- })
32
+
33
+ const sleepMilliseconds = 1000;
34
+ await sleep(sleepMilliseconds);
37
35
 
38
36
  // Mounts form and summary
39
37
  const summarySelector = document.querySelector('.summary-selector');
40
- expect(summarySelector.innerHTML).toContain('<iframe name="rebilly-instruments-summary" class="rebilly-instruments-iframe" loading="lazy" allow="payment" src="https://forms.local.rebilly.dev:3000/summary"></iframe>');
38
+ expect(summarySelector.innerHTML).toContain('<iframe name="rebilly-instruments-summary" class="rebilly-instruments-iframe" loading="lazy" allow="payment" src="https://forms.test.rebilly.dev/summary"></iframe>');
41
39
 
42
40
  // Theme config overrides initial styles
43
41
  const STYLE_VARS = document.querySelectorAll('style[type="text/css"]')[0];
@@ -1,3 +1,5 @@
1
+ import state from '../../state';
2
+
1
3
  function processCSS(rawCss) {
2
4
  const cssMap = {};
3
5
  [...rawCss.matchAll(/(--rebilly.*(?=:))[:\s](.*(?=;))/g)]
@@ -44,7 +46,6 @@ const getStyleProps = (obj, particle = '') => {
44
46
  }
45
47
 
46
48
  export default ({
47
- state,
48
49
  options = {}
49
50
  }) => {
50
51
  const fullCss = `
@@ -1,4 +1,6 @@
1
- export default async function setupFramepay (state = {}) {
1
+ import state from '../../state';
2
+
3
+ export default async function setupFramepay () {
2
4
  const {_dev} = state.options || {};
3
5
  const urls = {
4
6
  script: _dev?.framePayScriptLink || 'https://framepay.rebilly.com/rebilly.js',
@@ -1,9 +1,11 @@
1
- const triggerTranslations = ({state}) => {
1
+ import state from '../../state';
2
+
3
+ const triggerTranslations = () => {
2
4
  state.translate.init(state.options.locale, state.options.i18n);
3
5
  state.translate.translateItems();
4
6
  }
5
7
 
6
- export default ({state = {}}) => {
8
+ export default () => {
7
9
  if (
8
10
  state.options.locale === 'auto' &&
9
11
  state.data.riskMetadata?.browserData?.language
@@ -8,7 +8,7 @@ export const defaults = {
8
8
  labels: 'stacked'
9
9
  },
10
10
  addons: [],
11
- bumpOffers: [],
11
+ bumpOffer: [],
12
12
  paymentInstruments: {
13
13
  address: {
14
14
  name: 'default',
@@ -82,7 +82,6 @@ export function validateOptions(options) {
82
82
  export default ({
83
83
  options = {}
84
84
  } = {}) => {
85
-
86
85
  const sanitizedOptions = sanitizeOptions(options)
87
86
 
88
87
  validateOptions(sanitizedOptions);
@@ -138,7 +137,6 @@ export default ({
138
137
  // Add optional key's
139
138
  [
140
139
  'items',
141
- 'bumpOffers',
142
140
  'money',
143
141
  'invoiceId',
144
142
  'transactionId',
@@ -150,11 +148,15 @@ export default ({
150
148
  }
151
149
  });
152
150
 
153
- // only add "addons" if items are available
151
+ // only add "addons" or "bumpOffer" if items are available
154
152
  if (combinedOptions.items) {
155
153
  if (options.addons) {
156
154
  combinedOptions.addons = options.addons;
157
155
  }
156
+
157
+ if (options.bumpOffer) {
158
+ combinedOptions.bumpOffer = options.bumpOffer;
159
+ }
158
160
  }
159
161
 
160
162
  return combinedOptions;