@@ -26,6 +26,7 @@ describe('memoize decorator — per-test inline classes', () => {
2626 @memoize ( { strategy : 'concat' , ttl : 60_000 , max : 50 } )
2727 public async run ( a : number , b : string ) {
2828 this . calls += 1 ;
29+
2930 return `${ a } -${ b } ` ;
3031 }
3132 }
@@ -37,7 +38,7 @@ describe('memoize decorator — per-test inline classes', () => {
3738 */
3839 expect ( await sample . run ( 1 , 'x' ) ) . toBe ( '1-x' ) ;
3940 /**
40- * In this case
41+ * In this case
4142 */
4243 expect ( await sample . run ( 1 , 'x' ) ) . toBe ( '1-x' ) ;
4344 expect ( await sample . run ( 1 , 'x' ) ) . toBe ( '1-x' ) ;
@@ -52,6 +53,7 @@ describe('memoize decorator — per-test inline classes', () => {
5253 @memoize ( { strategy : 'concat' } )
5354 public async run ( a : unknown , b : unknown ) {
5455 this . calls += 1 ;
56+
5557 return `${ String ( a ) } |${ String ( b ) } ` ;
5658 }
5759 }
@@ -84,9 +86,11 @@ describe('memoize decorator — per-test inline classes', () => {
8486 it ( 'should memoize return value for stringified objects across several calls' , async ( ) => {
8587 class Sample {
8688 public calls = 0 ;
89+
8790 @memoize ( { strategy : 'concat' } )
8891 public async run ( x : unknown , y : unknown ) {
8992 this . calls += 1 ;
93+
9094 return 'ok' ;
9195 }
9296 }
@@ -103,9 +107,11 @@ describe('memoize decorator — per-test inline classes', () => {
103107 it ( 'should memoize return value for method with non-default arguments (NaN, Infinity, -0, Symbol, Date, RegExp) still cache same-args' , async ( ) => {
104108 class Sample {
105109 public calls = 0 ;
110+
106111 @memoize ( { strategy : 'concat' } )
107112 public async run ( ...args : unknown [ ] ) {
108113 this . calls += 1 ;
114+
109115 return args . map ( String ) . join ( ',' ) ;
110116 }
111117 }
@@ -127,27 +133,31 @@ describe('memoize decorator — per-test inline classes', () => {
127133
128134 class Sample {
129135 public calls = 0 ;
136+
130137 @memoize ( { strategy : 'hash' } )
131138 public async run ( ...args : unknown [ ] ) {
132139 this . calls += 1 ;
140+
133141 return 'ok' ;
134142 }
135143 }
136144 const sample = new Sample ( ) ;
137145
138- await sample . run ( { a : 1 } , undefined , 0 ) ;
139- await sample . run ( { a : 1 } , undefined , 0 ) ;
146+ await sample . run ( { a : 1 } , undefined , 0 ) ;
147+ await sample . run ( { a : 1 } , undefined , 0 ) ;
140148
141- expect ( hashSpy ) . toHaveBeenCalledWith ( [ { a : 1 } , undefined , 0 ] , 'blake2b512' , 'base64url' ) ;
149+ expect ( hashSpy ) . toHaveBeenCalledWith ( [ { a : 1 } , undefined , 0 ] , 'blake2b512' , 'base64url' ) ;
142150 expect ( sample . calls ) . toBe ( 1 ) ;
143151 } ) ;
144152
145153 it ( 'should not memoize return value with hash strategy and different arguments' , async ( ) => {
146154 class Sample {
147155 public calls = 0 ;
156+
148157 @memoize ( { strategy : 'hash' } )
149158 public async run ( ...args : unknown [ ] ) {
150159 this . calls += 1 ;
160+
151161 return 'ok' ;
152162 }
153163 }
@@ -163,9 +173,11 @@ describe('memoize decorator — per-test inline classes', () => {
163173 it ( 'should memoize return value with hash strategy across several calls with same args' , async ( ) => {
164174 class Sample {
165175 public calls = 0 ;
176+
166177 @memoize ( { strategy : 'hash' } )
167178 public async run ( arg : unknown ) {
168179 this . calls += 1 ;
180+
169181 return 'ok' ;
170182 }
171183 }
@@ -186,9 +198,11 @@ describe('memoize decorator — per-test inline classes', () => {
186198
187199 class Sample {
188200 public calls = 0 ;
201+
189202 @memoizeWithMockedTimers ( { strategy : 'concat' , ttl : 1_000 } )
190203 public async run ( x : string ) {
191204 this . calls += 1 ;
205+
192206 return x ;
193207 }
194208 }
@@ -204,16 +218,19 @@ describe('memoize decorator — per-test inline classes', () => {
204218
205219 await sample . run ( 'k1' ) ;
206220 expect ( sample . calls ) . toBe ( 2 ) ;
207-
208221 } ) ;
209222
210223 it ( 'error calls should never be momized' , async ( ) => {
211224 class Sample {
212225 public calls = 0 ;
226+
213227 @memoize ( )
214228 public async run ( x : number ) {
215229 this . calls += 1 ;
216- if ( x === 1 ) throw new Error ( 'boom' ) ;
230+ if ( x === 1 ) {
231+ throw new Error ( 'boom' ) ;
232+ }
233+
217234 return x * 2 ;
218235 }
219236 }
@@ -226,4 +243,87 @@ describe('memoize decorator — per-test inline classes', () => {
226243 await expect ( sample . run ( 1 ) ) . rejects . toThrow ( 'boom' ) ;
227244 expect ( sample . calls ) . toBe ( 2 ) ;
228245 } ) ;
246+
247+ it ( 'should NOT cache results listed in skipCache (primitives)' , async ( ) => {
248+ class Sample {
249+ public calls = 0 ;
250+
251+ @memoize ( { strategy : 'concat' , skipCache : [ null , undefined , 0 , false , '' ] } )
252+ public async run ( kind : 'null' | 'undef' | 'zero' | 'false' | 'empty' ) {
253+ this . calls += 1 ;
254+ switch ( kind ) {
255+ case 'null' : return null ;
256+ case 'undef' : return undefined ;
257+ case 'zero' : return 0 ;
258+ case 'false' : return false ;
259+ case 'empty' : return '' ;
260+ }
261+ }
262+ }
263+
264+ const sample = new Sample ( ) ;
265+
266+ // Each repeated call should invoke the original again because result is in skipCache.
267+ await sample . run ( 'null' ) ;
268+ await sample . run ( 'null' ) ;
269+
270+ await sample . run ( 'undef' ) ;
271+ await sample . run ( 'undef' ) ;
272+
273+ await sample . run ( 'zero' ) ;
274+ await sample . run ( 'zero' ) ;
275+
276+ await sample . run ( 'false' ) ;
277+ await sample . run ( 'false' ) ;
278+
279+ await sample . run ( 'empty' ) ;
280+ await sample . run ( 'empty' ) ;
281+
282+ // 5 kinds × 2 calls each = 10 calls, none cached
283+ expect ( sample . calls ) . toBe ( 10 ) ;
284+ } ) ;
285+
286+ it ( 'should cache results NOT listed in skipCache' , async ( ) => {
287+ class Sample {
288+ public calls = 0 ;
289+
290+ @memoize ( { strategy : 'concat' , skipCache : [ null , undefined ] } )
291+ public async run ( x : number ) {
292+ this . calls += 1 ;
293+ // returns a non-skipped primitive
294+ return x * 2 ;
295+ }
296+ }
297+
298+ const sample = new Sample ( ) ;
299+
300+ expect ( await sample . run ( 21 ) ) . toBe ( 42 ) ;
301+ expect ( await sample . run ( 21 ) ) . toBe ( 42 ) ;
302+
303+ expect ( sample . calls ) . toBe ( 1 ) ;
304+ } ) ;
305+
306+ it ( 'should use equality for skipCache with objects: deep equal objects are cached' , async ( ) => {
307+ const deepEqualObject = { a : 1 } ;
308+
309+ class Sample {
310+ public calls = 0 ;
311+
312+ @memoize ( { strategy : 'concat' , skipCache : [ deepEqualObject ] } )
313+ public async run ( ) {
314+ this . calls += 1 ;
315+
316+ return { a : 1 } ;
317+ }
318+ }
319+
320+ const sample = new Sample ( ) ;
321+
322+ const first = await sample . run ( ) ;
323+ const second = await sample . run ( ) ;
324+
325+ expect ( first ) . toEqual ( { a : 1 } ) ;
326+ expect ( second ) . toBe ( first ) ;
327+ expect ( sample . calls ) . toBe ( 1 ) ;
328+ } ) ;
229329} ) ;
0 commit comments