@@ -11,6 +11,7 @@ import {
1111import { getPatternsFromShopifyIgnore , applyIgnoreFilters } from './asset-ignore.js'
1212import { triggerBrowserFullReload } from './theme-environment/hot-reload/server.js'
1313import { removeFile , writeFile } from '@shopify/cli-kit/node/fs'
14+ import * as fsKit from '@shopify/cli-kit/node/fs'
1415import { test , describe , expect , vi , beforeEach } from 'vitest'
1516import chokidar from 'chokidar'
1617import { bulkUploadThemeAssets , deleteThemeAssets , fetchThemeAssets } from '@shopify/cli-kit/node/themes/api'
@@ -593,6 +594,92 @@ describe('theme-fs', () => {
593594 // Then
594595 await changeEventPromise
595596 } )
597+
598+ test ( 'writes template JSON into base when listing file does not exist' , async ( ) => {
599+ // Given
600+ const themeFileSystem = mountThemeFileSystem ( root , { listing : 'modern' } )
601+ await themeFileSystem . ready ( )
602+ const asset = { key : 'templates/index.json' , checksum : 'abcd' , value : '{"sections":{}}' }
603+ vi . mocked ( writeFile ) . mockClear ( )
604+
605+ // When
606+ await themeFileSystem . write ( asset )
607+
608+ // Then: with Smart behavior, if overlay file does NOT exist yet, write to base
609+ expect ( writeFile ) . toHaveBeenCalledWith ( `${ root } /templates/index.json` , asset . value )
610+ } )
611+
612+ test ( 'writes template JSON into listing folder when listing file already exists' , async ( ) => {
613+ // Given
614+ const themeFileSystem = mountThemeFileSystem ( root , { listing : 'modern' } )
615+ await themeFileSystem . ready ( )
616+ const asset = { key : 'templates/index.json' , checksum : 'abcd' , value : '{"sections":{}}' }
617+ // Simulate existing overlay file by making fileExists return true for the overlay check
618+ vi . spyOn ( fsKit , 'fileExists' ) . mockResolvedValueOnce ( true )
619+ vi . mocked ( writeFile ) . mockClear ( )
620+
621+ // When
622+ await themeFileSystem . write ( asset )
623+
624+ // Then: writes to overlay
625+ expect ( writeFile ) . toHaveBeenCalledWith ( `${ root } /listings/modern/templates/index.json` , asset . value )
626+ } )
627+
628+ test ( 'writes section JSON into listing folder when listing is active' , async ( ) => {
629+ // Given
630+ const themeFileSystem = mountThemeFileSystem ( root , { listing : 'modern' } )
631+ await themeFileSystem . ready ( )
632+ const asset = { key : 'sections/header.json' , checksum : 'abc1' , value : '{"name":"Header"}' }
633+ vi . mocked ( writeFile ) . mockClear ( )
634+
635+ // When
636+ await themeFileSystem . write ( asset )
637+
638+ // Then: Smart behavior writes to base if overlay does not exist
639+ expect ( writeFile ) . toHaveBeenCalledWith ( `${ root } /sections/header.json` , asset . value )
640+ } )
641+
642+ test ( 'writes section JSON into listing folder when listing file already exists' , async ( ) => {
643+ // Given
644+ const themeFileSystem = mountThemeFileSystem ( root , { listing : 'modern' } )
645+ await themeFileSystem . ready ( )
646+ const asset = { key : 'sections/header.json' , checksum : 'abc1' , value : '{"name":"Header"}' }
647+ // Simulate existing overlay file by making fileExists return true for the overlay check
648+ vi . spyOn ( fsKit , 'fileExists' ) . mockResolvedValueOnce ( true )
649+ vi . mocked ( writeFile ) . mockClear ( )
650+
651+ // When
652+ await themeFileSystem . write ( asset )
653+
654+ // Then: writes to overlay
655+ expect ( writeFile ) . toHaveBeenCalledWith ( `${ root } /listings/modern/sections/header.json` , asset . value )
656+ } )
657+
658+ test ( 'writes non-JSON files to base when listing is active' , async ( ) => {
659+ // Given
660+ const themeFileSystem = mountThemeFileSystem ( root , { listing : 'modern' } )
661+ await themeFileSystem . ready ( )
662+ const asset = { key : 'sections/announcement-bar.liquid' , checksum : 'abc2' , value : '{% comment %}x{% endcomment %}' }
663+
664+ // When
665+ await themeFileSystem . write ( asset as any )
666+
667+ // Then
668+ expect ( writeFile ) . toHaveBeenCalledWith ( `${ root } /sections/announcement-bar.liquid` , asset . value )
669+ } )
670+
671+ test ( 'writes template JSON to base when no listing is specified' , async ( ) => {
672+ // Given
673+ const themeFileSystem = mountThemeFileSystem ( root )
674+ await themeFileSystem . ready ( )
675+ const asset = { key : 'templates/index.json' , checksum : 'ef01' , value : '{"sections":{}}' }
676+
677+ // When
678+ await themeFileSystem . write ( asset )
679+
680+ // Then
681+ expect ( writeFile ) . toHaveBeenCalledWith ( `${ root } /templates/index.json` , asset . value )
682+ } )
596683 } )
597684
598685 describe ( 'handleFileDelete' , ( ) => {
0 commit comments