Skip to content

Commit 04e3092

Browse files
committed
[ImageLoader] Simplify getSize implementation, call failure callback when decoding fails
1 parent a5ba27c commit 04e3092

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import ImageLoader from '../index';
2+
3+
const testImage =
4+
'data:image/webp;base64,UklGRkYAAABXRUJQVlA4IDoAAADwAgCdASoXABMAPi0QhkKhoQ36AAwBYllAHYAAajokAAD+/SFF//G83mta3//9QZ/5Bn/kGfp4AAAA';
5+
const testImageWidth = 23;
6+
const testImageHeight = 19;
7+
8+
const DefaultImage = window.Image;
9+
10+
describe('ImageLoader', () => {
11+
afterEach(() => {
12+
window.Image = DefaultImage;
13+
});
14+
15+
test('Success callback is called when image loads', async () => {
16+
window.Image = MockImage;
17+
const successCallback = jest.fn();
18+
const failureCallback = jest.fn();
19+
ImageLoader.getSize(testImage, successCallback, failureCallback);
20+
await jest.runAllTimers();
21+
expect(failureCallback).toHaveBeenCalledTimes(0);
22+
expect(successCallback).toHaveBeenCalledTimes(1);
23+
expect(successCallback).toHaveBeenCalledWith(
24+
testImageWidth,
25+
testImageHeight
26+
);
27+
});
28+
29+
test('Failure callback is called when image fails to load', async () => {
30+
window.Image = NotLoadingMockImage;
31+
const successCallback = jest.fn();
32+
const failureCallback = jest.fn();
33+
ImageLoader.getSize(testImage, successCallback, failureCallback);
34+
await jest.runAllTimers();
35+
expect(failureCallback).toHaveBeenCalledTimes(1);
36+
expect(successCallback).toHaveBeenCalledTimes(0);
37+
});
38+
39+
test('Failure callback is called when image fails to decode', async () => {
40+
window.Image = NotDecodingMockImage;
41+
const successCallback = jest.fn();
42+
const failureCallback = jest.fn();
43+
ImageLoader.getSize(testImage, successCallback, failureCallback);
44+
await jest.runAllTimers();
45+
expect(failureCallback).toHaveBeenCalledTimes(1);
46+
expect(successCallback).toHaveBeenCalledTimes(0);
47+
});
48+
});
49+
50+
class MockImage {
51+
constructor(width = 0, height = 0) {
52+
this.width = width;
53+
this.height = height;
54+
this.naturalWidth = 0;
55+
this.naturalHeight = 0;
56+
this._src = '';
57+
}
58+
get src() {
59+
return this._src;
60+
}
61+
set src(uri) {
62+
this._src = uri;
63+
window.setTimeout(this.onload, 0);
64+
}
65+
decode() {
66+
this.naturalWidth = testImageWidth;
67+
this.naturalHeight = testImageHeight;
68+
return Promise.resolve();
69+
}
70+
onerror() {}
71+
onload() {}
72+
}
73+
74+
class NotLoadingMockImage extends MockImage {
75+
set src(uri) {
76+
this._src = uri;
77+
window.setTimeout(this.onerror, 0);
78+
}
79+
}
80+
81+
class NotDecodingMockImage extends MockImage {
82+
decode() {
83+
return Promise.reject();
84+
}
85+
}

Diff for: packages/react-native-web/src/modules/ImageLoader/index.js

+2-10
Original file line numberDiff line numberDiff line change
@@ -88,31 +88,23 @@ const ImageLoader = {
8888
success: (width: number, height: number) => void,
8989
failure: () => void
9090
) {
91-
let complete = false;
92-
const interval = setInterval(callback, 16);
9391
const requestId = ImageLoader.load(uri, callback, errorCallback);
94-
9592
function callback() {
9693
const image = requests[`${requestId}`];
9794
if (image) {
9895
const { naturalHeight, naturalWidth } = image;
9996
if (naturalHeight && naturalWidth) {
10097
success(naturalWidth, naturalHeight);
101-
complete = true;
98+
} else {
99+
errorCallback();
102100
}
103101
}
104-
if (complete) {
105-
ImageLoader.abort(requestId);
106-
clearInterval(interval);
107-
}
108102
}
109-
110103
function errorCallback() {
111104
if (typeof failure === 'function') {
112105
failure();
113106
}
114107
ImageLoader.abort(requestId);
115-
clearInterval(interval);
116108
}
117109
},
118110
has(uri: string): boolean {

0 commit comments

Comments
 (0)