/** * Wiring coverage for the main.ts gateway download transports. These functions * pull in main-process singletons (https/http, electronNet, the OAuth session, * the save dialog), so we assert on their source shape — the same approach as * oauth-session-request.test.ts — while gateway-file-download.test.ts unit-tests * the extracted streaming/decoding logic behaviorally. */ import assert from 'node:assert/strict' import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import { test } from 'vitest' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const source = fs.readFileSync(path.join(__dirname, 'main.ts'), 'utf8') function extract(startMarker: string, endMarker: string): string { const start = source.indexOf(startMarker) assert.notEqual(start, -1, `${startMarker} should exist`) const end = source.indexOf(endMarker, start + startMarker.length) assert.notEqual(end, -1, `boundary after ${startMarker} should exist`) return source.slice(start, end) } test('token transport streams to disk instead of buffering the whole body', () => { const fn = extract('function downloadViaTokenToFile', '\nfunction ') // Delegates byte-moving to the streaming finalizer... assert.match(fn, /finalizeGatewayDownload\(/) // ...and must NOT accumulate the full response before writing. assert.doesNotMatch(fn, /Buffer\.concat/) assert.doesNotMatch(fn, /chunks\.push/) // Idle timeout is dropped once headers arrive so the dialog/stream isn't killed. assert.match(fn, /setTimeout\(0\)/) }) test('oauth transport streams to disk instead of buffering the whole body', () => { const fn = extract('function downloadViaOauthSessionToFile', '\nasync function finalizeGatewayDownload') assert.match(fn, /electronNet\.request/) assert.match(fn, /finalizeGatewayDownload\(/) assert.doesNotMatch(fn, /Buffer\.concat/) assert.doesNotMatch(fn, /chunks\.push/) }) test('finalizeGatewayDownload prompts a save dialog then streams the response', () => { const fn = extract('async function finalizeGatewayDownload', '\nfunction readGatewayErrorText') assert.match(fn, /dialog\.showSaveDialog/) assert.match(fn, /pumpStreamToFile\(/) // Production deps come from one place so the streaming save and the data-URL // fallback share the exclusive-create + rename contract (#96597). assert.match(fn, /fsPumpDeps\(\)/) assert.doesNotMatch(fn, /fs\.createWriteStream/) // HTTP errors carry their status so a 404 can trigger the fallback. assert.match(fn, /error\.statusCode = statusCode/) }) test('data-URL fallback writes through the same failure-atomic primitive, never writeFile in place', () => { const fn = extract('async function saveGatewayFileViaDataUrl', '\n// Mint a single-use WS ticket') assert.match(fn, /dialog\.showSaveDialog/) assert.match(fn, /writeBufferToFile\(/) assert.match(fn, /fsPumpDeps\(\)/) // A direct writeFile truncates an existing destination before the write // completes; a mid-write failure would destroy it (#96597). assert.doesNotMatch(fn, /fs\.promises\.writeFile/) })