Skip to content

Commit

Permalink
useWidgetFetch add onStateChange callback and use it in FormulaWidget
Browse files Browse the repository at this point in the history
  • Loading branch information
zbigg committed Jun 21, 2023
1 parent a41a955 commit bab0af3
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 7 deletions.
26 changes: 21 additions & 5 deletions packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InvalidColumnError } from '@carto/react-core/';
import { DEFAULT_INVALID_COLUMN_ERR } from '../../src/widgets/utils/constants';
import { act, render, screen } from '@testing-library/react';
import { act, render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import useWidgetFetch from '../../src/hooks/useWidgetFetch';
import { mockClear, mockSetup } from '../mockReduxHooks';
Expand Down Expand Up @@ -45,6 +45,7 @@ describe('useWidgetFetch', () => {

it('should work correctly (no remote attempt)', async () => {
const onError = jest.fn();
const onStateChange = jest.fn();
const modelFn = jest
.fn()
.mockImplementation(
Expand All @@ -60,7 +61,8 @@ describe('useWidgetFetch', () => {
params: PARAMS_MOCK,
global: false,
attemptRemoteCalculation: false,
onError
onError,
onStateChange
}}
/>
);
Expand All @@ -75,11 +77,17 @@ describe('useWidgetFetch', () => {
});

expect(screen.getByText('loading')).toBeInTheDocument();
await waitFor(() => expect(onStateChange).toBeCalledWith({ state: 'loading' }));

await act(() => sleep(250));


expect(screen.getByText('data')).toBeInTheDocument();

expect(onStateChange).toBeCalledWith({ state: 'success', data: 'data' });

onStateChange.mockReset();

modelFn.mockImplementation(
() => new Promise((resolve, reject) => setTimeout(() => reject('ERROR'), 100))
);
Expand All @@ -93,7 +101,8 @@ describe('useWidgetFetch', () => {
params: PARAMS_MOCK,
global: true,
attemptRemoteCalculation: false,
onError
onError,
onStateChange
}}
/>
);
Expand All @@ -107,11 +116,14 @@ describe('useWidgetFetch', () => {
spatialFilter: null // never in global mode
});

expect(screen.getByText('loading')).toBeInTheDocument();
expect(onStateChange).toBeCalledWith({ state: 'loading' });

await waitFor(() => expect(onStateChange).toBeCalledWith({ state: 'loading' }));
await act(() => sleep(250));
expect(screen.queryByText('loading')).not.toBeInTheDocument();

expect(onError).toBeCalledTimes(1);
expect(onStateChange).toBeCalledWith({ state: 'error', error: 'ERROR' });

modelFn.mockRejectedValue(new InvalidColumnError('Invalid column'));

Expand All @@ -138,6 +150,7 @@ describe('useWidgetFetch', () => {

it('should work correctly (non-global, remote attempt)', async () => {
const onError = jest.fn();
const onStateChange = jest.fn();
const modelFn = jest
.fn()
.mockImplementation(
Expand All @@ -153,7 +166,8 @@ describe('useWidgetFetch', () => {
params: PARAMS_MOCK,
global: false,
attemptRemoteCalculation: true,
onError
onError,
onStateChange
}}
/>
);
Expand All @@ -166,6 +180,8 @@ describe('useWidgetFetch', () => {
remoteCalculation: true,
spatialFilter: spatialFilter
});
await waitFor(() => expect(onStateChange).toBeCalledWith({ state: 'loading' }));
await waitFor(() => expect(onStateChange).toBeCalledWith({ state: 'success', data: 'data' }));
});

it('should work correctly (global, remote attempt)', async () => {
Expand Down
8 changes: 6 additions & 2 deletions packages/react-widgets/src/hooks/useWidgetFetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default function useWidgetFetch(
params,
global,
onError,
onStateChange,
enabled = true,
attemptRemoteCalculation = false
}
Expand Down Expand Up @@ -57,6 +58,7 @@ export default function useWidgetFetch(
setIsLoading(true);
setWarning('');

onStateChange?.({ state: 'loading' });
if (source && isSourceReady && enabled) {
modelFn({
source,
Expand All @@ -66,15 +68,17 @@ export default function useWidgetFetch(
spatialFilter: geometryToIntersect
})
.then((data) => {
onStateChange?.({ state: 'success', data });
if (data !== null && data !== undefined) {
setData(data);
}
})
.catch((error) => {
onStateChange?.({ state: 'error', error });
if (InvalidColumnError.is(error)) {
setWarning(DEFAULT_INVALID_COLUMN_ERR);
} else if (onError) {
onError(error);
} else {
onError?.(error);
}
})
.finally(() => {
Expand Down
3 changes: 3 additions & 0 deletions packages/react-widgets/src/widgets/FormulaWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import WidgetWithAlert from './utils/WidgetWithAlert';
* @param {boolean} [props.animation] - Enable/disable widget animations on data updates. Enabled by default.
* @param {boolean} [props.global] - Enable/disable the viewport filtering in the data fetching.
* @param {Function} [props.onError] - Function to handle error messages from the widget.
* @param {Function} [props.onStateChange] - Callback to handle state updates of widgets
* @param {Object} [props.wrapperProps] - Extra props to pass to [WrapperWidgetUI](https://storybook-react.carto.com/?path=/docs/widgets-wrapperwidgetui--default)
* @param {Object} [props.droppingFeaturesAlertProps] - Extra props to pass to [NoDataAlert]() when dropping feature
*/
Expand All @@ -36,6 +37,7 @@ function FormulaWidget({
animation,
global,
onError,
onStateChange,
wrapperProps,
droppingFeaturesAlertProps
}) {
Expand All @@ -55,6 +57,7 @@ function FormulaWidget({
},
global,
onError,
onStateChange,
attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS)
});

Expand Down

0 comments on commit bab0af3

Please sign in to comment.