Skip to content

Commit b86d5fa

Browse files
author
molker
committed
Address PR Comments and Prepare for SDK Changes
1 parent 91efaf4 commit b86d5fa

5 files changed

Lines changed: 131 additions & 58 deletions

File tree

packages/contact-center/cc-components/src/components/task/OutdialCall/outdial-call.tsx

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ interface OutdialANIEntry {
4040
* @property startOutdial - Function to initiate the outdial call with the entered destination number.
4141
*/
4242
const OutdialCallComponent: React.FunctionComponent<OutdialCallComponentProps> = (props) => {
43-
const {startOutdial} = props;
43+
const {startOutdial, outdialANIEntries} = props;
4444

4545
// State Hooks
4646
const [destination, setDestination] = useState('');
@@ -53,21 +53,8 @@ const OutdialCallComponent: React.FunctionComponent<OutdialCallComponentProps> =
5353
[]
5454
);
5555

56-
const outdialANIEntries: OutdialANIEntry[] = [
57-
{number: '+1(234)567-8910', name: 'name 1'},
58-
{number: '+1(019)876-5432', name: 'name 2'},
59-
{number: '+1(019)876-5432', name: 'name 3'},
60-
{number: '+1(019)876-5432', name: 'name 4'},
61-
{number: '+1(019)876-5432', name: 'name 2'},
62-
{number: '+1(019)876-5432', name: 'name 2'},
63-
{number: '+1(019)876-5432', name: 'name 2'},
64-
{number: '+1(019)876-5432', name: 'name 2'},
65-
{number: '+1(019)876-5432', name: 'name 2'},
66-
{number: '+1(019)876-5432', name: 'name 2'},
67-
{number: '+1(019)876-5432', name: 'name 2'},
68-
{number: '+1(019)876-5432', name: 'name 2'},
69-
{number: '+1(019)876-5432', name: 'name 2'},
70-
];
56+
// Give Select an empty list if outdial ANI entries are not provided
57+
const outdialANIList: OutdialANIEntry[] = outdialANIEntries ?? [];
7158

7259
/**
7360
* validateOutboundNumber
@@ -107,6 +94,8 @@ const OutdialCallComponent: React.FunctionComponent<OutdialCallComponentProps> =
10794
<Input
10895
className="input"
10996
id="outdial-number-input"
97+
name="outdial-number-input"
98+
data-testid="outdial-number-input"
11099
helpText={isValidNumber}
111100
helpTextType={isValidNumber ? 'error' : 'default'}
112101
placeholder={OutdialStrings.DN_PLACEHOLDER}
@@ -130,19 +119,20 @@ const OutdialCallComponent: React.FunctionComponent<OutdialCallComponentProps> =
130119
className="input"
131120
label={OutdialStrings.ANI_SELECT_LABEL}
132121
id="outdial-ani-option"
133-
name="outdial-ani-option"
122+
name="outdial-ani-option-select"
134123
data-testid="outdial-ani-option-select"
135124
placeholder={OutdialStrings.ANI_SELECT_PLACEHOLDER}
136125
onChange={(event: CustomEvent) => {
137126
setSelectedANI(event.detail.value);
138127
}}
139128
>
140-
{outdialANIEntries.map((option: OutdialANIEntry, index: number) => {
129+
{outdialANIList.map((option: OutdialANIEntry, index: number) => {
141130
return (
142131
<Option
143132
selected={option.number === selectedANI}
144133
key={index}
145134
value={option.number}
135+
name={`outdial-ani-option-${index}`}
146136
data-testid={`outdial-ani-option-${index}`}
147137
>
148138
{option.name}
@@ -151,6 +141,7 @@ const OutdialCallComponent: React.FunctionComponent<OutdialCallComponentProps> =
151141
})}
152142
</Select>
153143
<Button
144+
data-testid="outdial-call-button"
154145
className="button"
155146
prefixIcon={'handset-regular'}
156147
onClick={() => startOutdial(destination)}

packages/contact-center/cc-components/src/components/task/task.types.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,20 @@ export interface OutdialCallProps {
465465
*/
466466
startOutdial: (destination: string) => void;
467467

468+
/**
469+
* Array of Outdial ANI entries.
470+
* TODO: update with exported type when SDK PR#4513 is merged
471+
*/
472+
outdialANIEntries?: Array<{
473+
organizationId?: string;
474+
id?: string;
475+
version?: number;
476+
name: string;
477+
number: string;
478+
createdTime?: number;
479+
lastUpdatedTime?: number;
480+
}>;
481+
468482
/**
469483
* CC SDK Instance.
470484
*/
@@ -476,7 +490,7 @@ export interface OutdialCallProps {
476490
logger: ILogger;
477491
}
478492

479-
export type OutdialCallComponentProps = Pick<OutdialCallProps, 'startOutdial'>;
493+
export type OutdialCallComponentProps = Pick<OutdialCallProps, 'startOutdial' | 'outdialANIEntries'>;
480494

481495
/**
482496
* Interface representing the properties for CallControlListItem component.
Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,140 @@
11
import React from 'react';
2-
import {render, fireEvent, screen} from '@testing-library/react';
2+
import {render, fireEvent, screen, waitFor} from '@testing-library/react';
33
import '@testing-library/jest-dom';
44
import OutdialCallComponent from '../../../../src/components/task/OutdialCall/outdial-call';
5+
import store from '@webex/cc-store';
56

6-
// This test suite is skipped because we have removed the :broken from the command
7-
// line in the package.json scripts to run these tests in pipeline
8-
describe.skip('OutdialCallComponent', () => {
7+
describe('OutdialCallComponent', () => {
98
const mockStartOutdial = jest.fn();
9+
const KEY_LIST = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'];
10+
let customEvent;
11+
12+
// Prevent warning 'CC-Widgets: UI Metrics: No logger found'
13+
store.store.logger = {
14+
log: jest.fn(),
15+
info: jest.fn(),
16+
warn: jest.fn(),
17+
error: jest.fn(),
18+
trace: jest.fn(),
19+
};
20+
21+
beforeEach(() => {
22+
jest.clearAllMocks();
23+
});
1024

1125
const props = {
1226
startOutdial: mockStartOutdial,
27+
outdialANIEntries: [
28+
{name: 'name 1', number: '1'},
29+
{name: 'name 2', number: '2'},
30+
],
1331
};
1432

1533
beforeEach(() => {
34+
// Create a custom event that mimics what the mdc-input component would fire
35+
customEvent = new Event('change', {bubbles: true});
1636
mockStartOutdial.mockClear();
1737
});
1838

1939
it('renders the component correctly', () => {
2040
render(<OutdialCallComponent {...props} />);
21-
expect(screen.getByPlaceholderText('Enter number to dial')).toBeInTheDocument();
22-
expect(screen.getByText('Outdial Call')).toBeInTheDocument();
41+
expect(screen.getByTestId('outdial-number-input')).toBeInTheDocument();
42+
KEY_LIST.forEach((key) => {
43+
expect(screen.getByText(key)).toBeInTheDocument();
44+
});
45+
expect(screen.getByTestId('outdial-ani-option-select')).toBeInTheDocument();
46+
expect(screen.getByTestId('outdial-call-button')).toBeInTheDocument();
2347
});
2448

25-
it('updates input value when typing directly', () => {
49+
it('updates input value when typing directly', async () => {
2650
render(<OutdialCallComponent {...props} />);
27-
const input = screen.getByPlaceholderText('Enter number to dial');
28-
fireEvent.change(input, {target: {value: '123'}});
29-
expect(input).toHaveValue('123');
51+
const input = await screen.findByTestId('outdial-number-input');
52+
53+
Object.defineProperty(customEvent, 'target', {
54+
writable: false,
55+
value: {value: '123'},
56+
});
57+
fireEvent(input, customEvent);
58+
59+
await waitFor(() => {
60+
expect(input).toHaveAttribute('value', '123');
61+
});
3062
});
3163

3264
it('updates input value when clicking keypad buttons', () => {
3365
render(<OutdialCallComponent {...props} />);
3466
fireEvent.click(screen.getByText('1'));
3567
fireEvent.click(screen.getByText('2'));
3668
fireEvent.click(screen.getByText('3'));
37-
expect(screen.getByPlaceholderText('Enter number to dial')).toHaveValue('123');
69+
expect(screen.getByTestId('outdial-number-input')).toHaveValue('123');
3870
});
3971

4072
it('calls startOutdial with correct payload when clicking call button', () => {
4173
render(<OutdialCallComponent {...props} />);
42-
const input = screen.getByPlaceholderText('Enter number to dial');
43-
fireEvent.change(input, {target: {value: '123'}});
74+
const input = screen.getByTestId('outdial-number-input');
75+
Object.defineProperty(customEvent, 'target', {
76+
writable: false,
77+
value: {value: '123'},
78+
});
79+
fireEvent(input, customEvent);
4480

45-
const callButton = screen.getByRole('button');
81+
const callButton = screen.getByTestId('outdial-call-button');
4682
fireEvent.click(callButton);
4783

48-
expect(mockStartOutdial).toHaveBeenCalledWith({
49-
entryPointId: 'test-entry-point',
50-
destination: '123',
51-
direction: 'OUTBOUND',
52-
attributes: {},
53-
mediaType: 'telephony',
54-
outboundType: 'OUTDIAL',
55-
});
84+
expect(mockStartOutdial).toHaveBeenCalledWith('123');
5685
});
5786

5887
it('allows special characters (* # +) from keypad', () => {
5988
render(<OutdialCallComponent {...props} />);
6089
fireEvent.click(screen.getByText('*'));
6190
fireEvent.click(screen.getByText('#'));
62-
expect(screen.getByPlaceholderText('Enter number to dial')).toHaveValue('*#');
91+
expect(screen.getByTestId('outdial-number-input')).toHaveValue('*#');
6392
});
6493

65-
it('does not allow invalid characters', () => {
94+
it('shows error help text when invalid characters are entered', async () => {
6695
render(<OutdialCallComponent {...props} />);
67-
const input = screen.getByPlaceholderText('Enter number to dial');
68-
fireEvent.change(input, {target: {value: 'abc'}});
69-
expect(input).toHaveValue('');
96+
const input = await screen.findByTestId('outdial-number-input');
97+
Object.defineProperty(customEvent, 'target', {
98+
writable: false,
99+
value: {value: 'abc'},
100+
});
101+
fireEvent(input, customEvent);
102+
await waitFor(() => expect(input).toHaveAttribute('help-text', 'Incorrect format.'));
70103
});
71104

72-
it('does not allow invalid characters when typing', () => {
105+
it('does not allow invalid characters when typing', async () => {
73106
render(<OutdialCallComponent {...props} />);
74-
const input = screen.getByPlaceholderText('Enter number to dial');
75-
fireEvent.change(input, {target: {value: '123abc'}});
76-
expect(input).toHaveValue('123');
107+
const input = await screen.findByTestId('outdial-number-input');
108+
Object.defineProperty(customEvent, 'target', {
109+
writable: false,
110+
value: {value: '123abc'},
111+
});
112+
fireEvent(input, customEvent);
113+
await waitFor(() => expect(input).toHaveAttribute('help-text', 'Incorrect format.'));
77114
});
78115

79-
it('does not allow empty input', () => {
116+
it('has no ANI entry options when the entry list is empty', async () => {
117+
render(<OutdialCallComponent startOutdial={mockStartOutdial} outdialANIEntries={[]} />);
118+
const select = await screen.findByTestId('outdial-ani-option-select');
119+
fireEvent.click(select);
120+
expect(screen.queryByText('name 1')).not.toBeInTheDocument();
121+
});
122+
123+
it('sets selected ani when an option is selected', async () => {
80124
render(<OutdialCallComponent {...props} />);
81-
const callButton = screen.getByRole('button');
82-
fireEvent.click(callButton);
83-
expect(mockStartOutdial).not.toHaveBeenCalled();
125+
const select = await screen.findByTestId('outdial-ani-option-select');
126+
fireEvent.click(select);
127+
const option = await screen.findByText('name 1');
128+
expect(option).toBeInTheDocument();
129+
fireEvent.click(option);
130+
await waitFor(() => {
131+
expect(option).toHaveAttribute('aria-selected', 'true');
132+
});
84133
});
85134

86-
it('should remove whitespace and only keep numbers', () => {
135+
it('does not allow empty input', async () => {
87136
render(<OutdialCallComponent {...props} />);
88-
const input = screen.getByPlaceholderText('Enter number to dial');
89-
fireEvent.change(input, {target: {value: ' 1 2 3 4 '}});
90-
expect(input).toHaveValue('1234');
137+
const callButton = await screen.findByTestId('outdial-call-button');
138+
expect(callButton).toBeDisabled();
91139
});
92140
});

packages/contact-center/task/src/OutdialCall/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ const OutdialCallInternal: React.FunctionComponent = observer(() => {
99
const {cc, logger} = store;
1010

1111
const result = useOutdialCall({cc, logger});
12+
// Uncomment after SDK PR#4513 is merged
13+
// const outdialANIEntries = getOutdialANIEntries({cc, logger});
1214
const props = {
1315
...result,
16+
// outdialANIEntries,
1417
};
1518

1619
return <OutdialCallComponent {...props} />;

packages/contact-center/task/src/helper.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,3 +872,20 @@ export const useOutdialCall = (props: useOutdialCallProps) => {
872872
startOutdial,
873873
};
874874
};
875+
876+
// Uncomment once SDK PR#4513 is merged
877+
// export const getOutdialANIEntries = async (props: useOutdialCallProps) => {
878+
// const {cc, logger} = props;
879+
// const agentProfile = cc.agentConfig;
880+
// const outdialANIId = agentProfile?.outdialANIId || '';
881+
// try {
882+
// const result = await cc.getOutdialANIEntries(outdialANIId);
883+
// return result;
884+
// } catch (error) {
885+
// logger.error(`Error fetching Outdial ANI entries: ${error}`, {
886+
// module: 'widget-OutdialCall#helper.ts',
887+
// method: 'getOutdialANIEntries',
888+
// });
889+
// throw error;
890+
// }
891+
// };

0 commit comments

Comments
 (0)