@@ -56,6 +56,18 @@ const renderComponent = (
5656const playButton = ( ) => screen . queryByTestId ( 'play-audio' ) ;
5757const pauseButton = ( ) => screen . queryByTestId ( 'pause-audio' ) ;
5858
59+ const clickToPlay = async ( ) => {
60+ await act ( async ( ) => {
61+ await fireEvent . click ( playButton ( ) ) ;
62+ } ) ;
63+ } ;
64+
65+ const clickToPause = async ( ) => {
66+ await act ( async ( ) => {
67+ await fireEvent . click ( pauseButton ( ) ) ;
68+ } ) ;
69+ } ;
70+
5971const expectAddErrorMessage = ( message ) => {
6072 expect ( addErrorSpy ) . toHaveBeenCalled ( ) ;
6173 const hit = addErrorSpy . mock . calls . find ( ( c ) => c ?. [ 0 ] ?. message === message ) ;
@@ -87,15 +99,16 @@ describe('Audio', () => {
8799 expect ( container . querySelector ( 'img' ) ) . not . toBeInTheDocument ( ) ;
88100 } ) ;
89101
90- it ( 'creates a playback Audio() with the right src' , ( ) => {
102+ it ( 'creates a playback Audio() with the right src only after clicked to play' , async ( ) => {
91103 renderComponent ( { og : audioAttachment } ) ;
104+ await clickToPlay ( ) ;
92105 expect ( createdAudios . length ) . toBe ( 1 ) ;
93106 expect ( createdAudios [ 0 ] . src ) . toBe ( audioAttachment . asset_url ) ;
94107 } ) ;
95108
96109 it ( 'shows the correct progress after clicking to the middle of a progress bar (seeking)' , async ( ) => {
97110 const { getByTestId } = renderComponent ( { og : audioAttachment } ) ;
98-
111+ await clickToPlay ( ) ;
99112 jest
100113 . spyOn ( HTMLDivElement . prototype , 'getBoundingClientRect' )
101114 . mockImplementationOnce ( ( ) => ( { width : 120 , x : 0 } ) ) ;
@@ -119,19 +132,16 @@ describe('Audio', () => {
119132 it ( 'shows the correct button if the song is paused/playing' , async ( ) => {
120133 renderComponent ( { og : { ...audioAttachment } } ) ;
121134
122- const audioPausedMock = jest . spyOn ( createdAudios [ 0 ] , 'paused' , 'get' ) ;
123-
124135 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
125136
126- await act ( async ( ) => {
127- await fireEvent . click ( playButton ( ) ) ;
128- } ) ;
137+ await clickToPlay ( ) ;
138+ const audioPausedMock = jest . spyOn ( createdAudios [ 0 ] , 'paused' , 'get' ) ;
139+
129140 expect ( pauseButton ( ) ) . toBeInTheDocument ( ) ;
130141
131142 audioPausedMock . mockReturnValueOnce ( false ) ;
132- await act ( async ( ) => {
133- await fireEvent . click ( pauseButton ( ) ) ;
134- } ) ;
143+
144+ await clickToPause ( ) ;
135145 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
136146
137147 expect ( addErrorSpy ) . not . toHaveBeenCalled ( ) ;
@@ -143,20 +153,19 @@ describe('Audio', () => {
143153 renderComponent ( {
144154 og : audioAttachment ,
145155 } ) ;
146- const audio = createdAudios [ 0 ] ;
147- audio . play . mockImplementationOnce ( ( ) => sleep ( 3000 ) ) ;
148-
149156 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
150157 expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
158+ jest
159+ . spyOn ( HTMLAudioElement . prototype , 'play' )
160+ . mockImplementationOnce ( ( ) => sleep ( 3000 ) ) ;
161+ await clickToPlay ( ) ;
151162
152- await act ( async ( ) => {
153- await fireEvent . click ( playButton ( ) ) ;
163+ await waitFor ( ( ) => {
164+ expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
165+ expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
154166 } ) ;
155- expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
156- expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
157167
158168 jest . advanceTimersByTime ( 2000 ) ;
159-
160169 await waitFor ( ( ) => {
161170 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
162171 expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
@@ -169,18 +178,18 @@ describe('Audio', () => {
169178 it ( 'registers error if pausing the audio after 2000ms of inactivity failed' , async ( ) => {
170179 jest . useFakeTimers ( 'modern' ) ;
171180 renderComponent ( { og : audioAttachment } ) ;
172- const audio = createdAudios [ 0 ] ;
173- audio . play . mockImplementationOnce ( ( ) => sleep ( 3000 ) ) ;
174- audio . pause . mockImplementationOnce ( ( ) => {
181+
182+ jest
183+ . spyOn ( HTMLAudioElement . prototype , 'play' )
184+ . mockImplementationOnce ( ( ) => sleep ( 3000 ) ) ;
185+ jest . spyOn ( HTMLAudioElement . prototype , 'pause' ) . mockImplementationOnce ( ( ) => {
175186 throw new Error ( '' ) ;
176187 } ) ;
177188
178- await act ( ( ) => {
179- fireEvent . click ( playButton ( ) ) ;
180- } ) ;
189+ await clickToPlay ( ) ;
190+
181191 jest . advanceTimersByTime ( 2000 ) ;
182192 await waitFor ( ( ) => {
183- expect ( audio . pause ) . toHaveBeenCalledWith ( ) ;
184193 expectAddErrorMessage ( 'Failed to play the recording' ) ;
185194 } ) ;
186195
@@ -192,48 +201,37 @@ describe('Audio', () => {
192201 renderComponent ( {
193202 og : audioAttachment ,
194203 } ) ;
195- const audio = createdAudios [ 0 ] ;
196- audio . play . mockRejectedValueOnce ( new Error ( errorText ) ) ;
197- const audioCanPlayTypeMock = jest
198- . spyOn ( audio , 'canPlayType' )
204+ jest
205+ . spyOn ( HTMLAudioElement . prototype , 'play' )
206+ . mockRejectedValueOnce ( new Error ( errorText ) ) ;
207+ const canPlaySpy = jest
208+ . spyOn ( HTMLAudioElement . prototype , 'canPlayType' )
199209 . mockReturnValue ( 'maybe' ) ;
200210
201211 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
202212 expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
203213
204- await act ( async ( ) => {
205- await fireEvent . click ( playButton ( ) ) ;
206- } ) ;
214+ await clickToPlay ( ) ;
207215 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
208216 expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
209217 expectAddErrorMessage ( errorText ) ;
210- audioCanPlayTypeMock . mockRestore ( ) ;
218+ canPlaySpy . mockRestore ( ) ;
211219 } ) ;
212220
213221 it ( 'should register error if the audio MIME type is not playable' , async ( ) => {
214222 renderComponent ( { og : { ...audioAttachment , mime_type : 'audio/mp4' } } ) ;
215- const audio = createdAudios [ 0 ] ;
216- const audioCanPlayTypeMock = jest . spyOn ( audio , 'canPlayType' ) . mockReturnValue ( '' ) ;
217-
218- expect ( audio . play ) . not . toHaveBeenCalled ( ) ;
219-
220- expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
221- expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
223+ const spy = jest . spyOn ( HTMLAudioElement . prototype , 'canPlayType' ) . mockReturnValue ( '' ) ;
222224
223- await act ( async ( ) => {
224- await fireEvent . click ( playButton ( ) ) ;
225- } ) ;
226- expect ( audio . play ) . not . toHaveBeenCalled ( ) ;
225+ await clickToPlay ( ) ;
227226 expect ( playButton ( ) ) . toBeInTheDocument ( ) ;
228227 expect ( pauseButton ( ) ) . not . toBeInTheDocument ( ) ;
229228 expectAddErrorMessage ( 'Recording format is not supported and cannot be reproduced' ) ;
230-
231- audioCanPlayTypeMock . mockRestore ( ) ;
229+ spy . mockRestore ( ) ;
232230 } ) ;
233231
234232 it ( 'shows the correct progress on timeupdate' , async ( ) => {
235233 renderComponent ( { og : audioAttachment } ) ;
236-
234+ await clickToPlay ( ) ;
237235 const audio = createdAudios [ 0 ] ;
238236 jest . spyOn ( audio , 'duration' , 'get' ) . mockReturnValue ( 100 ) ;
239237 jest . spyOn ( audio , 'currentTime' , 'get' ) . mockReturnValue ( 50 ) ;
@@ -245,7 +243,7 @@ describe('Audio', () => {
245243 } ) ;
246244 } ) ;
247245
248- it ( 'differentiates between in thread and in channel audio player' , ( ) => {
246+ it ( 'differentiates between in thread and in channel audio player' , async ( ) => {
249247 const message = generateMessage ( ) ;
250248 render (
251249 < WithAudioPlayback >
@@ -257,10 +255,17 @@ describe('Audio', () => {
257255 </ MessageProvider >
258256 </ WithAudioPlayback > ,
259257 ) ;
258+ const playButtons = screen . queryAllByTestId ( 'play-audio' ) ;
259+ expect ( playButtons . length ) . toBe ( 2 ) ;
260+ await Promise . all (
261+ playButtons . map ( async ( button ) => {
262+ await fireEvent . click ( button ) ;
263+ } ) ,
264+ ) ;
260265 expect ( createdAudios ) . toHaveLength ( 2 ) ;
261266 } ) ;
262267
263- it ( 'keeps a single copy of audio player for the same requester' , ( ) => {
268+ it ( 'keeps a single copy of audio player for the same requester' , async ( ) => {
264269 const message = generateMessage ( ) ;
265270 render (
266271 < WithAudioPlayback >
@@ -272,6 +277,13 @@ describe('Audio', () => {
272277 </ MessageProvider >
273278 </ WithAudioPlayback > ,
274279 ) ;
280+ const playButtons = screen . queryAllByTestId ( 'play-audio' ) ;
281+ expect ( playButtons . length ) . toBe ( 2 ) ;
282+ await Promise . all (
283+ playButtons . map ( async ( button ) => {
284+ await fireEvent . click ( button ) ;
285+ } ) ,
286+ ) ;
275287 expect ( createdAudios ) . toHaveLength ( 1 ) ;
276288 } ) ;
277289} ) ;
0 commit comments