From f497c1900e896a45daac66cf35776d9ad343f69e Mon Sep 17 00:00:00 2001 From: Brian Nguyen Date: Tue, 1 Mar 2022 11:59:31 -0500 Subject: [PATCH] refactor: converted QueryAutoRefresh to functional component (#18179) * converted file to functional component * refactor: convert class component to functional component * refactor: convert class component to functional" * Working on converting the shouldCheckForQueries test to RTL * Working on converting first test to RTL * Working on first test for queryAutoRefresh * Finished Tests, pushing for review * Cleaned up comments and console logs Co-authored-by: Josue Lugaro --- .../QueryAutoRefresh.test.jsx | 40 ++++----- .../components/QueryAutoRefresh/index.jsx | 86 +++++++++---------- 2 files changed, 59 insertions(+), 67 deletions(-) diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx index 06bf187e1185a..93cea6d08d65f 100644 --- a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx +++ b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/QueryAutoRefresh.test.jsx @@ -17,12 +17,14 @@ * under the License. */ import React from 'react'; -import { shallow } from 'enzyme'; -import sinon from 'sinon'; +import { render } from 'spec/helpers/testing-library'; +import { ThemeProvider, supersetTheme } from '@superset-ui/core'; import thunk from 'redux-thunk'; import configureStore from 'redux-mock-store'; import QueryAutoRefresh from 'src/SqlLab/components/QueryAutoRefresh'; import { initialState, runningQuery } from 'src/SqlLab/fixtures'; +import fetchMock from 'fetch-mock'; +import * as actions from 'src/SqlLab/actions/sqlLab'; describe('QueryAutoRefresh', () => { const middlewares = [thunk]; @@ -38,31 +40,29 @@ describe('QueryAutoRefresh', () => { sqlLab, }; const store = mockStore(state); - const getWrapper = () => - shallow() - .dive() - .dive(); - let wrapper; + const setup = (overrides = {}) => ( + + + + ); + + const mockFetch = fetchMock.get('glob:*/superset/queries/*', {}); it('shouldCheckForQueries', () => { - wrapper = getWrapper(); - expect(wrapper.instance().shouldCheckForQueries()).toBe(true); + render(setup(), { + useRedux: true, + }); + + expect(mockFetch.called()).toBe(true); }); it('setUserOffline', () => { - wrapper = getWrapper(); - const spy = sinon.spy(wrapper.instance().props.actions, 'setUserOffline'); + const spy = jest.spyOn(actions, 'setUserOffline'); - // state not changed - wrapper.setState({ - offline: false, + render(setup(), { + useRedux: true, }); - expect(spy.called).toBe(false); - // state is changed - wrapper.setState({ - offline: true, - }); - expect(spy.callCount).toBe(1); + expect(spy).toHaveBeenCalled(); }); }); diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx index b54936b691efe..43f6c5d8a7d6e 100644 --- a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx +++ b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.jsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; +import { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -28,31 +28,12 @@ const QUERY_UPDATE_BUFFER_MS = 5000; const MAX_QUERY_AGE_TO_POLL = 21600000; const QUERY_TIMEOUT_LIMIT = 10000; -class QueryAutoRefresh extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - offline: props.offline, - }; - } - - UNSAFE_componentWillMount() { - this.startTimer(); - } - - componentDidUpdate(prevProps) { - if (prevProps.offline !== this.state.offline) { - this.props.actions.setUserOffline(this.state.offline); - } - } - - componentWillUnmount() { - this.stopTimer(); - } +function QueryAutoRefresh({ offline, queries, queriesLastUpdate, actions }) { + const [offlineState, setOfflineState] = useState(offline); + let timer = null; - shouldCheckForQueries() { + const shouldCheckForQueries = () => { // if there are started or running queries, this method should return true - const { queries } = this.props; const now = new Date().getTime(); const isQueryRunning = q => ['running', 'started', 'pending', 'fetching'].indexOf(q.state) >= 0; @@ -60,46 +41,57 @@ class QueryAutoRefresh extends React.PureComponent { return Object.values(queries).some( q => isQueryRunning(q) && now - q.startDttm < MAX_QUERY_AGE_TO_POLL, ); - } - - startTimer() { - if (!this.timer) { - this.timer = setInterval(this.stopwatch.bind(this), QUERY_UPDATE_FREQ); - } - } - - stopTimer() { - clearInterval(this.timer); - this.timer = null; - } + }; - stopwatch() { + const stopwatch = () => { // only poll /superset/queries/ if there are started or running queries - if (this.shouldCheckForQueries()) { + if (shouldCheckForQueries()) { SupersetClient.get({ endpoint: `/superset/queries/${ - this.props.queriesLastUpdate - QUERY_UPDATE_BUFFER_MS + queriesLastUpdate - QUERY_UPDATE_BUFFER_MS }`, timeout: QUERY_TIMEOUT_LIMIT, }) .then(({ json }) => { if (Object.keys(json).length > 0) { - this.props.actions.refreshQueries(json); + actions.refreshQueries(json); } - this.setState({ offline: false }); + + setOfflineState(false); }) .catch(() => { - this.setState({ offline: true }); + setOfflineState(true); }); } else { - this.setState({ offline: false }); + setOfflineState(false); } - } + }; + + const startTimer = () => { + if (!timer) { + timer = setInterval(stopwatch(), QUERY_UPDATE_FREQ); + } + }; + + const stopTimer = () => { + clearInterval(timer); + timer = null; + }; + + useEffect(() => { + startTimer(); + return () => { + stopTimer(); + }; + }, []); - render() { - return null; - } + useEffect(() => { + actions.setUserOffline(offlineState); + }, [offlineState]); + + return null; } + QueryAutoRefresh.propTypes = { offline: PropTypes.bool.isRequired, queries: PropTypes.object.isRequired,