• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yext / answers-search-ui / 25056892734

28 Apr 2026 01:51PM UTC coverage: 61.914% (+0.09%) from 61.826%
25056892734

Pull #1989

github

web-flow
Merge eda7070fa into e1bc6bfc0
Pull Request #1989: v2.0.0

2050 of 3451 branches covered (59.4%)

Branch coverage included in aggregate %.

12 of 18 new or added lines in 5 files covered. (66.67%)

17 existing lines in 3 files now uncovered.

3495 of 5505 relevant lines covered (63.49%)

26.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.63
/src/ui/speechrecognition/speechrecognizer.js
1
/* eslint-disable new-cap */
2
import { isMicrosoftEdge, isSafari } from '../../core/utils/useragent';
3
import { transformSpeechRecognitionLocaleForEdge } from '../../core/speechrecognition/locales';
4
import TranslationFlagger from '../i18n/translationflagger';
5
import alert from '../alert';
6

7
/**
8
 * Responsible for recognizing speech
9
 */
10
export default class SpeechRecognizer {
11
  constructor (locale) {
12
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
2!
13
    this._speechRecognition = new SpeechRecognition();
2✔
14
    this._speechRecognition.interimResults = true;
2✔
15

16
    this._speechRecognition.lang = isMicrosoftEdge()
2!
17
      ? transformSpeechRecognitionLocaleForEdge(locale)
18
      : locale;
19

20
    /**
21
     * The latest result from speech recognition
22
     * @type {string}
23
     */
24
    this._latestResult = '';
2✔
25

26
    /**
27
     * The timeout ID of the silence threshold timeout
28
     * @type {number|null}
29
     */
30
    this._silenceThresholdTimeout = null;
2✔
31

32
    /**
33
     * The amount of silence after the last detected word before triggering a search.
34
     * This is primarily used for Safari since Edge and Chrome typically detect the end of
35
     * voice search phrase very quickly.
36
     */
37
    this._silenceThresholdToSearch = 1000;
2✔
38

39
    /**
40
     * Indicates that speech recognition is currently active.
41
     * This is used to prevent the speech recognizer from starting while it is already active.
42
     * @type {boolean}
43
     */
44
    this._recognitionActive = false;
2✔
45

46
    this._init();
2✔
47
  }
48

49
  _init () {
50
    this._speechRecognition.addEventListener('start', () => {
2✔
51
      this._recognitionActive = true;
1✔
52
    });
53
    this._speechRecognition.addEventListener('end', () => {
2✔
54
      this._recognitionActive = false;
×
UNCOV
55
      this._onCompleteHandler && this._onCompleteHandler(this._latestResult);
×
56
    });
57
    this._speechRecognition.addEventListener('result', event => {
2✔
UNCOV
58
      this._handleResultEvent(event);
×
59
    });
60
    this._speechRecognition.addEventListener('error', event => {
2✔
UNCOV
61
      this._handleErrorEvent(event);
×
62
    });
63
  }
64

65
  /**
66
   * Handles a search recognition result event
67
   * @param {SpeechRecognitionEvent} event
68
   */
69
  _handleResultEvent (event) {
70
    /**
71
     * Set a timeout to stop the speech recognition if no words are detected for the configured amount
72
     * of time. Every time a result comes in, reset that timeout.
73
     */
74
    clearTimeout(this._silenceThresholdTimeout);
×
75
    this._silenceThresholdTimeout = setTimeout(() => {
×
UNCOV
76
      this.stop();
×
77
    }, this._silenceThresholdToSearch);
78

79
    const result = event.results[0][0].transcript;
×
UNCOV
80
    const isFinalResult = event.results[0].isFinal;
×
81

82
    if (result !== this._latestResult) {
×
83
      this._onResultHandler && this._onResultHandler(result);
×
UNCOV
84
      this._latestResult = result;
×
85
    }
86
    if (isFinalResult) {
×
UNCOV
87
      this.stop();
×
88
    }
89
  }
90

91
  /**
92
   * Handles a speech recognition error
93
   * @param {SpeechRecognitionError} event
94
   */
95
  _handleErrorEvent (event) {
96
    if (event.error === 'service-not-allowed') {
×
97
      let errorMsg = TranslationFlagger.flag({ phrase: 'Speech Recognition is not available.' });
×
98
      if (isSafari()) {
×
UNCOV
99
        errorMsg += '\n' + TranslationFlagger.flag({ phrase: 'Note: For Safari users, Siri must be enabled' });
×
100
      }
UNCOV
101
      alert(errorMsg);
×
102
    } else {
UNCOV
103
      console.warn(event);
×
104
    }
UNCOV
105
    this._onError && this._onError();
×
106
  }
107

108
  /**
109
   * Starts the speech recognizer if it has not already started
110
   */
111
  start () {
112
    try {
1✔
113
      !this._recognitionActive && this._speechRecognition.start();
1✔
114
    } catch (err) {
UNCOV
115
      console.warn(err);
×
116
    }
117
  }
118

119
  /**
120
   * Stops the speech recognizer if it is active
121
   */
122
  stop () {
123
    this._recognitionActive && this._speechRecognition.stop();
1✔
124
  }
125

126
  /**
127
   * Sets the callback which is called when an error occurs
128
   * @param {Function} cb
129
   */
130
  onError (cb) {
131
    this._onError = cb;
2✔
132
  }
133

134
  /**
135
   * Sets the callback which is called when a result is detected
136
   * @param {Function} cb
137
   */
138
  onResult (cb) {
139
    this._onResultHandler = cb;
2✔
140
  }
141

142
  /**
143
   * Sets the callback which is called when speech recognition is complete
144
   * @param {Function} cb
145
   */
146
  onComplete (cb) {
147
    this._onCompleteHandler = cb;
2✔
148
  }
149
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc