@capillarytech/creatives-library 8.0.309 → 8.0.310
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants/unified.js +1 -5
- package/initialState.js +2 -0
- package/package.json +1 -1
- package/services/api.js +0 -17
- package/services/tests/api.test.js +0 -85
- package/utils/common.js +8 -5
- package/utils/commonUtils.js +93 -46
- package/utils/tagValidations.js +223 -83
- package/utils/tests/commonUtil.test.js +124 -316
- package/utils/tests/tagValidations.test.js +358 -441
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +49 -78
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +34 -134
- package/v2Components/CommonTestAndPreview/actions.js +0 -10
- package/v2Components/CommonTestAndPreview/constants.js +1 -15
- package/v2Components/CommonTestAndPreview/index.js +19 -80
- package/v2Components/CommonTestAndPreview/messages.js +0 -94
- package/v2Components/CommonTestAndPreview/reducer.js +0 -10
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +0 -53
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -31
- package/v2Components/CommonTestAndPreview/tests/index.test.js +0 -36
- package/v2Components/CommonTestAndPreview/tests/reducer.test.js +0 -71
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +0 -377
- package/v2Components/CommonTestAndPreview/tests/selectors.test.js +0 -17
- package/v2Components/ErrorInfoNote/index.js +5 -2
- package/v2Components/FormBuilder/index.js +203 -137
- package/v2Components/FormBuilder/messages.js +8 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
- package/v2Containers/Cap/mockData.js +14 -0
- package/v2Containers/Cap/reducer.js +55 -3
- package/v2Containers/Cap/tests/reducer.test.js +102 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -5
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -13
- package/v2Containers/CreativesContainer/constants.js +0 -6
- package/v2Containers/CreativesContainer/index.js +7 -47
- package/v2Containers/Email/index.js +5 -1
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +70 -23
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +120 -20
- package/v2Containers/FTP/index.js +51 -2
- package/v2Containers/FTP/messages.js +4 -0
- package/v2Containers/InApp/index.js +107 -35
- package/v2Containers/InApp/tests/index.test.js +6 -17
- package/v2Containers/InappAdvance/index.js +112 -4
- package/v2Containers/InappAdvance/tests/index.test.js +0 -2
- package/v2Containers/Line/Container/Text/index.js +1 -0
- package/v2Containers/MobilePush/Create/index.js +19 -59
- package/v2Containers/MobilePush/Edit/index.js +20 -48
- package/v2Containers/MobilePushNew/index.js +32 -12
- package/v2Containers/MobilepushWrapper/index.js +1 -3
- package/v2Containers/Rcs/index.js +37 -12
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +1276 -1408
- package/v2Containers/Sms/Create/index.js +3 -39
- package/v2Containers/Sms/Create/messages.js +0 -4
- package/v2Containers/Sms/Edit/index.js +3 -35
- package/v2Containers/Sms/commonMethods.js +6 -3
- package/v2Containers/SmsTrai/Edit/index.js +47 -11
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +294 -327
- package/v2Containers/SmsWrapper/index.js +0 -2
- package/v2Containers/TemplatesV2/index.js +13 -28
- package/v2Containers/Viber/index.js +1 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
- package/v2Containers/WebPush/Create/index.js +2 -2
- package/v2Containers/WebPush/Create/utils/validation.js +8 -17
- package/v2Containers/WebPush/Create/utils/validation.test.js +24 -44
- package/v2Containers/Whatsapp/index.js +17 -9
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +4872 -5246
- package/v2Containers/Zalo/index.js +11 -3
- package/v2Components/CommonTestAndPreview/AddTestCustomer.js +0 -42
- package/v2Components/CommonTestAndPreview/CustomerCreationModal.js +0 -284
- package/v2Components/CommonTestAndPreview/ExistingCustomerModal.js +0 -72
- package/v2Components/CommonTestAndPreview/tests/AddTestCustomer.test.js +0 -66
- package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -657
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +0 -172
- package/v2Components/CommonTestAndPreview/tests/CustomerCreationModal.test.js +0 -466
- package/v2Components/CommonTestAndPreview/tests/ExistingCustomerModal.test.js +0 -114
- package/v2Containers/Sms/tests/commonMethods.test.js +0 -122
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for CustomValuesEditor Component
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import '@testing-library/jest-dom';
|
|
6
|
-
import React from 'react';
|
|
7
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
8
|
-
import { IntlProvider } from 'react-intl';
|
|
9
|
-
import PropTypes from 'prop-types';
|
|
10
|
-
import CustomValuesEditor from '../CustomValuesEditor';
|
|
11
|
-
|
|
12
|
-
const scope = 'app.v2Components.TestAndPreviewSlidebox';
|
|
13
|
-
const mockMessages = {
|
|
14
|
-
[`${scope}.extractingTags`]: 'Extracting tags...',
|
|
15
|
-
[`${scope}.valuesMissing`]: 'Some values are missing',
|
|
16
|
-
[`${scope}.showJSON`]: 'Show JSON',
|
|
17
|
-
[`${scope}.personalizationTags`]: 'Personalization Tags',
|
|
18
|
-
[`${scope}.customValues`]: 'Custom Values',
|
|
19
|
-
[`${scope}.enterValue`]: 'Enter value',
|
|
20
|
-
[`${scope}.discardCustomValues`]: 'Discard custom values',
|
|
21
|
-
[`${scope}.updatePreview`]: 'Update Preview',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const TestWrapper = ({ children }) => (
|
|
25
|
-
<IntlProvider locale="en" messages={mockMessages}>
|
|
26
|
-
{children}
|
|
27
|
-
</IntlProvider>
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
TestWrapper.propTypes = {
|
|
31
|
-
children: PropTypes.node.isRequired,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
describe('CustomValuesEditor', () => {
|
|
35
|
-
const defaultProps = {
|
|
36
|
-
isExtractingTags: false,
|
|
37
|
-
isUpdatePreviewDisabled: false,
|
|
38
|
-
showJSON: false,
|
|
39
|
-
setShowJSON: jest.fn(),
|
|
40
|
-
customValues: { 'user.firstName': 'John', 'user.lastName': 'Doe' },
|
|
41
|
-
handleJSONTextChange: jest.fn(),
|
|
42
|
-
extractedTags: [
|
|
43
|
-
{ name: 'firstName', fullPath: 'user.firstName' },
|
|
44
|
-
{ name: 'lastName', fullPath: 'user.lastName' },
|
|
45
|
-
],
|
|
46
|
-
requiredTags: [{ name: 'firstName', fullPath: 'user.firstName' }],
|
|
47
|
-
optionalTags: [{ name: 'lastName', fullPath: 'user.lastName' }],
|
|
48
|
-
handleCustomValueChange: jest.fn(),
|
|
49
|
-
handleDiscardCustomValues: jest.fn(),
|
|
50
|
-
handleUpdatePreview: jest.fn(),
|
|
51
|
-
isUpdatingPreview: false,
|
|
52
|
-
formatMessage: jest.fn((msg) => msg.defaultMessage || msg.id),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
jest.clearAllMocks();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('renders loading state when isExtractingTags is true', () => {
|
|
60
|
-
render(
|
|
61
|
-
<TestWrapper>
|
|
62
|
-
<CustomValuesEditor {...defaultProps} isExtractingTags />
|
|
63
|
-
</TestWrapper>
|
|
64
|
-
);
|
|
65
|
-
expect(screen.getByText('Extracting tags...')).toBeInTheDocument();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('renders values missing message when isUpdatePreviewDisabled is true', () => {
|
|
69
|
-
render(
|
|
70
|
-
<TestWrapper>
|
|
71
|
-
<CustomValuesEditor {...defaultProps} isUpdatePreviewDisabled />
|
|
72
|
-
</TestWrapper>
|
|
73
|
-
);
|
|
74
|
-
expect(screen.getByText(/Some values are missing/i)).toBeInTheDocument();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('renders Show JSON toggle and calls setShowJSON when toggled', () => {
|
|
78
|
-
render(
|
|
79
|
-
<TestWrapper>
|
|
80
|
-
<CustomValuesEditor {...defaultProps} />
|
|
81
|
-
</TestWrapper>
|
|
82
|
-
);
|
|
83
|
-
expect(screen.getByText('Show JSON')).toBeInTheDocument();
|
|
84
|
-
const switchInput = document.querySelector('input[type="checkbox"]');
|
|
85
|
-
if (switchInput) {
|
|
86
|
-
fireEvent.click(switchInput);
|
|
87
|
-
expect(defaultProps.setShowJSON).toHaveBeenCalled();
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('renders JSON editor when showJSON is true', () => {
|
|
92
|
-
render(
|
|
93
|
-
<TestWrapper>
|
|
94
|
-
<CustomValuesEditor {...defaultProps} showJSON />
|
|
95
|
-
</TestWrapper>
|
|
96
|
-
);
|
|
97
|
-
const textarea = document.querySelector('textarea.json-textarea');
|
|
98
|
-
expect(textarea).toBeInTheDocument();
|
|
99
|
-
expect(textarea.value).toContain('user.firstName');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('calls handleJSONTextChange when JSON textarea is changed', () => {
|
|
103
|
-
render(
|
|
104
|
-
<TestWrapper>
|
|
105
|
-
<CustomValuesEditor {...defaultProps} showJSON />
|
|
106
|
-
</TestWrapper>
|
|
107
|
-
);
|
|
108
|
-
const textarea = document.querySelector('textarea.json-textarea');
|
|
109
|
-
fireEvent.change(textarea, { target: { value: '{"foo":"bar"}' } });
|
|
110
|
-
expect(defaultProps.handleJSONTextChange).toHaveBeenCalledWith('{"foo":"bar"}');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('renders required and optional tag inputs when showJSON is false', () => {
|
|
114
|
-
render(
|
|
115
|
-
<TestWrapper>
|
|
116
|
-
<CustomValuesEditor {...defaultProps} />
|
|
117
|
-
</TestWrapper>
|
|
118
|
-
);
|
|
119
|
-
expect(screen.getByText('Personalization Tags')).toBeInTheDocument();
|
|
120
|
-
expect(screen.getByText('Custom Values')).toBeInTheDocument();
|
|
121
|
-
expect(screen.getByDisplayValue('John')).toBeInTheDocument();
|
|
122
|
-
expect(screen.getByDisplayValue('Doe')).toBeInTheDocument();
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('calls handleCustomValueChange when tag input is changed', () => {
|
|
126
|
-
render(
|
|
127
|
-
<TestWrapper>
|
|
128
|
-
<CustomValuesEditor {...defaultProps} />
|
|
129
|
-
</TestWrapper>
|
|
130
|
-
);
|
|
131
|
-
const inputs = document.querySelectorAll('input[type="text"]');
|
|
132
|
-
fireEvent.change(inputs[0], { target: { value: 'Jane' } });
|
|
133
|
-
expect(defaultProps.handleCustomValueChange).toHaveBeenCalledWith('user.firstName', 'Jane');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('calls handleDiscardCustomValues when Discard button is clicked', () => {
|
|
137
|
-
render(
|
|
138
|
-
<TestWrapper>
|
|
139
|
-
<CustomValuesEditor {...defaultProps} />
|
|
140
|
-
</TestWrapper>
|
|
141
|
-
);
|
|
142
|
-
const discardBtn = screen.getByText(/Discard custom values/i);
|
|
143
|
-
fireEvent.click(discardBtn);
|
|
144
|
-
expect(defaultProps.handleDiscardCustomValues).toHaveBeenCalled();
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('calls handleUpdatePreview when Update Preview button is clicked', () => {
|
|
148
|
-
render(
|
|
149
|
-
<TestWrapper>
|
|
150
|
-
<CustomValuesEditor {...defaultProps} />
|
|
151
|
-
</TestWrapper>
|
|
152
|
-
);
|
|
153
|
-
const updateBtn = screen.getByText('Update Preview');
|
|
154
|
-
fireEvent.click(updateBtn);
|
|
155
|
-
expect(defaultProps.handleUpdatePreview).toHaveBeenCalled();
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('renders nothing for tags table when extractedTags is empty', () => {
|
|
159
|
-
render(
|
|
160
|
-
<TestWrapper>
|
|
161
|
-
<CustomValuesEditor
|
|
162
|
-
{...defaultProps}
|
|
163
|
-
extractedTags={[]}
|
|
164
|
-
requiredTags={[]}
|
|
165
|
-
optionalTags={[]}
|
|
166
|
-
/>
|
|
167
|
-
</TestWrapper>
|
|
168
|
-
);
|
|
169
|
-
expect(screen.getByText(/Show JSON/i)).toBeInTheDocument();
|
|
170
|
-
expect(screen.queryByText(/Personalization Tags/i)).not.toBeInTheDocument();
|
|
171
|
-
});
|
|
172
|
-
});
|
|
@@ -1,466 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for CustomerCreationModal
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
7
|
-
import { IntlProvider } from 'react-intl';
|
|
8
|
-
import PropTypes from 'prop-types';
|
|
9
|
-
import CustomerCreationModal from '../CustomerCreationModal';
|
|
10
|
-
import { CHANNELS, CUSTOMER_MODAL_NEW } from '../constants';
|
|
11
|
-
|
|
12
|
-
const mockGetMembersLookup = jest.fn();
|
|
13
|
-
jest.mock('../../../services/api', () => ({
|
|
14
|
-
getMembersLookup: (...args) => mockGetMembersLookup(...args),
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
const mockMessages = {
|
|
18
|
-
'app.v2Components.TestAndPreviewSlidebox.customerCreationModalTitle': 'Add new test customer',
|
|
19
|
-
'app.v2Components.TestAndPreviewSlidebox.customerCreationModalDescription': 'This customer profile will be available for testing.',
|
|
20
|
-
'app.v2Components.TestAndPreviewSlidebox.customerName': 'Name',
|
|
21
|
-
'app.v2Components.TestAndPreviewSlidebox.customerNamePlaceholder': 'Enter the name',
|
|
22
|
-
'app.v2Components.TestAndPreviewSlidebox.customerEmailPlaceholder': 'Enter the Email',
|
|
23
|
-
'app.v2Components.TestAndPreviewSlidebox.customerMobilePlaceholder': 'Enter the Mobile Number',
|
|
24
|
-
'app.v2Components.TestAndPreviewSlidebox.saveButton': 'Save',
|
|
25
|
-
'app.v2Components.TestAndPreviewSlidebox.cancelButton': 'Cancel',
|
|
26
|
-
'app.v2Components.TestAndPreviewSlidebox.customerMobileNumber': 'Mobile Number',
|
|
27
|
-
'app.v2Components.TestAndPreviewSlidebox.emailAlreadyExists': 'This email already exists.',
|
|
28
|
-
'app.v2Components.TestAndPreviewSlidebox.mobileAlreadyExists': 'This mobile already exists.',
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const TestWrapper = ({ children }) => (
|
|
32
|
-
<IntlProvider locale="en" messages={mockMessages}>
|
|
33
|
-
{children}
|
|
34
|
-
</IntlProvider>
|
|
35
|
-
);
|
|
36
|
-
TestWrapper.propTypes = { children: PropTypes.node };
|
|
37
|
-
|
|
38
|
-
describe('CustomerCreationModal', () => {
|
|
39
|
-
const defaultProps = {
|
|
40
|
-
customerModal: [true, CUSTOMER_MODAL_NEW],
|
|
41
|
-
setCustomerModal: jest.fn(),
|
|
42
|
-
channel: CHANNELS.EMAIL,
|
|
43
|
-
customerData: { name: '', email: '', mobile: '' },
|
|
44
|
-
setCustomerData: jest.fn(),
|
|
45
|
-
onSave: jest.fn(),
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
jest.clearAllMocks();
|
|
50
|
-
mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('renders modal with title and form fields when visible', () => {
|
|
54
|
-
render(
|
|
55
|
-
<TestWrapper>
|
|
56
|
-
<CustomerCreationModal {...defaultProps} />
|
|
57
|
-
</TestWrapper>
|
|
58
|
-
);
|
|
59
|
-
expect(screen.getByText(/add new test customer/i)).toBeTruthy();
|
|
60
|
-
expect(screen.getByPlaceholderText(/enter the name/i)).toBeTruthy();
|
|
61
|
-
expect(screen.getByPlaceholderText(/enter the email/i)).toBeTruthy();
|
|
62
|
-
expect(screen.getByPlaceholderText(/enter the mobile number/i)).toBeTruthy();
|
|
63
|
-
expect(screen.getByRole('button', { name: /save/i })).toBeTruthy();
|
|
64
|
-
expect(screen.getByRole('button', { name: /cancel/i })).toBeTruthy();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('calls setCustomerModal when Cancel is clicked', () => {
|
|
68
|
-
render(
|
|
69
|
-
<TestWrapper>
|
|
70
|
-
<CustomerCreationModal {...defaultProps} />
|
|
71
|
-
</TestWrapper>
|
|
72
|
-
);
|
|
73
|
-
fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
|
|
74
|
-
expect(defaultProps.setCustomerModal).toHaveBeenCalledWith([false, '']);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('calls setCustomerData when name input changes', () => {
|
|
78
|
-
render(
|
|
79
|
-
<TestWrapper>
|
|
80
|
-
<CustomerCreationModal {...defaultProps} />
|
|
81
|
-
</TestWrapper>
|
|
82
|
-
);
|
|
83
|
-
fireEvent.change(screen.getByPlaceholderText(/enter the name/i), { target: { value: 'John' } });
|
|
84
|
-
expect(defaultProps.setCustomerData).toHaveBeenCalledWith(expect.objectContaining({ name: 'John' }));
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('calls onSave when Save is clicked with no validation errors', async () => {
|
|
88
|
-
render(
|
|
89
|
-
<TestWrapper>
|
|
90
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: 'a@b.co', mobile: '' }} />
|
|
91
|
-
</TestWrapper>
|
|
92
|
-
);
|
|
93
|
-
const saveBtn = screen.getByRole('button', { name: /save/i });
|
|
94
|
-
fireEvent.click(saveBtn);
|
|
95
|
-
await waitFor(() => expect(defaultProps.onSave).toHaveBeenCalled());
|
|
96
|
-
expect(defaultProps.onSave).toHaveBeenCalledWith(expect.any(Object), expect.any(Function));
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('formats mobile input with digits only when channel is SMS', () => {
|
|
100
|
-
const setCustomerData = jest.fn();
|
|
101
|
-
render(
|
|
102
|
-
<TestWrapper>
|
|
103
|
-
<CustomerCreationModal
|
|
104
|
-
{...defaultProps}
|
|
105
|
-
channel={CHANNELS.SMS}
|
|
106
|
-
setCustomerData={setCustomerData}
|
|
107
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
108
|
-
/>
|
|
109
|
-
</TestWrapper>
|
|
110
|
-
);
|
|
111
|
-
const mobileInput = screen.getByPlaceholderText(/enter the mobile number/i);
|
|
112
|
-
fireEvent.change(mobileInput, { target: { value: '91 234 567 890' } });
|
|
113
|
-
expect(setCustomerData).toHaveBeenCalledWith(expect.objectContaining({ mobile: '91234567890' }));
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('shows validation error for invalid email after debounce', async () => {
|
|
117
|
-
jest.useFakeTimers();
|
|
118
|
-
render(
|
|
119
|
-
<TestWrapper>
|
|
120
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
121
|
-
</TestWrapper>
|
|
122
|
-
);
|
|
123
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
124
|
-
fireEvent.change(emailInput, { target: { value: 'invalid' } });
|
|
125
|
-
jest.advanceTimersByTime(600);
|
|
126
|
-
await waitFor(() => {
|
|
127
|
-
expect(screen.queryByText(/please enter a valid email address/i)).toBeTruthy();
|
|
128
|
-
});
|
|
129
|
-
jest.useRealTimers();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('shows emailAlreadyExists when valid email exists in system', async () => {
|
|
133
|
-
jest.useFakeTimers();
|
|
134
|
-
mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: true, customerDetails: [] } });
|
|
135
|
-
render(
|
|
136
|
-
<TestWrapper>
|
|
137
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
138
|
-
</TestWrapper>
|
|
139
|
-
);
|
|
140
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
141
|
-
fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
|
|
142
|
-
jest.advanceTimersByTime(600);
|
|
143
|
-
await waitFor(() => {
|
|
144
|
-
expect(mockGetMembersLookup).toHaveBeenCalledWith('email', 'user@example.com');
|
|
145
|
-
});
|
|
146
|
-
await waitFor(() => {
|
|
147
|
-
expect(screen.queryByText(/this email already exists/i)).toBeTruthy();
|
|
148
|
-
}, { timeout: 1000 });
|
|
149
|
-
jest.useRealTimers();
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('clears email error when email is cleared', async () => {
|
|
153
|
-
jest.useFakeTimers();
|
|
154
|
-
render(
|
|
155
|
-
<TestWrapper>
|
|
156
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: 'bad', mobile: '' }} />
|
|
157
|
-
</TestWrapper>
|
|
158
|
-
);
|
|
159
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
160
|
-
fireEvent.change(emailInput, { target: { value: '' } });
|
|
161
|
-
jest.advanceTimersByTime(600);
|
|
162
|
-
await waitFor(() => {
|
|
163
|
-
expect(screen.queryByText(/please enter a valid email address/i)).toBeFalsy();
|
|
164
|
-
});
|
|
165
|
-
jest.useRealTimers();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('performLookup catch returns success false and does not set exists error', async () => {
|
|
169
|
-
jest.useFakeTimers();
|
|
170
|
-
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
171
|
-
mockGetMembersLookup.mockRejectedValue(new Error('Network error'));
|
|
172
|
-
render(
|
|
173
|
-
<TestWrapper>
|
|
174
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
175
|
-
</TestWrapper>
|
|
176
|
-
);
|
|
177
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
178
|
-
fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
|
|
179
|
-
jest.advanceTimersByTime(600);
|
|
180
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
|
|
181
|
-
await waitFor(() => {
|
|
182
|
-
expect(screen.queryByText(/this email already exists/i)).toBeFalsy();
|
|
183
|
-
});
|
|
184
|
-
consoleSpy.mockRestore();
|
|
185
|
-
jest.useRealTimers();
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('shows validation error for invalid mobile when channel is SMS', async () => {
|
|
189
|
-
jest.useFakeTimers();
|
|
190
|
-
render(
|
|
191
|
-
<TestWrapper>
|
|
192
|
-
<CustomerCreationModal
|
|
193
|
-
{...defaultProps}
|
|
194
|
-
channel={CHANNELS.SMS}
|
|
195
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
196
|
-
/>
|
|
197
|
-
</TestWrapper>
|
|
198
|
-
);
|
|
199
|
-
const mobileInput = screen.getByPlaceholderText(/enter the mobile number/i);
|
|
200
|
-
fireEvent.change(mobileInput, { target: { value: '12' } });
|
|
201
|
-
jest.advanceTimersByTime(600);
|
|
202
|
-
await waitFor(() => {
|
|
203
|
-
expect(screen.queryByText(/please enter a valid mobile number/i)).toBeTruthy();
|
|
204
|
-
}, { timeout: 500 });
|
|
205
|
-
jest.useRealTimers();
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('Save button is disabled when validation errors present', async () => {
|
|
209
|
-
jest.useFakeTimers();
|
|
210
|
-
render(
|
|
211
|
-
<TestWrapper>
|
|
212
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: 'invalid', mobile: '' }} />
|
|
213
|
-
</TestWrapper>
|
|
214
|
-
);
|
|
215
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
216
|
-
fireEvent.change(emailInput, { target: { value: 'bad' } });
|
|
217
|
-
jest.advanceTimersByTime(600);
|
|
218
|
-
await waitFor(() => {
|
|
219
|
-
const saveBtn = screen.getByRole('button', { name: /save/i });
|
|
220
|
-
expect(saveBtn.disabled).toBe(true);
|
|
221
|
-
});
|
|
222
|
-
jest.useRealTimers();
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('clears email error when valid email does not exist in system', async () => {
|
|
226
|
-
jest.useFakeTimers();
|
|
227
|
-
mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
|
|
228
|
-
render(
|
|
229
|
-
<TestWrapper>
|
|
230
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
231
|
-
</TestWrapper>
|
|
232
|
-
);
|
|
233
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
234
|
-
fireEvent.change(emailInput, { target: { value: 'newuser@example.com' } });
|
|
235
|
-
jest.advanceTimersByTime(600);
|
|
236
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalledWith('email', 'newuser@example.com'));
|
|
237
|
-
await waitFor(() => {
|
|
238
|
-
expect(screen.queryByText(/this email already exists/i)).toBeFalsy();
|
|
239
|
-
}, { timeout: 500 });
|
|
240
|
-
jest.useRealTimers();
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it('shows mobileAlreadyExists when valid mobile exists in system', async () => {
|
|
244
|
-
jest.useFakeTimers();
|
|
245
|
-
mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: true, customerDetails: [] } });
|
|
246
|
-
render(
|
|
247
|
-
<TestWrapper>
|
|
248
|
-
<CustomerCreationModal
|
|
249
|
-
{...defaultProps}
|
|
250
|
-
channel={CHANNELS.SMS}
|
|
251
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
252
|
-
/>
|
|
253
|
-
</TestWrapper>
|
|
254
|
-
);
|
|
255
|
-
const mobileInput = screen.getByPlaceholderText(/enter the mobile number/i);
|
|
256
|
-
fireEvent.change(mobileInput, { target: { value: '9123456789' } });
|
|
257
|
-
jest.advanceTimersByTime(600);
|
|
258
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalledWith('mobile', '9123456789'));
|
|
259
|
-
await waitFor(() => {
|
|
260
|
-
expect(screen.queryByText(/this mobile already exists/i)).toBeTruthy();
|
|
261
|
-
}, { timeout: 1000 });
|
|
262
|
-
jest.useRealTimers();
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('clears previous email validation timeout when email changes again before debounce', () => {
|
|
266
|
-
jest.useFakeTimers();
|
|
267
|
-
mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
|
|
268
|
-
render(
|
|
269
|
-
<TestWrapper>
|
|
270
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
271
|
-
</TestWrapper>
|
|
272
|
-
);
|
|
273
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
274
|
-
fireEvent.change(emailInput, { target: { value: 'first@example.com' } });
|
|
275
|
-
jest.advanceTimersByTime(200);
|
|
276
|
-
fireEvent.change(emailInput, { target: { value: 'second@example.com' } });
|
|
277
|
-
jest.advanceTimersByTime(600);
|
|
278
|
-
expect(mockGetMembersLookup).toHaveBeenCalledWith('email', 'second@example.com');
|
|
279
|
-
jest.useRealTimers();
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it('clears previous mobile validation timeout when mobile changes again before debounce', () => {
|
|
283
|
-
jest.useFakeTimers();
|
|
284
|
-
mockGetMembersLookup.mockResolvedValue({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
|
|
285
|
-
render(
|
|
286
|
-
<TestWrapper>
|
|
287
|
-
<CustomerCreationModal
|
|
288
|
-
{...defaultProps}
|
|
289
|
-
channel={CHANNELS.SMS}
|
|
290
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
291
|
-
/>
|
|
292
|
-
</TestWrapper>
|
|
293
|
-
);
|
|
294
|
-
const mobileInput = screen.getByPlaceholderText(/enter the mobile number/i);
|
|
295
|
-
fireEvent.change(mobileInput, { target: { value: '9111111111' } });
|
|
296
|
-
jest.advanceTimersByTime(200);
|
|
297
|
-
fireEvent.change(mobileInput, { target: { value: '9222222222' } });
|
|
298
|
-
jest.advanceTimersByTime(600);
|
|
299
|
-
expect(mockGetMembersLookup).toHaveBeenCalledWith('mobile', '9222222222');
|
|
300
|
-
jest.useRealTimers();
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
it('cleans up timeouts on unmount', () => {
|
|
304
|
-
jest.useFakeTimers();
|
|
305
|
-
const { unmount } = render(
|
|
306
|
-
<TestWrapper>
|
|
307
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
308
|
-
</TestWrapper>
|
|
309
|
-
);
|
|
310
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
311
|
-
fireEvent.change(emailInput, { target: { value: 'unmount@example.com' } });
|
|
312
|
-
unmount();
|
|
313
|
-
jest.advanceTimersByTime(1000);
|
|
314
|
-
jest.useRealTimers();
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it('disables Save when required email is missing (EMAIL channel)', () => {
|
|
318
|
-
render(
|
|
319
|
-
<TestWrapper>
|
|
320
|
-
<CustomerCreationModal
|
|
321
|
-
{...defaultProps}
|
|
322
|
-
channel={CHANNELS.EMAIL}
|
|
323
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
324
|
-
/>
|
|
325
|
-
</TestWrapper>
|
|
326
|
-
);
|
|
327
|
-
const saveBtn = screen.getByRole('button', { name: /save/i });
|
|
328
|
-
expect(saveBtn.disabled).toBe(true);
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it('disables Save when required mobile is missing (SMS channel)', () => {
|
|
332
|
-
render(
|
|
333
|
-
<TestWrapper>
|
|
334
|
-
<CustomerCreationModal
|
|
335
|
-
{...defaultProps}
|
|
336
|
-
channel={CHANNELS.SMS}
|
|
337
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
338
|
-
/>
|
|
339
|
-
</TestWrapper>
|
|
340
|
-
);
|
|
341
|
-
const saveBtn = screen.getByRole('button', { name: /save/i });
|
|
342
|
-
expect(saveBtn.disabled).toBe(true);
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
it('disables Save and Cancel during lookup', async () => {
|
|
346
|
-
let resolveLookup;
|
|
347
|
-
mockGetMembersLookup.mockImplementation(() => new Promise((resolve) => { resolveLookup = resolve; }));
|
|
348
|
-
render(
|
|
349
|
-
<TestWrapper>
|
|
350
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
351
|
-
</TestWrapper>
|
|
352
|
-
);
|
|
353
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
354
|
-
fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
|
|
355
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
|
|
356
|
-
await waitFor(() => {
|
|
357
|
-
expect(screen.getByRole('button', { name: /save/i }).disabled).toBe(true);
|
|
358
|
-
expect(screen.getByRole('button', { name: /cancel/i }).disabled).toBe(true);
|
|
359
|
-
});
|
|
360
|
-
resolveLookup({ success: true, status: {}, response: { exists: false, customerDetails: [] } });
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it('shows email already exists when lookup returns "merged customer found"', async () => {
|
|
364
|
-
jest.useFakeTimers();
|
|
365
|
-
mockGetMembersLookup.mockResolvedValue({
|
|
366
|
-
success: false,
|
|
367
|
-
message: 'Merged customer found',
|
|
368
|
-
status: {},
|
|
369
|
-
response: {},
|
|
370
|
-
});
|
|
371
|
-
render(
|
|
372
|
-
<TestWrapper>
|
|
373
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
374
|
-
</TestWrapper>
|
|
375
|
-
);
|
|
376
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
377
|
-
fireEvent.change(emailInput, { target: { value: 'merged@example.com' } });
|
|
378
|
-
jest.advanceTimersByTime(600);
|
|
379
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalledWith('email', 'merged@example.com'));
|
|
380
|
-
await waitFor(() => {
|
|
381
|
-
expect(screen.queryByText(/this email already exists|already existing user profile/i)).toBeTruthy();
|
|
382
|
-
}, { timeout: 1000 });
|
|
383
|
-
jest.useRealTimers();
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
it('does not show already exists when lookup returns success: false with other message', async () => {
|
|
387
|
-
jest.useFakeTimers();
|
|
388
|
-
mockGetMembersLookup.mockResolvedValue({
|
|
389
|
-
success: false,
|
|
390
|
-
message: 'Server error',
|
|
391
|
-
status: {},
|
|
392
|
-
response: {},
|
|
393
|
-
});
|
|
394
|
-
render(
|
|
395
|
-
<TestWrapper>
|
|
396
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
397
|
-
</TestWrapper>
|
|
398
|
-
);
|
|
399
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
400
|
-
fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
|
|
401
|
-
jest.advanceTimersByTime(600);
|
|
402
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
|
|
403
|
-
await waitFor(() => {
|
|
404
|
-
expect(screen.queryByText(/this email already exists/i)).toBeFalsy();
|
|
405
|
-
});
|
|
406
|
-
jest.useRealTimers();
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
it('does not show already exists when response has status.isError', async () => {
|
|
410
|
-
jest.useFakeTimers();
|
|
411
|
-
mockGetMembersLookup.mockResolvedValue({
|
|
412
|
-
success: true,
|
|
413
|
-
status: { isError: true },
|
|
414
|
-
response: { exists: false, customerDetails: [] },
|
|
415
|
-
});
|
|
416
|
-
render(
|
|
417
|
-
<TestWrapper>
|
|
418
|
-
<CustomerCreationModal {...defaultProps} customerData={{ name: '', email: '', mobile: '' }} />
|
|
419
|
-
</TestWrapper>
|
|
420
|
-
);
|
|
421
|
-
const emailInput = screen.getByPlaceholderText(/enter the email/i);
|
|
422
|
-
fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
|
|
423
|
-
jest.advanceTimersByTime(600);
|
|
424
|
-
await waitFor(() => expect(mockGetMembersLookup).toHaveBeenCalled());
|
|
425
|
-
await waitFor(() => {
|
|
426
|
-
expect(screen.queryByText(/this email already exists/i)).toBeFalsy();
|
|
427
|
-
});
|
|
428
|
-
jest.useRealTimers();
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
it('shows (Optional) for email when channel is SMS', () => {
|
|
432
|
-
render(
|
|
433
|
-
<TestWrapper>
|
|
434
|
-
<CustomerCreationModal
|
|
435
|
-
{...defaultProps}
|
|
436
|
-
channel={CHANNELS.SMS}
|
|
437
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
438
|
-
/>
|
|
439
|
-
</TestWrapper>
|
|
440
|
-
);
|
|
441
|
-
const optionals = screen.getAllByText(/\(optional\)/i);
|
|
442
|
-
expect(optionals.length).toBeGreaterThanOrEqual(2);
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
it('shows (Optional) for mobile when channel is EMAIL', () => {
|
|
446
|
-
render(
|
|
447
|
-
<TestWrapper>
|
|
448
|
-
<CustomerCreationModal
|
|
449
|
-
{...defaultProps}
|
|
450
|
-
channel={CHANNELS.EMAIL}
|
|
451
|
-
customerData={{ name: '', email: '', mobile: '' }}
|
|
452
|
-
/>
|
|
453
|
-
</TestWrapper>
|
|
454
|
-
);
|
|
455
|
-
expect(screen.getAllByText(/\(optional\)/i).length).toBeGreaterThanOrEqual(2);
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
it('renders modal description', () => {
|
|
459
|
-
render(
|
|
460
|
-
<TestWrapper>
|
|
461
|
-
<CustomerCreationModal {...defaultProps} />
|
|
462
|
-
</TestWrapper>
|
|
463
|
-
);
|
|
464
|
-
expect(screen.getByText(/this customer profile will be available for testing/i)).toBeTruthy();
|
|
465
|
-
});
|
|
466
|
-
});
|