-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathdtmf.input.html
More file actions
197 lines (165 loc) · 7.93 KB
/
dtmf.input.html
File metadata and controls
197 lines (165 loc) · 7.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone@7.8.7/babel.min.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react@16.8.6/umd/react.production.min.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.production.min.js"></script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<script crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
</head>
<body>
<main id="webchat"></main>
<!--
Test: DTMF (Dual-Tone Multi-Frequency) Input
This test validates DTMF keypad input during voice sessions:
1. User is in voice mode
2. User presses keypad digits (DTMF tones)
3. Server processes DTMF input
4. Bot responds accordingly
-->
<script type="module">
import { setupMockMediaDevices } from '/assets/esm/speechToSpeech/mockMediaDevices.js';
setupMockMediaDevices();
</script>
<script type="text/babel">
run(async function () {
const {
React,
ReactDOM: { render },
WebChat: { FluentThemeProvider, ReactWebChat, testIds }
} = window;
const { directLine, store } = testHelpers.createDirectLineEmulator();
// Multi-modal experience: server announces audio, consumer opted into voice mode.
directLine.setCapability('getVoiceConfiguration', { sampleRate: 24000, chunkIntervalMs: 100 }, { emitEvent: false });
directLine.setCapability('getIsVoiceModeEnabled', true, { emitEvent: false });
// Intercept postActivity to capture outgoing DTMF events
const capturedDtmfEvents = [];
const originalPostActivity = directLine.postActivity.bind(directLine);
directLine.postActivity = (activity) => {
if (activity.name === 'media.end' && activity.type === 'event') {
capturedDtmfEvents.push(activity);
}
return originalPostActivity(activity);
};
render(
<FluentThemeProvider variant="fluent">
<ReactWebChat
directLine={directLine}
store={store}
styleOptions={{
disableFileUpload: true,
hideTelephoneKeypadButton: false,
}}
/>
</FluentThemeProvider>,
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// ===== STEP 1: Verify mic button and turn on =====
const micButton = document.querySelector(`[data-testid="${testIds.sendBoxMicrophoneButton}"]`);
expect(micButton).toBeTruthy();
// GIVEN: Recording is active
await host.click(micButton);
await pageConditions.became(
'Recording started',
() => micButton.getAttribute('aria-label')?.includes('Microphone on'),
1000
);
// ===== STEP 2: Bot prompts for DTMF input =====
await directLine.emulateIncomingVoiceActivity({
type: 'event',
name: 'media.end',
from: { role: 'bot' },
text: 'Please enter your 4-digit PIN using your keypad.',
value: { transcription: 'Please enter your 4-digit PIN using your keypad.', origin: 'agent' },
valueType: 'application/vnd.microsoft.activity.azure.directline.audio.transcript'
});
await pageConditions.numActivitiesShown(1);
// ===== STEP 3: Click telephony keypad button =====
const keypadButton = document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadToolbarButton}"]`);
expect(keypadButton).toBeTruthy();
await host.click(keypadButton);
// Wait for keypad to open
await pageConditions.became(
'Keypad opened',
() => document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton1}"]`),
1000
);
// ===== STEP 4: Click 1, 2, 3, 4 on keypad =====
const key1 = document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton1}"]`);
const key2 = document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton2}"]`);
const key3 = document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton3}"]`);
const key4 = document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton4}"]`);
expect(key1).toBeTruthy();
expect(key2).toBeTruthy();
expect(key3).toBeTruthy();
expect(key4).toBeTruthy();
// THEN: Should show keypad open
await host.snapshot('local');
await host.click(key1);
await host.click(key2);
await host.click(key3);
await host.click(key4);
// ===== STEP 5: Verify DTMF events were sent via postActivity =====
await pageConditions.became(
'DTMF events sent via postActivity',
() => capturedDtmfEvents.length >= 4,
1000
);
expect(capturedDtmfEvents.length).toBe(4);
await host.click(keypadButton);
await directLine.emulateIncomingVoiceActivity({
type: 'event',
name: 'media.end',
value: { transcription: '/DTMFKey 1', origin: 'user' },
valueType: 'application/vnd.microsoft.activity.azure.directline.audio.transcript'
});
await directLine.emulateIncomingVoiceActivity({
type: 'event',
name: 'media.end',
value: { transcription: '/DTMFKey 2', origin: 'user' },
valueType: 'application/vnd.microsoft.activity.azure.directline.audio.transcript'
});
await directLine.emulateIncomingVoiceActivity({
type: 'event',
name: 'media.end',
value: { transcription: '/DTMFKey 3', origin: 'user' },
valueType: 'application/vnd.microsoft.activity.azure.directline.audio.transcript'
});
await directLine.emulateIncomingVoiceActivity({
type: 'event',
name: 'media.end',
value: { transcription: '/DTMFKey 4', origin: 'user' },
valueType: 'application/vnd.microsoft.activity.azure.directline.audio.transcript'
});
// ===== STEP 6: Verify user transcript with 4 incoming "/DTMFKey {1/2/3/4}" =====
await pageConditions.numActivitiesShown(5); // 1 bot prompt + 4 user DTMF
const activities = pageElements.activityContents();
expect(activities[0]).toHaveProperty('textContent', 'Please enter your 4-digit PIN using your keypad.');
expect(activities[1]).toHaveProperty('textContent', '/DTMFKey 1');
expect(activities[2]).toHaveProperty('textContent', '/DTMFKey 2');
expect(activities[3]).toHaveProperty('textContent', '/DTMFKey 3');
expect(activities[4]).toHaveProperty('textContent', '/DTMFKey 4');
// ===== STEP 7: Bot responds =====
await directLine.emulateIncomingVoiceActivity({
type: 'event',
name: 'media.end',
from: { role: 'bot' },
value: { transcription: 'Thank you. Your PIN has been verified.', origin: 'agent' },
valueType: 'application/vnd.microsoft.activity.azure.directline.audio.transcript'
});
// THEN: Bot message appears
await pageConditions.numActivitiesShown(6);
const finalActivities = pageElements.activityContents();
expect(finalActivities[5]).toHaveProperty('textContent', 'Thank you. Your PIN has been verified.');
// THEN: Should show DTMF conversation
await pageConditions.scrollToBottomCompleted();
await host.snapshot('local');
await host.click(micButton);
});
</script>
</body>
</html>