From baa1dbe777236420507bddfa65e4684eb501c61d Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Mon, 16 Nov 2020 11:46:29 -0500 Subject: [PATCH] fix(minHeight): issues/501 restructure resize event (#507) * minHeight, restructure resize, autoUpdate as separate params --- .../__snapshots__/graphCard.test.js.snap | 30 ++++--- .../__snapshots__/inventoryList.test.js.snap | 21 ++++- .../__snapshots__/minHeight.test.js.snap | 6 +- .../minHeight/__tests__/minHeight.test.js | 78 +++++++++++-------- src/components/minHeight/minHeight.js | 74 +++++++++--------- 5 files changed, 123 insertions(+), 86 deletions(-) diff --git a/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap b/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap index 2614bef2d..4b6602e04 100644 --- a/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap +++ b/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap @@ -70,9 +70,10 @@ exports[`GraphCard Component should render a non-connected component: non-connec className="curiosity-usage-graph" > @@ -123,9 +124,10 @@ exports[`GraphCard Component should render a non-connected component: non-connec
@@ -252,9 +255,10 @@ exports[`GraphCard Component should render multiple states: error with 403 statu
@@ -377,9 +382,10 @@ exports[`GraphCard Component should render multiple states: error with 500 statu
@@ -502,9 +509,10 @@ exports[`GraphCard Component should render multiple states: fulfilled 1`] = `
@@ -627,9 +636,10 @@ exports[`GraphCard Component should render multiple states: pending 1`] = `
@@ -152,9 +154,10 @@ exports[`InventoryList Component should handle variations in data: filtered data
@@ -256,9 +263,10 @@ exports[`InventoryList Component should handle variations in data: variable data
@@ -356,9 +368,10 @@ exports[`InventoryList Component should render a non-connected component: non-co
lorem ipsum diff --git a/src/components/minHeight/__tests__/minHeight.test.js b/src/components/minHeight/__tests__/minHeight.test.js index b99a4cac6..42f2e536c 100644 --- a/src/components/minHeight/__tests__/minHeight.test.js +++ b/src/components/minHeight/__tests__/minHeight.test.js @@ -3,6 +3,14 @@ import { mount, shallow } from 'enzyme'; import { MinHeight } from '../minHeight'; describe('MinHeight Component', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.runAllTimers(); + }); + it('should render a non-connected component', () => { const props = {}; @@ -12,67 +20,75 @@ describe('MinHeight Component', () => { it('should set minHeight in relation to contents and props', () => { const props = { - autoUpdate: true + updateOnContent: true }; - const component = shallow(lorem ipsum); - - expect(component.instance().setMinHeight).toBeDefined(); + const component = mount(lorem ipsum); + const componentInstance = component.instance(); - // initial height should be zero - expect(component.instance().updatedMinHeight).toEqual(0); + // initial minHeight should be undefined + componentInstance.containerRef.current = { style: {} }; + expect(componentInstance.containerRef.current.style.minHeight).toBe(undefined); // set the container size arbitrarily - component.instance().containerRef.current = { clientHeight: 100 }; - component.instance().componentDidUpdate(); - expect(component.instance().updatedMinHeight).toEqual(100); + componentInstance.containerRef.current = { clientHeight: 75, style: {} }; + componentInstance.innerContainerRef.current = { clientHeight: 75 }; + jest.runAllTimers(); + expect(componentInstance.containerRef.current.style.minHeight).toBe('75px'); // set a minimum minHeight component.setProps({ minHeight: 200 }); - expect(component.instance().updatedMinHeight).toEqual(200); + jest.runAllTimers(); + expect(componentInstance.containerRef.current.style.minHeight).toBe('200px'); // disable "on update" minHeight adjustments - component.setProps({ autoUpdate: false, minHeight: 300 }); - expect(component.instance().updatedMinHeight).toEqual(200); + component.setProps({ updateOnContent: false, minHeight: 300 }); + jest.runAllTimers(); + expect(componentInstance.containerRef.current.style.minHeight).toBe('200px'); }); it('should set minHeight on resize', () => { const props = {}; const component = shallow(lorem ipsum); + const componentInstance = component.instance(); - expect(component.instance().onResizeContainer).toBeDefined(); + expect(componentInstance.onResizeContainer).toBeDefined(); // initial height and width should be zero - expect(component.instance().updatedMinHeight).toEqual(0); - expect(component.instance().updatedContainerWidth).toEqual(0); + componentInstance.containerRef.current = {}; + expect(componentInstance.updatedContainerWidth).toBe(0); // set the container size arbitrarily and force handleResize to fire - component.instance().containerRef.current = { clientHeight: 100, clientWidth: 200 }; + componentInstance.containerRef.current = { clientHeight: 100, clientWidth: 200, style: {} }; + componentInstance.innerContainerRef.current = { clientHeight: 100, clientWidth: 200 }; global.dispatchEvent(new Event('resize')); - expect(component.instance().updatedMinHeight).toEqual(100); - expect(component.instance().updatedContainerWidth).toEqual(200); + expect(componentInstance.containerRef.current.style.minHeight).toBe('100px'); + expect(componentInstance.updatedContainerWidth).toBe(200); // set the container size arbitrarily and force handleResize to fire - component.instance().containerRef.current = { clientHeight: 1000, clientWidth: 1337 }; + componentInstance.containerRef.current = { clientHeight: 1000, clientWidth: 1337, style: {} }; + componentInstance.innerContainerRef.current = { clientHeight: 1000, clientWidth: 1337 }; + global.dispatchEvent(new Event('resize')); + expect(componentInstance.containerRef.current.style.minHeight).toBe('1000px'); + expect(componentInstance.updatedContainerWidth).toBe(1337); + + componentInstance.containerRef.current = { clientHeight: 600, clientWidth: 600, style: { minHeight: '1000px' } }; + componentInstance.innerContainerRef.current = { clientHeight: 600, clientWidth: 600 }; + component.setProps({ updateOnResize: false }); global.dispatchEvent(new Event('resize')); - expect(component.instance().updatedMinHeight).toEqual(1000); - expect(component.instance().updatedContainerWidth).toEqual(1337); + expect(componentInstance.containerRef.current.style.minHeight).toBe('1000px'); + expect(componentInstance.updatedContainerWidth).toBe(1337); }); it('should attempt to handle a ResizeObserver', () => { - const observe = jest.fn(); - const unobserve = jest.fn(); - - window.ResizeObserver = jest.fn().mockImplementation(() => ({ - observe, - unobserve - })); - const props = {}; + const setResizeObserver = jest.spyOn(MinHeight.prototype, 'setResizeObserver'); + const component = mount(lorem ipsum); - expect(observe).toHaveBeenCalledTimes(1); + expect(setResizeObserver).toHaveBeenCalledTimes(1); + const resizeObserver = jest.spyOn(component.instance(), 'resizeObserver'); component.unmount(); - expect(unobserve).toHaveBeenCalledTimes(1); + expect(resizeObserver).toHaveBeenCalledTimes(1); }); it('should run componentWillUnmount method successfully', () => { diff --git a/src/components/minHeight/minHeight.js b/src/components/minHeight/minHeight.js index aeace0bda..e617fe9a2 100644 --- a/src/components/minHeight/minHeight.js +++ b/src/components/minHeight/minHeight.js @@ -13,22 +13,28 @@ class MinHeight extends React.Component { innerContainerRef = React.createRef(); - updatedMinHeight = 0; - updatedContainerWidth = 0; resizeObserver = helpers.noop; componentDidMount() { - this.setMinHeight(); - this.setResizeObserver(); + const { updateOnResize } = this.props; + window.setTimeout(() => { + this.setMinHeight(); + }); + + if (updateOnResize) { + this.setResizeObserver(); + } } componentDidUpdate() { - const { autoUpdate } = this.props; + const { updateOnContent } = this.props; - if (autoUpdate) { - this.setMinHeight(); + if (updateOnContent) { + window.setTimeout(() => { + this.setMinHeight(); + }); } } @@ -43,9 +49,10 @@ class MinHeight extends React.Component { */ onResizeContainer = () => { const { updatedContainerWidth } = this; + const { updateOnResize } = this.props; const clientWidth = this.containerRef?.current?.clientWidth || 0; - if (clientWidth !== updatedContainerWidth) { + if (updateOnResize && clientWidth !== updatedContainerWidth) { this.updatedContainerWidth = clientWidth; this.setMinHeight(true); } @@ -54,26 +61,27 @@ class MinHeight extends React.Component { /** * Set minHeight on mount or update. * - * @param {boolean} resetMinHeight + * @param {boolean} reset */ - setMinHeight(resetMinHeight) { - const { updatedMinHeight } = this; + setMinHeight(reset = false) { const { minHeight: overrideMinHeight } = this.props; const { current: domElement = {} } = this.containerRef; const { current: innerDomElement = {} } = this.innerContainerRef; - if (resetMinHeight && domElement.style) { - domElement.style.minHeight = innerDomElement?.clientHeight || 0; - } + if (domElement?.style) { + let clientHeight; - const clientHeight = domElement?.clientHeight || 0; + if (reset) { + clientHeight = innerDomElement?.clientHeight || 0; + } else { + clientHeight = domElement?.clientHeight || 0; + } - if (clientHeight !== updatedMinHeight) { - this.updatedMinHeight = clientHeight; - } + if (overrideMinHeight > clientHeight) { + clientHeight = overrideMinHeight; + } - if (overrideMinHeight > this.updatedMinHeight) { - this.updatedMinHeight = overrideMinHeight; + domElement.style.minHeight = `${clientHeight}px`; } } @@ -81,17 +89,8 @@ class MinHeight extends React.Component { * Set ResizeObserver for scenarios when min-height needs to be updated. */ setResizeObserver() { - const containerElement = this.containerRef.current; - const { ResizeObserver } = window; - - if (containerElement && ResizeObserver) { - const resizeObserver = new ResizeObserver(this.onResizeContainer); - resizeObserver.observe(containerElement); - this.resizeObserver = () => resizeObserver.unobserve(containerElement); - } else { - window.addEventListener('resize', this.onResizeContainer); - this.resizeObserver = () => window.removeEventListener('resize', this.onResizeContainer); - } + window.addEventListener('resize', this.onResizeContainer); + this.resizeObserver = () => window.removeEventListener('resize', this.onResizeContainer); } /** @@ -100,11 +99,10 @@ class MinHeight extends React.Component { * @returns {Node} */ render() { - const { updatedMinHeight } = this; const { children } = this.props; return ( -
+
{children}
); @@ -114,10 +112,11 @@ class MinHeight extends React.Component { /** * Prop types. * - * @type {{minHeight: number, autoUpdate: boolean, children: Node}} + * @type {{minHeight: number, children: Node, updateOnContent: boolean, updateOnResize: boolean}} */ MinHeight.propTypes = { - autoUpdate: PropTypes.bool, + updateOnContent: PropTypes.bool, + updateOnResize: PropTypes.bool, children: PropTypes.node.isRequired, minHeight: PropTypes.number }; @@ -125,10 +124,11 @@ MinHeight.propTypes = { /** * Default props. * - * @type {{minHeight: number, autoUpdate: boolean}} + * @type {{minHeight: number, updateOnContent: boolean, updateOnResize: boolean}} */ MinHeight.defaultProps = { - autoUpdate: false, + updateOnContent: false, + updateOnResize: true, minHeight: 0 };