@ordergroove/offers 2.44.0 → 2.44.1-alpha-PR-1167-2.36

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 (40) hide show
  1. package/dist/bundle-report.html +42 -39
  2. package/dist/offers.js +69 -69
  3. package/dist/offers.js.map +4 -4
  4. package/package.json +2 -2
  5. package/src/components/FrequencyStatus.js +14 -10
  6. package/src/components/Offer.js +33 -14
  7. package/src/components/OptinButton.js +2 -2
  8. package/src/components/OptinSelect.js +6 -5
  9. package/src/components/OptinStatus.js +16 -9
  10. package/src/components/Price.js +3 -3
  11. package/src/components/SelectFrequency.js +11 -6
  12. package/src/components/TestWizard.js +45 -41
  13. package/src/components/UpsellModal.js +9 -3
  14. package/src/components/__tests__/Offer.spec.js +0 -19
  15. package/src/components/__tests__/OptinStatus.spec.js +17 -4
  16. package/src/core/__tests__/actions.spec.js +47 -1
  17. package/src/core/__tests__/base.spec.js +0 -77
  18. package/src/core/__tests__/experiments.spec.js +0 -3
  19. package/src/core/__tests__/offerRequest.spec.js +2 -1
  20. package/src/core/__tests__/selectors.spec.js +7 -7
  21. package/src/core/actions-preview.js +6 -3
  22. package/src/core/actions.js +22 -13
  23. package/src/core/base.js +0 -23
  24. package/src/core/offerRequest.js +1 -1
  25. package/src/core/{reducer.js → reducer.ts} +30 -10
  26. package/src/core/selectors.ts +215 -0
  27. package/src/core/types/api.ts +71 -0
  28. package/src/core/types/reducer.ts +94 -0
  29. package/src/core/types/utility.ts +1 -0
  30. package/src/core/utils.ts +32 -15
  31. package/src/make-api.js +1 -1
  32. package/src/shopify/__tests__/reducers/config.spec.js +603 -0
  33. package/src/shopify/__tests__/shopifyReducer.spec.js +69 -744
  34. package/src/shopify/__tests__/utils.spec.js +24 -1
  35. package/src/shopify/reducers/config.ts +185 -0
  36. package/src/shopify/shopifyMiddleware.ts +2 -9
  37. package/src/shopify/{shopifyReducer.js → shopifyReducer.ts} +50 -195
  38. package/src/shopify/utils.ts +25 -0
  39. package/src/core/selectors.js +0 -192
  40. package/src/types.ts +0 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/offers",
3
- "version": "2.44.0",
3
+ "version": "2.44.1-alpha-PR-1167-2.36+cf24ab29",
4
4
  "description": "offer state component",
5
5
  "author": "Eugenio Lattanzio <eugenio63@gmail.com>",
6
6
  "homepage": "https://github.com/ordergroove/plush-toys#readme",
@@ -49,5 +49,5 @@
49
49
  "@ordergroove/offers-templates": "^0.9.7",
50
50
  "@types/lodash.memoize": "^4.1.9"
51
51
  },
52
- "gitHead": "6920106790e66edb68d2f452825f9dc4be5911d4"
52
+ "gitHead": "cf24ab29685dd3a20acce3d0c6ce8eea63c073f8"
53
53
  }
@@ -1,9 +1,12 @@
1
1
  import { html, css } from 'lit-element';
2
2
  import {
3
- makeProductFrequencySelector,
3
+ makeProductFrequencyOptedInSelector,
4
4
  makeOptedinSelector,
5
- configSelector,
5
+ getFallbackValue,
6
6
  templatesSelector,
7
+ makeProductSpecificDefaultFrequencySelector,
8
+ makeProductFrequenciesSelector,
9
+ makeProductFrequencyOptionsSelector,
7
10
  makeProductDefaultFrequencySelector
8
11
  } from '../core/selectors';
9
12
  import { connect } from '../core/connect';
@@ -89,14 +92,15 @@ export class FrequencyStatus extends withProduct(TemplateElement) {
89
92
 
90
93
  export const mapStateToProps = (state, ownProps) => ({
91
94
  subscribed: makeOptedinSelector(ownProps.product)(state),
92
- frequency: makeProductFrequencySelector(ownProps.product)(state),
93
- productDefaultFrequency: makeProductDefaultFrequencySelector((ownProps.product || {}).id)(state),
94
- configDefaultFrequency: state.config?.defaultFrequency,
95
- frequenciesText: state.config?.frequenciesText,
96
- config: state.config,
97
- ...configSelector(state, ownProps, 'frequencies'),
98
- ...configSelector(state, ownProps, 'defaultFrequency'),
99
- ...templatesSelector(state, ownProps)
95
+ frequency: makeProductFrequencyOptedInSelector(ownProps.product)(state),
96
+ productDefaultFrequency: makeProductSpecificDefaultFrequencySelector((ownProps.product || {}).id)(state),
97
+ frequencies:
98
+ // it's unclear whether the getFallbackValue result is ever used here, but leaving for backwards compatibility
99
+ makeProductFrequencyOptionsSelector(ownProps.product?.id)(state) || getFallbackValue(ownProps, 'frequencies'),
100
+ defaultFrequency:
101
+ makeProductDefaultFrequencySelector(ownProps.product?.id)(state) || getFallbackValue(ownProps, 'defaultFrequency'),
102
+ ...templatesSelector(state, ownProps),
103
+ productFrequencies: makeProductFrequenciesSelector(ownProps.product)(state)
100
104
  });
101
105
 
102
106
  export const ConnectedFrequencyStatus = connect(mapStateToProps)(FrequencyStatus);
@@ -12,14 +12,16 @@ import {
12
12
  } from '../core/actions';
13
13
  import {
14
14
  isSameProduct,
15
- configSelector,
15
+ getFallbackValue,
16
16
  templatesSelector,
17
17
  makeOptedoutSelector,
18
- makeProductFrequencySelector,
19
- makeProductDefaultFrequencySelector,
18
+ makeProductFrequencyOptedInSelector,
19
+ makeProductSpecificDefaultFrequencySelector,
20
20
  optedinSelector,
21
21
  autoshipSelector,
22
- makeOptedinSelector
22
+ makeOptedinSelector,
23
+ kebabCase,
24
+ makeProductDefaultFrequencySelector
23
25
  } from '../core/selectors';
24
26
  import { product as productProp, auth as authProp } from '../core/props';
25
27
  import { TemplateElement } from '../core/base';
@@ -339,12 +341,6 @@ export class Offer extends TemplateElement {
339
341
  }
340
342
  }
341
343
 
342
- // product-specific frequency lists are not supported in cart offers
343
- if (this.isCart && this.config?.hasProductSpecificFrequencies) {
344
- logProductSpecificFrequencyListWarning();
345
- return false;
346
- }
347
-
348
344
  return true;
349
345
  }
350
346
 
@@ -368,7 +364,27 @@ export class Offer extends TemplateElement {
368
364
  return freq.currentFrequency;
369
365
  }
370
366
 
371
- return this.getOption('defaultFrequency');
367
+ // not certain if this logic was used or not -- the following code was inlined from a shared function that was only used here
368
+ const attributeValue = this.getValueFromAttribute('defaultFrequency');
369
+ if (attributeValue) {
370
+ return attributeValue;
371
+ }
372
+
373
+ if (this.template && this.template.config && typeof this.template.config.defaultFrequency !== 'undefined') {
374
+ return this.template.config.defaultFrequency;
375
+ }
376
+
377
+ return this.configDefaultFrequency;
378
+ }
379
+
380
+ getValueFromAttribute(key) {
381
+ const attrName = kebabCase(key);
382
+ if (this.hasAttribute(attrName)) {
383
+ const attr = this.getAttribute(attrName);
384
+ if (attr.toString().toLowerCase() === 'true') return true;
385
+ if (attr.toString().toLowerCase() === 'false') return false;
386
+ return attr;
387
+ }
372
388
  }
373
389
  }
374
390
 
@@ -376,9 +392,12 @@ export const mapStateToProps = (state, ownProps) => ({
376
392
  config: state.config,
377
393
  auth: state.auth,
378
394
  offerId: ((state.productOffer || {})[(ownProps.product || {}).id] || [])[0],
379
- productFrequency: makeProductFrequencySelector(ownProps.product)(state),
380
- productDefaultFrequency: makeProductDefaultFrequencySelector((ownProps.product || {}).id)(state),
381
- ...configSelector(state, ownProps, 'autoshipByDefault', autoshipSelector(state)[(ownProps.product || {}).id]),
395
+ configDefaultFrequency: makeProductDefaultFrequencySelector(ownProps.product?.id)(state),
396
+ productFrequency: makeProductFrequencyOptedInSelector(ownProps.product)(state),
397
+ productDefaultFrequency: makeProductSpecificDefaultFrequencySelector((ownProps.product || {}).id)(state),
398
+ autoshipByDefault:
399
+ (state.config && state.config.autoshipByDefault) ||
400
+ getFallbackValue(ownProps, 'autoshipByDefault', autoshipSelector(state)[(ownProps.product || {}).id]),
382
401
  ...(makeOptedoutSelector(ownProps.product)(state) && { autoshipByDefault: false }),
383
402
  optedin: optedinSelector(state),
384
403
  subscribed: makeOptedinSelector(ownProps.product)(state),
@@ -21,7 +21,7 @@ export class OptinButton extends OptinStatus {
21
21
  if (changed.has('subscribed') || changed.has('frequencies')) {
22
22
  if (platform.shopify_selling_plans && this.store) {
23
23
  let buttonFreq = this.getAttribute('default-frequency');
24
- buttonFreq = frequencyToSellingPlan(buttonFreq, this.store.getState().config);
24
+ buttonFreq = frequencyToSellingPlan(buttonFreq, this.productFrequencies);
25
25
  this.sellingPlanFreq = buttonFreq;
26
26
  }
27
27
  this.frequencyMatch = this.frequency === this.optinFrequency;
@@ -40,7 +40,7 @@ export class OptinButton extends OptinStatus {
40
40
  freq = this.offer ? this.offer.defaultFrequency : this.defaultFrequency;
41
41
  }
42
42
  if (platform.shopify_selling_plans && this.store) {
43
- freq = frequencyToSellingPlan(freq, this.store.getState().config);
43
+ freq = frequencyToSellingPlan(freq, this.productFrequencies);
44
44
  }
45
45
 
46
46
  return freq;
@@ -5,7 +5,7 @@ import { OptinStatus, mapStateToProps as mapStateToPropsOptinStatus } from './Op
5
5
  import { mapStateToProps, frequencyText } from './FrequencyStatus';
6
6
  import { connect } from '../core/connect';
7
7
  import { defaultFrequency } from '../core/props';
8
- import { configSelector } from '../core/selectors';
8
+ import { getFallbackValue, makeProductFrequencyOptionsSelector } from '../core/selectors';
9
9
 
10
10
  export class OptinSelect extends withChildOptions(OptinStatus) {
11
11
  static get properties() {
@@ -51,14 +51,13 @@ export class OptinSelect extends withChildOptions(OptinStatus) {
51
51
  const { options: childOptions } = this.childOptions;
52
52
  let options;
53
53
  if (this.frequencies?.length) {
54
+ const { frequenciesText } = this.productFrequencies;
54
55
  options = [
55
56
  ...([childOptions.find(option => option.value === 'optedOut')] || []),
56
57
  ...this.frequencies.map((value, ix) => ({
57
58
  value,
58
59
  text:
59
- this.frequenciesText && ix in this.frequenciesText
60
- ? this.frequenciesText[ix]
61
- : frequencyText(value, this.defaultFrequency)
60
+ frequenciesText && ix in frequenciesText ? frequenciesText[ix] : frequencyText(value, this.defaultFrequency)
62
61
  }))
63
62
  ];
64
63
  } else {
@@ -79,7 +78,9 @@ export const ConnectedOptinSelect = connect(
79
78
  (state, ownProps) => ({
80
79
  ...mapStateToPropsOptinStatus(state, ownProps),
81
80
  ...mapStateToProps(state, ownProps),
82
- ...configSelector(state, ownProps, 'frequencies')
81
+ frequencies:
82
+ // it's unclear whether the getFallbackValue result is ever used here, but leaving for backwards compatibility
83
+ makeProductFrequencyOptionsSelector(ownProps.product?.id)(state) || getFallbackValue(ownProps, 'frequencies')
83
84
  }),
84
85
  { productChangeFrequency, optoutProduct }
85
86
  )(OptinSelect);
@@ -1,11 +1,14 @@
1
1
  import { html, css } from 'lit-element';
2
2
  import {
3
3
  makeOptedinSelector,
4
- makeProductDefaultFrequencySelector,
4
+ makeProductSpecificDefaultFrequencySelector,
5
5
  makeProductPrepaidShipmentsOptedInSelector,
6
- makeProductFrequencySelector,
7
- configSelector,
8
- templatesSelector
6
+ makeProductFrequencyOptedInSelector,
7
+ getFallbackValue,
8
+ templatesSelector,
9
+ makeProductFrequenciesSelector,
10
+ makeProductDefaultFrequencySelector,
11
+ makeProductFrequencyOptionsSelector
9
12
  } from '../core/selectors';
10
13
  import { connect } from '../core/connect';
11
14
  import { subscribed } from '../core/props';
@@ -130,12 +133,16 @@ export class OptinStatus extends withProduct(TemplateElement) {
130
133
 
131
134
  export const mapStateToProps = (state, ownProps = {}) => ({
132
135
  subscribed: makeOptedinSelector(ownProps.product)(state),
133
- frequency: makeProductFrequencySelector(ownProps.product)(state),
134
- productDefaultFrequency: makeProductDefaultFrequencySelector((ownProps.product || {}).id)(state),
136
+ frequency: makeProductFrequencyOptedInSelector(ownProps.product)(state),
137
+ productDefaultFrequency: makeProductSpecificDefaultFrequencySelector((ownProps.product || {}).id)(state),
135
138
  prepaidShipmentsOptedIn: makeProductPrepaidShipmentsOptedInSelector(ownProps.product)(state),
136
- ...configSelector(state, ownProps, 'defaultFrequency'),
137
- ...configSelector(state, ownProps, 'frequencies'),
138
- ...templatesSelector(state, ownProps)
139
+ defaultFrequency:
140
+ makeProductDefaultFrequencySelector(ownProps.product?.id)(state) || getFallbackValue(ownProps, 'defaultFrequency'),
141
+ frequencies:
142
+ // it's unclear whether the getFallbackValue result is ever used here, but leaving for backwards compatibility
143
+ makeProductFrequencyOptionsSelector(ownProps.product?.id)(state) || getFallbackValue(ownProps, 'frequencies'),
144
+ ...templatesSelector(state, ownProps),
145
+ productFrequencies: makeProductFrequenciesSelector(ownProps.product)(state)
139
146
  });
140
147
 
141
148
  export const ConnectedOptinStatus = connect(mapStateToProps)(OptinStatus);
@@ -3,7 +3,7 @@ import { connect } from '../core/connect';
3
3
 
4
4
  import { withProduct } from '../core/resolveProperties';
5
5
  import { TemplateElement } from '../core/base';
6
- import { makeProductFrequencySelector } from '../core/selectors';
6
+ import { makeProductDefaultFrequencySelector, makeProductFrequencyOptedInSelector } from '../core/selectors';
7
7
  import { safeProductId } from '../core/utils';
8
8
 
9
9
  export class Price extends withProduct(TemplateElement) {
@@ -81,8 +81,8 @@ export class Price extends withProduct(TemplateElement) {
81
81
  }
82
82
  const mapStateToProps = (state, ownProps) => ({
83
83
  productPlans: state.productPlans,
84
- configDefaultFrequency: state.config?.defaultFrequency,
85
- frequency: makeProductFrequencySelector(ownProps.product)(state)
84
+ configDefaultFrequency: makeProductDefaultFrequencySelector(ownProps.product?.id)(state),
85
+ frequency: makeProductFrequencyOptedInSelector(ownProps.product)(state)
86
86
  });
87
87
 
88
88
  export default connect(mapStateToProps)(Price);
@@ -65,8 +65,12 @@ export class SelectFrequency extends withChildOptions(FrequencyStatus) {
65
65
  }
66
66
 
67
67
  // this runs for shopify selling plans translated to freq
68
- if (this.config?.frequencies?.length && result && this.config?.frequenciesEveryPeriod?.length) {
69
- return frequencyToSellingPlan(result, this.config);
68
+ if (
69
+ this.productFrequencies?.frequencies?.length &&
70
+ result &&
71
+ this.productFrequencies?.frequenciesEveryPeriod?.length
72
+ ) {
73
+ return frequencyToSellingPlan(result, this.productFrequencies);
70
74
  }
71
75
 
72
76
  return result;
@@ -90,10 +94,11 @@ export class SelectFrequency extends withChildOptions(FrequencyStatus) {
90
94
  if (this.frequencies?.length) {
91
95
  options = this.frequencies.map((value, ix) => {
92
96
  let text;
93
- if (this.config.frequenciesEveryPeriod && ix in this.config.frequenciesEveryPeriod) {
94
- text = frequencyText(this.config.frequenciesEveryPeriod[ix], defaultFrequency);
95
- } else if (this.frequenciesText && ix in this.frequenciesText) {
96
- text = this.frequenciesText[ix];
97
+ const { frequenciesEveryPeriod, frequenciesText } = this.productFrequencies;
98
+ if (frequenciesEveryPeriod && ix in frequenciesEveryPeriod) {
99
+ text = frequencyText(frequenciesEveryPeriod[ix], defaultFrequency);
100
+ } else if (frequenciesText && ix in frequenciesText) {
101
+ text = frequenciesText[ix];
97
102
  } else {
98
103
  text = frequencyText(value, this.defaultFrequency);
99
104
  }
@@ -194,50 +194,54 @@ export class TestWizard extends LitElement {
194
194
  const offer = document.querySelectorAll('og-offer')[ix];
195
195
  const productId = offer.product.id;
196
196
  offer.store.dispatch(
197
- actions.receiveOffer({
198
- in_stock: { [productId]: inStock },
199
- eligibility_groups: { [productId]: groups },
200
- result: 'success',
201
- autoship: { [productId]: autoship },
202
- module_view: { regular: '58a01e9aacbe40389b5c7325d79091bb' },
203
- modifiers: {},
204
- incentives_display: {
205
- '47c01e9aacbe40389b5c7325d79091aa': {
206
- field: 'sub_total',
207
- object: 'order',
208
- type: 'Discount Percent',
209
- value: 5
197
+ actions.receiveOffer(
198
+ {
199
+ in_stock: { [productId]: inStock },
200
+ eligibility_groups: { [productId]: groups },
201
+ result: 'success',
202
+ autoship: { [productId]: autoship },
203
+ module_view: { regular: '58a01e9aacbe40389b5c7325d79091bb' },
204
+ modifiers: {},
205
+ incentives_display: {
206
+ '47c01e9aacbe40389b5c7325d79091aa': {
207
+ field: 'sub_total',
208
+ object: 'order',
209
+ type: 'Discount Percent',
210
+ value: 5
211
+ },
212
+ e6534b9d877f41e586c37b7d8abc3a58: {
213
+ field: 'total_price',
214
+ object: 'item',
215
+ type: 'Discount Percent',
216
+ value: 5
217
+ },
218
+ f35e842710b24929922db4a529eecd40: {
219
+ field: 'total_price',
220
+ object: 'item',
221
+ type: 'Discount Percent',
222
+ value: 10
223
+ },
224
+ '5be321d7c17f4e18a757212b9a20bfcc': {
225
+ field: 'total_price',
226
+ object: 'item',
227
+ type: 'Discount Percent',
228
+ value: 1
229
+ }
210
230
  },
211
- e6534b9d877f41e586c37b7d8abc3a58: {
212
- field: 'total_price',
213
- object: 'item',
214
- type: 'Discount Percent',
215
- value: 5
216
- },
217
- f35e842710b24929922db4a529eecd40: {
218
- field: 'total_price',
219
- object: 'item',
220
- type: 'Discount Percent',
221
- value: 10
222
- },
223
- '5be321d7c17f4e18a757212b9a20bfcc': {
224
- field: 'total_price',
225
- object: 'item',
226
- type: 'Discount Percent',
227
- value: 1
231
+ incentives: {
232
+ [productId]: {
233
+ initial: ['5be321d7c17f4e18a757212b9a20bfcc'],
234
+ ongoing: [
235
+ 'e6534b9d877f41e586c37b7d8abc3a58',
236
+ '47c01e9aacbe40389b5c7325d79091aa',
237
+ 'f35e842710b24929922db4a529eecd40'
238
+ ]
239
+ }
228
240
  }
229
241
  },
230
- incentives: {
231
- [productId]: {
232
- initial: ['5be321d7c17f4e18a757212b9a20bfcc'],
233
- ongoing: [
234
- 'e6534b9d877f41e586c37b7d8abc3a58',
235
- '47c01e9aacbe40389b5c7325d79091aa',
236
- 'f35e842710b24929922db4a529eecd40'
237
- ]
238
- }
239
- }
240
- })
242
+ {},
243
+ productId
244
+ )
241
245
  );
242
246
  this.runTests();
243
247
  };
@@ -2,7 +2,12 @@ import { html } from 'lit-element';
2
2
  import { concludeUpsell, createIu } from '../core/actions';
3
3
  import { connect } from '../core/connect';
4
4
  import { auth, defaultFrequency } from '../core/props';
5
- import { makeOptedinSelector, makeProductFrequencySelector, configSelector } from '../core/selectors';
5
+ import {
6
+ makeOptedinSelector,
7
+ makeProductFrequencyOptedInSelector,
8
+ getFallbackValue,
9
+ makeProductDefaultFrequencySelector
10
+ } from '../core/selectors';
6
11
  import { withProduct } from '../core/resolveProperties';
7
12
  import { TemplateElement } from '../core/base';
8
13
 
@@ -102,8 +107,9 @@ export const mapStateToProps = (state, ownProps) => ({
102
107
  auth: state.auth,
103
108
  offerId: state.offerId,
104
109
  subscribed: makeOptedinSelector(ownProps.product)(state),
105
- frequency: makeProductFrequencySelector(ownProps.product)(state),
106
- ...configSelector(state, ownProps, 'defaultFrequency'),
110
+ frequency: makeProductFrequencyOptedInSelector(ownProps.product)(state),
111
+ defaultFrequency:
112
+ makeProductDefaultFrequencySelector(ownProps.product?.id)(state) || getFallbackValue(ownProps, 'defaultFrequency'),
107
113
  nextUpcomingOrder: state.previewUpsellOffer ? { public_id: 'preview-order-id' } : state.nextUpcomingOrder,
108
114
  isPreview: state.previewUpsellOffer
109
115
  });
@@ -369,22 +369,3 @@ describe('multi-currency', () => {
369
369
  assertOfferShown(element);
370
370
  });
371
371
  });
372
-
373
- describe('product specific frequencies', () => {
374
- it('should hide the offer when on cart', async () => {
375
- const element = await getOfferElement({
376
- hasProductSpecificFrequencies: true
377
- });
378
- element.isCart = true;
379
- await element.updateComplete;
380
-
381
- assertOfferHidden(element);
382
- });
383
-
384
- it('should show the offer when not on cart', async () => {
385
- const element = await getOfferElement({
386
- hasProductSpecificFrequencies: true
387
- });
388
- assertOfferShown(element);
389
- });
390
- });
@@ -29,10 +29,23 @@ describe('OptinStatus', () => {
29
29
  describe('mapStateToProps', () => {
30
30
  it('should pick defaultFrequency from config', () => {
31
31
  expect(
32
- mapStateToProps({
33
- config: { defaultFrequency: 'foo from config' },
34
- locale: { defaultFrequency: 'foo from locale' }
35
- })
32
+ mapStateToProps(
33
+ {
34
+ config: {
35
+ productFrequencies: {
36
+ 123: {
37
+ defaultFrequency: 'foo from config'
38
+ }
39
+ }
40
+ },
41
+ locale: { defaultFrequency: 'foo from locale' }
42
+ },
43
+ {
44
+ product: {
45
+ id: '123'
46
+ }
47
+ }
48
+ )
36
49
  ).toEqual(jasmine.objectContaining({ defaultFrequency: 'foo from config' }));
37
50
  });
38
51
 
@@ -19,7 +19,8 @@ import {
19
19
  receiveCreateOneTime,
20
20
  createIu,
21
21
  requestConvertOneTimeToSubscription,
22
- receiveConvertOneTime
22
+ receiveConvertOneTime,
23
+ productChangePrepaidShipments
23
24
  } from '../actions';
24
25
  import * as constants from '../constants';
25
26
  import { api } from '../api';
@@ -246,6 +247,51 @@ describe('redux actions', function () {
246
247
  expect(dispatch.calls.argsFor(1)[0]).toEqual(unauthorized(new Error('some reason')));
247
248
  });
248
249
  });
250
+
251
+ describe('actions.productChangePrepaidShipments', () => {
252
+ function changePrepaidShipments(prepaidShipments) {
253
+ const getState = jasmine.createSpy('getState').and.returnValue({
254
+ config: {
255
+ prepaidSellingPlans: {
256
+ 'yum prepaid id': [
257
+ { numberShipments: 3, sellingPlan: 'yum prepaid selling plan id 1' },
258
+ {
259
+ numberShipments: 4,
260
+ sellingPlan: 'yum prepaid selling plan id 2'
261
+ }
262
+ ]
263
+ },
264
+ productFrequencies: {
265
+ 'yum prepaid id': {
266
+ frequencies: ['yum selling plan id 1']
267
+ }
268
+ }
269
+ }
270
+ });
271
+ const dispatch = jasmine.createSpy('dispatch');
272
+ productChangePrepaidShipments(
273
+ {
274
+ id: 'yum prepaid id'
275
+ },
276
+ prepaidShipments,
277
+ {}
278
+ )(dispatch, getState);
279
+
280
+ return {
281
+ dispatchedFrequency: dispatch.calls.argsFor(0)[0]?.payload.frequency
282
+ };
283
+ }
284
+
285
+ it('sets frequency to the corresponding selling plan', () => {
286
+ const { dispatchedFrequency } = changePrepaidShipments(4);
287
+ expect(dispatchedFrequency).toEqual('yum prepaid selling plan id 2');
288
+ });
289
+
290
+ it('sets frequency to the first frequency when prepaidShipments is null', () => {
291
+ const { dispatchedFrequency } = changePrepaidShipments(null);
292
+ expect(dispatchedFrequency).toEqual('yum selling plan id 1');
293
+ });
294
+ });
249
295
  });
250
296
 
251
297
  describe('actions.iu', () => {
@@ -10,84 +10,7 @@ class MockElement extends TemplateElement {
10
10
 
11
11
  customElements.define('og-test-element', MockElement);
12
12
  describe('TemplateElement', () => {
13
- describe('getOption', () => {
14
- it('should get option from attribute', () => {
15
- const el = new MockElement();
16
- el.setAttribute('foo', 'bar');
17
- expect(el.getOption('foo')).toEqual('bar');
18
- });
19
-
20
- it('should return undefined given element does not have attribute', () => {
21
- const el = new MockElement();
22
- el.setAttribute('yum', 'egg');
23
- expect(el.getOption('clam')).toBeUndefined();
24
- });
25
-
26
- it('should return boolean given element has attribute with true string', () => {
27
- [
28
- ['one', 'true'],
29
- ['two', 'True']
30
- ].forEach(([attrName, attrValue]) => {
31
- const el = new MockElement();
32
- el.setAttribute(attrName, attrValue);
33
- expect(el.getOption(attrName)).toBe(true);
34
- });
35
- });
36
-
37
- it('should return boolean given element has attribute with false string', () => {
38
- [
39
- ['three', 'false'],
40
- ['four', 'False']
41
- ].forEach(([attrName, attrValue]) => {
42
- const el = new MockElement();
43
- el.setAttribute(attrName, attrValue);
44
- expect(el.getOption(attrName)).toBe(false);
45
- });
46
- });
47
-
48
- it('should get option from attribute in kebabCase', () => {
49
- const el = new MockElement();
50
- el.setAttribute('foo-bar', 'bar');
51
- expect(el.getOption('fooBar')).toEqual('bar');
52
- });
53
-
54
- it('should get option from config', () => {
55
- const el = new MockElement();
56
- el.config = { fooBar: 'bar' };
57
- expect(el.getOption('fooBar')).toEqual('bar');
58
- });
59
-
60
- it('should get option from template.config', () => {
61
- const el = new MockElement();
62
- el.template = { config: { fooBar: 'bar' } };
63
- expect(el.getOption('fooBar')).toEqual('bar');
64
- });
65
-
66
- it('should template.config take precedence over config', () => {
67
- const el = new MockElement();
68
- el.config = { fooBar: 'baz' };
69
- el.template = { config: { fooBar: 'bar' } };
70
- expect(el.getOption('fooBar')).toEqual('bar');
71
- });
72
-
73
- it('should attribute take precedence over template.config', () => {
74
- const el = new MockElement();
75
- el.setAttribute('foo-bar', 'foo');
76
- el.config = { fooBar: 'baz' };
77
- el.template = { config: { fooBar: 'bar' } };
78
- expect(el.getOption('fooBar')).toEqual('foo');
79
- });
80
- });
81
-
82
13
  describe('applyTemplate', () => {
83
- it('should attribute take precedence over template.config', () => {
84
- const el = new MockElement();
85
- el.setAttribute('foo-bar', 'foo');
86
- el.config = { fooBar: 'baz' };
87
- el.template = { config: { fooBar: 'bar' } };
88
- expect(el.getOption('fooBar')).toEqual('foo');
89
- });
90
-
91
14
  it('should only set innerHTML if change from prev', () => {
92
15
  const el = new MockElement();
93
16
  /* eslint no-underscore-dangle: ["error", { "allow": ["_templateMarkup"] }] */
@@ -222,7 +222,6 @@ describe('experiments.shopify', () => {
222
222
  };
223
223
 
224
224
  const expectedNoModifiedProductPlans = {
225
- 9102227276060: undefined,
226
225
  48026227736860: [
227
226
  {
228
227
  frequency: '690446729500',
@@ -326,7 +325,6 @@ describe('experiments.shopify', () => {
326
325
  await new Promise(r => setTimeout(r, 10));
327
326
 
328
327
  const expectedVariantAProductPlans = {
329
- 9102227276060: undefined,
330
328
  48026227736860: [
331
329
  {
332
330
  frequency: '690446729500',
@@ -386,7 +384,6 @@ describe('experiments.shopify', () => {
386
384
  await new Promise(r => setTimeout(r, 10));
387
385
 
388
386
  const expectedVariantBProductPlans = {
389
- 9102227276060: undefined,
390
387
  48026227736860: [
391
388
  {
392
389
  frequency: '690489590044',
@@ -4,6 +4,7 @@ import { environment, merchantId, offer, sessionId } from '../reducer';
4
4
  import { requestOffer } from '../actions';
5
5
  import { createStore, combineReducers, applyMiddleware } from 'redux';
6
6
  import { FETCH_RESPONSE_ERROR } from '../constants';
7
+ import thunk from 'redux-thunk';
7
8
 
8
9
  const mockOfferResponse = (productId, inStock = true, autoship = true, defaultFrequency) => {
9
10
  return Promise.resolve({
@@ -44,7 +45,7 @@ describe('offerRequest', () => {
44
45
  sessionId: 'x.y.z',
45
46
  lastError: null
46
47
  },
47
- applyMiddleware(offerRequestMiddleware)
48
+ applyMiddleware(offerRequestMiddleware, thunk)
48
49
  );
49
50
  });
50
51