From 04e3092599143e51e5792c214ca24b99bb679ce7 Mon Sep 17 00:00:00 2001 From: lkinasiewicz Date: Mon, 30 Dec 2024 14:14:59 +0100 Subject: [PATCH] [ImageLoader] Simplify getSize implementation, call failure callback when decoding fails --- .../ImageLoader/__tests__/index-test.js | 85 +++++++++++++++++++ .../src/modules/ImageLoader/index.js | 12 +-- 2 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 packages/react-native-web/src/modules/ImageLoader/__tests__/index-test.js diff --git a/packages/react-native-web/src/modules/ImageLoader/__tests__/index-test.js b/packages/react-native-web/src/modules/ImageLoader/__tests__/index-test.js new file mode 100644 index 000000000..4f8daae15 --- /dev/null +++ b/packages/react-native-web/src/modules/ImageLoader/__tests__/index-test.js @@ -0,0 +1,85 @@ +import ImageLoader from '../index'; + +const testImage = + 'data:image/webp;base64,UklGRkYAAABXRUJQVlA4IDoAAADwAgCdASoXABMAPi0QhkKhoQ36AAwBYllAHYAAajokAAD+/SFF//G83mta3//9QZ/5Bn/kGfp4AAAA'; +const testImageWidth = 23; +const testImageHeight = 19; + +const DefaultImage = window.Image; + +describe('ImageLoader', () => { + afterEach(() => { + window.Image = DefaultImage; + }); + + test('Success callback is called when image loads', async () => { + window.Image = MockImage; + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + ImageLoader.getSize(testImage, successCallback, failureCallback); + await jest.runAllTimers(); + expect(failureCallback).toHaveBeenCalledTimes(0); + expect(successCallback).toHaveBeenCalledTimes(1); + expect(successCallback).toHaveBeenCalledWith( + testImageWidth, + testImageHeight + ); + }); + + test('Failure callback is called when image fails to load', async () => { + window.Image = NotLoadingMockImage; + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + ImageLoader.getSize(testImage, successCallback, failureCallback); + await jest.runAllTimers(); + expect(failureCallback).toHaveBeenCalledTimes(1); + expect(successCallback).toHaveBeenCalledTimes(0); + }); + + test('Failure callback is called when image fails to decode', async () => { + window.Image = NotDecodingMockImage; + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + ImageLoader.getSize(testImage, successCallback, failureCallback); + await jest.runAllTimers(); + expect(failureCallback).toHaveBeenCalledTimes(1); + expect(successCallback).toHaveBeenCalledTimes(0); + }); +}); + +class MockImage { + constructor(width = 0, height = 0) { + this.width = width; + this.height = height; + this.naturalWidth = 0; + this.naturalHeight = 0; + this._src = ''; + } + get src() { + return this._src; + } + set src(uri) { + this._src = uri; + window.setTimeout(this.onload, 0); + } + decode() { + this.naturalWidth = testImageWidth; + this.naturalHeight = testImageHeight; + return Promise.resolve(); + } + onerror() {} + onload() {} +} + +class NotLoadingMockImage extends MockImage { + set src(uri) { + this._src = uri; + window.setTimeout(this.onerror, 0); + } +} + +class NotDecodingMockImage extends MockImage { + decode() { + return Promise.reject(); + } +} diff --git a/packages/react-native-web/src/modules/ImageLoader/index.js b/packages/react-native-web/src/modules/ImageLoader/index.js index 892db9929..bf1dfb5a8 100644 --- a/packages/react-native-web/src/modules/ImageLoader/index.js +++ b/packages/react-native-web/src/modules/ImageLoader/index.js @@ -88,31 +88,23 @@ const ImageLoader = { success: (width: number, height: number) => void, failure: () => void ) { - let complete = false; - const interval = setInterval(callback, 16); const requestId = ImageLoader.load(uri, callback, errorCallback); - function callback() { const image = requests[`${requestId}`]; if (image) { const { naturalHeight, naturalWidth } = image; if (naturalHeight && naturalWidth) { success(naturalWidth, naturalHeight); - complete = true; + } else { + errorCallback(); } } - if (complete) { - ImageLoader.abort(requestId); - clearInterval(interval); - } } - function errorCallback() { if (typeof failure === 'function') { failure(); } ImageLoader.abort(requestId); - clearInterval(interval); } }, has(uri: string): boolean {