@@ -6,9 +6,12 @@ import * as http from 'http';
66import * as path from 'path' ;
77
88import { test , expect } from '../../fixtures/index' ;
9- import { waitForAppReady } from '../../helpers/appReadiness' ;
10- import { electronBinaryPath , appDir , emptyConfig } from '../../helpers/config' ;
11- import { closeElectronAppFast } from '../../helpers/electronApp' ;
9+ import {
10+ closeDownloadTestApp ,
11+ launchAppWithDownloadsDir ,
12+ readDownloadsState ,
13+ triggerDownloadFromPopup ,
14+ } from '../../helpers/downloads' ;
1215
1316// ── MM-T1538: Download a video ────────────────────────────────────────
1417// Verifies a real end-to-end download path for a video MIME type:
@@ -17,19 +20,6 @@ import {closeElectronAppFast} from '../../helpers/electronApp';
1720// 3. DownloadsManager (src/main/downloadsManager.ts) handles will-download
1821// 4. We assert: the file lands on disk AND downloads.json records it
1922// with state "completed"
20- //
21- // Pattern mirrors download_completion.test.ts so the two tests differ only
22- // in MIME type and content — keeping the download flow exercised for the
23- // file type MM-T1538 specifically targets (video) without duplicating the
24- // scaffolding.
25-
26- function readJsonFile < T > ( filePath : string ) : T | undefined {
27- try {
28- return JSON . parse ( fs . readFileSync ( filePath , 'utf-8' ) ) as T ;
29- } catch {
30- return undefined ;
31- }
32- }
3323
3424async function startVideoServer ( filename : string , body : Buffer ) {
3525 const server = http . createServer ( ( request , response ) => {
@@ -54,17 +44,20 @@ async function startVideoServer(filename: string, body: Buffer) {
5444 ` ) ;
5545 } ) ;
5646
57- await new Promise < void > ( ( resolve ) =>
58- server . listen ( 0 , '127.0.0.1' , ( ) => resolve ( ) ) ,
59- ) ;
47+ await new Promise < void > ( ( resolve , reject ) => {
48+ server . once ( 'error' , reject ) ;
49+ server . listen ( 0 , '127.0.0.1' , ( ) => resolve ( ) ) ;
50+ } ) ;
6051 const address = server . address ( ) ;
6152 if ( ! address || typeof address === 'string' ) {
6253 throw new Error ( 'Failed to start local video download server' ) ;
6354 }
6455
6556 return {
66- server,
6757 url : `http://127.0.0.1:${ address . port } ` ,
58+ close : ( ) => new Promise < void > ( ( resolve , reject ) => {
59+ server . close ( ( error ) => ( error ? reject ( error ) : resolve ( ) ) ) ;
60+ } ) ,
6861 } ;
6962}
7063
@@ -74,100 +67,31 @@ test(
7467 async ( { } , testInfo ) => {
7568 const filename = 'sample-video.mp4' ;
7669
77- // Minimal .mp4 — magic bytes are enough for the download-manager
78- // pipeline; we never play the file, only assert it landed on disk.
7970 const videoBody = Buffer . from ( [
8071 0x00 , 0x00 , 0x00 , 0x18 , 0x66 , 0x74 , 0x79 , 0x70 ,
8172 0x6d , 0x70 , 0x34 , 0x32 , 0x00 , 0x00 , 0x00 , 0x00 ,
8273 0x6d , 0x70 , 0x34 , 0x32 , 0x69 , 0x73 , 0x6f , 0x6d ,
8374 ] ) ;
8475
85- const { server , url } = await startVideoServer ( filename , videoBody ) ;
76+ const { url , close : closeVideoServer } = await startVideoServer ( filename , videoBody ) ;
8677
8778 const userDataDir = path . join ( testInfo . outputDir , 'userdata' ) ;
88- const downloadsDir = path . join ( testInfo . outputDir , 'Downloads' ) ;
89- const config = {
90- ...emptyConfig ,
91- downloadLocation : downloadsDir ,
92- } ;
93-
94- fs . mkdirSync ( userDataDir , { recursive : true } ) ;
95- fs . mkdirSync ( downloadsDir , { recursive : true } ) ;
96- fs . writeFileSync (
97- path . join ( userDataDir , 'config.json' ) ,
98- JSON . stringify ( config ) ,
99- ) ;
100-
101- const { _electron : electron } = await import ( 'playwright' ) ;
102- const app = await electron . launch ( {
103- executablePath : electronBinaryPath ,
104- args : [
105- appDir ,
106- `--user-data-dir=${ userDataDir } ` ,
107- '--no-sandbox' ,
108- '--disable-gpu' ,
109- ] ,
110- env : { ...process . env , NODE_ENV : 'test' } ,
111- timeout : 60_000 ,
112- } ) ;
113-
114- const savedPath = path . join ( downloadsDir , filename ) ;
79+ const downloadLocation = path . join ( testInfo . outputDir , 'Downloads' ) ;
80+ const app = await launchAppWithDownloadsDir ( userDataDir , downloadLocation ) ;
81+ const savedPath = path . join ( downloadLocation , filename ) ;
11582
11683 try {
117- await waitForAppReady ( app ) ;
118- const mainWindow = app . windows ( ) . find ( ( window ) => window . url ( ) . includes ( 'index' ) ) ;
119- expect ( mainWindow ) . toBeDefined ( ) ;
120- await mainWindow ! . waitForLoadState ( ) ;
121-
122- const popupPromise = app . waitForEvent ( 'window' , {
123- predicate : ( window ) => window . url ( ) . startsWith ( url ) ,
124- timeout : 15_000 ,
125- } ) ;
126-
127- await app . evaluate ( async ( { BrowserWindow} , popupUrl ) => {
128- const popup = new BrowserWindow ( {
129- show : true ,
130- width : 900 ,
131- height : 700 ,
132- } ) ;
133- await popup . loadURL ( popupUrl ) ;
134- ( global as any ) . __videoDownloadPopup = popup ;
135- } , url ) ;
136-
137- const popupWindow = await popupPromise ;
138- await popupWindow . waitForLoadState ( ) ;
139- await popupWindow . click ( '#download-link' ) ;
140-
141- await expect .
142- poll ( ( ) => fs . existsSync ( savedPath ) , { timeout : 15_000 } ) .
143- toBe ( true ) ;
144-
145- // Verify the downloaded bytes match what we served
146- await expect .
147- poll ( ( ) => fs . readFileSync ( savedPath ) . equals ( videoBody ) , { timeout : 15_000 } ) .
148- toBe ( true ) ;
149-
150- // DownloadsManager must record the download as completed
151- await expect .
152- poll (
153- ( ) => {
154- const downloads = readJsonFile < Record < string , { state ?: string ; mimeType ?: string } > > (
155- path . join ( userDataDir , 'downloads.json' ) ,
156- ) ;
157- return downloads ?. [ filename ] ?. state ;
158- } ,
159- { timeout : 15_000 } ,
160- ) .
161- toBe ( 'completed' ) ;
84+ await triggerDownloadFromPopup ( app , url ) ;
85+
86+ await expect . poll ( ( ) => fs . existsSync ( savedPath ) , { timeout : 15_000 } ) . toBe ( true ) ;
87+ await expect . poll ( ( ) => fs . readFileSync ( savedPath ) . equals ( videoBody ) , { timeout : 15_000 } ) . toBe ( true ) ;
88+ await expect . poll (
89+ ( ) => readDownloadsState ( userDataDir ) [ filename ] ?. state ,
90+ { timeout : 15_000 } ,
91+ ) . toBe ( 'completed' ) ;
16292 } finally {
163- try {
164- await closeElectronAppFast ( app , userDataDir ) ;
165- } finally {
166- await new Promise < void > ( ( resolve , reject ) =>
167- server . close ( ( error ) => ( error ? reject ( error ) : resolve ( ) ) ) ,
168- ) ;
169- fs . rmSync ( downloadsDir , { recursive : true , force : true } ) ;
170- }
93+ await closeDownloadTestApp ( app , userDataDir , downloadLocation ) ;
94+ await closeVideoServer ( ) ;
17195 }
17296 } ,
17397) ;
0 commit comments