@@ -227,6 +227,50 @@ describe("canvasCapture", () => {
227227 expect ( updated . nodes [ 0 ] . text ) . toBe ( "Updated" ) ;
228228 } ) ;
229229
230+ it ( "aborts configured text-node write when canvas changed concurrently" , async ( ) => {
231+ const canvasFile = {
232+ path : "Boards/Plan.canvas" ,
233+ basename : "Plan" ,
234+ extension : "canvas" ,
235+ } ;
236+ let modifyCalls = 0 ;
237+ let readCalls = 0 ;
238+ const initial = JSON . stringify ( {
239+ nodes : [ { id : "t1" , type : "text" , text : "Current" } ] ,
240+ } ) ;
241+ const changed = JSON . stringify ( {
242+ nodes : [ { id : "t1" , type : "text" , text : "Changed elsewhere" } ] ,
243+ } ) ;
244+
245+ const app = createApp ( {
246+ vault : {
247+ getAbstractFileByPath : ( path : string ) =>
248+ path === "Boards/Plan.canvas" ? ( canvasFile as any ) : null ,
249+ read : async ( ) => {
250+ readCalls += 1 ;
251+ return readCalls === 1 ? initial : changed ;
252+ } ,
253+ modify : async ( ) => {
254+ modifyCalls += 1 ;
255+ } ,
256+ } ,
257+ } ) ;
258+
259+ const target = await resolveConfiguredCanvasCaptureTarget (
260+ app ,
261+ "Boards/Plan.canvas" ,
262+ "t1" ,
263+ "append" ,
264+ ) ;
265+ expect ( target . kind ) . toBe ( "text" ) ;
266+ if ( target . kind !== "text" ) return ;
267+
268+ await expect (
269+ setCanvasTextCaptureContent ( app , target , "Updated" ) ,
270+ ) . rejects . toThrow ( "Canvas target changed while capture was running" ) ;
271+ expect ( modifyCalls ) . toBe ( 0 ) ;
272+ } ) ;
273+
230274 it ( "fails configured canvas capture when node id does not exist" , async ( ) => {
231275 const canvasFile = {
232276 path : "Boards/Plan.canvas" ,
0 commit comments