11import { promises as fs } from 'fs' ;
22import * as path from 'path' ;
3- import { join } from 'path' ;
3+ import { join , dirname } from 'path' ;
44
55import {
66 getOutfilePath ,
77 isDirectory ,
88 isFile ,
99 readJsonFile ,
10+ useFileSystemCache ,
1011 useTemporaryFile ,
1112 validateDirPath ,
1213 validateFilePath ,
@@ -20,13 +21,15 @@ jest.mock('fs');
2021
2122const BASE_PATH = '/snap' ;
2223const MANIFEST_PATH = join ( BASE_PATH , NpmSnapFileNames . Manifest ) ;
24+ const CACHE_PATH = join ( process . cwd ( ) , 'node_modules/.cache/snaps' ) ;
2325
2426/**
2527 * Clears out all the files in the in-memory file system, and writes the default
2628 * files to the `BASE_PATH` folder, including sub-folders.
2729 */
2830async function resetFileSystem ( ) {
2931 await fs . rm ( BASE_PATH , { recursive : true , force : true } ) ;
32+ await fs . rm ( CACHE_PATH , { recursive : true , force : true } ) ;
3033
3134 // Create `dist` folder.
3235 await fs . mkdir ( join ( BASE_PATH , 'dist' ) , { recursive : true } ) ;
@@ -262,3 +265,95 @@ describe('useTemporaryFile', () => {
262265 expect ( await isFile ( filePath ) ) . toBe ( false ) ;
263266 } ) ;
264267} ) ;
268+
269+ describe ( 'useFileSystemCache' , ( ) => {
270+ beforeEach ( async ( ) => {
271+ await resetFileSystem ( ) ;
272+ } ) ;
273+
274+ const cachedFunction = useFileSystemCache ( 'foo' , 5000 , async ( ) => {
275+ return 'foo' ;
276+ } ) ;
277+
278+ const cachedFilePath = join ( CACHE_PATH , 'foo.json' ) ;
279+
280+ it ( 'writes cached value to the file system' , async ( ) => {
281+ const spy = jest . spyOn ( fs , 'writeFile' ) ;
282+ expect ( await cachedFunction ( ) ) . toBe ( 'foo' ) ;
283+
284+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
285+
286+ const cacheValue = await fs . readFile ( cachedFilePath , 'utf8' ) ;
287+ const cacheJson = JSON . parse ( cacheValue ) ;
288+
289+ expect ( cacheJson ) . toStrictEqual ( {
290+ timestamp : expect . any ( Number ) ,
291+ value : 'foo' ,
292+ } ) ;
293+ } ) ;
294+
295+ it ( 'reads cached value from the file system' , async ( ) => {
296+ const readSpy = jest . spyOn ( fs , 'readFile' ) ;
297+ const writeSpy = jest . spyOn ( fs , 'writeFile' ) ;
298+
299+ expect ( await cachedFunction ( ) ) . toBe ( 'foo' ) ;
300+ expect ( await cachedFunction ( ) ) . toBe ( 'foo' ) ;
301+
302+ expect ( readSpy ) . toHaveBeenCalledTimes ( 2 ) ;
303+ expect ( writeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
304+
305+ const cacheValue = await fs . readFile ( cachedFilePath , 'utf8' ) ;
306+ const cacheJson = JSON . parse ( cacheValue ) ;
307+
308+ expect ( cacheJson ) . toStrictEqual ( {
309+ timestamp : expect . any ( Number ) ,
310+ value : 'foo' ,
311+ } ) ;
312+ } ) ;
313+
314+ it ( 'discards cached value if it is expired' , async ( ) => {
315+ await fs . mkdir ( dirname ( cachedFilePath ) , { recursive : true } ) ;
316+ await fs . writeFile (
317+ cachedFilePath ,
318+ JSON . stringify ( { timestamp : Date . now ( ) - 6000 , value : 'bar' } ) ,
319+ ) ;
320+
321+ const readSpy = jest . spyOn ( fs , 'readFile' ) ;
322+ const writeSpy = jest . spyOn ( fs , 'writeFile' ) ;
323+
324+ expect ( await cachedFunction ( ) ) . toBe ( 'foo' ) ;
325+
326+ expect ( readSpy ) . toHaveBeenCalledTimes ( 1 ) ;
327+ expect ( writeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
328+
329+ const cacheValue = await fs . readFile ( cachedFilePath , 'utf8' ) ;
330+ const cacheJson = JSON . parse ( cacheValue ) ;
331+
332+ expect ( cacheJson ) . toStrictEqual ( {
333+ timestamp : expect . any ( Number ) ,
334+ value : 'foo' ,
335+ } ) ;
336+ } ) ;
337+
338+ it ( 'skips persisting undefined' , async ( ) => {
339+ const fn = useFileSystemCache ( 'foo' , 5000 , async ( ) => {
340+ return undefined ;
341+ } ) ;
342+
343+ const spy = jest . spyOn ( fs , 'writeFile' ) ;
344+ expect ( await fn ( ) ) . toBeUndefined ( ) ;
345+
346+ expect ( spy ) . toHaveBeenCalledTimes ( 0 ) ;
347+ } ) ;
348+
349+ it ( 'skips persisting null' , async ( ) => {
350+ const fn = useFileSystemCache ( 'foo' , 5000 , async ( ) => {
351+ return null ;
352+ } ) ;
353+
354+ const spy = jest . spyOn ( fs , 'writeFile' ) ;
355+ expect ( await fn ( ) ) . toBeNull ( ) ;
356+
357+ expect ( spy ) . toHaveBeenCalledTimes ( 0 ) ;
358+ } ) ;
359+ } ) ;
0 commit comments