@availity/feedback 9.1.14 → 10.0.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.
@@ -0,0 +1,347 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, waitFor, cleanup } from '@testing-library/react';
3
+ import { avLogMessagesApiV2, avRegionsApi } from '@availity/api-axios';
4
+ import { FeedbackForm } from '../index.js';
5
+
6
+ vi.mock('@availity/api-axios');
7
+
8
+ vi.useFakeTimers();
9
+
10
+ avLogMessagesApiV2.info = vi.fn(() => Promise.resolve());
11
+
12
+ avRegionsApi.getCurrentRegion = vi.fn(() =>
13
+ Promise.resolve({
14
+ data: {
15
+ regions: [
16
+ {
17
+ id: 'some region id',
18
+ },
19
+ ],
20
+ },
21
+ })
22
+ );
23
+
24
+ afterEach(cleanup);
25
+
26
+ describe('FeedbackForm', () => {
27
+ beforeEach(() => {
28
+ // reset log messages api mock
29
+ avLogMessagesApiV2.info.mockClear();
30
+ avLogMessagesApiV2.info = vi.fn(() => Promise.resolve());
31
+ });
32
+ test('should disable submit button until smile selected', () => {
33
+ const { getByText } = render(<FeedbackForm name="Payer Space" />);
34
+
35
+ const submitButton = getByText('Send Feedback');
36
+
37
+ expect(submitButton.getAttribute('disabled')).not.toBe(null);
38
+
39
+ fireEvent.click(getByText('Smiley face'));
40
+
41
+ expect(submitButton.getAttribute('disabled')).toBe(null);
42
+ });
43
+
44
+ test('should indicate active smiley', () => {
45
+ const { getByText } = render(<FeedbackForm name="Payer Space" />);
46
+
47
+ // Get the Option with the smiley face
48
+ const smileyFeedbackField = getByText('Smiley face');
49
+
50
+ // Simulate the Click
51
+ fireEvent.click(smileyFeedbackField);
52
+
53
+ expect(smileyFeedbackField.parentElement.className).toContain('btn-primary');
54
+
55
+ expect(smileyFeedbackField.parentElement).toHaveAttribute('aria-pressed', 'true');
56
+ });
57
+
58
+ test.todo('should submit with feedback text value', async () => {
59
+ const onFeedbackSent = vi.fn();
60
+
61
+ const { getByLabelText, getByText } = render(<FeedbackForm onFeedbackSent={onFeedbackSent} name="Payer Space" />);
62
+
63
+ // Simulate the Click
64
+ fireEvent.click(getByText('Smiley face'));
65
+
66
+ // Get the Input Node for the Feedback
67
+ const feedbackNode = getByLabelText('What do you like?');
68
+
69
+ // Simulate a user typing the value below into the field
70
+ fireEvent.change(feedbackNode, {
71
+ target: { value: 'some good text here' },
72
+ });
73
+
74
+ // Check if the Input Got Updated
75
+ expect(feedbackNode.value).toEqual('some good text here');
76
+
77
+ fireEvent.click(getByText('Send Feedback'));
78
+
79
+ await waitFor(
80
+ () => {
81
+ expect(onFeedbackSent).toHaveBeenCalledWith(
82
+ expect.objectContaining({
83
+ active: 'smile',
84
+ feedback: 'some good text here',
85
+ })
86
+ );
87
+ },
88
+ { timeout: 2500 }
89
+ );
90
+ });
91
+
92
+ test.todo('should submit without feedback text value when feedbackText set to false', async () => {
93
+ const onFeedbackSent = vi.fn();
94
+
95
+ const { getByText } = render(<FeedbackForm onFeedbackSent={onFeedbackSent} name="Payer Space" feedbackText={false}/>);
96
+
97
+ // Simulate the Click
98
+ fireEvent.click(getByText('Smiley face'));
99
+
100
+ fireEvent.click(getByText('Send Feedback'));
101
+
102
+ await waitFor(
103
+ () => {
104
+ expect(onFeedbackSent).toHaveBeenCalledWith(
105
+ expect.objectContaining({
106
+ active: 'smile',
107
+ })
108
+ );
109
+ },
110
+ { timeout: 2500 }
111
+ );
112
+ });
113
+
114
+ test.todo('should submit and disable button when clicked', async () => {
115
+ // mock log messages api to return a promise that resolves after 3 seconds
116
+ avLogMessagesApiV2.info = vi.fn(
117
+ () =>
118
+ new Promise((resolve) => {
119
+ setTimeout(resolve, 3000);
120
+ })
121
+ );
122
+ const { getByLabelText, getByText } = render(<FeedbackForm name="Payer Space" />);
123
+
124
+ // Simulate the Click
125
+ fireEvent.click(getByText('Smiley face'));
126
+
127
+ // Get the Input Node for the Feedback
128
+ const feedbackNode = getByLabelText('What do you like?');
129
+
130
+ // Simulate a user typing the value below into the field
131
+ fireEvent.change(feedbackNode, {
132
+ target: { value: 'some good text here' },
133
+ });
134
+
135
+ // find the submit button
136
+ const submitButton = getByText('Send Feedback');
137
+ // click the submit button twice
138
+ fireEvent.click(submitButton);
139
+ // wait for the button to be disabled
140
+ await waitFor(() => expect(submitButton).toBeDisabled());
141
+ fireEvent.click(submitButton);
142
+ // wait for log messages to have been called once
143
+ await waitFor(() => expect(avLogMessagesApiV2.info).toHaveBeenCalledTimes(1));
144
+
145
+ // wait for success message to show
146
+ await waitFor(() => expect(getByText('Thank you for your feedback.')).toBeInTheDocument(), { timeout: 5000 });
147
+ });
148
+
149
+ test.todo('should submit with feedback text value when enter is pressed', async () => {
150
+ const onFeedbackSent = vi.fn();
151
+
152
+ const { getByLabelText, getByText } = render(<FeedbackForm onFeedbackSent={onFeedbackSent} name="Payer Space" />);
153
+
154
+ // Simulate the Click
155
+ fireEvent.click(getByText('Smiley face'));
156
+
157
+ // Get the Input Node for the Feedback
158
+ const feedbackNode = getByLabelText('What do you like?');
159
+
160
+ // Simulate a user typing the value below into the field
161
+ fireEvent.change(feedbackNode, {
162
+ target: { value: 'some good text here' },
163
+ });
164
+
165
+ // Check if the Input Got Updated
166
+ expect(feedbackNode.value).toEqual('some good text here');
167
+
168
+ fireEvent.keyDown(getByText('Send Feedback'), {
169
+ key: 'Enter',
170
+ keyCode: 13,
171
+ });
172
+
173
+ await waitFor(
174
+ () => {
175
+ expect(onFeedbackSent).toHaveBeenCalledWith(
176
+ expect.objectContaining({
177
+ active: 'smile',
178
+ feedback: 'some good text here',
179
+ })
180
+ );
181
+ },
182
+ { timeout: 2500 }
183
+ );
184
+ });
185
+
186
+ test.todo('should submit with custom analytics', async () => {
187
+ const infoFn = vi.fn();
188
+ const onFeedbackSent = vi.fn();
189
+
190
+ const { getByLabelText, getByText } = render(
191
+ <FeedbackForm
192
+ onFeedbackSent={onFeedbackSent}
193
+ name="Payer Space"
194
+ analytics={{
195
+ info: infoFn,
196
+ }}
197
+ />
198
+ );
199
+
200
+ // Simulate the Click
201
+ fireEvent.click(getByText('Smiley face'));
202
+
203
+ // Get the Input Node for the Feedback
204
+ const feedbackNode = getByLabelText('What do you like?');
205
+
206
+ // Simulate a user typing the value below into the field
207
+ fireEvent.change(feedbackNode, {
208
+ target: { value: 'some good text here' },
209
+ });
210
+
211
+ // Check if the Input Got Updated
212
+ expect(feedbackNode.value).toEqual('some good text here');
213
+
214
+ fireEvent.click(getByText('Send Feedback'));
215
+
216
+ await waitFor(() => expect(infoFn).toHaveBeenCalledTimes(1));
217
+ });
218
+
219
+ test('should render custom face icons', () => {
220
+ const faceOptions = [
221
+ {
222
+ icon: 'happy',
223
+ description: 'Happy face',
224
+ },
225
+ {
226
+ icon: 'okay',
227
+ description: 'Okay face',
228
+ },
229
+ {
230
+ icon: 'sad',
231
+ description: 'Sad face',
232
+ },
233
+ {
234
+ icon: 'confused',
235
+ description: 'Confused face',
236
+ },
237
+ ];
238
+
239
+ const { getByTestId } = render(<FeedbackForm name="Payer Space" faceOptions={faceOptions} />);
240
+
241
+ const faceOptionFields = getByTestId('face-options');
242
+
243
+ expect(faceOptionFields.childElementCount).toBe(4);
244
+
245
+ for (const faceOption of faceOptions) {
246
+ expect(faceOptionFields.getElementsByClassName(`icon-${faceOption.icon}`)).not.toBe(null);
247
+ }
248
+ });
249
+
250
+ test('should render about options', () => {
251
+ const aboutOptions = [
252
+ {
253
+ value: 'this space',
254
+ label: 'This Payer Space',
255
+ },
256
+ {
257
+ value: 'that space',
258
+ label: 'That Payer Space',
259
+ },
260
+ {
261
+ value: 'portal',
262
+ label: 'Portal as a whole',
263
+ },
264
+ {
265
+ value: 'availity',
266
+ label: 'Availity as a whole',
267
+ },
268
+ ];
269
+ const { getByText } = render(<FeedbackForm name="Payer Space" aboutOptions={aboutOptions} />);
270
+
271
+ // Simulate the Click First
272
+ fireEvent.click(getByText('Smiley face'));
273
+
274
+ // Label text on the Select Field to know we rendered it
275
+ expect(getByText('This is about')).toBeDefined();
276
+ });
277
+
278
+ test('should render custom label when provided', async () => {
279
+ const { getByText } = render(
280
+ <FeedbackForm
281
+ name="Test Space"
282
+ aboutOptions={[
283
+ { label: 'Payer 1', value: 'payer1' },
284
+ { label: 'Payer 2', value: 'payer2' },
285
+ { label: 'Payer 3', value: 'payer3' },
286
+ { label: 'Payer 4', value: 'payer4' },
287
+ ]}
288
+ aboutLabel="Select payer..."
289
+ />
290
+ );
291
+
292
+ fireEvent.click(getByText('Meh face'));
293
+ expect(getByText('Select payer...')).toBeDefined();
294
+ });
295
+
296
+ test('should render additional comments input', () => {
297
+ const { getByText } = render(<FeedbackForm name="Payer Space" additionalComments />);
298
+
299
+ fireEvent.click(getByText('Smiley face'));
300
+
301
+ expect(getByText('Additional Comments... (Optional)')).toBeDefined();
302
+ });
303
+
304
+ test('should show support', () => {
305
+ const { getByText } = render(<FeedbackForm name="Payer Space" showSupport additionalComments />);
306
+
307
+ expect(getByText('Open a support ticket')).toBeDefined();
308
+ });
309
+
310
+ test('should render default heading as div with stylings of h5', () => {
311
+ const { getByText } = render(<FeedbackForm name="Payer Space" />);
312
+
313
+ const header = getByText('Tell us what you think about Payer Space');
314
+
315
+ expect(header.parentElement).toHaveClass('h5');
316
+ expect(header.parentElement).toHaveAttribute('role', 'heading');
317
+ expect(header.parentElement).toHaveAttribute('aria-level', '2');
318
+ expect(header.tagName).toEqual('DIV');
319
+ });
320
+
321
+ test('should have smileys in a group element', () => {
322
+ const { getByTestId } = render(<FeedbackForm name="Payer Space" />);
323
+
324
+ const smileyGroup = getByTestId('face-options');
325
+
326
+ expect(smileyGroup).toHaveAttribute('role', 'group');
327
+ expect(smileyGroup).toHaveAttribute('aria-labelledby', 'feedback-form-header');
328
+ });
329
+
330
+ test.todo('should focus first SmileField button by default', async () => {
331
+ const { getByText } = render(<FeedbackForm name="Payer Space" />);
332
+
333
+ const firstFeedbackButton = getByText('Smiley face').closest('button');
334
+ await waitFor(() => {
335
+ expect(firstFeedbackButton).toHaveFocus();
336
+ });
337
+ });
338
+
339
+ test.todo('should not focus first SmileField button if autofocus is set to false', async () => {
340
+ const { getByText } = render(<FeedbackForm name="Payer Space" autoFocusFeedbackButton={false} />);
341
+
342
+ const firstFeedbackButton = getByText('Smiley face').closest('button');
343
+ await waitFor(() => {
344
+ expect(firstFeedbackButton).not.toHaveFocus();
345
+ });
346
+ });
347
+ });
@@ -0,0 +1,143 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, cleanup, waitFor } from '@testing-library/react';
3
+ import { avOrganizationsApi, avWebQLApi } from '@availity/api-axios';
4
+ import nativeForm from '@availity/native-form';
5
+ import SupportForm from '../src/SupportForm';
6
+
7
+ vi.mock('@availity/api-axios');
8
+ vi.mock('@availity/native-form');
9
+
10
+ afterEach(cleanup);
11
+
12
+ const selectItem = async (container, getByText, name) => {
13
+ const select = container.querySelector('.av__control');
14
+ fireEvent.keyDown(select, { key: 'ArrowDown', keyCode: 40 });
15
+
16
+ const selectOption = await waitFor(() => getByText(name));
17
+
18
+ expect(selectOption).toBeDefined();
19
+
20
+ fireEvent.click(selectOption);
21
+
22
+ expect(container.querySelector('.av__option--is-selected')).toBeDefined();
23
+ expect(select.querySelector('.av__placeholder')).toBe(null);
24
+ };
25
+
26
+ describe('SupportForm', () => {
27
+ test('it ssos', async () => {
28
+ const setSupportIsActive = vi.fn();
29
+ const setBlocking = vi.fn();
30
+ const { container, getByText, getByTestId } = render(
31
+ <SupportForm setSupportIsActive={setSupportIsActive} setBlocking={setBlocking} />
32
+ );
33
+
34
+ avOrganizationsApi.postGet.mockResolvedValue({
35
+ data: {
36
+ organizations: [
37
+ {
38
+ id: 'org1',
39
+ customerId: 'cid1',
40
+ name: 'Org 1',
41
+ },
42
+ {
43
+ id: 'org2',
44
+ customerId: 'cid2',
45
+ name: 'Org 2',
46
+ },
47
+ {
48
+ id: 'org3',
49
+ customerId: 'cid3',
50
+ name: 'Org 3',
51
+ },
52
+ {
53
+ id: 'org4',
54
+ customerId: 'cid4',
55
+ name: 'Org 4',
56
+ },
57
+ {
58
+ id: 'org5',
59
+ customerId: 'cid5',
60
+ name: 'Org 5',
61
+ },
62
+ ],
63
+ },
64
+ });
65
+
66
+ avOrganizationsApi.getOrganizations.mockResolvedValue({
67
+ data: {
68
+ totalCount: 5,
69
+ count: 5,
70
+ offset: 0,
71
+ limit: 50,
72
+ organizations: [
73
+ {
74
+ id: 'org1',
75
+ customerId: 'cid1',
76
+ name: 'Org 1',
77
+ },
78
+ {
79
+ id: 'org2',
80
+ customerId: 'cid2',
81
+ name: 'Org 2',
82
+ },
83
+ {
84
+ id: 'org3',
85
+ customerId: 'cid3',
86
+ name: 'Org 3',
87
+ },
88
+ {
89
+ id: 'org4',
90
+ customerId: 'cid4',
91
+ name: 'Org 4',
92
+ },
93
+ {
94
+ id: 'org5',
95
+ customerId: 'cid5',
96
+ name: 'Org 5',
97
+ },
98
+ ],
99
+ },
100
+ });
101
+
102
+ avWebQLApi.create.mockResolvedValue({
103
+ data: {
104
+ data: {
105
+ salesforceUser: {
106
+ id: 'sf1',
107
+ accountId: 'acct1',
108
+ newCommunity: 'newComm',
109
+ },
110
+ },
111
+ },
112
+ });
113
+
114
+ await selectItem(container, getByText, 'Org 1');
115
+
116
+ await fireEvent.click(getByTestId('submit-btn'));
117
+
118
+ await waitFor(() => expect(avOrganizationsApi.getOrganizations).toHaveBeenCalledTimes(1));
119
+ expect(avWebQLApi.create).toHaveBeenCalledTimes(1);
120
+ expect(nativeForm).toHaveBeenCalledTimes(1);
121
+
122
+ expect(nativeForm.mock.calls[0][0]).toBe('BJx3fqX3BH');
123
+ expect(nativeForm.mock.calls[0][1].orgGenKey).toBe('cid1');
124
+ expect(nativeForm.mock.calls[0][1].organizationName).toBe('Org 1');
125
+ expect(nativeForm.mock.calls[0][1].partyId).toBe('org1');
126
+ expect(nativeForm.mock.calls[0][1].payerId).toBe('AVAILITY');
127
+ expect(nativeForm.mock.calls[0][1].X_Client_ID).toBe('5430d59f-c5cc-4be7-be5a-34472ec30fe9');
128
+ expect(nativeForm.mock.calls[0][1].X_XSRF_TOKEN).toBeDefined();
129
+ expect(nativeForm.mock.calls[0][2].action).toBe('/ms/api/availity/internal/spc/magneto/sso/v1/saml/E-t_s_JQ0P');
130
+ expect(nativeForm.mock.calls[0][2].target).toBe('_blank');
131
+ });
132
+
133
+ test('should render default heading as div with stylings of h5', () => {
134
+ const { getByText } = render(<SupportForm />);
135
+
136
+ const header = getByText('Open Support Ticket');
137
+
138
+ expect(header.parentElement).toHaveClass('h5');
139
+ expect(header.parentElement).toHaveAttribute('role', 'heading');
140
+ expect(header.parentElement).toHaveAttribute('aria-level', '2');
141
+ expect(header.tagName).toEqual('DIV');
142
+ });
143
+ });
@@ -0,0 +1,17 @@
1
+ import { defineProject } from 'vitest/config';
2
+
3
+ export default defineProject({
4
+ test: {
5
+ name: 'feedback',
6
+ globals: true,
7
+ environment: 'jsdom',
8
+ setupFiles: ['../../vitest.setup.ts'],
9
+ include: ['src/**/*.test.{ts,tsx,js,jsx}', 'tests/**/*.test.{ts,tsx,js,jsx}'],
10
+ env: { TZ: 'UTC' },
11
+ server: {
12
+ deps: {
13
+ inline: [/lodash/, /@availity\/yup/],
14
+ },
15
+ },
16
+ },
17
+ });
package/jest.config.js DELETED
@@ -1,7 +0,0 @@
1
- const global = require('../../jest/global-config');
2
-
3
- module.exports = {
4
- ...global,
5
- displayName: 'feedback',
6
- coverageDirectory: '../../coverage/feedback',
7
- };
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "../../dist/out-tsc",
5
- "module": "commonjs",
6
- "types": ["jest", "node", "@testing-library/jest-dom"],
7
- "allowJs": true
8
- },
9
- "include": ["**/*.test.js", "**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
10
- }
File without changes
File without changes