Skip to content
Permalink
Browse files

Android: Add error description to Image onError callback (#22737)

Summary:
fixes #19073

Changelog:
----------

[Android] [Fixed] - Add error description to Image onError callback
Pull Request resolved: #22737

Differential Revision: D13676224

Pulled By: hramos

fbshipit-source-id: 0dea7e97ae6517b8980ad02827f19d22cd3ef933
  • Loading branch information...
Jyrno42 authored and facebook-github-bot committed Jan 25, 2019
1 parent 527fc9d commit 7795a672d3a24a5b50df6ad6d30555d856b557cc
@@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- needed for screenshot tests -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- needed for image onError tests -->
<uses-permission android:name="android.permission.INTERNET" />

<application
android:hardwareAccelerated="false">
@@ -7,6 +7,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- needed for screenshot tests -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- needed for image onError tests -->
<uses-permission android:name="android.permission.INTERNET" />

<application
android:hardwareAccelerated="false">
@@ -0,0 +1,46 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.tests;

import android.view.View;
import com.facebook.react.testing.ReactAppInstrumentationTestCase;
import com.facebook.react.testing.ReactInstanceSpecForTest;
import com.facebook.react.testing.StringRecordingModule;

/**
* Simple test case to check that onError does not get called with undefined
*/
public class ImageErrorTestCase extends ReactAppInstrumentationTestCase {

private StringRecordingModule mStringRecordingModule;

@Override
protected String getReactApplicationKeyUnderTest() {
return "ImageErrorTestApp";
}

public void testErrorHasCause() throws Exception {
assertNotNull(getViewByTestId("image-1"));
assertNotNull(getViewByTestId("image-2"));
assertNotNull(getViewByTestId("image-3"));

Thread.sleep(3000);

assertEquals(3, mStringRecordingModule.getCalls().size());
assertEquals("Got error: Unsupported uri scheme! Uri is: ", mStringRecordingModule.getCalls().get(0));
assertEquals("Got error: /does/not/exist: open failed: ENOENT (No such file or directory)", mStringRecordingModule.getCalls().get(1));
assertEquals("Got error: Unexpected HTTP code Response{protocol=http/1.1, code=404, message=Not Found, url=https://typo_error_facebook.github.io/react/logo-og.png}", mStringRecordingModule.getCalls().get(2));
}

@Override
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
mStringRecordingModule = new StringRecordingModule();
return super.createReactInstanceSpecForTest()
.addNativeModule(mStringRecordingModule);
}
}
@@ -0,0 +1,58 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/

'use strict';

const React = require('React');
const Image = require('Image');
const StyleSheet = require('StyleSheet');
const View = require('View');

const RecordingModule = require('NativeModules').Recording;

class ImageErrorTestApp extends React.Component {
onError = e => {
RecordingModule.record('Got error: ' + e.nativeEvent.error);
};

render() {
// For some reason image-2 needs explicit height. Without it onError is not triggered.
return (
<View>
<Image
testID="image-1"
source={{uri: '/does/not/exist'}}
onError={this.onError}
/>
<Image
testID="image-2"
source={{uri: 'file:///does/not/exist'}}
style={styles.image}
onError={this.onError}
/>
<Image
testID="image-3"
source={{
uri: 'https://TYPO_ERROR_facebook.github.io/react/logo-og.png',
}}
onError={this.onError}
/>
</View>
);
}
}

const styles = StyleSheet.create({
image: {
height: 50,
width: 50,
},
});

module.exports = ImageErrorTestApp;
@@ -58,6 +58,10 @@ const apps = [
appKey: 'ImageOverlayColorTestApp',
component: () => require('ImageOverlayColorTestApp'),
},
{
appKey: 'ImageErrorTestApp',
component: () => require('ImageErrorTestApp'),
},
{
appKey: 'InitialPropsTestApp',
component: () => require('InitialPropsTestApp'),
@@ -33,13 +33,18 @@
private final @Nullable String mImageUri;
private final int mWidth;
private final int mHeight;
private final @Nullable String mImageError;

public ImageLoadEvent(int viewId, @ImageEventType int eventType) {
this(viewId, eventType, null);
}

public ImageLoadEvent(int viewId, @ImageEventType int eventType, boolean error, String message) {
this(viewId, eventType, null, 0, 0, message);
}

public ImageLoadEvent(int viewId, @ImageEventType int eventType, String imageUri) {
this(viewId, eventType, imageUri, 0, 0);
this(viewId, eventType, imageUri, 0, 0, null);
}

public ImageLoadEvent(
@@ -48,11 +53,22 @@ public ImageLoadEvent(
@Nullable String imageUri,
int width,
int height) {
this(viewId, eventType, imageUri, width, height, null);
}

public ImageLoadEvent(
int viewId,
@ImageEventType int eventType,
@Nullable String imageUri,
int width,
int height,
@Nullable String message) {
super(viewId);
mEventType = eventType;
mImageUri = imageUri;
mWidth = width;
mHeight = height;
mImageError = message;
}

public static String eventNameForType(@ImageEventType int eventType) {
@@ -88,7 +104,7 @@ public short getCoalescingKey() {
public void dispatch(RCTEventEmitter rctEventEmitter) {
WritableMap eventData = null;

if (mImageUri != null || mEventType == ON_LOAD) {
if (mImageUri != null || (mEventType == ON_LOAD || mEventType == ON_ERROR)) {
eventData = Arguments.createMap();

if (mImageUri != null) {
@@ -103,6 +119,8 @@ public void dispatch(RCTEventEmitter rctEventEmitter) {
source.putString("url", mImageUri);
}
eventData.putMap("source", source);
} else if (mEventType == ON_ERROR) {
eventData.putString("error", mImageError);
}
}

@@ -262,9 +262,8 @@ public void onFinalImageSet(
@Override
public void onFailure(String id, Throwable throwable) {
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), ImageLoadEvent.ON_ERROR));
mEventDispatcher.dispatchEvent(
new ImageLoadEvent(getId(), ImageLoadEvent.ON_LOAD_END));
new ImageLoadEvent(getId(), ImageLoadEvent.ON_ERROR,
true, throwable.getMessage()));
}
};
}

0 comments on commit 7795a67

Please sign in to comment.
You can’t perform that action at this time.