@@ -646,6 +646,41 @@ describe("KnockGuideClient", () => {
646646 ) ;
647647 } ) ;
648648
649+ test ( "marks guide step as interacted and returns new guide object" , async ( ) => {
650+ const client = new KnockGuideClient ( mockKnock , channelId ) ;
651+
652+ // Mock the store to have the guide so setStepMessageAttrs can find it
653+ const stateWithGuides = {
654+ guideGroups : [ mockDefaultGroup ] ,
655+ guideGroupDisplayLogs : { } ,
656+ guides : { [ mockGuide . key ] : mockGuide } ,
657+ previewGuides : { } ,
658+ queries : { } ,
659+ location : undefined ,
660+ counter : 0 ,
661+ debug : { forcedGuideKey : null , previewSessionId : null } ,
662+ } ;
663+ mockStore . state = stateWithGuides ;
664+ mockStore . getState . mockReturnValue ( stateWithGuides ) ;
665+
666+ // Store the original guide reference
667+ const originalGuideRef = mockStore . state . guides [ mockGuide . key ] ;
668+
669+ await client . markAsInteracted ( mockGuide , mockStep , { action : "clicked" } ) ;
670+
671+ // Get the setState function and execute it to verify the state changes
672+ const setStateCalls = mockStore . setState . mock . calls ;
673+ const stateUpdateFn = setStateCalls . find (
674+ ( call ) => typeof call [ 0 ] === "function" ,
675+ ) ?. [ 0 ] ;
676+
677+ const newState = stateUpdateFn ( stateWithGuides ) ;
678+
679+ // Verify that the guide object is a new reference (not the same object)
680+ // This ensures useStore triggers a re-render
681+ expect ( newState . guides [ mockGuide . key ] ) . not . toBe ( originalGuideRef ) ;
682+ } ) ;
683+
649684 test ( "marks guide step as archived" , async ( ) => {
650685 const client = new KnockGuideClient ( mockKnock , channelId ) ;
651686
@@ -2650,6 +2685,110 @@ describe("KnockGuideClient", () => {
26502685 } ) ;
26512686 } ) ;
26522687
2688+ test ( "setStepMessageAttrs returns guide as new object when step is updated" , ( ) => {
2689+ const mockGuide = {
2690+ key : "test_guide" ,
2691+ steps : [
2692+ {
2693+ ref : "step_1" ,
2694+ message : { id : "msg_123" , seen_at : null } ,
2695+ } ,
2696+ ] ,
2697+ } as unknown as KnockGuide ;
2698+
2699+ const stateWithGuides = {
2700+ guideGroups : [ ] ,
2701+ guideGroupDisplayLogs : { } ,
2702+ guides : { [ mockGuide . key ] : mockGuide } ,
2703+ previewGuides : { } ,
2704+ queries : { } ,
2705+ location : undefined ,
2706+ counter : 0 ,
2707+ debug : { forcedGuideKey : null , previewSessionId : null } ,
2708+ } ;
2709+
2710+ mockStore . state = stateWithGuides ;
2711+ mockStore . getState . mockReturnValue ( stateWithGuides ) ;
2712+
2713+ const client = new KnockGuideClient ( mockKnock , channelId ) ;
2714+
2715+ // Store the original guide reference
2716+ const originalGuideRef = mockStore . state . guides [ mockGuide . key ] ;
2717+
2718+ // Update the step message attributes
2719+ client [ "setStepMessageAttrs" ] ( "test_guide" , "step_1" , {
2720+ seen_at : "2023-01-01T00:00:00Z" ,
2721+ } ) ;
2722+
2723+ // Get the setState function and execute it to verify the state changes
2724+ const setStateCalls = mockStore . setState . mock . calls ;
2725+ const stateUpdateFn = setStateCalls . find (
2726+ ( call ) => typeof call [ 0 ] === "function" ,
2727+ ) ?. [ 0 ] ;
2728+
2729+ const newState = stateUpdateFn ( stateWithGuides ) ;
2730+
2731+ // Verify that the guide object is a new reference (not the same object)
2732+ expect ( newState . guides [ "test_guide" ] ) . not . toBe ( originalGuideRef ) ;
2733+
2734+ // Verify that the step message was updated
2735+ expect ( newState . guides [ "test_guide" ] ! . steps [ 0 ] ! . message . seen_at ) . toBe (
2736+ "2023-01-01T00:00:00Z" ,
2737+ ) ;
2738+ } ) ;
2739+
2740+ test ( "setStepMessageAttrs returns same guide object when step is not found" , ( ) => {
2741+ const mockGuide = {
2742+ key : "test_guide" ,
2743+ steps : [
2744+ {
2745+ ref : "step_1" ,
2746+ message : { id : "msg_123" , seen_at : null } ,
2747+ } ,
2748+ ] ,
2749+ } as unknown as KnockGuide ;
2750+
2751+ const stateWithGuides = {
2752+ guideGroups : [ ] ,
2753+ guideGroupDisplayLogs : { } ,
2754+ guides : { [ mockGuide . key ] : mockGuide } ,
2755+ previewGuides : { } ,
2756+ queries : { } ,
2757+ location : undefined ,
2758+ counter : 0 ,
2759+ debug : { forcedGuideKey : null , previewSessionId : null } ,
2760+ } ;
2761+
2762+ mockStore . state = stateWithGuides ;
2763+ mockStore . getState . mockReturnValue ( stateWithGuides ) ;
2764+
2765+ const client = new KnockGuideClient ( mockKnock , channelId ) ;
2766+
2767+ // Store the original guide reference
2768+ const originalGuideRef = mockStore . state . guides [ mockGuide . key ] ;
2769+
2770+ // Try to update a non-existent step
2771+ client [ "setStepMessageAttrs" ] ( "test_guide" , "non_existent_step" , {
2772+ seen_at : "2023-01-01T00:00:00Z" ,
2773+ } ) ;
2774+
2775+ // Get the setState function and execute it to verify the state changes
2776+ const setStateCalls = mockStore . setState . mock . calls ;
2777+ const stateUpdateFn = setStateCalls . find (
2778+ ( call ) => typeof call [ 0 ] === "function" ,
2779+ ) ?. [ 0 ] ;
2780+
2781+ const newState = stateUpdateFn ( stateWithGuides ) ;
2782+
2783+ // Verify that the guide object is the same reference (no update occurred)
2784+ expect ( newState . guides [ "test_guide" ] ) . toBe ( originalGuideRef ) ;
2785+
2786+ // Verify that the step message was NOT updated
2787+ expect ( newState . guides [ "test_guide" ] ! . steps [ 0 ] ! . message . seen_at ) . toBe (
2788+ null ,
2789+ ) ;
2790+ } ) ;
2791+
26532792 test ( "buildQueryParams handles missing data and tenant" , ( ) => {
26542793 const client = new KnockGuideClient ( mockKnock , channelId ) ;
26552794
0 commit comments