@@ -8,6 +8,10 @@ export interface WhenOptions {
8
8
export interface BehaviorStack < TFunc extends AnyFunction > {
9
9
use : ( args : Parameters < TFunc > ) => BehaviorEntry < Parameters < TFunc > > | undefined
10
10
11
+ getAll : ( ) => readonly BehaviorEntry < Parameters < TFunc > > [ ]
12
+
13
+ getUnmatchedCalls : ( ) => readonly Parameters < TFunc > [ ]
14
+
11
15
bindArgs : < TArgs extends Parameters < TFunc > > (
12
16
args : TArgs ,
13
17
options : WhenOptions ,
@@ -24,80 +28,115 @@ export interface BoundBehaviorStack<TReturn> {
24
28
25
29
export interface BehaviorEntry < TArgs extends unknown [ ] > {
26
30
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
32
34
}
33
35
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
+
34
51
export interface BehaviorOptions < TValue > {
35
52
value : TValue
36
- times : number | undefined
53
+ maxCallCount : number | undefined
37
54
}
38
55
39
56
export const createBehaviorStack = <
40
57
TFunc extends AnyFunction ,
41
58
> ( ) : BehaviorStack < TFunc > => {
42
59
const behaviors : BehaviorEntry < Parameters < TFunc > > [ ] = [ ]
60
+ const unmatchedCalls : Parameters < TFunc > [ ] = [ ]
43
61
44
62
return {
63
+ getAll : ( ) => behaviors ,
64
+
65
+ getUnmatchedCalls : ( ) => unmatchedCalls ,
66
+
45
67
use : ( args ) => {
46
68
const behavior = behaviors
47
69
. filter ( ( b ) => behaviorAvailable ( b ) )
48
70
. find ( behaviorMatches ( args ) )
49
71
50
- if ( behavior ?. times !== undefined ) {
51
- behavior . times -= 1
72
+ if ( ! behavior ) {
73
+ unmatchedCalls . push ( args )
74
+ return undefined
52
75
}
53
76
77
+ behavior . calls . push ( args )
54
78
return behavior
55
79
} ,
56
80
57
81
bindArgs : ( args , options ) => ( {
58
82
addReturn : ( values ) => {
59
83
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
+ ) ,
65
92
)
66
93
} ,
67
94
addResolve : ( values ) => {
68
95
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
+ ) ,
74
104
)
75
105
} ,
76
106
addThrow : ( values ) => {
77
107
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
+ ) ,
83
116
)
84
117
} ,
85
118
addReject : ( values ) => {
86
119
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
+ ) ,
92
128
)
93
129
} ,
94
130
addDo : ( values ) => {
95
131
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
+ ) ,
101
140
)
102
141
} ,
103
142
} ) ,
@@ -114,14 +153,17 @@ const getBehaviorOptions = <TValue>(
114
153
115
154
return values . map ( ( value , index ) => ( {
116
155
value,
117
- times : times ?? ( index < values . length - 1 ? 1 : undefined ) ,
156
+ maxCallCount : times ?? ( index < values . length - 1 ? 1 : undefined ) ,
118
157
} ) )
119
158
}
120
159
121
160
const behaviorAvailable = < TArgs extends unknown [ ] > (
122
161
behavior : BehaviorEntry < TArgs > ,
123
162
) : boolean => {
124
- return behavior . times === undefined || behavior . times > 0
163
+ return (
164
+ behavior . maxCallCount === undefined ||
165
+ behavior . calls . length < behavior . maxCallCount
166
+ )
125
167
}
126
168
127
169
const behaviorMatches = < TArgs extends unknown [ ] > ( args : TArgs ) => {
0 commit comments