diff --git a/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js b/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js
index 3412f3e06..9e4618231 100644
--- a/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js
+++ b/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js
@@ -3,7 +3,9 @@ import { DEFAULT_INVALID_COLUMN_ERR } from '../../src/widgets/utils/constants';
import { act, render, screen } from '@testing-library/react';
import React from 'react';
import useWidgetFetch from '../../src/hooks/useWidgetFetch';
-import { mockReduxHooks } from '../mockReduxHooks';
+import { mockClear, mockReduxHooks, mockSetup } from '../mockReduxHooks';
+import { selectViewport } from '@carto/react-redux';
+import bboxPolygon from '@turf/bbox-polygon';
const PARAMS_MOCK = {
column: '__test__'
@@ -11,15 +13,37 @@ const PARAMS_MOCK = {
const SOURCE_MOCK = {
id: 'test',
- data: 'testTable'
+ data: 'testTable',
+ type: 'table',
+ credentials: {
+ apiVersion: 'v3'
+ }
};
+const viewport = [-10, -5, 8, 9];
+const spatialFilter = bboxPolygon([-10, -5, 8, 9]).geometry;
+
jest.mock('../../src/hooks/useWidgetSource', () => () => SOURCE_MOCK);
describe('useWidgetFetch', () => {
- mockReduxHooks();
+ beforeAll(() => {
+ const { useDispatch, useSelector } = mockSetup();
+ const defaultSelector = jest.fn();
+
+ useDispatch.mockReturnValue(jest.fn());
+ useSelector.mockImplementation((selector) => {
+ if (selector === selectViewport) {
+ return viewport;
+ }
+ return defaultSelector;
+ });
+ });
- test('should work correctly', async () => {
+ afterAll(() => {
+ mockClear();
+ });
+
+ it('should work correctly (no remote attempt)', async () => {
const onError = jest.fn();
const modelFn = jest
.fn()
@@ -35,6 +59,7 @@ describe('useWidgetFetch', () => {
dataSource: 'test',
params: PARAMS_MOCK,
global: false,
+ attemptRemoteCalculation: false,
onError
}}
/>
@@ -44,7 +69,9 @@ describe('useWidgetFetch', () => {
expect(modelFn).toBeCalledWith({
source: SOURCE_MOCK,
...PARAMS_MOCK,
- global: false
+ global: false,
+ remoteCalculation: false,
+ spatialFilter: spatialFilter
});
expect(screen.getByText('loading')).toBeInTheDocument();
@@ -65,6 +92,7 @@ describe('useWidgetFetch', () => {
dataSource: 'test',
params: PARAMS_MOCK,
global: true,
+ attemptRemoteCalculation: false,
onError
}}
/>
@@ -74,7 +102,9 @@ describe('useWidgetFetch', () => {
expect(modelFn).toBeCalledWith({
source: SOURCE_MOCK,
...PARAMS_MOCK,
- global: true
+ global: true,
+ remoteCalculation: false,
+ spatialFilter: null // never in global mode
});
expect(screen.getByText('loading')).toBeInTheDocument();
@@ -93,6 +123,7 @@ describe('useWidgetFetch', () => {
dataSource: 'test',
params: PARAMS_MOCK,
global: false,
+ remoteCalculation: false,
onError
}}
/>
@@ -104,6 +135,70 @@ describe('useWidgetFetch', () => {
expect(onError).toBeCalledTimes(1);
expect(screen.queryByText(DEFAULT_INVALID_COLUMN_ERR)).toBeInTheDocument();
});
+
+ it('should work correctly (non-global, remote attempt)', async () => {
+ const onError = jest.fn();
+ const modelFn = jest
+ .fn()
+ .mockImplementation(
+ () => new Promise((resolve) => setTimeout(() => resolve('data'), 100))
+ );
+
+ const { rerender } = render(
+
+ );
+
+ // Test modelFn is called with the right params
+ expect(modelFn).toBeCalledWith({
+ source: SOURCE_MOCK,
+ ...PARAMS_MOCK,
+ global: false,
+ remoteCalculation: true,
+ spatialFilter: spatialFilter
+ });
+ });
+
+ it('should work correctly (global, remote attempt)', async () => {
+ const onError = jest.fn();
+ const modelFn = jest
+ .fn()
+ .mockImplementation(
+ () => new Promise((resolve) => setTimeout(() => resolve('data'), 100))
+ );
+
+ const { rerender } = render(
+
+ );
+
+ // Test modelFn is called with the right params
+ expect(modelFn).toBeCalledWith({
+ source: SOURCE_MOCK,
+ ...PARAMS_MOCK,
+ global: true,
+ remoteCalculation: true,
+ spatialFilter: null // no spatial filter for glboal case
+ });
+ });
});
// Aux
diff --git a/packages/react-widgets/__tests__/mockReduxHooks.js b/packages/react-widgets/__tests__/mockReduxHooks.js
index 726f5c4e7..65e4397ef 100644
--- a/packages/react-widgets/__tests__/mockReduxHooks.js
+++ b/packages/react-widgets/__tests__/mockReduxHooks.js
@@ -11,6 +11,10 @@ export function mockReduxHooks(dispatchValue, selectorValue) {
useSelectorSpy.mockReturnValue(mockSelectorFn);
}
+export function mockSetup() {
+ return { useDispatch: useDispatchSpy, useSelector: useSelectorSpy };
+}
+
export function mockClear() {
useDispatchSpy.mockClear();
useSelectorSpy.mockClear();
diff --git a/packages/react-widgets/__tests__/models/utils.test.js b/packages/react-widgets/__tests__/models/utils.test.js
index 8a3775f78..91d5fed9a 100644
--- a/packages/react-widgets/__tests__/models/utils.test.js
+++ b/packages/react-widgets/__tests__/models/utils.test.js
@@ -41,19 +41,34 @@ const fromRemote = jest.fn();
describe('utils', () => {
describe('wrapModelCall', () => {
- test('should work correctly', () => {
- const props = { source: V2_SOURCE, global: false };
- wrapModelCall(props, fromLocal, fromRemote);
- expect(fromLocal).toHaveBeenCalledWith(props);
+ const cases = [
+ // source, global, remoteCalculation, expectedFn
+ [V2_SOURCE, false, false, fromLocal],
+ [V3_SOURCE, false, false, fromLocal],
+ [V3_SOURCE, true, false, fromRemote],
+ [V2_SOURCE, false, true, fromLocal],
+ [V3_SOURCE, false, true, fromRemote],
+ [V3_SOURCE, true, true, fromRemote]
+ ];
+
+ test.each(cases)(
+ 'should work correctly',
+ (source, global, remoteCalculation, expectedFn) => {
+ const props = { source, global, remoteCalculation };
+ wrapModelCall(props, fromLocal, fromRemote);
+ expect(expectedFn).toHaveBeenCalledWith(props);
+ }
+ );
- const props2 = { source: V3_SOURCE, global: true };
- wrapModelCall(props2, fromLocal, fromRemote);
- expect(fromRemote).toHaveBeenCalledWith(props2);
+ test('should throw error if global is true but fromRemote is missing', () => {
+ expect(() =>
+ wrapModelCall({ source: V3_SOURCE, global: true }, fromLocal)
+ ).toThrowError();
});
- test('should throw error if global is true but fromRemote is missing', () => {
+ test('should throw error if remoteCalculation is true but fromRemote is missing', () => {
expect(() =>
- wrapModelCall({ source: V2_SOURCE, global: true }, fromLocal)
+ wrapModelCall({ source: V3_SOURCE, remoteCalculation: true }, fromLocal)
).toThrowError();
});
diff --git a/packages/react-widgets/src/models/utils.js b/packages/react-widgets/src/models/utils.js
index d05c3f0ad..732bf2e52 100644
--- a/packages/react-widgets/src/models/utils.js
+++ b/packages/react-widgets/src/models/utils.js
@@ -30,6 +30,10 @@ export function wrapModelCall(props, fromLocal, fromRemote) {
return fromRemote(props);
} else if (remoteCalculation && isRemoteCalculationSupported(props)) {
+ if (!fromRemote) {
+ throw new Error(`Remote calculation isn't supported for this widget`);
+ }
+
// The widget supports remote calculation, preferred whenever possible
return fromRemote(props);
} else {