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

Commit 5c330b4

Browse files
committed
Add tests for immutable and mutable and fix lots of false passes (try/catch and .then)
1 parent 280e3d8 commit 5c330b4

File tree

3 files changed

+384
-265
lines changed

3 files changed

+384
-265
lines changed

tests/CacheableImage.test.tsx

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,61 @@
11
import 'should'
22
import { mockData } from './mockData'
3-
import { imageCacheHoc } from '../src/index'
4-
import { Image } from 'react-native'
5-
import sinon from 'sinon'
3+
import { imageCacheHoc, ReactNativeImageCacheHocOptions } from '../src/index'
4+
import { Image, Text } from 'react-native'
65
import 'should-sinon'
76
import RNFS from 'react-native-fs'
87
import { shallow } from 'enzyme'
98
import React from 'react'
9+
import { mocked } from 'ts-jest/utils'
1010

1111
describe('CacheableImage', function () {
1212
const originalWarn = console.warn
1313
afterEach(() => (console.warn = originalWarn))
14+
const MockedRNFS = mocked(RNFS, true)
15+
16+
beforeEach(function () {
17+
jest.clearAllMocks()
18+
})
1419

1520
it('HOC options validation should work as expected.', () => {
1621
// Check validation is catching bad option input.
17-
try {
22+
23+
expect(() =>
1824
imageCacheHoc(Image, {
19-
validProtocols: 'string',
20-
})
21-
} catch (error) {
22-
error.should.deepEqual(
23-
new Error('validProtocols option must be an array of protocol strings.'),
24-
)
25-
}
25+
validProtocols: 'string' as any,
26+
}),
27+
).toThrow('validProtocols option must be an array of protocol strings.')
2628

27-
try {
29+
expect(() =>
2830
imageCacheHoc(Image, {
29-
fileHostWhitelist: 'string',
30-
})
31-
} catch (error) {
32-
error.should.deepEqual(
33-
new Error('fileHostWhitelist option must be an array of host strings.'),
34-
)
35-
}
31+
fileHostWhitelist: 'string' as any,
32+
}),
33+
).toThrow('fileHostWhitelist option must be an array of host strings.')
3634

37-
try {
35+
expect(() =>
3836
imageCacheHoc(Image, {
39-
cachePruneTriggerLimit: 'string',
40-
})
41-
} catch (error) {
42-
error.should.deepEqual(new Error('cachePruneTriggerLimit option must be an integer.'))
43-
}
37+
cachePruneTriggerLimit: 'string' as any,
38+
}),
39+
).toThrow('cachePruneTriggerLimit option must be an integer.')
4440

45-
try {
41+
expect(() =>
4642
imageCacheHoc(Image, {
47-
fileDirName: 1,
48-
})
49-
} catch (error) {
50-
error.should.deepEqual(new Error('fileDirName option must be string'))
51-
}
43+
fileDirName: 1 as any,
44+
}),
45+
).toThrow('fileDirName option must be string')
5246

53-
try {
47+
expect(() =>
5448
imageCacheHoc(Image, {
55-
defaultPlaceholder: 5478329,
56-
})
57-
} catch (error) {
58-
error.should.deepEqual(
59-
new Error(
60-
'defaultPlaceholder option object must include "component" and "props" properties (props can be an empty object)',
61-
),
62-
)
63-
}
49+
defaultPlaceholder: 5478329 as any,
50+
}),
51+
).toThrow('defaultPlaceholder option must be a JSX.Element')
6452

65-
const validOptions = {
53+
const validOptions: ReactNativeImageCacheHocOptions = {
6654
validProtocols: ['http', 'https'],
6755
fileHostWhitelist: ['i.redd.it', 'localhost'],
6856
cachePruneTriggerLimit: 1024 * 1024 * 10,
6957
fileDirName: 'test-dir',
70-
defaultPlaceholder: {
71-
component: Image,
72-
props: {},
73-
},
58+
defaultPlaceholder: <Text>Default Placeholder</Text>,
7459
}
7560

7661
// Valid options shouldn't throw an error
@@ -109,7 +94,7 @@ describe('CacheableImage', function () {
10994

11095
it('#flush static method should work as expected.', () => {
11196
// Mock unlink to always be true.
112-
RNFS.unlink.mockResolvedValue(true)
97+
MockedRNFS.unlink.mockResolvedValueOnce()
11398

11499
const CacheableImage = imageCacheHoc(Image)
115100

@@ -140,8 +125,7 @@ describe('CacheableImage', function () {
140125
})
141126

142127
it('#_validateImageComponent should validate bad component props correctly.', () => {
143-
const consoleOutput = []
144-
console.warn = (output) => consoleOutput.push(output)
128+
console.warn = jest.fn()
145129

146130
// Verify source uri prop only accepts web accessible urls.
147131

@@ -153,9 +137,10 @@ describe('CacheableImage', function () {
153137
},
154138
})
155139

156-
expect(consoleOutput).toEqual([
140+
expect(console.warn).toHaveBeenNthCalledWith(
141+
1,
157142
'Invalid source prop. <CacheableImage> props.source.uri should be a web accessible url with a valid protocol and host. NOTE: Default valid protocol is https, default valid hosts are *.',
158-
])
143+
)
159144

160145
// Verify source uri prop only accepts web accessible urls from whitelist if whitelist set.
161146

@@ -170,10 +155,10 @@ describe('CacheableImage', function () {
170155
},
171156
})
172157

173-
expect(consoleOutput).toEqual([
158+
expect(console.warn).toHaveBeenNthCalledWith(
159+
2,
174160
'Invalid source prop. <CacheableImage> props.source.uri should be a web accessible url with a valid protocol and host. NOTE: Default valid protocol is https, default valid hosts are *.',
175-
'Invalid source prop. <CacheableImage> props.source.uri should be a web accessible url with a valid protocol and host. NOTE: Default valid protocol is https, default valid hosts are *.',
176-
])
161+
)
177162

178163
// Verify source uri prop only accepts web accessible urls from correct protocols if protocol list set.
179164

@@ -188,11 +173,10 @@ describe('CacheableImage', function () {
188173
},
189174
})
190175

191-
expect(consoleOutput).toEqual([
192-
'Invalid source prop. <CacheableImage> props.source.uri should be a web accessible url with a valid protocol and host. NOTE: Default valid protocol is https, default valid hosts are *.',
193-
'Invalid source prop. <CacheableImage> props.source.uri should be a web accessible url with a valid protocol and host. NOTE: Default valid protocol is https, default valid hosts are *.',
176+
expect(console.warn).toHaveBeenNthCalledWith(
177+
3,
194178
'Invalid source prop. <CacheableImage> props.source.uri should be a web accessible url with a valid protocol and host. NOTE: Default valid protocol is https, default valid hosts are *.',
195-
])
179+
)
196180
})
197181

198182
it('Verify component is actually still mounted before calling setState() in componentDidMount().', async () => {
@@ -206,7 +190,7 @@ describe('CacheableImage', function () {
206190
mockData.basePath +
207191
'/react-native-image-cache-hoc/cd7d2199cd8e088cdfd9c99fc6359666adc36289.png',
208192
)
209-
}, 1000) // Mock 1 second delay for this async function to complete.
193+
}, 500) // Mock 0.5 second delay for this async function to complete.
210194
}),
211195
)
212196

@@ -217,30 +201,24 @@ describe('CacheableImage', function () {
217201
// executing, setState() will not be called by an unmounted component when componentDidMount() resumes execution after
218202
// completing async work.
219203
// See: https://github.com/billmalarky/react-native-image-cache-hoc/issues/6#issuecomment-354490597
220-
cacheableImage.setState = sinon.spy() // Mock setState with function tracker to ensure it doesn't get called on unmounted component.
204+
const setStateSpy = jest.spyOn(cacheableImage, 'setState')
221205
cacheableImage.componentDidMount()
222206
cacheableImage.unmounted$.value.should.be.false()
223207
cacheableImage.componentWillUnmount()
224208
cacheableImage.unmounted$.value.should.be.true()
225209

226210
// Wait for componentDidMount() to complete execution.
227211
await new Promise((resolve) => {
228-
setTimeout(resolve, 2000)
212+
setTimeout(resolve, 1000)
229213
})
230214

231215
// Ensure that setState() was not called on unmounted component.
232-
cacheableImage.setState.should.not.be.called()
216+
expect(setStateSpy).not.toBeCalled()
217+
218+
setStateSpy.mockRestore()
233219
})
234220

235221
it('componentDidUpdate should not throw any uncaught errors.', (done) => {
236-
RNFS.downloadFile
237-
.mockReturnValueOnce({
238-
promise: Promise.resolve({ statusCode: 200 }),
239-
})
240-
.mockReturnValueOnce({
241-
promise: Promise.resolve({ statusCode: 200 }),
242-
})
243-
244222
const CacheableImage = imageCacheHoc(Image)
245223

246224
const wrapper = shallow(<CacheableImage {...mockData.mockCacheableImageProps} />)
@@ -284,4 +262,29 @@ describe('CacheableImage', function () {
284262
done()
285263
})
286264
})
265+
266+
it('When render with onLoadFinished prop, event should be called with image size', (done) => {
267+
const CacheableImage = imageCacheHoc(Image)
268+
269+
const onLoadFinished = jest.fn()
270+
271+
const getSizeMock = jest
272+
.spyOn(Image, 'getSize')
273+
.mockImplementation((uri: string, success: (width: number, height: number) => void) => {
274+
success(100, 200)
275+
})
276+
277+
shallow(
278+
<CacheableImage {...mockData.mockCacheableImageProps} onLoadFinished={onLoadFinished} />,
279+
)
280+
281+
setImmediate(() => {
282+
expect(getSizeMock).toHaveBeenCalledTimes(1)
283+
expect(onLoadFinished).toHaveBeenCalled()
284+
285+
getSizeMock.mockRestore()
286+
287+
done()
288+
})
289+
})
287290
})

0 commit comments

Comments
 (0)