@@ -288,6 +288,61 @@ describe("KnockGuideClient", () => {
288288 ) ;
289289 } ) ;
290290
291+ test ( "stores ineligible_guides from fetch response into the store" , async ( ) => {
292+ const mockIneligibleGuides = [
293+ {
294+ __typename : "GuideIneligibilityMarker" as const ,
295+ key : "guide_123" ,
296+ reason : "marked_as_archived" ,
297+ message : "User has archived this guide already" ,
298+ } ,
299+ {
300+ __typename : "GuideIneligibilityMarker" as const ,
301+ key : "guide_456" ,
302+ reason : "not_in_target_audience" ,
303+ message : "User is not a member of the target audience" ,
304+ } ,
305+ ] ;
306+
307+ const mockResponse = {
308+ entries : [
309+ {
310+ __typename : "Guide" ,
311+ channel_id : channelId ,
312+ id : "guide_789" ,
313+ key : "active_guide" ,
314+ type : "test" ,
315+ semver : "1.0.0" ,
316+ active : true ,
317+ steps : [ ] ,
318+ activation_url_rules : [ ] ,
319+ activation_url_patterns : [ ] ,
320+ bypass_global_group_limit : false ,
321+ inserted_at : new Date ( ) . toISOString ( ) ,
322+ updated_at : new Date ( ) . toISOString ( ) ,
323+ } ,
324+ ] ,
325+ guide_groups : [ ] ,
326+ guide_group_display_logs : { } ,
327+ ineligible_guides : mockIneligibleGuides ,
328+ } ;
329+
330+ vi . mocked ( mockKnock . user . getGuides ) . mockResolvedValueOnce ( mockResponse ) ;
331+
332+ const client = new KnockGuideClient (
333+ mockKnock ,
334+ channelId ,
335+ defaultTargetParams ,
336+ ) ;
337+
338+ await client . fetch ( ) ;
339+
340+ expect ( client . store . state . ineligibleGuides ) . toEqual ( {
341+ guide_123 : mockIneligibleGuides [ 0 ] ,
342+ guide_456 : mockIneligibleGuides [ 1 ] ,
343+ } ) ;
344+ } ) ;
345+
291346 test ( "handles fetch errors" , async ( ) => {
292347 const mockError = new Error ( "Network error" ) ;
293348 vi . mocked ( mockKnock . user . getGuides ) . mockRejectedValueOnce ( mockError ) ;
@@ -938,7 +993,7 @@ describe("KnockGuideClient", () => {
938993 } ) ;
939994 } ) ;
940995
941- describe ( "select " , ( ) => {
996+ describe ( "selectGuide " , ( ) => {
942997 const mockStep = {
943998 ref : "step_1" ,
944999 schema_key : "foo" ,
@@ -1972,6 +2027,73 @@ describe("KnockGuideClient", () => {
19722027 expect ( result2 ) . toBeDefined ( ) ;
19732028 expect ( result2 ! . type ) . toBe ( "banner" ) ;
19742029 } ) ;
2030+
2031+ test ( "skips ineligible guides during selection" , ( ) => {
2032+ const stateWithGuides = {
2033+ guideGroups : [ mockDefaultGroup ] ,
2034+ guideGroupDisplayLogs : { } ,
2035+ guides : mockGuides ,
2036+ ineligibleGuides : {
2037+ feature_tour : {
2038+ __typename : "GuideIneligibilityMarker" as const ,
2039+ key : "feature_tour" ,
2040+ reason : "target_conditions_not_met" ,
2041+ message : "User does not match the targeting conditions" ,
2042+ } ,
2043+ } ,
2044+ previewGuides : { } ,
2045+ queries : { } ,
2046+ location : undefined ,
2047+ counter : 0 ,
2048+ debug : { forcedGuideKey : null , previewSessionId : null } ,
2049+ } ;
2050+
2051+ const client = new KnockGuideClient ( mockKnock , channelId ) ;
2052+ const result = client [ "_selectGuide" ] ( stateWithGuides ) ;
2053+
2054+ // feature_tour is first in display_sequence but is ineligible,
2055+ // so it should be skipped and onboarding should be selected next
2056+ expect ( result ! . key ) . toBe ( "onboarding" ) ;
2057+ } ) ;
2058+
2059+ test ( "skips all ineligible guides and returns undefined when all are ineligible" , ( ) => {
2060+ const stateWithGuides = {
2061+ guideGroups : [ mockDefaultGroup ] ,
2062+ guideGroupDisplayLogs : { } ,
2063+ guides : mockGuides ,
2064+ ineligibleGuides : {
2065+ feature_tour : {
2066+ __typename : "GuideIneligibilityMarker" as const ,
2067+ key : "feature_tour" ,
2068+ reason : "marked_as_archived" ,
2069+ message : "User has archived this guide already" ,
2070+ } ,
2071+ onboarding : {
2072+ __typename : "GuideIneligibilityMarker" as const ,
2073+ key : "onboarding" ,
2074+ reason : "marked_as_archived" ,
2075+ message : "User has archived this guide already" ,
2076+ } ,
2077+ system_status : {
2078+ __typename : "GuideIneligibilityMarker" as const ,
2079+ key : "system_status" ,
2080+ reason : "marked_as_archived" ,
2081+ message : "User has archived this guide already" ,
2082+ } ,
2083+ } ,
2084+ previewGuides : { } ,
2085+ queries : { } ,
2086+ location : undefined ,
2087+ counter : 0 ,
2088+ debug : { forcedGuideKey : null , previewSessionId : null } ,
2089+ } ;
2090+
2091+ const client = new KnockGuideClient ( mockKnock , channelId ) ;
2092+ const result = client [ "_selectGuide" ] ( stateWithGuides ) ;
2093+
2094+ // All guides are ineligible, so should return undefined
2095+ expect ( result ) . toBeUndefined ( ) ;
2096+ } ) ;
19752097 } ) ;
19762098
19772099 describe ( "selectGuides" , ( ) => {
0 commit comments