From 4c6571e79bff84567573bebd80ec06e7249b7645 Mon Sep 17 00:00:00 2001 From: Antonio Sejas Date: Fri, 6 Feb 2026 09:03:34 +0000 Subject: [PATCH 1/2] Fix site thumbnail not refreshing after content changes The thumbnail was only recaptured when the theme path changed, so adding new posts and restarting the site would leave the thumbnail stale. Now updateCachedThumbnail() runs on every loadThemeDetails() call while persistThemeDetails() remains gated on actual theme changes. --- src/ipc-handlers.ts | 2 +- src/tests/ipc-handlers.test.ts | 73 +++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/ipc-handlers.ts b/src/ipc-handlers.ts index ae50b45644..3720c35dd2 100644 --- a/src/ipc-handlers.ts +++ b/src/ipc-handlers.ts @@ -788,8 +788,8 @@ export async function loadThemeDetails( sendIpcEventToRendererWithWindow( parentWindow, 'thumbnail-loading', { id } ); } await server.persistThemeDetails(); - await server.updateCachedThumbnail(); } + await server.updateCachedThumbnail(); const thumbnailPath = getSiteThumbnailPath( id ); const thumbnailData = await getImageData( thumbnailPath ); sendIpcEventToRendererWithWindow( parentWindow, 'thumbnail-loaded', { diff --git a/src/tests/ipc-handlers.test.ts b/src/tests/ipc-handlers.test.ts index 806e895e52..a183d549a4 100644 --- a/src/tests/ipc-handlers.test.ts +++ b/src/tests/ipc-handlers.test.ts @@ -9,7 +9,13 @@ import { readFile } from 'atomically'; import { vi } from 'vitest'; import { bumpStat } from 'common/lib/bump-stat'; import { StatsGroup, StatsMetric } from 'common/types/stats'; -import { createSite, isFullscreen, importSite, getXdebugEnabledSite } from 'src/ipc-handlers'; +import { + createSite, + isFullscreen, + importSite, + getXdebugEnabledSite, + loadThemeDetails, +} from 'src/ipc-handlers'; import { importBackup, defaultImporterOptions } from 'src/lib/import-export/import/import-manager'; import { BackupArchiveInfo } from 'src/lib/import-export/import/types'; import { getMainWindow } from 'src/main-window'; @@ -41,6 +47,9 @@ vi.mock( 'src/main-window' ); vi.mock( 'src/lib/import-export/import/import-manager' ); vi.mock( 'common/lib/bump-stat' ); vi.mock( 'atomically' ); +vi.mock( 'src/lib/get-image-data', () => ( { + getImageData: vi.fn().mockResolvedValue( 'data:image/png;base64,mock' ), +} ) ); vi.mock( 'common/lib/port-finder', () => ( { portFinder: { @@ -349,3 +358,65 @@ describe( 'getXdebugEnabledSite', () => { } ); } ); } ); + +describe( 'loadThemeDetails', () => { + it( 'should update thumbnail even when theme has not changed', async () => { + const themeDetails = { name: 'Twenty Twenty-Four', path: '/themes/twentytwentyfour' }; + const mockServer = { + details: { + id: 'test-site-id', + running: true, + themeDetails, + }, + getThemeDetails: vi.fn().mockResolvedValue( themeDetails ), + persistThemeDetails: vi.fn().mockResolvedValue( undefined ), + updateCachedThumbnail: vi.fn().mockResolvedValue( undefined ), + }; + vi.mocked( SiteServer.get ).mockReturnValue( mockServer as unknown as SiteServer ); + + await loadThemeDetails( mockIpcMainInvokeEvent, 'test-site-id' ); + + expect( mockServer.updateCachedThumbnail ).toHaveBeenCalled(); + } ); + + it( 'should persist theme details and update thumbnail when theme has changed', async () => { + const oldThemeDetails = { name: 'Twenty Twenty-Four', path: '/themes/twentytwentyfour' }; + const newThemeDetails = { name: 'Twenty Twenty-Five', path: '/themes/twentytwentyfive' }; + const mockServer = { + details: { + id: 'test-site-id', + running: true, + themeDetails: oldThemeDetails, + }, + getThemeDetails: vi.fn().mockResolvedValue( newThemeDetails ), + persistThemeDetails: vi.fn().mockResolvedValue( undefined ), + updateCachedThumbnail: vi.fn().mockResolvedValue( undefined ), + }; + vi.mocked( SiteServer.get ).mockReturnValue( mockServer as unknown as SiteServer ); + + await loadThemeDetails( mockIpcMainInvokeEvent, 'test-site-id' ); + + expect( mockServer.persistThemeDetails ).toHaveBeenCalled(); + expect( mockServer.updateCachedThumbnail ).toHaveBeenCalled(); + } ); + + it( 'should not persist theme details when theme has not changed', async () => { + const themeDetails = { name: 'Twenty Twenty-Four', path: '/themes/twentytwentyfour' }; + const mockServer = { + details: { + id: 'test-site-id', + running: true, + themeDetails, + }, + getThemeDetails: vi.fn().mockResolvedValue( themeDetails ), + persistThemeDetails: vi.fn().mockResolvedValue( undefined ), + updateCachedThumbnail: vi.fn().mockResolvedValue( undefined ), + }; + vi.mocked( SiteServer.get ).mockReturnValue( mockServer as unknown as SiteServer ); + + await loadThemeDetails( mockIpcMainInvokeEvent, 'test-site-id' ); + + expect( mockServer.persistThemeDetails ).not.toHaveBeenCalled(); + expect( mockServer.updateCachedThumbnail ).toHaveBeenCalled(); + } ); +} ); From 7f421b8d6f37b0a62d6037a373c04a217d8d690f Mon Sep 17 00:00:00 2001 From: Antonio Sejas Date: Mon, 9 Feb 2026 14:37:01 +0000 Subject: [PATCH 2/2] Unify test cases when theme has not been modified --- src/tests/ipc-handlers.test.ts | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/tests/ipc-handlers.test.ts b/src/tests/ipc-handlers.test.ts index a183d549a4..1850da8863 100644 --- a/src/tests/ipc-handlers.test.ts +++ b/src/tests/ipc-handlers.test.ts @@ -360,7 +360,7 @@ describe( 'getXdebugEnabledSite', () => { } ); describe( 'loadThemeDetails', () => { - it( 'should update thumbnail even when theme has not changed', async () => { + it( 'should update thumbnail but not persist theme details when theme has not changed', async () => { const themeDetails = { name: 'Twenty Twenty-Four', path: '/themes/twentytwentyfour' }; const mockServer = { details: { @@ -376,6 +376,7 @@ describe( 'loadThemeDetails', () => { await loadThemeDetails( mockIpcMainInvokeEvent, 'test-site-id' ); + expect( mockServer.persistThemeDetails ).not.toHaveBeenCalled(); expect( mockServer.updateCachedThumbnail ).toHaveBeenCalled(); } ); @@ -399,24 +400,4 @@ describe( 'loadThemeDetails', () => { expect( mockServer.persistThemeDetails ).toHaveBeenCalled(); expect( mockServer.updateCachedThumbnail ).toHaveBeenCalled(); } ); - - it( 'should not persist theme details when theme has not changed', async () => { - const themeDetails = { name: 'Twenty Twenty-Four', path: '/themes/twentytwentyfour' }; - const mockServer = { - details: { - id: 'test-site-id', - running: true, - themeDetails, - }, - getThemeDetails: vi.fn().mockResolvedValue( themeDetails ), - persistThemeDetails: vi.fn().mockResolvedValue( undefined ), - updateCachedThumbnail: vi.fn().mockResolvedValue( undefined ), - }; - vi.mocked( SiteServer.get ).mockReturnValue( mockServer as unknown as SiteServer ); - - await loadThemeDetails( mockIpcMainInvokeEvent, 'test-site-id' ); - - expect( mockServer.persistThemeDetails ).not.toHaveBeenCalled(); - expect( mockServer.updateCachedThumbnail ).toHaveBeenCalled(); - } ); } );