Skip to content
This repository was archived by the owner on Apr 15, 2025. It is now read-only.

Commit b34145d

Browse files
committed
Added CacheableImage.cacheFile() and CacheableImage.purge() static methods and tests.
1 parent ad3cf73 commit b34145d

File tree

5 files changed

+191
-3
lines changed

5 files changed

+191
-3
lines changed

index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@
77
'use strict';
88

99
import imageCacheHoc from './lib/imageCacheHoc';
10+
import FileSystemFactory, { FileSystem } from './lib/FileSystem';
1011

11-
export default imageCacheHoc;
12+
export default imageCacheHoc;
13+
export { FileSystemFactory, FileSystem }; // Allow access to FS logic for advanced users.

lib/FileSystem.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ export class FileSystem {
120120
*
121121
* Wrapper for https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#existspathstringpromise
122122
*
123-
* @param path - local file path.
123+
* @param path - local relative file path.
124124
* @returns {Promise} - boolean promise for if file exists at path or not.
125125
*/
126126
exists(path) {
127127
this._validatePath(path);
128-
return RNFetchBlob.fs.exists(this.baseFilePath + path);
128+
return RNFetchBlob.fs.exists(pathLib.resolve(this.baseFilePath + path));
129129
}
130130

131131
/**
@@ -304,6 +304,24 @@ export class FileSystem {
304304

305305
}
306306

307+
/**
308+
* Used to delete local files and directories
309+
*
310+
* @param path - local relative file path.
311+
* @returns {Promise} - boolean promise for if deletion was successful.
312+
*/
313+
async unlink(path) {
314+
this._validatePath(path);
315+
316+
try {
317+
await RNFetchBlob.fs.unlink(pathLib.resolve(this.baseFilePath + path));
318+
return true;
319+
} catch (error) {
320+
return false;
321+
}
322+
323+
}
324+
307325
}
308326

309327
/**

lib/imageCacheHoc.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,49 @@ export default function imageCacheHoc(Image, options = {}) {
4444
})
4545
};
4646

47+
/**
48+
*
49+
* Manually cache a file.
50+
* Can be used to pre-warm caches.
51+
* If calling this method repeatedly to cache a long list of files,
52+
* be sure to use a queue and limit concurrency so your app performance does not suffer.
53+
*
54+
* @param url {String} - url of file to download.
55+
* @param permanent {Boolean} - whether the file should be saved to the tmp or permanent cache directory.
56+
* @returns {Promise} promise that resolves to an object that contains cached file info.
57+
*/
58+
static async cacheFile(url, permanent = false) {
59+
60+
const fileSystem = FileSystemFactory();
61+
const localFilePath = await fileSystem.getLocalFilePathFromUrl(url, permanent);
62+
63+
return {
64+
url: url,
65+
cacheType: (permanent ? 'permanent' : 'cache'),
66+
localFilePath
67+
};
68+
69+
}
70+
71+
/**
72+
*
73+
* Delete all locally stored image files created by react-native-image-cache-hoc (cache AND permanent).
74+
* Calling this method will cause a performance hit on your app until the local files are rebuilt.
75+
*
76+
* @returns {Promise} promise that resolves to an object that contains the flush results.
77+
*/
78+
static async flush() {
79+
80+
const fileSystem = FileSystemFactory();
81+
const results = await Promise.all([fileSystem.unlink('permanent'), fileSystem.unlink('cache')]);
82+
83+
return {
84+
permanentDirFlushed: results[0],
85+
cacheDirFlushed: results[1]
86+
};
87+
88+
}
89+
4790
constructor(props) {
4891
super(props);
4992

tests/CacheableImage.test.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,93 @@ describe('CacheableImage', function() {
8888

8989
});
9090

91+
it('#cacheFile static method should work as expected for cache dir files.', () => {
92+
93+
// RNFetchBlob Mocks
94+
const RNFetchBlob = require('react-native-fetch-blob');
95+
96+
// Mock that file does not exist on local fs.
97+
RNFetchBlob.fs.exists
98+
.mockReturnValue(false);
99+
100+
// Mock fetch result
101+
RNFetchBlob.fetch
102+
.mockReturnValue({
103+
path: () => {
104+
return '/this/is/path/to/file.jpg';
105+
}
106+
});
107+
108+
const CacheableImage = imageCacheHoc(Image);
109+
110+
return CacheableImage.cacheFile('https://i.redd.it/rc29s4bz61uz.png')
111+
.then(result => {
112+
113+
result.should.deepEqual({
114+
url: 'https://i.redd.it/rc29s4bz61uz.png',
115+
cacheType: 'cache',
116+
localFilePath: '/this/is/path/to/file.jpg'
117+
});
118+
119+
});
120+
121+
});
122+
123+
it('#cacheFile static method should work as expected for permanent dir files.', () => {
124+
125+
// RNFetchBlob Mocks
126+
const RNFetchBlob = require('react-native-fetch-blob');
127+
128+
// Mock that file does not exist on local fs.
129+
RNFetchBlob.fs.exists
130+
.mockReturnValue(false);
131+
132+
// Mock fetch result
133+
RNFetchBlob.fetch
134+
.mockReturnValue({
135+
path: () => {
136+
return '/this/is/path/to/file.jpg';
137+
}
138+
});
139+
140+
const CacheableImage = imageCacheHoc(Image);
141+
142+
return CacheableImage.cacheFile('https://i.redd.it/rc29s4bz61uz.png', true)
143+
.then(result => {
144+
145+
result.should.deepEqual({
146+
url: 'https://i.redd.it/rc29s4bz61uz.png',
147+
cacheType: 'permanent',
148+
localFilePath: '/this/is/path/to/file.jpg'
149+
});
150+
151+
});
152+
153+
});
154+
155+
it('#flush static method should work as expected.', () => {
156+
157+
// RNFetchBlob Mocks
158+
const RNFetchBlob = require('react-native-fetch-blob');
159+
160+
// Mock unlink to always be true.
161+
RNFetchBlob.fs.unlink
162+
.mockReturnValue(true);
163+
164+
const CacheableImage = imageCacheHoc(Image);
165+
166+
return CacheableImage.flush()
167+
.then(result => {
168+
169+
result.should.deepEqual({
170+
permanentDirFlushed: true,
171+
cacheDirFlushed: true
172+
});
173+
174+
});
175+
176+
});
177+
91178
it('#constructor should initialize class object properties correctly.', () => {
92179

93180
const CacheableImage = imageCacheHoc(Image);

tests/FileSystem.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,42 @@ describe('lib/FileSystem', function() {
290290

291291
});
292292

293+
it('#unlink should only accept valid paths.', () => {
294+
295+
const fileSystem = FileSystemFactory();
296+
297+
const badFileName = '/../../../../../bad-file-name.jpg';
298+
299+
return fileSystem.unlink(badFileName)
300+
.then(() => {
301+
throw new Error('Bad file path was accepted.');
302+
})
303+
.catch((error) => {
304+
let resolvedPath = pathLib.resolve(mockData.basePath + badFileName);
305+
306+
error.should.deepEqual(new Error(resolvedPath + ' is not a valid file path.'));
307+
});
308+
309+
});
310+
311+
it('#unlink should work as expected for valid paths.', () => {
312+
313+
// RNFetchBlob Mocks
314+
const RNFetchBlob = require('react-native-fetch-blob');
315+
316+
// Mock unlink to be true.
317+
RNFetchBlob.fs.unlink
318+
.mockReturnValueOnce(true);
319+
320+
const fileSystem = FileSystemFactory();
321+
322+
const validPath = '/permanent/valid.jpg';
323+
324+
return fileSystem.unlink(validPath)
325+
.then( result => {
326+
result.should.be.true();
327+
});
328+
329+
});
330+
293331
});

0 commit comments

Comments
 (0)