@capillarytech/creatives-library 7.17.44 → 7.17.46-alpha.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.
@@ -183,7 +183,7 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
183
183
  onVisibleChange={this.togglePopoverVisibility}
184
184
  content={<div>
185
185
  <Spin tip="Getting tags..." spinning={this.props.loading}>
186
- <Search style={{ marginBottom: 8, width: '250px'}} placeholder="Search" onChange={this.onChange} />
186
+ <Search style={{ marginBottom: 8, width: '250px'}} placeholder={this.props.intl.formatMessage(messages.searchText)} onChange={this.onChange} />
187
187
  {this.props.moduleFilterEnabled ? <CapSelect getPopupContainer={(triggerNode) => triggerNode.parentNode} style={{width: '250px', marginBottom: '16px', minWidth: 'initial', display: 'inherit'}} onChange={this.props.onContextChange} defaultValue="All" options={options}>
188
188
  </CapSelect> : ''}
189
189
  <Tree
@@ -34,4 +34,8 @@ export default defineMessages({
34
34
  id: 'creatives.components.CapTagList.loyalty',
35
35
  defaultMessage: 'Loyalty',
36
36
  },
37
+ "searchText": {
38
+ id: 'creatives.components.CapTagList.searchText',
39
+ defaultMessage: 'Search',
40
+ },
37
41
  });
@@ -24,6 +24,7 @@ import EDMEditor from "../../components/Edmeditor";
24
24
  import CustomPopOver from '../../components/CustomPopOver';
25
25
  import './_formBuilder.scss';
26
26
  import {updateCharCount, checkUnicode} from "../../utils/smsCharCountV2";
27
+ import globalMessages from '../../v2Containers/Cap/messages';
27
28
  import messages from './messages';
28
29
  const TabPane = Tabs.TabPane;
29
30
  const {Column} = Table;
@@ -1516,8 +1517,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1516
1517
  this.setState({errorData: formData});
1517
1518
  } else {
1518
1519
  const tempTab = ifError ? currentTab : this.state.currentTab;
1519
- const version = `Version ${this.state.currentTab}`;
1520
- formData[tabCount].name = `Copy of ${formData[tempTab - 1].name ? formData[tempTab - 1].name : version}`;
1520
+ const version = `${this.props.intl.formatMessage(messages.version)} ${this.state.currentTab}`;
1521
+ formData[tabCount].name = `${this.props?.intl?.formatMessage(globalMessages.copyOf)} ${formData[tempTab - 1].name ? formData[tempTab - 1].name : version}`;
1521
1522
  formData[tabCount].base = false;
1522
1523
  const initialTab = this.state.currentTab;
1523
1524
  this.setState({formData, tabCount: tabCount + 1, currentTab: tabCount + 1, tabKey: formData[tabCount].tabKey}, () => {
@@ -54,4 +54,8 @@ export default defineMessages({
54
54
  id: 'creatives.components.FormBuilder.ok',
55
55
  defaultMessage: 'Ok',
56
56
  },
57
+ Version: {
58
+ id: 'creatives.components.FormBuilder.version',
59
+ defaultMessage: 'Version',
60
+ },
57
61
  });
@@ -7,6 +7,8 @@ export const TRAI_DLT = 'TRAI_DLT';
7
7
  export const CARD_BASED_SCOPE = 'CARD_BASED_SCOPE';
8
8
  export const HOSPITALITY_BASED_SCOPE = 'HOSPITALITY_BASED_SCOPE';
9
9
  export const REGISTRATION_CUSTOM_FIELD = 'Registration custom fields';
10
+ export const GIFT_CARDS = 'GIFT_CARDS';
11
+ export const PROMO_ENGINE = 'PROMO_ENGINE';
10
12
  export const CUSTOM_TAG = 'CustomTagMessage';
11
13
  export const CUSTOMER_EXTENDED_FIELD = 'Customer extended fields';
12
14
  export const EXTENDED_TAG = 'ExtendedTagMessage';
@@ -43,5 +45,29 @@ export const HOSPITALITY_RELATED_TAGS = [
43
45
  "email",
44
46
  "resID_Source",
45
47
  ];
48
+ export const GIFT_VOUCHER_RELATED_TAGS = [
49
+ "gift_voucher",
50
+ "gift_voucher_expiry_date.FORMAT_1",
51
+ "gift_voucher_expiry_date.FORMAT_2",
52
+ "gift_voucher_expiry_date.FORMAT_3",
53
+ "gift_voucher_expiry_date.FORMAT_4",
54
+ "gift_voucher_expiry_date.FORMAT_5",
55
+ "gift_voucher_expiry_date.FORMAT_6",
56
+ "gift_voucher_expiry_date.FORMAT_7",
57
+ "gift_voucher_expiry_date.FORMAT_8",
58
+ "gift_voucher_expiry_date",
59
+ ];
60
+ export const PROMO_ENGINE_RELATED_TAGS = [
61
+ "promotion",
62
+ "promotion_expiry_date.FORMAT_1",
63
+ "promotion_expiry_date.FORMAT_2",
64
+ "promotion_expiry_date.FORMAT_3",
65
+ "promotion_expiry_date.FORMAT_4",
66
+ "promotion_expiry_date.FORMAT_5",
67
+ "promotion_expiry_date.FORMAT_6",
68
+ "promotion_expiry_date.FORMAT_7",
69
+ "promotion_expiry_date.FORMAT_8",
70
+ "promotion_expiry_date",
71
+ ];
46
72
 
47
73
  export const CUSTOMER_BARCODE_TAG = "customer_barcode";
@@ -336,7 +336,7 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
336
336
  <CapInput
337
337
  className="search-text"
338
338
  style={{width: '210px'}}
339
- placeholder="Search"
339
+ placeholder={this.props.intl.formatMessage(messages.searchText)}
340
340
  prefix={<i className="material-icons" style={{color: '#707070', fontSize: '16px'}}>search</i>}
341
341
  value={this.state.searchText}
342
342
  onChange={(e) => this.searchAsset(e.target.value)}
@@ -86,4 +86,8 @@ export default defineMessages({
86
86
  id: 'creatives.containers.Assets.Gallery.assetDeleteFailed',
87
87
  defaultMessage: 'Image deletion failed.',
88
88
  },
89
+ searchText: {
90
+ id: 'creatives.components.CapTagList.searchText',
91
+ defaultMessage: 'Search',
92
+ },
89
93
  });
@@ -3104,7 +3104,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
3104
3104
  <CapInput
3105
3105
  className="search-text"
3106
3106
  style={{width: '210px'}}
3107
- placeholder="Search"
3107
+ placeholder={this.props.intl.formatMessage(messages.searchText)}
3108
3108
  prefix={<i className="material-icons" style={{color: '#707070', fontSize: '16px'}}>search</i>}
3109
3109
  value={this.state.searchText}
3110
3110
  onChange={(e) => this.searchAsset(e.target.value)}
@@ -866,7 +866,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
866
866
  duplicateTemplate(template) {
867
867
 
868
868
  const duplicateObj = _.cloneDeep(template);
869
- duplicateObj.name = `Copy of ${template.name} ${moment().format('MM-DD-YYYY HH:mm:ss')}`;
869
+ duplicateObj.name = `${this.props.intl.formatMessage(messages.copyOf)} ${template.name} ${moment().format('MM-DD-YYYY HH:mm:ss')}`;
870
870
  delete duplicateObj._id;
871
871
  if (this.state.channel.toLowerCase() === "sms") {
872
872
  this.props.smsActions.createTemplate(duplicateObj);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.17.44",
4
+ "version": "7.17.46-alpha.0",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/utils/common.js CHANGED
@@ -7,12 +7,16 @@ import {
7
7
  CARD_BASED_SCOPE,
8
8
  HOSPITALITY_RELATED_TAGS,
9
9
  HOSPITALITY_BASED_SCOPE,
10
+ GIFT_CARDS,
11
+ PROMO_ENGINE,
10
12
  EXTENDED_TAG,
11
13
  CUSTOMER_EXTENDED_FIELD,
12
14
  CUSTOM_TAG,
13
15
  REGISTRATION_CUSTOM_FIELD,
14
16
  JP_LOCALE_HIDE_FEATURE,
15
17
  ENABLE_CUSTOMER_BARCODE_TAG,
18
+ PROMO_ENGINE_RELATED_TAGS,
19
+ GIFT_VOUCHER_RELATED_TAGS,
16
20
  } from '../containers/App/constants';
17
21
  import { apiMessageFormatHandler } from './commonUtils';
18
22
 
@@ -66,7 +70,15 @@ export const hasHospitalityBasedScope = Auth.hasFeatureAccess.bind(
66
70
  null,
67
71
  HOSPITALITY_BASED_SCOPE,
68
72
  );
73
+ export const hasPromoFeature = Auth.hasFeatureAccess.bind(
74
+ null,
75
+ PROMO_ENGINE,
76
+ );
69
77
 
78
+ export const hasGiftVoucherFeature = Auth.hasFeatureAccess.bind(
79
+ null,
80
+ GIFT_CARDS,
81
+ );
70
82
  export const hasJPLocaleHideFeatureEnabled = Auth.hasFeatureAccess.bind(
71
83
  null,
72
84
  JP_LOCALE_HIDE_FEATURE,
@@ -85,16 +97,25 @@ export const filterTags = (tagsToFilter, tagsList) => tagsList?.filter(
85
97
  export function getTreeStructuredTags({tagsList, userLocale = 'en', offerDetails = [], disableTagsDetails = {}}) {
86
98
  const mainTags = {};
87
99
  const { disableRelatedTags, childTagsToDisable, parentTagstoDisable} = disableTagsDetails;
100
+ const excludedTagList = [];
88
101
 
89
- let clonedTags = tagsList;
90
102
  if (!hasCardBasedScope()) {
91
- //filtering CARD_RELATED_TAGS if org does not have CARD_BASED_SCOPE feature enabled
92
- clonedTags = filterTags(CARD_RELATED_TAGS, tagsList);
103
+ excludedTagList.push(CARD_RELATED_TAGS);
93
104
  }
105
+
94
106
  if (!hasHospitalityBasedScope()) {
95
- //filtering HOSPITALITY_RELATED_TAGS if org does not have HOSPITALITY_BASED_SCOPE feature enabled
96
- clonedTags = filterTags(HOSPITALITY_RELATED_TAGS, tagsList);
107
+ excludedTagList.push(HOSPITALITY_RELATED_TAGS);
108
+ }
109
+
110
+ if (!hasPromoFeature()) {
111
+ excludedTagList.push(PROMO_ENGINE_RELATED_TAGS);
97
112
  }
113
+
114
+ if (!hasGiftVoucherFeature()) {
115
+ excludedTagList.push(GIFT_VOUCHER_RELATED_TAGS);
116
+ }
117
+ const clonedTags = filterTags(excludedTagList, tagsList);
118
+
98
119
  _.forEach(clonedTags, (temp) => {
99
120
  const tag = temp.definition;
100
121
  if (!tag['tag-header']) { //if tag doesn't have subtag(s), which means this tag itself is tag and not a tag header.
@@ -294,8 +315,8 @@ export const isTraiDLTEnable = (isFullMode, smsRegister) => {
294
315
  return isTraiDltFeature;
295
316
  };
296
317
 
297
-
298
- export const intlKeyGenerator = (value = "") => String(value).replace(/[^a-zA-Z0-9_]/g, "").toLowerCase();
318
+ //Input: " Spaces In Input "---> Output: "spaces_in_input"
319
+ export const intlKeyGenerator = (value = "") => String(value).replace(/[^a-zA-Z0-9_ ]/g, "").replace(/ /g, "_").toLowerCase();
299
320
 
300
321
  export const handleInjectedData = (data, scope) => {
301
322
  let tagType;
@@ -307,6 +328,7 @@ export const handleInjectedData = (data, scope) => {
307
328
  } else if (tag?.name === CUSTOMER_EXTENDED_FIELD) {
308
329
  tagType = EXTENDED_TAG;
309
330
  }
331
+
310
332
  if (tag?.name) {
311
333
  const name = tag.name;
312
334
  const key = intlKeyGenerator(name);
@@ -350,4 +372,4 @@ export const handleInjectedData = (data, scope) => {
350
372
 
351
373
  export const handlePreviewInNewTab = (previewUrl) => {
352
374
  window.open(previewUrl, '_blank');
353
- }
375
+ };
@@ -51,7 +51,7 @@ describe("handleInjectedData", () => {
51
51
  const result = handleInjectedData(data, "scope");
52
52
  const intlKey = intlKeyGenerator("scope");
53
53
  expect(intlKey).toEqual('scope');
54
- expect(result.tag1.name).toEqual(<FormattedMessage defaultMessage="Registration Fields" id="scope.registrationfields" values={{}} />);
54
+ expect(result.tag1.name).toEqual(<FormattedMessage defaultMessage="Registration Fields" id="scope.registration_fields" values={{}} />);
55
55
  });
56
56
 
57
57
  it("adds tagType for Registration custom fields", () => {
@@ -65,7 +65,7 @@ describe("handleInjectedData", () => {
65
65
  const intlKey = intlKeyGenerator();
66
66
  expect(intlKey).toEqual('');
67
67
  expect(result.tag1.name).toEqual(
68
- <FormattedMessage defaultMessage="Registration custom fields" id="scope.registrationcustomfields_name.CustomTagMessage" values={{}} />
68
+ <FormattedMessage defaultMessage="Registration custom fields" id="scope.registration_custom_fields_name.CustomTagMessage" values={{}} />
69
69
  );
70
70
  });
71
71
 
@@ -79,7 +79,7 @@ describe("handleInjectedData", () => {
79
79
  const result = handleInjectedData(data, "scope");
80
80
 
81
81
  expect(result.tag1.name).toEqual(
82
- <FormattedMessage defaultMessage="Customer extended fields" id="scope.customerextendedfields_name.ExtendedTagMessage" values={{}} />
82
+ <FormattedMessage defaultMessage="Customer extended fields" id="scope.customer_extended_fields_name.ExtendedTagMessage" values={{}} />
83
83
  );
84
84
  });
85
85
  it("adds tagType for Customer extended fields fields", () => {
@@ -157,7 +157,7 @@ describe("handleInjectedData", () => {
157
157
  const result = handleInjectedData(data, "scope");
158
158
 
159
159
  expect(result.tag1.subtags.subtag1.desc).toEqual(
160
- <FormattedMessage defaultMessage="Enter your first name" id="scope.enteryourfirstname" values={{}} />
160
+ <FormattedMessage defaultMessage="Enter your first name" id="scope.enter_your_first_name" values={{}} />
161
161
  );
162
162
  });
163
163
  it("replaces subtag name desc with intl key", () => {
@@ -175,7 +175,7 @@ describe("handleInjectedData", () => {
175
175
  const result = handleInjectedData(data, "scope");
176
176
 
177
177
  expect(result.tag1.subtags.subtag1.desc).toEqual(
178
- <FormattedMessage defaultMessage="Enter your first name" id="scope.enteryourfirstname" values={{}} />
178
+ <FormattedMessage defaultMessage="Enter your first name" id="scope.enter_your_first_name" values={{}} />
179
179
  );
180
180
  });
181
181
  });
@@ -1669,7 +1669,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1669
1669
  } else {
1670
1670
  const tempTab = ifError ? currentTab : this.state.currentTab;
1671
1671
  const version = `Version ${this.state.currentTab}`;
1672
- formData[tabCount].name = `Copy of ${formData[tempTab - 1].name ? formData[tempTab - 1].name : version}`;
1672
+ formData[tabCount].name = `${this.props?.intl?.formatMessage(globalMessages.copyOf)} ${formData[tempTab - 1].name ? formData[tempTab - 1].name : version}`;
1673
1673
  formData[tabCount].base = false;
1674
1674
  const initialTab = this.state.currentTab;
1675
1675
  this.setState({formData, tabCount: tabCount + 1, currentTab: tabCount + 1, tabKey: formData[tabCount].tabKey}, () => {
@@ -201,5 +201,9 @@ export default defineMessages({
201
201
  id: `creatives.componentsV2.unbalanacedCurlyBraces`,
202
202
  defaultMessage: 'Invalid label, please close all curly braces'
203
203
  },
204
+ "copyOf": {
205
+ id: 'creatives.componentsV2.copyOf',
206
+ defaultMessage: 'Copy of',
207
+ },
204
208
  });
205
209
 
@@ -61,8 +61,9 @@ export function SlideBoxHeader(props) {
61
61
  email: <FormattedMessage {...messages.emailHeader} />,
62
62
  mobilepush: <FormattedMessage {...messages.pushNotificationHeader} />,
63
63
  wechat: <FormattedMessage {...messages.wechat} />,
64
- no_communication: 'NO_COMMUNICATION',
65
- ftp: 'FTP',
64
+ line: <FormattedMessage {...messages.lineHeader} />,
65
+ no_communication: <FormattedMessage {...messages.noCommunication} />,
66
+ ftp: <FormattedMessage {...messages.ftp} />,
66
67
  whatsapp: <FormattedMessage {...messages.whatsappTemplate} />,
67
68
  rcs: <FormattedMessage {...messages.rcsCreative} />,
68
69
  zalo: <FormattedMessage {...messages.zaloTemplate} />,
@@ -341,5 +341,13 @@ export default defineMessages({
341
341
  "wechat": {
342
342
  id: `${scope}.wechat`,
343
343
  defaultMessage: `Wechat`,
344
- }
344
+ },
345
+ "ftp": {
346
+ id: `${scope}.ftp`,
347
+ defaultMessage: `FTP`,
348
+ },
349
+ "noCommunication": {
350
+ id: `${scope}.noCommunication`,
351
+ defaultMessage: `NO_COMMUNICATION`,
352
+ },
345
353
  });
@@ -98,7 +98,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
98
98
  //Form tags object with tag headers
99
99
  _.forEach(tagsList, (temp) => {
100
100
  const tag = temp.definition;
101
- const { locale : userLocale } = this.props?.intl || {};
101
+ const { locale: userLocale } = this.props?.intl || {};
102
102
  if (!tag['tag-header']) {
103
103
  mainTags[tag.value] = {
104
104
  "name": tag?.label[userLocale] ? tag?.label[userLocale] : tag?.label?.en,
@@ -117,7 +117,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
117
117
  });
118
118
 
119
119
  const mainTagsCloned = _.cloneDeep(mainTags);
120
- //Insert subtags in tag headers and reomve them from top level
120
+ //Insert subtags in tag headers and remove them from top level
121
121
  const result = {};
122
122
  _.forEach(mainTagsCloned, (tag, key) => {
123
123
  if (tag['tag-header']) {
@@ -623,13 +623,24 @@
623
623
  margin: auto;
624
624
  }
625
625
  }
626
- .whatsapp-rcs-template-name, .zalo-template-name {
626
+ .whatsapp-rcs-template-name {
627
627
  max-width: 170px;
628
628
  overflow: hidden;
629
629
  white-space: nowrap;
630
630
  text-overflow: ellipsis;
631
631
  }
632
632
 
633
+ .zalo-template-name{
634
+ max-width: 170px;
635
+ overflow: hidden;
636
+ white-space: nowrap;
637
+ text-overflow: ellipsis;
638
+ color: $CAP_G01;
639
+ font-size: $FONT_SIZE_M;
640
+ font-weight: $FONT_WEIGHT_MEDIUM;
641
+ line-height: normal;
642
+ }
643
+
633
644
  .zalo-view-tooltip {
634
645
  padding: $CAP_SPACE_06 $CAP_SPACE_12;
635
646
  }
@@ -108,7 +108,8 @@ import {
108
108
  import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
109
109
  import { getWhatsappContent, getWhatsappStatus, getWhatsappCategory, getWhatsappCta } from '../Whatsapp/utils';
110
110
  import { getRCSContent } from '../Rcs/utils';
111
- import zaloMessages from '../Zalo/messages'
111
+ import zaloMessages from '../Zalo/messages';
112
+ import globalMessages from '../../v2Containers/Cap/messages';
112
113
  import { handlePreviewInNewTab } from '../../utils/common';
113
114
 
114
115
  import { MOBILE_PUSH, WECHAT, SMS, EMAIL, EBILL, LINE, VIBER, FACEBOOK, WHATSAPP, RCS, ZALO } from '../CreativesContainer/constants';
@@ -1202,7 +1203,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1202
1203
  } = template;
1203
1204
  templateData.title = (
1204
1205
  <CapRow>
1205
- <CapLabel label='label16' className="zalo-template-name">
1206
+ <CapLabel className="zalo-template-name">
1206
1207
  {templateId}
1207
1208
  </CapLabel>
1208
1209
  <CapRow
@@ -1755,7 +1756,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1755
1756
 
1756
1757
  duplicateTemplate(template) {
1757
1758
  const duplicateObj = cloneDeep(template);
1758
- duplicateObj.name = `${this.props.intl.formatMessage(messages.copyOf)} ${template?.name} ${moment().format('MM-DD-YYYY HH:mm:ss')}`;
1759
+ duplicateObj.name = `${this.props.intl.formatMessage(globalMessages.copyOf)} ${template?.name} ${moment().format('MM-DD-YYYY HH:mm:ss')}`;
1759
1760
  delete duplicateObj._id;
1760
1761
 
1761
1762
  if (this.state.channel.toLowerCase() === "mobilepush") {
@@ -267,7 +267,6 @@ exports[`Test Templates container Should render temlates when Zalo templates are
267
267
  "title": <CapRow>
268
268
  <CapLabel
269
269
  className="zalo-template-name"
270
- label="label16"
271
270
  type="label1"
272
271
  >
273
272
 
@@ -357,7 +356,6 @@ exports[`Test Templates container Should render temlates when Zalo templates are
357
356
  "title": <CapRow>
358
357
  <CapLabel
359
358
  className="zalo-template-name"
360
- label="label16"
361
359
  type="label1"
362
360
  >
363
361
 
@@ -0,0 +1,52 @@
1
+ import { fromJS } from "immutable";
2
+ import { makeSelectZalo, selectZaloDomain } from "../selectors";
3
+ import { zaloTemplateInfoData } from "./mockData";
4
+
5
+ describe("makeSelectZalo", () => {
6
+ it("returns the expected object with default values when substate is empty", () => {
7
+ // Arrange
8
+ const state = fromJS({ zalo: {} });
9
+ const expected = {
10
+ zaloTemplateInfoStatus: undefined,
11
+ zaloTemplateInfoValue: undefined,
12
+ zaloTemplateInfoError: undefined,
13
+ zaloTemplatePreviewData: undefined,
14
+ };
15
+ const selector = makeSelectZalo();
16
+
17
+ // Act
18
+ const result = selector(state);
19
+
20
+ // Assert
21
+ expect(result).toEqual(expected);
22
+ });
23
+
24
+ it("returns the expected object when substate has values", () => {
25
+ // Arrange
26
+ const state = fromJS({
27
+ zalo: zaloTemplateInfoData,
28
+ });
29
+ const expected = {
30
+ zaloTemplateInfoStatus: "success",
31
+ zaloTemplateInfoValue: fromJS(zaloTemplateInfoData.zaloTemplateInfoValue),
32
+ zaloTemplateInfoError: null,
33
+ zaloTemplatePreviewData: undefined,
34
+ };
35
+ const selector = makeSelectZalo();
36
+
37
+ // Act
38
+ const result = selector(state);
39
+
40
+ // Assert
41
+ expect(result).toEqual(expected);
42
+ });
43
+
44
+ it("returns the expected object with default values when substate is empty", () => {
45
+ // Arrange
46
+ const state = fromJS({ zalo: {} });
47
+ const expected = fromJS({});
48
+ const result = selectZaloDomain(state);
49
+ // Assert
50
+ expect(result).toEqual(expected);
51
+ });
52
+ });