-
Notifications
You must be signed in to change notification settings - Fork 485
TTS: Increase test coverage #1524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,7 +5,7 @@ import PageChunkIterator from '@/src/plugins/tts/PageChunkIterator.js'; | |||||
| /** @typedef {import('@/src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */ | ||||||
|
|
||||||
| // Skipping because it's flaky. Fix in #672 | ||||||
| describe.skip('AbstractTTSEngine', () => { | ||||||
| describe('AbstractTTSEngine', () => { | ||||||
| test('stops playing once done', async () => { | ||||||
| class DummyEngine extends AbstractTTSEngine { | ||||||
| getVoices() { return []; } | ||||||
|
|
@@ -20,6 +20,63 @@ describe.skip('AbstractTTSEngine', () => { | |||||
| }); | ||||||
| }); | ||||||
|
|
||||||
| describe('Non Flaky AbstractTTSEngine', () => { | ||||||
| let d; | ||||||
| beforeEach(() => { | ||||||
| class DummyEngine extends AbstractTTSEngine { | ||||||
| getVoices() { return []; } | ||||||
| } | ||||||
| d = new DummyEngine(DUMMY_TTS_ENGINE_OPTS); | ||||||
| }); | ||||||
|
|
||||||
| test('should trigger start event', () => { | ||||||
| const triggerStub = sinon.spy(d.events, 'trigger'); | ||||||
| d._chunkIterator = { next: sinon.stub().resolves(PageChunkIterator.AT_END) }; | ||||||
| d.start(0, 0); | ||||||
| expect(triggerStub.callCount).toBe(1); | ||||||
| }); | ||||||
|
|
||||||
| test('should handle pause and resume events for state changes', () => { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| const triggerStub = sinon.spy(d.events, 'trigger'); | ||||||
| d.activeSound = { pause: sinon.stub() }; | ||||||
|
|
||||||
| d.paused = true; | ||||||
| d.pause(); | ||||||
| expect(triggerStub.callCount).toBe(0); | ||||||
|
|
||||||
| d.paused = false; | ||||||
| d.pause(); | ||||||
| expect(triggerStub.callCount).toBe(1); | ||||||
| expect(d.paused).toBeTruthy(); | ||||||
| }); | ||||||
|
|
||||||
| test('should trigger resume event', () => { | ||||||
| const triggerStub = sinon.spy(d.events, 'trigger'); | ||||||
| d.activeSound = { resume: sinon.stub() }; | ||||||
|
|
||||||
| d.paused = true; | ||||||
| d.resume(); | ||||||
| expect(triggerStub.callCount).toBe(1); | ||||||
| expect(d.paused).toBeFalsy(); | ||||||
| }); | ||||||
|
|
||||||
| test('togglePlayPause', () => { | ||||||
| const triggerSpy = sinon.spy(d.events, 'trigger'); | ||||||
| d.activeSound = { | ||||||
| resume: sinon.stub(), | ||||||
| pause: sinon.stub(), | ||||||
| }; | ||||||
| d.paused = true; | ||||||
| d.togglePlayPause(); | ||||||
| expect(d.paused).toBeFalsy(); | ||||||
|
|
||||||
| d.togglePlayPause(); | ||||||
| expect(d.paused).toBeTruthy(); | ||||||
| expect(triggerSpy.callCount).toBe(2); | ||||||
| }); | ||||||
|
|
||||||
| }); | ||||||
|
|
||||||
| for (const dummyVoice of [dummyVoiceHyphens, dummyVoiceUnderscores]) { | ||||||
| describe(`getBestBookVoice with BCP47 ${dummyVoice == dummyVoiceUnderscores ? '+' : '-'} underscores`, () => { | ||||||
| const { getBestBookVoice } = AbstractTTSEngine; | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -15,11 +15,13 @@ beforeEach(() => { | |||||
| this.text = text; | ||||||
| Object.assign(this, eventTargetMixin()); | ||||||
| }; | ||||||
| // mockSomeConstantValueGetter.mockReturnValue(false); | ||||||
| }); | ||||||
|
|
||||||
| afterEach(() => { | ||||||
| delete window.speechSynthesis; | ||||||
| delete window.SpeechSynthesisUtterance; | ||||||
| // mockSomeConstantValueGetter.mockReset(); | ||||||
| }); | ||||||
|
|
||||||
| describe('WebTTSEngine', () => { | ||||||
|
|
@@ -92,6 +94,17 @@ describe('WebTTSSound', () => { | |||||
| }); | ||||||
| }); | ||||||
|
|
||||||
| test('reloading should store the charIndex for the sound', async () => { | ||||||
| const sound = new WebTTSSound('hello world'); | ||||||
| sound.load(); | ||||||
| sound.play(); | ||||||
| sound.utterance.dispatchEvent('pause', {target: {text: 'hello world'}}); | ||||||
| await afterEventLoop(); | ||||||
| sound.reload(); | ||||||
| await afterEventLoop(); | ||||||
| expect(sound._charIndex).not.toBe(0); | ||||||
| }); | ||||||
|
|
||||||
| describe('_chromePausingBugFix', () => { | ||||||
| /** @type {sinon.SinonFakeTimers} */ | ||||||
| let clock = null; | ||||||
|
|
@@ -167,12 +180,69 @@ describe('WebTTSSound', () => { | |||||
| sound.started = true; | ||||||
| sound.paused = true; | ||||||
| const dispatchSpy = sinon.spy(sound.utterance, 'dispatchEvent'); | ||||||
| sound.play = sinon.stub(); | ||||||
| sound.resume(); | ||||||
| clock.tick(1000); | ||||||
| sound.stop = sinon.stub(); | ||||||
| clock.restore(); | ||||||
|
|
||||||
| await afterEventLoop(); | ||||||
| expect(dispatchSpy.callCount).toBe(1); | ||||||
| expect(sound.play.callCount).toBe(1); | ||||||
| expect(dispatchSpy.args[0][0].type).toBe('resume'); | ||||||
| }); | ||||||
|
|
||||||
| test('resume continues playing if not started or stopped', async() => { | ||||||
| const sound = new WebTTSSound('hello world'); | ||||||
| sound.load(); | ||||||
| sound.play = sinon.stub(); | ||||||
| sound.resume(); | ||||||
| await afterEventLoop(); | ||||||
| expect(sound.play.callCount).toBe(1); | ||||||
| }); | ||||||
|
|
||||||
| test('fire finish event', async () => { | ||||||
| const sound = new WebTTSSound('hello world'); | ||||||
| sound.load(); | ||||||
| const dispatchSpy = sinon.spy(sound.utterance, 'dispatchEvent'); | ||||||
| sound.play(); | ||||||
| sound.stop = sinon.stub(); | ||||||
| sound.finish(); | ||||||
| await afterEventLoop(); | ||||||
| expect(dispatchSpy.args[0][0].type).toBe('finish'); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is likely what we might want in the trigger stub in the other file, to better test that they're actually triggering the right event. |
||||||
| }); | ||||||
|
|
||||||
| test('pause immediately fails if already in paused state', async() => { | ||||||
| const sound = new WebTTSSound('pausing on a pause'); | ||||||
| sound.load(); | ||||||
| sound.play(); | ||||||
| const checkSpeech = jest.spyOn(speechSynthesis, 'pause'); | ||||||
| sound.paused = true; | ||||||
| sound.pause(); | ||||||
| expect(checkSpeech).toHaveBeenCalledTimes(0); | ||||||
| }); | ||||||
| }); | ||||||
|
|
||||||
| const mockSomeConstantValueGetter = jest.fn(); | ||||||
| jest.mock('../../../../src/plugins/tts/utils', () => ({ | ||||||
| ...jest.requireActual('../../../../src/plugins/tts/utils'), | ||||||
| get DEBUG_READ_ALOUD() { | ||||||
| return mockSomeConstantValueGetter; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this will fix this always being truthy? I think it's currently returning the just fn itself, which is truthy
Suggested change
|
||||||
| }, | ||||||
| })); | ||||||
|
|
||||||
| describe('DEBUG_READ_ALOUD', () => { | ||||||
| test('debug listeners should be added', async () => { | ||||||
| mockSomeConstantValueGetter.mockReturnValue(true); | ||||||
| const sound = new WebTTSSound('debug world'); | ||||||
| console.log = sinon.stub(); | ||||||
| expect(console.log.callCount).toBe(0); | ||||||
| sound.load(); | ||||||
| const EVENTS = ['pause', 'resume', 'start', 'end', 'error', 'boundary', 'mark', 'finish']; | ||||||
|
|
||||||
| EVENTS.forEach((event) => { | ||||||
| sound.utterance.dispatchEvent(event); | ||||||
| }); | ||||||
| expect(console.log.callCount).toBe(EVENTS.length); | ||||||
| }); | ||||||
| }); | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These describe blocks can be combined