From a4c3e7da3ad771a15b8fb4905ee166cd1d18f7d8 Mon Sep 17 00:00:00 2001 From: Krist Wongsuphasawat Date: Wed, 5 Dec 2018 14:27:45 -0800 Subject: [PATCH] Add `createLoadableRenderer` (#49) feat: Add `createLoadableRenderer` --- .../superset-ui/package.json | 2 +- .../packages/superset-ui-chart/package.json | 10 ++- .../src/components/createLoadableRenderer.js | 47 ++++++++++ .../packages/superset-ui-chart/src/index.js | 3 + .../createLoadableRenderer.test.jsx | 87 +++++++++++++++++++ .../superset-ui-chart/test/index.test.js | 2 + 6 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/components/createLoadableRenderer.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/components/createLoadableRenderer.test.jsx diff --git a/superset-frontend/temporary_superset_ui/superset-ui/package.json b/superset-frontend/temporary_superset_ui/superset-ui/package.json index 34c86f1797c25..adcc4b45806ac 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/package.json +++ b/superset-frontend/temporary_superset_ui/superset-ui/package.json @@ -10,7 +10,7 @@ "build:esm": "NODE_ENV=production beemo babel ./src --out-dir esm/ --esm --minify --workspaces=\"@superset-ui/!(demo|generator-superset)\"", "build:ts": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|chart)\"", "lint": "beemo create-config prettier && beemo eslint \"./packages/*/{src,test,storybook}/**/*.{js,jsx,ts,tsx}\"", - "jest": "beemo jest --color --coverage", + "jest": "beemo jest --color --coverage --react", "postrelease": "lerna run gh-pages", "prepare-release": "git checkout master && git pull --rebase origin master && lerna bootstrap && yarn run test", "prerelease": "yarn run build", diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/package.json b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/package.json index b29eb13e59f59..e7ff59690b367 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/package.json +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/package.json @@ -26,7 +26,15 @@ "access": "public" }, "dependencies": { - "@superset-ui/core": "^0.3.0", + "@superset-ui/core": "^0.7.0", + "prop-types": "^15.6.2", + "react-loadable": "^5.5.0", "reselect": "^4.0.0" + }, + "devDependencies": { + "react": "^15 || ^16" + }, + "peerDependencies": { + "react": "^15 || ^16" } } diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/components/createLoadableRenderer.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/components/createLoadableRenderer.js new file mode 100644 index 0000000000000..f47324aadb526 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/components/createLoadableRenderer.js @@ -0,0 +1,47 @@ +import Loadable from 'react-loadable'; +import PropTypes from 'prop-types'; + +const propTypes = { + onRenderFailure: PropTypes.func, + onRenderSuccess: PropTypes.func, +}; + +const defaultProps = { + onRenderFailure() {}, + onRenderSuccess() {}, +}; + +export default function createLoadableRenderer(options) { + /* eslint-disable-next-line babel/new-cap */ + const LoadableRenderer = Loadable.Map(options); + + // Extends the behavior of LoadableComponent + // generated by react-loadable + // to provide post-render listeners + class CustomLoadableRenderer extends LoadableRenderer { + componentDidMount() { + this.afterRender(); + } + + componentDidUpdate() { + this.afterRender(); + } + + afterRender() { + const { loaded, loading, error } = this.state; + if (!loading) { + if (error) { + this.props.onRenderFailure(error); + } else if (loaded && Object.keys(loaded).length > 0) { + this.props.onRenderSuccess(); + } + } + } + } + + CustomLoadableRenderer.defaultProps = defaultProps; + CustomLoadableRenderer.propTypes = propTypes; + CustomLoadableRenderer.preload = LoadableRenderer.preload; + + return CustomLoadableRenderer; +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/index.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/index.js index 3e8dfc65984f8..70b85846de4c3 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/index.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/src/index.js @@ -1,6 +1,9 @@ export { default as ChartMetadata } from './models/ChartMetadata'; export { default as ChartPlugin } from './models/ChartPlugin'; export { default as ChartProps } from './models/ChartProps'; + +export { default as createLoadableRenderer } from './components/createLoadableRenderer'; + export { default as getChartBuildQueryRegistry, } from './registries/ChartBuildQueryRegistrySingleton'; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/components/createLoadableRenderer.test.jsx b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/components/createLoadableRenderer.test.jsx new file mode 100644 index 0000000000000..9234a57db045d --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/components/createLoadableRenderer.test.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import createLoadableRenderer from '../../src/components/createLoadableRenderer'; + +describe('createLoadableRenderer', () => { + function TestComponent() { + return
test
; + } + let loadChartSuccess; + let render; + let loading; + let LoadableRenderer; + + beforeEach(() => { + loadChartSuccess = jest.fn(() => Promise.resolve(TestComponent)); + render = jest.fn(loaded => { + const { Chart } = loaded; + + return ; + }); + loading = jest.fn(() =>
Loading
); + LoadableRenderer = createLoadableRenderer({ + loader: { + Chart: loadChartSuccess, + }, + loading, + render, + }); + }); + + describe('returns a LoadableRenderer class', () => { + it('LoadableRenderer.preload() preloads the lazy-load components', () => { + expect(LoadableRenderer.preload).toBeInstanceOf(Function); + LoadableRenderer.preload(); + expect(loadChartSuccess).toHaveBeenCalledTimes(1); + }); + + it('calls onRenderSuccess when succeeds', done => { + const onRenderSuccess = jest.fn(); + const onRenderFailure = jest.fn(); + shallow( + , + ); + expect(loadChartSuccess).toHaveBeenCalled(); + setTimeout(() => { + expect(render).toHaveBeenCalledTimes(1); + expect(onRenderSuccess).toHaveBeenCalledTimes(1); + expect(onRenderFailure).not.toHaveBeenCalled(); + done(); + }, 10); + }); + + it('calls onRenderFailure when fails', done => { + const loadChartFailure = jest.fn(() => Promise.reject(new Error('Invalid chart'))); + const FailedRenderer = createLoadableRenderer({ + loader: { + Chart: loadChartFailure, + }, + loading, + render, + }); + const onRenderSuccess = jest.fn(); + const onRenderFailure = jest.fn(); + shallow( + , + ); + expect(loadChartFailure).toHaveBeenCalledTimes(1); + setTimeout(() => { + expect(render).not.toHaveBeenCalled(); + expect(onRenderSuccess).not.toHaveBeenCalled(); + expect(onRenderFailure).toHaveBeenCalledTimes(1); + done(); + }, 10); + }); + + it('renders the lazy-load components', done => { + const wrapper = shallow(); + // lazy-loaded component not rendered immediately + expect(wrapper.find(TestComponent)).toHaveLength(0); + setTimeout(() => { + // but rendered after the component is loaded. + expect(wrapper.find(TestComponent)).toHaveLength(1); + done(); + }, 10); + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/index.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/index.test.js index 0ac49b42abcb1..b48acbf3dbaee 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/index.test.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart/test/index.test.js @@ -2,6 +2,7 @@ import { ChartMetadata, ChartPlugin, ChartProps, + createLoadableRenderer, getChartBuildQueryRegistry, getChartComponentRegistry, getChartMetadataRegistry, @@ -14,6 +15,7 @@ describe('index', () => { ChartMetadata, ChartPlugin, ChartProps, + createLoadableRenderer, getChartBuildQueryRegistry, getChartComponentRegistry, getChartMetadataRegistry,