From 4a41dff5d174471091e9af99658cfdfdf3df45f7 Mon Sep 17 00:00:00 2001
From: "Jules Sam. Randolph"
Date: Tue, 9 Feb 2021 10:09:30 -0300
Subject: [PATCH] feat: graceful handling of missing `source` prop
Also, the user will receive messages in dev mode about outdated props
such as `html` and `uri`.
---
packages/render-html/jest.config.js | 5 ++-
packages/render-html/src/RenderHTML.tsx | 8 ++--
packages/render-html/src/RenderHTMLDebug.tsx | 41 +++++++++++++-----
packages/render-html/src/SourceLoader.tsx | 3 ++
.../component.render-html-dev.test.tsx | 43 +++++++++++++++++++
...est.tsx => component.render-html.test.tsx} | 18 ++++++--
6 files changed, 100 insertions(+), 18 deletions(-)
create mode 100644 packages/render-html/src/__tests__/component.render-html-dev.test.tsx
rename packages/render-html/src/__tests__/{component.html.test.tsx => component.render-html.test.tsx} (62%)
diff --git a/packages/render-html/jest.config.js b/packages/render-html/jest.config.js
index b454f9464..e401087c4 100644
--- a/packages/render-html/jest.config.js
+++ b/packages/render-html/jest.config.js
@@ -1,5 +1,8 @@
module.exports = {
preset: 'react-native',
testRegex: 'src/.*(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
- coveragePathIgnorePatterns: ['/node_modules/', '__tests__']
+ coveragePathIgnorePatterns: ['/node_modules/', '__tests__'],
+ globals: {
+ __DEV__: true
+ }
};
diff --git a/packages/render-html/src/RenderHTML.tsx b/packages/render-html/src/RenderHTML.tsx
index 18c02272a..beffc370c 100644
--- a/packages/render-html/src/RenderHTML.tsx
+++ b/packages/render-html/src/RenderHTML.tsx
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
-import { Platform } from 'react-native';
+import { Dimensions, Platform } from 'react-native';
import { RenderResolvedHTMLProps, RenderHTMLProps } from './shared-types';
import useTTree from './hooks/useTTree';
import SharedPropsContext, {
@@ -149,7 +149,8 @@ const defaultProps: {
]
}),
triggerTREInvalidationPropNames: [],
- debug: __DEV__
+ debug: __DEV__,
+ contentWidth: undefined
};
function RenderResolvedHTML(props: RenderResolvedHTMLProps) {
@@ -168,11 +169,12 @@ export default function RenderHTML({
...props
}: RenderHTMLProps) {
const normalizedProps = {
+ contentWidth: Dimensions.get('window').width,
...props,
defaultTextProps: { ...defaultProps.defaultTextProps, ...defaultTextProps }
};
return (
-
+
}>
diff --git a/packages/render-html/src/RenderHTMLDebug.tsx b/packages/render-html/src/RenderHTMLDebug.tsx
index 2d88f0f7e..20b75b68b 100644
--- a/packages/render-html/src/RenderHTMLDebug.tsx
+++ b/packages/render-html/src/RenderHTMLDebug.tsx
@@ -1,25 +1,46 @@
import React, { Fragment } from 'react';
import { PropsWithChildren } from 'react';
import { useEffect } from 'react';
+import lookupRecord from './helpers/lookupRecord';
import { RenderHTMLProps } from './shared-types';
-function RenderHTMLProd(props: PropsWithChildren) {
+export function RenderHTMLProd(props: PropsWithChildren) {
return {props.children};
}
-function RenderHTMLDev(props: PropsWithChildren) {
+export const messages = {
+ outdatedUriProp:
+ "You're attempting to use an outdated prop, 'uri'. This prop has been discontinued since version 6. " +
+ "Use 'source={{ uri }}' instead.",
+ outdatedHtmlProp:
+ "You're attempting to use an outdated prop, 'html'. This prop has been discontinued since version 6. " +
+ "Use 'source={{ html }}' instead.",
+ noSource:
+ 'No source prop was provided to RenderHTML. Nothing will be rendered',
+ contentWidth:
+ 'You should always pass contentWidth prop to properly handle screen rotations ' +
+ 'and have a seemless support for images scaling. ' +
+ 'In the meantime, HTML will fallback to Dimensions.window().width, but its ' +
+ 'layout will become inconsistent after screen rotations. ' +
+ 'You are encouraged to use useWindowDimensions hook, see: ' +
+ 'https://reactnative.dev/docs/usewindowdimensions'
+};
+
+export function RenderHTMLDev(props: PropsWithChildren) {
useEffect(() => {
if (typeof props.contentWidth !== 'number') {
- console.warn(
- 'You should always pass contentWidth prop to properly handle screen rotations ' +
- 'and have a seemless support for images scaling. ' +
- 'In the meantime, HTML will fallback to Dimensions.window().width, but its ' +
- 'layout will become inconsistent after screen rotations. ' +
- 'You are encouraged to use useWindowDimensions hook, see: ' +
- 'https://reactnative.dev/docs/usewindowdimensions'
- );
+ console.warn(messages.contentWidth);
}
}, [props.contentWidth]);
+ if (!props.source) {
+ console.warn(messages.noSource);
+ }
+ if (lookupRecord(props, 'html')) {
+ console.warn(messages.outdatedHtmlProp);
+ }
+ if (lookupRecord(props, 'uri')) {
+ console.warn(messages.outdatedUriProp);
+ }
return {props.children};
}
diff --git a/packages/render-html/src/SourceLoader.tsx b/packages/render-html/src/SourceLoader.tsx
index 73b3a065a..83867261d 100644
--- a/packages/render-html/src/SourceLoader.tsx
+++ b/packages/render-html/src/SourceLoader.tsx
@@ -40,6 +40,9 @@ export default function SourceLoader({
source,
...props
}: SourceLoaderProps): ReactElement | null {
+ if (!source) {
+ return null;
+ }
if (isUriSource(source)) {
return React.createElement(UriSourceLoader, { source, ...props });
}
diff --git a/packages/render-html/src/__tests__/component.render-html-dev.test.tsx b/packages/render-html/src/__tests__/component.render-html-dev.test.tsx
new file mode 100644
index 000000000..15b32c659
--- /dev/null
+++ b/packages/render-html/src/__tests__/component.render-html-dev.test.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { render } from 'react-native-testing-library';
+import { RenderHTMLDev, messages } from '../RenderHTMLDebug';
+
+describe('RenderHTMLDev', () => {
+ it('should warn when contentWidth has not been provided', () => {
+ console.warn = jest.fn();
+ render(
+ Hello world
' }} debug={false} />
+ );
+ expect(console.warn).toHaveBeenNthCalledWith(1, messages.contentWidth);
+ });
+ it('should warn when source has not been provided', () => {
+ console.warn = jest.fn();
+ //@ts-expect-error
+ render();
+ expect(console.warn).toHaveBeenNthCalledWith(1, messages.noSource);
+ });
+ it('should warn when outdated html prop has been provided', () => {
+ console.warn = jest.fn();
+ render(
+ React.createElement(RenderHTMLDev, {
+ source: { html: 'hello world' },
+ //@ts-expect-error
+ html: 'hello world',
+ debug: false
+ })
+ );
+ expect(console.warn).toHaveBeenNthCalledWith(1, messages.outdatedHtmlProp);
+ });
+ it('should warn when outdated uri prop has been provided', () => {
+ console.warn = jest.fn();
+ render(
+ React.createElement(RenderHTMLDev, {
+ source: { html: 'hello world' },
+ //@ts-expect-error
+ uri: 'https://foo.bar/',
+ debug: false
+ })
+ );
+ expect(console.warn).toHaveBeenNthCalledWith(1, messages.outdatedUriProp);
+ });
+});
diff --git a/packages/render-html/src/__tests__/component.html.test.tsx b/packages/render-html/src/__tests__/component.render-html.test.tsx
similarity index 62%
rename from packages/render-html/src/__tests__/component.html.test.tsx
rename to packages/render-html/src/__tests__/component.render-html.test.tsx
index 352f4d7ef..e81e3bde6 100644
--- a/packages/render-html/src/__tests__/component.html.test.tsx
+++ b/packages/render-html/src/__tests__/component.render-html.test.tsx
@@ -1,14 +1,24 @@
import React from 'react';
import { render } from 'react-native-testing-library';
-import HTML from '../RenderHTML';
+import RenderHTML from '../RenderHTML';
import ImgTag from '../elements/IMGElement';
-describe('ImgTag', () => {
+describe('RenderHTML', () => {
+ it('should render without error when providing a source', () => {
+ expect(() =>
+ render(
+ Hello world' }} debug={false} />
+ )
+ ).not.toThrow();
+ });
+ it('should render without error when missing a source', () => {
+ expect(() => render()).not.toThrow();
+ });
it('should update ImgTag contentWidth when contentWidth prop changes', () => {
const contentWidth = 300;
const nextContentWidth = 200;
const { UNSAFE_getByType, update } = render(
- ' }}
debug={false}
contentWidth={contentWidth}
@@ -16,7 +26,7 @@ describe('ImgTag', () => {
);
expect(UNSAFE_getByType(ImgTag).props.contentWidth).toBe(contentWidth);
update(
-