@@ -3,6 +3,7 @@ import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core
33import { Delta } from 'quill' ;
44import { BehaviorSubject } from 'rxjs' ;
55import { anything , instance , mock , verify , when } from 'ts-mockito' ;
6+ import { ActivatedBookChapterService , RouteBookChapter } from 'xforge-common/activated-book-chapter.service' ;
67import { configureTestingModule } from 'xforge-common/test-utils' ;
78import { TextDocId } from '../../../../../core/models/text-doc' ;
89import { EditorReadyService } from '../base-services/editor-ready.service' ;
@@ -21,6 +22,7 @@ const mockInsightStateService = mock(LynxInsightStateService);
2122const mockEditorReadyService = mock ( QuillEditorReadyService ) ;
2223const mockOverlayService = mock ( LynxInsightOverlayService ) ;
2324const mockLynxWorkspaceService = mock ( LynxWorkspaceService ) ;
25+ const mockActivatedBookChapterService = mock ( ActivatedBookChapterService ) ;
2426const mockDestroyRef = mock ( DestroyRef ) ;
2527const mockTextModelConverter = mock < LynxTextModelConverter > ( ) ;
2628
@@ -33,6 +35,7 @@ describe('LynxInsightEditorObjectsComponent', () => {
3335 { provide : EditorReadyService , useMock : mockEditorReadyService } ,
3436 { provide : LynxInsightOverlayService , useMock : mockOverlayService } ,
3537 { provide : LynxWorkspaceService , useMock : mockLynxWorkspaceService } ,
38+ { provide : ActivatedBookChapterService , useMock : mockActivatedBookChapterService } ,
3639 { provide : DestroyRef , useMock : mockDestroyRef }
3740 ] ,
3841 schemas : [ NO_ERRORS_SCHEMA ]
@@ -274,6 +277,60 @@ describe('LynxInsightEditorObjectsComponent', () => {
274277 } ) ) ;
275278 } ) ;
276279
280+ describe ( 'book/chapter navigation' , ( ) => {
281+ it ( 'should clear display state when changing chapters' , fakeAsync ( ( ) => {
282+ const env = new TestEnvironment ( ) ;
283+ const testInsight = env . createTestInsight ( ) ;
284+
285+ env . setEditorReady ( true ) ;
286+ env . setFilteredInsights ( [ testInsight ] ) ;
287+ tick ( ) ;
288+ flush ( ) ;
289+
290+ // Set some display state (simulate active insights)
291+ env . setDisplayState ( {
292+ activeInsightIds : [ testInsight . id ] ,
293+ actionOverlayActive : true ,
294+ promptActive : true ,
295+ cursorActiveInsightIds : [ testInsight . id ]
296+ } ) ;
297+ tick ( ) ;
298+
299+ // Trigger chapter change
300+ env . changeBookChapter ( 'MAT' , 2 ) ;
301+ tick ( ) ;
302+
303+ // Verify clearDisplayState was called on chapter change
304+ verify ( mockInsightStateService . clearDisplayState ( ) ) . atLeast ( 1 ) ;
305+ } ) ) ;
306+
307+ it ( 'should clear display state when changing books' , fakeAsync ( ( ) => {
308+ const env = new TestEnvironment ( ) ;
309+ const testInsight = env . createTestInsight ( ) ;
310+
311+ env . setEditorReady ( true ) ;
312+ env . setFilteredInsights ( [ testInsight ] ) ;
313+ tick ( ) ;
314+ flush ( ) ;
315+
316+ // Set some display state (simulate active insights)
317+ env . setDisplayState ( {
318+ activeInsightIds : [ testInsight . id ] ,
319+ actionOverlayActive : true ,
320+ promptActive : true ,
321+ cursorActiveInsightIds : [ testInsight . id ]
322+ } ) ;
323+ tick ( ) ;
324+
325+ // Trigger book change
326+ env . changeBookChapter ( 'MRK' , 1 ) ;
327+ tick ( ) ;
328+
329+ // Verify clearDisplayState was called on book change
330+ verify ( mockInsightStateService . clearDisplayState ( ) ) . atLeast ( 1 ) ;
331+ } ) ) ;
332+ } ) ;
333+
277334 describe ( 'cleanup' , ( ) => {
278335 it ( 'should remove all insight formatting on destroy' , fakeAsync ( ( ) => {
279336 const env = new TestEnvironment ( ) ;
@@ -320,6 +377,7 @@ class TestEnvironment {
320377 private editorReadySubject : BehaviorSubject < boolean > ;
321378 private filteredInsightsSubject : BehaviorSubject < LynxInsight [ ] > ;
322379 private displayStateSubject : BehaviorSubject < LynxInsightDisplayState > ;
380+ private activatedBookChapterSubject : BehaviorSubject < RouteBookChapter | undefined > ;
323381
324382 constructor ( args : TestEnvArgs = { } ) {
325383 const textModelConverter = instance ( mockTextModelConverter ) ;
@@ -335,6 +393,11 @@ class TestEnvironment {
335393 cursorActiveInsightIds : [ ]
336394 } ) ;
337395
396+ this . activatedBookChapterSubject = new BehaviorSubject < RouteBookChapter | undefined > ( {
397+ bookId : 'MAT' ,
398+ chapter : 1
399+ } ) ;
400+
338401 // Create mock editor
339402 const mockRoot = document . createElement ( 'div' ) ;
340403 const actualEditor = {
@@ -362,6 +425,7 @@ class TestEnvironment {
362425 when ( mockEditorReadyService . listenEditorReadyState ( anything ( ) ) ) . thenReturn ( this . editorReadySubject ) ;
363426 when ( mockInsightStateService . filteredChapterInsights$ ) . thenReturn ( this . filteredInsightsSubject ) ;
364427 when ( mockInsightStateService . displayState$ ) . thenReturn ( this . displayStateSubject ) ;
428+ when ( mockActivatedBookChapterService . activatedBookChapter$ ) . thenReturn ( this . activatedBookChapterSubject ) ;
365429 when ( mockInsightStateService . updateDisplayState ( anything ( ) ) ) . thenReturn ( ) ;
366430 when ( mockInsightStateService . clearDisplayState ( ) ) . thenReturn ( ) ;
367431 when ( mockInsightRenderService . render ( anything ( ) , anything ( ) ) ) . thenResolve ( ) ;
@@ -412,6 +476,10 @@ class TestEnvironment {
412476 this . displayStateSubject . next ( fullState ) ;
413477 }
414478
479+ changeBookChapter ( bookId : string , chapter : number ) : void {
480+ this . activatedBookChapterSubject . next ( { bookId, chapter } ) ;
481+ }
482+
415483 triggerSelectionChange ( selection : LynxInsightRange | undefined ) : void {
416484 const handlers = this . eventHandlers . get ( 'selection-change' ) ;
417485 if ( handlers ) {
0 commit comments