diff --git a/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap b/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap
new file mode 100644
index 000000000..175d971cf
--- /dev/null
+++ b/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap
@@ -0,0 +1,46 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AttachmentImage it matches snapshot 1`] = `
+
+
+
+
+
+`;
diff --git a/app/components/message_attachments/attachment_image/attachment_image.js b/app/components/message_attachments/attachment_image/attachment_image.js
index dfb04ac13..5b8165a0f 100644
--- a/app/components/message_attachments/attachment_image/attachment_image.js
+++ b/app/components/message_attachments/attachment_image/attachment_image.js
@@ -48,6 +48,12 @@ export default class AttachmentImage extends PureComponent {
}
}
+ componentDidUpdate(prevProps) {
+ if (this.props.imageUrl && (prevProps.imageUrl !== this.props.imageUrl)) {
+ ImageCacheManager.cache(null, this.props.imageUrl, this.setImageUrl);
+ }
+ }
+
handlePreviewImage = () => {
const {actions, imageUrl} = this.props;
const {
diff --git a/app/components/message_attachments/attachment_image/attachment_image.test.js b/app/components/message_attachments/attachment_image/attachment_image.test.js
new file mode 100644
index 000000000..3661ec762
--- /dev/null
+++ b/app/components/message_attachments/attachment_image/attachment_image.test.js
@@ -0,0 +1,135 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import ImageCacheManager from 'app/utils/image_cache_manager';
+import {Image} from 'react-native';
+import {shallow} from 'enzyme';
+import React from 'react';
+
+const originalCacheFn = ImageCacheManager.cache;
+const originalGetSizeFn = Image.getSize;
+
+import Preferences from 'mattermost-redux/constants/preferences';
+
+import AttachmentImage from './attachment_image';
+
+describe('AttachmentImage', () => {
+ const baseProps = {
+ actions: {
+ showModalOverCurrentContext: jest.fn(),
+ },
+ deviceHeight: 256,
+ deviceWidth: 128,
+ imageMetadata: {width: 32, height: 32},
+ imageUrl: 'https://images.com/image.png',
+ theme: Preferences.THEMES.default,
+ };
+
+ afterEach(() => {
+ Image.getSize = originalGetSizeFn;
+ ImageCacheManager.cache = originalCacheFn;
+ });
+
+ test('it matches snapshot', () => {
+ const cacheFn = jest.fn((_, url, callback) => {
+ callback(url);
+ });
+ ImageCacheManager.cache = cacheFn;
+
+ const wrapper = shallow();
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('it sets state based on props', () => {
+ const cacheFn = jest.fn((_, url, callback) => {
+ callback(url);
+ });
+ ImageCacheManager.cache = cacheFn;
+
+ const wrapper = shallow();
+
+ const state = wrapper.state();
+ expect(state.hasImage).toBe(true);
+ expect(state.imageUri).toBe('https://images.com/image.png');
+ expect(state.originalWidth).toBe(32);
+ expect(cacheFn).toHaveBeenCalled();
+ });
+
+ test('it does not render image if no imageUrl is provided', () => {
+ const cacheFn = jest.fn((_, url, callback) => {
+ callback(url);
+ });
+ ImageCacheManager.cache = cacheFn;
+
+ const props = {...baseProps, imageUrl: null, imageMetadata: null};
+ const wrapper = shallow();
+
+ const state = wrapper.state();
+ expect(state.hasImage).toBe(false);
+ expect(state.imageUri).toBe(null);
+ expect(cacheFn).not.toHaveBeenCalled();
+ });
+
+ test('it calls Image.getSize if metadata is not present', () => {
+ const cacheFn = jest.fn((_, url, callback) => {
+ callback(url);
+ });
+ const getSizeFn = jest.fn((_, callback) => {
+ callback(64, 64);
+ });
+ ImageCacheManager.cache = cacheFn;
+ Image.getSize = getSizeFn;
+
+ const props = {...baseProps, imageMetadata: null};
+ const wrapper = shallow();
+
+ const state = wrapper.state();
+ expect(state.hasImage).toBe(true);
+ expect(state.imageUri).toBe('https://images.com/image.png');
+ expect(state.originalWidth).toBe(64);
+ expect(cacheFn).toHaveBeenCalled();
+ expect(getSizeFn).toHaveBeenCalled();
+ });
+
+ test('it updates image when imageUrl prop changes', () => {
+ const cacheFn = jest.fn((_, url, callback) => {
+ callback(url);
+ });
+ ImageCacheManager.cache = cacheFn;
+
+ const wrapper = shallow();
+
+ wrapper.setProps({
+ imageUrl: 'https://someothersite.com/picture.png',
+ imageMetadata: {
+ width: 96,
+ height: 96,
+ },
+ });
+
+ const state = wrapper.state();
+ expect(state.hasImage).toBe(true);
+ expect(state.imageUri).toBe('https://someothersite.com/picture.png');
+ expect(state.originalWidth).toBe(96);
+ expect(cacheFn).toHaveBeenCalledTimes(2);
+ });
+
+ test('it does not update image when an unrelated prop changes', () => {
+ const cacheFn = jest.fn((_, url, callback) => {
+ callback(url);
+ });
+ ImageCacheManager.cache = cacheFn;
+
+ const wrapper = shallow();
+
+ wrapper.setProps({
+ theme: {...Preferences.THEMES.default},
+ });
+
+ const state = wrapper.state();
+ expect(state.hasImage).toBe(true);
+ expect(state.imageUri).toBe('https://images.com/image.png');
+ expect(state.originalWidth).toBe(32);
+ expect(cacheFn).toHaveBeenCalledTimes(1);
+ });
+});