@@ -8,6 +8,10 @@ export interface WhenOptions {
88export interface BehaviorStack < TFunc extends AnyFunction > {
99 use : ( args : Parameters < TFunc > ) => BehaviorEntry < Parameters < TFunc > > | undefined
1010
11+ getAll : ( ) => readonly BehaviorEntry < Parameters < TFunc > > [ ]
12+
13+ getUnmatchedCalls : ( ) => readonly Parameters < TFunc > [ ]
14+
1115 bindArgs : < TArgs extends Parameters < TFunc > > (
1216 args : TArgs ,
1317 options : WhenOptions ,
@@ -24,80 +28,115 @@ export interface BoundBehaviorStack<TReturn> {
2428
2529export interface BehaviorEntry < TArgs extends unknown [ ] > {
2630 args : TArgs
27- returnValue ?: unknown
28- rejectError ?: unknown
29- throwError ?: unknown
30- doCallback ?: AnyFunction | undefined
31- times ?: number | undefined
31+ behavior : Behavior
32+ calls : TArgs [ ]
33+ maxCallCount ?: number | undefined
3234}
3335
36+ export const BehaviorType = {
37+ RETURN : 'return' ,
38+ RESOLVE : 'resolve' ,
39+ THROW : 'throw' ,
40+ REJECT : 'reject' ,
41+ DO : 'do' ,
42+ } as const
43+
44+ export type Behavior =
45+ | { type : typeof BehaviorType . RETURN ; value : unknown }
46+ | { type : typeof BehaviorType . RESOLVE ; value : unknown }
47+ | { type : typeof BehaviorType . THROW ; error : unknown }
48+ | { type : typeof BehaviorType . REJECT ; error : unknown }
49+ | { type : typeof BehaviorType . DO ; callback : AnyFunction }
50+
3451export interface BehaviorOptions < TValue > {
3552 value : TValue
36- times : number | undefined
53+ maxCallCount : number | undefined
3754}
3855
3956export const createBehaviorStack = <
4057 TFunc extends AnyFunction ,
4158> ( ) : BehaviorStack < TFunc > => {
4259 const behaviors : BehaviorEntry < Parameters < TFunc > > [ ] = [ ]
60+ const unmatchedCalls : Parameters < TFunc > [ ] = [ ]
4361
4462 return {
63+ getAll : ( ) => behaviors ,
64+
65+ getUnmatchedCalls : ( ) => unmatchedCalls ,
66+
4567 use : ( args ) => {
4668 const behavior = behaviors
4769 . filter ( ( b ) => behaviorAvailable ( b ) )
4870 . find ( behaviorMatches ( args ) )
4971
50- if ( behavior ?. times !== undefined ) {
51- behavior . times -= 1
72+ if ( ! behavior ) {
73+ unmatchedCalls . push ( args )
74+ return undefined
5275 }
5376
77+ behavior . calls . push ( args )
5478 return behavior
5579 } ,
5680
5781 bindArgs : ( args , options ) => ( {
5882 addReturn : ( values ) => {
5983 behaviors . unshift (
60- ...getBehaviorOptions ( values , options ) . map ( ( { value, times } ) => ( {
61- args,
62- times,
63- returnValue : value ,
64- } ) ) ,
84+ ...getBehaviorOptions ( values , options ) . map (
85+ ( { value, maxCallCount } ) => ( {
86+ args,
87+ maxCallCount,
88+ behavior : { type : BehaviorType . RETURN , value } ,
89+ calls : [ ] ,
90+ } ) ,
91+ ) ,
6592 )
6693 } ,
6794 addResolve : ( values ) => {
6895 behaviors . unshift (
69- ...getBehaviorOptions ( values , options ) . map ( ( { value, times } ) => ( {
70- args,
71- times,
72- returnValue : Promise . resolve ( value ) ,
73- } ) ) ,
96+ ...getBehaviorOptions ( values , options ) . map (
97+ ( { value, maxCallCount } ) => ( {
98+ args,
99+ maxCallCount,
100+ behavior : { type : BehaviorType . RESOLVE , value } ,
101+ calls : [ ] ,
102+ } ) ,
103+ ) ,
74104 )
75105 } ,
76106 addThrow : ( values ) => {
77107 behaviors . unshift (
78- ...getBehaviorOptions ( values , options ) . map ( ( { value, times } ) => ( {
79- args,
80- times,
81- throwError : value ,
82- } ) ) ,
108+ ...getBehaviorOptions ( values , options ) . map (
109+ ( { value, maxCallCount } ) => ( {
110+ args,
111+ maxCallCount,
112+ behavior : { type : BehaviorType . THROW , error : value } ,
113+ calls : [ ] ,
114+ } ) ,
115+ ) ,
83116 )
84117 } ,
85118 addReject : ( values ) => {
86119 behaviors . unshift (
87- ...getBehaviorOptions ( values , options ) . map ( ( { value, times } ) => ( {
88- args,
89- times,
90- rejectError : value ,
91- } ) ) ,
120+ ...getBehaviorOptions ( values , options ) . map (
121+ ( { value, maxCallCount } ) => ( {
122+ args,
123+ maxCallCount,
124+ behavior : { type : BehaviorType . REJECT , error : value } ,
125+ calls : [ ] ,
126+ } ) ,
127+ ) ,
92128 )
93129 } ,
94130 addDo : ( values ) => {
95131 behaviors . unshift (
96- ...getBehaviorOptions ( values , options ) . map ( ( { value, times } ) => ( {
97- args,
98- times,
99- doCallback : value ,
100- } ) ) ,
132+ ...getBehaviorOptions ( values , options ) . map (
133+ ( { value, maxCallCount } ) => ( {
134+ args,
135+ maxCallCount,
136+ behavior : { type : BehaviorType . DO , callback : value } ,
137+ calls : [ ] ,
138+ } ) ,
139+ ) ,
101140 )
102141 } ,
103142 } ) ,
@@ -114,14 +153,17 @@ const getBehaviorOptions = <TValue>(
114153
115154 return values . map ( ( value , index ) => ( {
116155 value,
117- times : times ?? ( index < values . length - 1 ? 1 : undefined ) ,
156+ maxCallCount : times ?? ( index < values . length - 1 ? 1 : undefined ) ,
118157 } ) )
119158}
120159
121160const behaviorAvailable = < TArgs extends unknown [ ] > (
122161 behavior : BehaviorEntry < TArgs > ,
123162) : boolean => {
124- return behavior . times === undefined || behavior . times > 0
163+ return (
164+ behavior . maxCallCount === undefined ||
165+ behavior . calls . length < behavior . maxCallCount
166+ )
125167}
126168
127169const behaviorMatches = < TArgs extends unknown [ ] > ( args : TArgs ) => {
0 commit comments