@@ -601,3 +601,98 @@ describe("matchFixture — first-match-wins", () => {
601601 expect ( matchFixture ( [ noMatch , match ] , req ) ) . toBe ( match ) ;
602602 } ) ;
603603} ) ;
604+
605+ // ---------------------------------------------------------------------------
606+ // matchFixture — requestTransform
607+ // ---------------------------------------------------------------------------
608+
609+ describe ( "matchFixture — requestTransform" , ( ) => {
610+ const stripTimestamp = ( req : ChatCompletionRequest ) : ChatCompletionRequest => ( {
611+ ...req ,
612+ messages : req . messages . map ( ( m ) => ( {
613+ ...m ,
614+ content :
615+ typeof m . content === "string"
616+ ? m . content . replace ( / \d { 4 } - \d { 2 } - \d { 2 } T [ \d : . Z + - ] + / g, "" )
617+ : m . content ,
618+ } ) ) ,
619+ } ) ;
620+
621+ it ( "uses exact equality for string userMessage when transform is set" , ( ) => {
622+ const fixture = makeFixture ( { userMessage : "Event: happened" } ) ;
623+ const req = makeReq ( {
624+ messages : [ { role : "user" , content : "Event: 2026-03-30T13:19:38Z happened" } ] ,
625+ } ) ;
626+ // Without transform: substring "Event: happened" is NOT in the original text
627+ expect ( matchFixture ( [ fixture ] , req ) ) . toBeNull ( ) ;
628+ // With transform: timestamps stripped, exact match succeeds
629+ expect ( matchFixture ( [ fixture ] , req , undefined , stripTimestamp ) ) . toBe ( fixture ) ;
630+ } ) ;
631+
632+ it ( "substring match still works without transform" , ( ) => {
633+ const fixture = makeFixture ( { userMessage : "hello" } ) ;
634+ const req = makeReq ( { messages : [ { role : "user" , content : "say hello world" } ] } ) ;
635+ expect ( matchFixture ( [ fixture ] , req ) ) . toBe ( fixture ) ;
636+ } ) ;
637+
638+ it ( "exact match rejects substring matches when transform is set" , ( ) => {
639+ const identity = ( req : ChatCompletionRequest ) : ChatCompletionRequest => req ;
640+ const fixture = makeFixture ( { userMessage : "hello" } ) ;
641+ const req = makeReq ( { messages : [ { role : "user" , content : "say hello world" } ] } ) ;
642+ // With transform (identity): exact match fails because "say hello world" !== "hello"
643+ expect ( matchFixture ( [ fixture ] , req , undefined , identity ) ) . toBeNull ( ) ;
644+ } ) ;
645+
646+ it ( "uses exact equality for string inputText when transform is set" , ( ) => {
647+ const stripPrefix = ( req : ChatCompletionRequest ) : ChatCompletionRequest => ( {
648+ ...req ,
649+ embeddingInput : req . embeddingInput ?. split ( " | " ) [ 0 ] ,
650+ } ) ;
651+ const fixture = makeFixture ( { inputText : "concept" } ) ;
652+ const req = {
653+ ...makeReq ( ) ,
654+ embeddingInput : "concept | session-abc-123" ,
655+ } as ChatCompletionRequest ;
656+ // Without transform: substring "concept" is in "concept | session-abc-123"
657+ expect ( matchFixture ( [ fixture ] , req ) ) . toBe ( fixture ) ;
658+ // With transform: embeddingInput becomes "concept", exact match succeeds
659+ expect ( matchFixture ( [ fixture ] , req , undefined , stripPrefix ) ) . toBe ( fixture ) ;
660+ } ) ;
661+
662+ it ( "exact inputText rejects substring matches when transform is set" , ( ) => {
663+ const identity = ( req : ChatCompletionRequest ) : ChatCompletionRequest => req ;
664+ const fixture = makeFixture ( { inputText : "concept" } ) ;
665+ const req = {
666+ ...makeReq ( ) ,
667+ embeddingInput : "concept | session-abc-123" ,
668+ } as ChatCompletionRequest ;
669+ // With transform (identity): exact match fails
670+ expect ( matchFixture ( [ fixture ] , req , undefined , identity ) ) . toBeNull ( ) ;
671+ } ) ;
672+
673+ it ( "regexp matching still works with transform" , ( ) => {
674+ // After stripTimestamp, content becomes "Event: happened" (double space)
675+ const fixture = makeFixture ( { userMessage : / ^ E v e n t : \s + h a p p e n e d $ / } ) ;
676+ const req = makeReq ( {
677+ messages : [ { role : "user" , content : "Event: 2026-03-30T13:19:38Z happened" } ] ,
678+ } ) ;
679+ // Regexp matches the transformed text
680+ expect ( matchFixture ( [ fixture ] , req , undefined , stripTimestamp ) ) . toBe ( fixture ) ;
681+ } ) ;
682+
683+ it ( "predicate receives transformed request" , ( ) => {
684+ let capturedModel = "" ;
685+ const transform = ( req : ChatCompletionRequest ) : ChatCompletionRequest => ( {
686+ ...req ,
687+ model : "transformed-model" ,
688+ } ) ;
689+ const fixture = makeFixture ( {
690+ predicate : ( r ) => {
691+ capturedModel = r . model ;
692+ return true ;
693+ } ,
694+ } ) ;
695+ matchFixture ( [ fixture ] , makeReq ( { model : "original-model" } ) , undefined , transform ) ;
696+ expect ( capturedModel ) . toBe ( "transformed-model" ) ;
697+ } ) ;
698+ } ) ;
0 commit comments