@@ -188,6 +188,138 @@ test.describe('Canvas settings', { tag: '@canvas' }, () => {
188188 } )
189189 } )
190190
191+ test . describe ( 'Comfy.Canvas.NavigationMode' , ( ) => {
192+ test ( 'picking a preset never persists custom' , async ( { comfyPage } ) => {
193+ const modeWrites : unknown [ ] = [ ]
194+ comfyPage . page . on ( 'request' , ( request ) => {
195+ if (
196+ request . method ( ) === 'POST' &&
197+ request . url ( ) . endsWith ( '/api/settings/Comfy.Canvas.NavigationMode' )
198+ ) {
199+ modeWrites . push ( request . postDataJSON ( ) )
200+ }
201+ } )
202+
203+ await comfyPage . settings . setSetting (
204+ 'Comfy.Canvas.NavigationMode' ,
205+ 'standard'
206+ )
207+ await comfyPage . workflow . reloadAndWaitForApp ( )
208+
209+ // A preset also writes the two overrides it implies; those writes must
210+ // not read back as the user hand-picking an override.
211+ expect ( modeWrites ) . toContain ( 'standard' )
212+ expect ( modeWrites ) . not . toContain ( 'custom' )
213+ expect (
214+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.NavigationMode' )
215+ ) . toBe ( 'standard' )
216+ } )
217+
218+ test ( 'picking custom leaves the overrides untouched' , async ( {
219+ comfyPage
220+ } ) => {
221+ // Arrive on the standard pair first, so both overrides differ from their
222+ // defaults and a handler that rewrote them would be caught.
223+ await comfyPage . settings . setSetting (
224+ 'Comfy.Canvas.NavigationMode' ,
225+ 'standard'
226+ )
227+
228+ await comfyPage . settings . setSetting (
229+ 'Comfy.Canvas.NavigationMode' ,
230+ 'custom'
231+ )
232+ await comfyPage . workflow . reloadAndWaitForApp ( )
233+
234+ expect (
235+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.NavigationMode' )
236+ ) . toBe ( 'custom' )
237+ expect (
238+ await comfyPage . settings . getSetting (
239+ 'Comfy.Canvas.LeftMouseClickBehavior'
240+ )
241+ ) . toBe ( 'select' )
242+ expect (
243+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.MouseWheelScroll' )
244+ ) . toBe ( 'panning' )
245+ } )
246+
247+ // A mode stored before the overrides shipped in 1.27.4 is the only value on
248+ // record, so they load as their defaults — which describe a different mode.
249+ test . describe ( 'stored without the override settings' , ( ) => {
250+ test . use ( {
251+ initialSettings : { 'Comfy.Canvas.NavigationMode' : 'standard' }
252+ } )
253+
254+ test ( 'keeps the stored preset through load' , async ( { comfyPage } ) => {
255+ expect (
256+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.NavigationMode' )
257+ ) . toBe ( 'standard' )
258+ } )
259+
260+ // Reads the server, not the store: the migration is idempotent, so an
261+ // in-memory read passes whether or not the write ever landed.
262+ test ( 'persists the stored preset to the overrides' , async ( {
263+ comfyPage
264+ } ) => {
265+ expect (
266+ await comfyPage . settings . getPersistedSetting (
267+ 'Comfy.Canvas.LeftMouseClickBehavior'
268+ )
269+ ) . toBe ( 'select' )
270+ expect (
271+ await comfyPage . settings . getPersistedSetting (
272+ 'Comfy.Canvas.MouseWheelScroll'
273+ )
274+ ) . toBe ( 'panning' )
275+ } )
276+ } )
277+
278+ // Every profile that already loaded a 1.27.4+ build has the mode demoted to
279+ // 'custom' with the overrides never written. The original choice is
280+ // unrecoverable, so this pins the no-op as deliberate.
281+ test . describe ( 'already demoted to custom' , ( ) => {
282+ test . use ( {
283+ initialSettings : { 'Comfy.Canvas.NavigationMode' : 'custom' }
284+ } )
285+
286+ test ( 'is left as custom' , async ( { comfyPage } ) => {
287+ expect (
288+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.NavigationMode' )
289+ ) . toBe ( 'custom' )
290+ } )
291+ } )
292+
293+ test . describe ( 'stored with only one override' , ( ) => {
294+ test . use ( {
295+ initialSettings : {
296+ 'Comfy.Canvas.NavigationMode' : 'standard' ,
297+ 'Comfy.Canvas.MouseWheelScroll' : 'zoom'
298+ }
299+ } )
300+
301+ test ( 'fills the gap without overwriting the stored override' , async ( {
302+ comfyPage
303+ } ) => {
304+ expect (
305+ await comfyPage . settings . getSetting (
306+ 'Comfy.Canvas.LeftMouseClickBehavior'
307+ )
308+ ) . toBe ( 'select' )
309+ expect (
310+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.MouseWheelScroll' )
311+ ) . toBe ( 'zoom' )
312+
313+ // select + zoom is no preset, so demoting the mode is correct here.
314+ // Overwriting the stored 'zoom' to match the mode instead would
315+ // discard a real preference, which is the bug this all started as.
316+ expect (
317+ await comfyPage . settings . getSetting ( 'Comfy.Canvas.NavigationMode' )
318+ ) . toBe ( 'custom' )
319+ } )
320+ } )
321+ } )
322+
191323 test . describe ( 'Comfy.Canvas.LeftMouseClickBehavior' , ( ) => {
192324 test ( 'override to panning makes empty left-drag pan the canvas' , async ( {
193325 comfyPage
0 commit comments