@@ -11,6 +11,7 @@ import type { ReactNode } from 'react';
1111/**
1212 * Internal dependencies
1313 */
14+ import { captureCsvDownloads } from '../../test-utils' ;
1415import TopPostsWidget from '../render' ;
1516
1617jest . mock ( '@automattic/jetpack-script-data' , ( ) => ( {
@@ -276,43 +277,25 @@ describe( 'TopPostsWidget', () => {
276277 } ) ;
277278
278279 describe ( 'CSV export' , ( ) => {
279- let blobs : Blob [ ] ;
280- let clickSpy : jest . SpyInstance ;
281- let originalCreateObjectURL : typeof window . URL . createObjectURL ;
282- let originalRevokeObjectURL : typeof window . URL . revokeObjectURL ;
280+ let downloads : ReturnType < typeof captureCsvDownloads > ;
283281
284282 beforeEach ( ( ) => {
285283 jest . useFakeTimers ( ) ;
286- blobs = [ ] ;
287- originalCreateObjectURL = window . URL . createObjectURL ;
288- originalRevokeObjectURL = window . URL . revokeObjectURL ;
289- // jsdom defines neither, so `jest.spyOn` has nothing to wrap.
290- const createObjectURL = jest . fn ( ( blob : Blob ) => {
291- blobs . push ( blob ) ;
292- return 'blob:mock' ;
293- } ) ;
294- const revokeObjectURL = jest . fn ( ) ;
295- window . URL . createObjectURL = createObjectURL ;
296- window . URL . revokeObjectURL = revokeObjectURL ;
297- // An anchor click would reach jsdom's unimplemented navigation.
298- clickSpy = jest . spyOn ( HTMLAnchorElement . prototype , 'click' ) . mockImplementation ( ( ) => { } ) ;
284+ downloads = captureCsvDownloads ( ) ;
299285 } ) ;
300286
301287 afterEach ( ( ) => {
302288 jest . useRealTimers ( ) ;
303- clickSpy . mockRestore ( ) ;
304- window . URL . createObjectURL = originalCreateObjectURL ;
305- window . URL . revokeObjectURL = originalRevokeObjectURL ;
289+ downloads . restore ( ) ;
306290 } ) ;
307291
308292 async function downloadCsvLines ( ) {
309- // This package does not depend on @testing -library/user-event.
310- // eslint-disable-next-line testing-library/prefer-user-event
311- fireEvent . click ( await screen . findByRole ( 'button' , { name : / D o w n l o a d C S V / } ) ) ;
293+ const user = userEvent . setup ( { advanceTimers : jest . advanceTimersByTime } ) ;
294+ await user . click ( await screen . findByRole ( 'button' , { name : / D o w n l o a d C S V / } ) ) ;
312295
313- await waitFor ( ( ) => expect ( blobs ) . toHaveLength ( 1 ) ) ;
296+ await waitFor ( ( ) => expect ( downloads . files ) . toHaveLength ( 1 ) ) ;
314297
315- return ( await blobs [ 0 ] . text ( ) ) . replace ( '\ufeff' , '' ) . split ( '\n' ) ;
298+ return downloads . lines ( ) ;
316299 }
317300
318301 it ( 'downloads the full Posts & pages report instead of the rows on screen' , async ( ) => {
@@ -404,10 +387,7 @@ describe( 'TopPostsWidget', () => {
404387 '"Tags","80",""' ,
405388 '"Tags > video","80","https://example.com/tag/video/"' ,
406389 ] ) ;
407- expect ( clickSpy . mock . contexts [ 0 ] ) . toHaveProperty (
408- 'download' ,
409- 'archives-2026-03-01_2026-03-10.csv'
410- ) ;
390+ expect ( downloads . files [ 0 ] . filename ) . toBe ( 'archives-2026-03-01_2026-03-10.csv' ) ;
411391 } ) ;
412392 } ) ;
413393
0 commit comments