diff --git a/packages/react-native/Libraries/Image/__tests__/Image-itest.js b/packages/react-native/Libraries/Image/__tests__/Image-itest.js index d946941d444a4e..ae74a839cc000d 100644 --- a/packages/react-native/Libraries/Image/__tests__/Image-itest.js +++ b/packages/react-native/Libraries/Image/__tests__/Image-itest.js @@ -169,6 +169,165 @@ describe('', () => { ); }); }); + + describe('defaultSource', () => { + it('can provide a default image to display', () => { + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render( + , + ); + }); + + expect( + root.getRenderedOutput({props: ['defaultSource']}).toJSX(), + ).toEqual( + , + ); + }); + }); + + describe('height', () => { + it('provides height for image', () => { + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render(); + }); + + expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual( + , + ); + }); + }); + + describe('loading progress', () => { + ( + [ + ['onError', 'fails to load'], + ['onLoadStart', 'start loading'], + ['onProgress', 'is loading'], + ['onLoad', 'loads successfully'], + ['onLoadEnd', 'ends loading'], + ] as const + ).forEach(([onProp, event]) => { + it(`${onProp} is called when image ${event}`, () => { + const onPropCallback = jest.fn(); + const ref = createRef(); + + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render( + { + onProp === 'onError' && onPropCallback(); + }} + onLoad={() => { + onProp === 'onLoad' && onPropCallback(); + }} + onLoadStart={() => { + onProp === 'onLoadStart' && onPropCallback(); + }} + onLoadEnd={() => { + onProp === 'onLoadEnd' && onPropCallback(); + }} + onProgress={() => { + onProp === 'onProgress' && onPropCallback(); + }} + />, + ); + }); + + expect(onPropCallback).toHaveBeenCalledTimes(0); + + const image = ensureInstance(ref.current, ReactNativeElement); + Fantom.dispatchNativeEvent(image, onProp, {}); + + expect(onPropCallback).toHaveBeenCalledTimes(1); + }); + }); + }); + + describe('referrerPolicy', () => { + ( + [ + 'no-referrer', + 'no-referrer-when-downgrade', + 'origin', + 'origin-when-cross-origin', + 'same-origin', + 'strict-origin', + 'strict-origin-when-cross-origin', + 'unsafe-url', + ] as const + ).forEach(referrerPolicy => { + it(`${referrerPolicy} sets correct "Referrer-Policy" header`, () => { + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render( + , + ); + }); + + expect( + root.getRenderedOutput({props: ['source-header']}).toJSX(), + ).toEqual( + , + ); + }); + }); + }); + + describe('resizeMode', () => { + it('is set to "cover" by default', () => { + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render(); + }); + + expect(root.getRenderedOutput({props: ['resizeMode']}).toJSX()).toEqual( + , + ); + + Fantom.runTask(() => { + root.render(); + }); + + expect(root.getRenderedOutput({props: ['resizeMode']}).toJSX()).toEqual( + , + ); + }); + + (['stretch', 'contain', 'repeat', 'center'] as const).forEach( + resizeMode => { + it(`can be set to "${resizeMode}"`, () => { + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render( + , + ); + }); + + expect( + root.getRenderedOutput({props: ['resizeMode']}).toJSX(), + ).toEqual(); + }); + }, + ); + }); }); describe('ref', () => { diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.cpp index 19d5501f09b0da..dca045f67ce7d3 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.cpp @@ -304,8 +304,30 @@ SharedDebugStringConvertibleList ImageProps::getDebugProps() const { SharedDebugStringConvertibleList{ debugStringConvertibleItem( "blurRadius", blurRadius, imageProps.blurRadius), + debugStringConvertibleItem( + "resizeMode", + toString(resizeMode), + toString(imageProps.resizeMode)), }; } + +inline std::string toString(ImageResizeMode resizeMode) { + switch (resizeMode) { + case ImageResizeMode::Cover: + return "cover"; + case ImageResizeMode::Contain: + return "contain"; + case ImageResizeMode::Stretch: + return "stretch"; + case ImageResizeMode::Center: + return "center"; + case ImageResizeMode::Repeat: + return "repeat"; + case ImageResizeMode::None: + return "none"; + } +} + #endif } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.h b/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.h index 43cdc51ac5b716..1b753d7ffa0b84 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.h @@ -34,7 +34,7 @@ class ImageProps final : public ViewProps { ImageSources sources{}; ImageSource defaultSource{}; ImageSource loadingIndicatorSource{}; - ImageResizeMode resizeMode{ImageResizeMode::Stretch}; + ImageResizeMode resizeMode{ImageResizeMode::Cover}; Float blurRadius{}; EdgeInsets capInsets{}; SharedColor tintColor{};