11// npx jest src/shared/__tests__/modes.test.ts
22
3- import type { ModeConfig } from "@roo-code/types"
3+ import type { ModeConfig , PromptComponent } from "@roo-code/types"
44
55// Mock setup must come before imports
66jest . mock ( "vscode" )
@@ -374,7 +374,6 @@ describe("FileRestrictionError", () => {
374374
375375describe ( "getModeSelection" , ( ) => {
376376 const builtInAskMode = modes . find ( ( m ) => m . slug === "ask" ) !
377-
378377 const customModesList : ModeConfig [ ] = [
379378 {
380379 slug : "code" , // Override
@@ -408,8 +407,8 @@ describe("getModeSelection", () => {
408407 expect ( selection . baseInstructions ) . toBe ( builtInAskMode . customInstructions || "" )
409408 } )
410409
411- test ( "should prioritize promptComponent for built-in mode" , ( ) => {
412- const selection = getModeSelection ( "ask" , promptComponentAsk )
410+ test ( "should prioritize promptComponent for built-in mode if no custom mode exists for that slug " , ( ) => {
411+ const selection = getModeSelection ( "ask" , promptComponentAsk ) // "ask" is not in customModesList
413412 expect ( selection . roleDefinition ) . toBe ( promptComponentAsk . roleDefinition )
414413 expect ( selection . baseInstructions ) . toBe ( promptComponentAsk . customInstructions )
415414 } )
@@ -421,21 +420,21 @@ describe("getModeSelection", () => {
421420 expect ( selection . baseInstructions ) . toBe ( customCode . customInstructions )
422421 } )
423422
424- test ( "should prioritize customMode over promptComponent and built-in mode when all define properties " , ( ) => {
423+ test ( "should prioritize customMode over promptComponent and built-in mode" , ( ) => {
425424 const selection = getModeSelection ( "code" , promptComponentCode , customModesList )
426425 const customCode = customModesList . find ( ( m ) => m . slug === "code" ) !
427426 expect ( selection . roleDefinition ) . toBe ( customCode . roleDefinition )
428427 expect ( selection . baseInstructions ) . toBe ( customCode . customInstructions )
429428 } )
430429
431- test ( "should return new custom mode details" , ( ) => {
430+ test ( "should return new custom mode details if it exists " , ( ) => {
432431 const selection = getModeSelection ( "new-custom" , undefined , customModesList )
433432 const newCustom = customModesList . find ( ( m ) => m . slug === "new-custom" ) !
434433 expect ( selection . roleDefinition ) . toBe ( newCustom . roleDefinition )
435434 expect ( selection . baseInstructions ) . toBe ( newCustom . customInstructions )
436435 } )
437436
438- test ( "customMode properties take precedence for new custom mode even with promptComponent" , ( ) => {
437+ test ( "customMode takes precedence for a new custom mode even if promptComponent is provided " , ( ) => {
439438 const promptComponentNew : PromptComponent = {
440439 roleDefinition : "Prompt New Custom Role" ,
441440 customInstructions : "Prompt New Custom Instructions" ,
@@ -446,33 +445,24 @@ describe("getModeSelection", () => {
446445 expect ( selection . baseInstructions ) . toBe ( newCustomMode . customInstructions )
447446 } )
448447
449- test ( "should fallback to default (first) mode if slug does not exist" , ( ) => {
448+ test ( "should return empty strings if slug does not exist in custom, prompt, or built-in modes " , ( ) => {
450449 const selection = getModeSelection ( "non-existent-mode" , undefined , customModesList )
451- expect ( selection . roleDefinition ) . toBe ( modes [ 0 ] . roleDefinition )
452- expect ( selection . baseInstructions ) . toBe ( modes [ 0 ] . customInstructions || "" )
453- } )
454-
455- test ( "customMode.roleDefinition is used if defined, ignoring promptComponent's; customMode.customInstructions also from customMode" , ( ) => {
456- const selection = getModeSelection ( "code" , { roleDefinition : "Prompt Role Only" } , customModesList )
457- const customCodeMode = customModesList . find ( ( m ) => m . slug === "code" ) !
458- expect ( selection . roleDefinition ) . toBe ( customCodeMode . roleDefinition )
459- expect ( selection . baseInstructions ) . toBe ( customCodeMode . customInstructions )
450+ expect ( selection . roleDefinition ) . toBe ( "" )
451+ expect ( selection . baseInstructions ) . toBe ( "" )
460452 } )
461453
462- test ( "customMode.customInstructions is used if defined, ignoring promptComponent's; customMode.roleDefinition also from customMode" , ( ) => {
463- const selection = getModeSelection ( "code" , { customInstructions : "Prompt Instructions Only" } , customModesList )
454+ test ( "customMode's properties are used if customMode exists, ignoring promptComponent's properties" , ( ) => {
455+ const selection = getModeSelection (
456+ "code" ,
457+ { roleDefinition : "Prompt Role Only" , customInstructions : "Prompt Instructions Only" } ,
458+ customModesList ,
459+ )
464460 const customCodeMode = customModesList . find ( ( m ) => m . slug === "code" ) !
465- expect ( selection . roleDefinition ) . toBe ( customCodeMode . roleDefinition )
466- expect ( selection . baseInstructions ) . toBe ( customCodeMode . customInstructions )
467- } )
468-
469- test ( "customMode takes precedence over built-in when no promptComponent" , ( ) => {
470- const selection = getModeSelection ( "code" , undefined , customModesList )
471- expect ( selection . roleDefinition ) . toBe ( customModesList . find ( ( m ) => m . slug === "code" ) ! . roleDefinition )
472- expect ( selection . baseInstructions ) . toBe ( customModesList . find ( ( m ) => m . slug === "code" ) ! . customInstructions )
461+ expect ( selection . roleDefinition ) . toBe ( customCodeMode . roleDefinition ) // Takes from customCodeMode
462+ expect ( selection . baseInstructions ) . toBe ( customCodeMode . customInstructions ) // Takes from customCodeMode
473463 } )
474464
475- test ( "handles undefined customInstructions in modes gracefully" , ( ) => {
465+ test ( "handles undefined customInstructions in customMode gracefully" , ( ) => {
476466 const modesWithoutCustomInstructions : ModeConfig [ ] = [
477467 {
478468 slug : "no-instr" ,
@@ -484,65 +474,106 @@ describe("getModeSelection", () => {
484474 ]
485475 const selection = getModeSelection ( "no-instr" , undefined , modesWithoutCustomInstructions )
486476 expect ( selection . roleDefinition ) . toBe ( "Role for no instructions" )
487- expect ( selection . baseInstructions ) . toBe ( "" ) // Should default to empty string
477+ expect ( selection . baseInstructions ) . toBe ( "" ) // Defaults to empty string
488478 } )
489479
490- test ( "handles undefined roleDefinition in modes gracefully by falling back " , ( ) => {
491- const modesWithoutRoleDef : ModeConfig [ ] = [
480+ test ( "handles empty or undefined roleDefinition in customMode gracefully" , ( ) => {
481+ const modesWithEmptyRoleDef : ModeConfig [ ] = [
492482 {
493- slug : "no -role" ,
494- name : "No Role Mode" ,
495- roleDefinition : "" , // Ensure roleDefinition is present
496- customInstructions : "Instructions for no role" ,
483+ slug : "empty -role" ,
484+ name : "Empty Role Mode" ,
485+ roleDefinition : "" ,
486+ customInstructions : "Instructions for empty role" ,
497487 groups : [ "read" ] ,
498488 } ,
499489 ]
500- // Since 'no-role' is a custom mode not overriding a built-in, and it lacks a role,
501- // the logic in getModeSelection might fall back if not handled.
502- // The current getModeBySlug logic in getModeSelection will fetch this mode.
503- // Then, isCustom will be true.
504- // roleDefinition = modeConfig?.roleDefinition (undefined) || promptComponent?.roleDefinition (undefined) || ""
505- // So it should become ""
506- const selection = getModeSelection ( "no-role" , undefined , modesWithoutRoleDef )
490+ const selection = getModeSelection ( "empty-role" , undefined , modesWithEmptyRoleDef )
507491 expect ( selection . roleDefinition ) . toBe ( "" )
508- expect ( selection . baseInstructions ) . toBe ( "Instructions for no role" )
492+ expect ( selection . baseInstructions ) . toBe ( "Instructions for empty role" )
493+
494+ const modesWithUndefinedRoleDef : ModeConfig [ ] = [
495+ {
496+ slug : "undefined-role" ,
497+ name : "Undefined Role Mode" ,
498+ roleDefinition : "" , // Test undefined explicitly by using an empty string
499+ customInstructions : "Instructions for undefined role" ,
500+ groups : [ "read" ] ,
501+ } ,
502+ ]
503+ const selection2 = getModeSelection ( "undefined-role" , undefined , modesWithUndefinedRoleDef )
504+ expect ( selection2 . roleDefinition ) . toBe ( "" )
505+ expect ( selection2 . baseInstructions ) . toBe ( "Instructions for undefined role" )
509506 } )
510507
511- test ( "promptComponent fills customInstructions if customMode's is undefined" , ( ) => {
512- const customModeRoleOnly : ModeConfig [ ] = [
513- { slug : "role-custom" , name : "Role Custom" , roleDefinition : "Custom Role Only" , groups : [ "read" ] } ,
508+ test ( "customMode's defined properties take precedence, undefined ones in customMode result in ''" , ( ) => {
509+ const customModeRoleOnlyList : ModeConfig [ ] = [
510+ // Renamed for clarity
511+ {
512+ slug : "role-custom" ,
513+ name : "Role Custom" ,
514+ roleDefinition : "Custom Role Only" ,
515+ groups : [ "read" ] /* customInstructions undefined */ ,
516+ } ,
514517 ]
515518 const promptComponentInstrOnly : PromptComponent = { customInstructions : "Prompt Instructions Only" }
516- const selection = getModeSelection ( "role-custom" , promptComponentInstrOnly , customModeRoleOnly )
517- expect ( selection . roleDefinition ) . toBe ( "Custom Role Only" )
518- expect ( selection . baseInstructions ) . toBe ( "Prompt Instructions Only" )
519+ // "role-custom" exists in customModeRoleOnlyList
520+ const selection = getModeSelection ( "role-custom" , promptComponentInstrOnly , customModeRoleOnlyList )
521+ // customMode is chosen.
522+ expect ( selection . roleDefinition ) . toBe ( "Custom Role Only" ) // From customMode
523+ expect ( selection . baseInstructions ) . toBe ( "" ) // From customMode (undefined || '' -> '')
519524 } )
520525
521- test ( "promptComponent fills roleDefinition if customMode's is undefined" , ( ) => {
522- const customModeInstrOnly : ModeConfig [ ] = [
526+ test ( "customMode's defined properties take precedence, empty string ones in customMode are used" , ( ) => {
527+ const customModeInstrOnlyList : ModeConfig [ ] = [
528+ // Renamed for clarity
523529 {
524530 slug : "instr-custom" ,
525531 name : "Instr Custom" ,
526- roleDefinition : "" , // Added to satisfy ModeConfig type
532+ roleDefinition : "" , // Explicitly empty
527533 customInstructions : "Custom Instructions Only" ,
528534 groups : [ "read" ] ,
529535 } ,
530536 ]
531537 const promptComponentRoleOnly : PromptComponent = { roleDefinition : "Prompt Role Only" }
532- const selection = getModeSelection ( "instr-custom" , promptComponentRoleOnly , customModeInstrOnly )
533- expect ( selection . roleDefinition ) . toBe ( "Prompt Role Only" )
534- expect ( selection . baseInstructions ) . toBe ( "Custom Instructions Only" )
538+ // "instr-custom" exists in customModeInstrOnlyList
539+ const selection = getModeSelection ( "instr-custom" , promptComponentRoleOnly , customModeInstrOnlyList )
540+ // customMode is chosen
541+ expect ( selection . roleDefinition ) . toBe ( "" ) // From customMode ( "" || '' -> "")
542+ expect ( selection . baseInstructions ) . toBe ( "Custom Instructions Only" ) // From customMode
535543 } )
536544
537- test ( "builtInMode fills properties if customMode and promptComponent's are undefined " , ( ) => {
545+ test ( "customMode with empty/undefined fields takes precedence over promptComponent and builtInMode " , ( ) => {
538546 const customModeMinimal : ModeConfig [ ] = [
539- { slug : "ask" , name : "Custom Ask Minimal" , roleDefinition : "" , groups : [ "read" ] } , // No roleDef or customInstr
547+ { slug : "ask" , name : "Custom Ask Minimal" , roleDefinition : "" , groups : [ "read" ] } , // roleDef empty, customInstr undefined
540548 ]
541- const promptComponentMinimal : PromptComponent = { } // No roleDef or customInstr
549+ const promptComponentMinimal : PromptComponent = {
550+ roleDefinition : "Prompt Min Role" ,
551+ customInstructions : "Prompt Min Instr" ,
552+ }
553+ // "ask" is in customModeMinimal
542554 const selection = getModeSelection ( "ask" , promptComponentMinimal , customModeMinimal )
555+ // customMode is chosen
556+ expect ( selection . roleDefinition ) . toBe ( "" ) // From customModeMinimal
557+ expect ( selection . baseInstructions ) . toBe ( "" ) // From customModeMinimal
558+ } )
559+
560+ test ( "promptComponent is used if customMode for slug does not exist, even if customModesList is provided" , ( ) => {
561+ // 'ask' is not in customModesList, but 'code' and 'new-custom' are.
562+ const selection = getModeSelection ( "ask" , promptComponentAsk , customModesList )
563+ expect ( selection . roleDefinition ) . toBe ( promptComponentAsk . roleDefinition )
564+ expect ( selection . baseInstructions ) . toBe ( promptComponentAsk . customInstructions )
565+ } )
543566
544- // According to original logic, if customMode provides "", that takes precedence.
545- expect ( selection . roleDefinition ) . toBe ( "" ) // Was builtInAskMode.roleDefinition
546- expect ( selection . baseInstructions ) . toBe ( "" ) // Was builtInAskMode.customInstructions || ""
567+ test ( "builtInMode is used if customMode for slug does not exist and promptComponent is not provided" , ( ) => {
568+ // 'ask' is not in customModesList
569+ const selection = getModeSelection ( "ask" , undefined , customModesList )
570+ expect ( selection . roleDefinition ) . toBe ( builtInAskMode . roleDefinition )
571+ expect ( selection . baseInstructions ) . toBe ( builtInAskMode . customInstructions || "" )
572+ } )
573+
574+ test ( "promptComponent is used if customMode is not provided (undefined customModesList)" , ( ) => {
575+ const selection = getModeSelection ( "ask" , promptComponentAsk , undefined )
576+ expect ( selection . roleDefinition ) . toBe ( promptComponentAsk . roleDefinition )
577+ expect ( selection . baseInstructions ) . toBe ( promptComponentAsk . customInstructions )
547578 } )
548579} )
0 commit comments