@@ -11,7 +11,7 @@ import {
1111 V2_TRAMPOLINE_VERSION ,
1212} from './binaries.js'
1313import { fetch , Response } from '@shopify/cli-kit/node/http'
14- import { fileExists , removeFile } from '@shopify/cli-kit/node/fs'
14+ import { fileExists , removeFile , writeFile } from '@shopify/cli-kit/node/fs'
1515import { describe , expect , test , vi } from 'vitest'
1616import { gzipSync } from 'zlib'
1717
@@ -174,6 +174,52 @@ describe('javy', () => {
174174 expect ( fetch ) . toHaveBeenCalledOnce ( )
175175 await expect ( fileExists ( javy . path ) ) . resolves . toBeTruthy ( )
176176 } )
177+
178+ test ( 'does not return early when file exists but rename is in progress' , async ( ) => {
179+ // Given
180+ await removeFile ( javy . path )
181+ await expect ( fileExists ( javy . path ) ) . resolves . toBeFalsy ( )
182+
183+ let resolveDownload ! : ( ) => void
184+ const blockDownload = new Promise < void > ( ( resolve ) => {
185+ resolveDownload = resolve
186+ } )
187+
188+ vi . mocked ( fetch ) . mockImplementation ( async ( ) => {
189+ await blockDownload
190+ return new Response ( gzipSync ( 'javy binary' ) )
191+ } )
192+
193+ // When
194+ // Start first download — will block at fetch
195+ const firstDownload = downloadBinary ( javy )
196+
197+ // Allow first download to reach fetch and register in downloadsInProgress
198+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1 ) )
199+
200+ // Simulate file appearing on disk (e.g., non-atomic moveFile creating the destination
201+ // while the download is still tracked as in-progress)
202+ await writeFile ( javy . path , 'incomplete binary' )
203+
204+ // Start second download — should wait for first, not return early
205+ let secondResolved = false
206+ const secondDownload = downloadBinary ( javy ) . then ( ( ) => {
207+ secondResolved = true
208+ } )
209+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1 ) )
210+
211+ // Then — second download should be blocked waiting for first
212+ expect ( secondResolved ) . toBe ( false )
213+
214+ // Complete the first download
215+ resolveDownload ( )
216+ await Promise . all ( [ firstDownload , secondDownload ] )
217+
218+ // Only one fetch should have been made
219+ expect ( fetch ) . toHaveBeenCalledOnce ( )
220+ expect ( secondResolved ) . toBe ( true )
221+ await expect ( fileExists ( javy . path ) ) . resolves . toBeTruthy ( )
222+ } )
177223} )
178224
179225describe ( 'javy-plugin' , ( ) => {
0 commit comments