Skip to content

Commit

Permalink
Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefano Pettini committed May 2, 2023
1 parent fb815fe commit b6d0241
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 15 deletions.
107 changes: 101 additions & 6 deletions packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,47 @@ 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__'
};

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()
Expand All @@ -35,6 +59,7 @@ describe('useWidgetFetch', () => {
dataSource: 'test',
params: PARAMS_MOCK,
global: false,
attemptRemoteCalculation: false,
onError
}}
/>
Expand All @@ -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();
Expand All @@ -65,6 +92,7 @@ describe('useWidgetFetch', () => {
dataSource: 'test',
params: PARAMS_MOCK,
global: true,
attemptRemoteCalculation: false,
onError
}}
/>
Expand All @@ -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();
Expand All @@ -93,6 +123,7 @@ describe('useWidgetFetch', () => {
dataSource: 'test',
params: PARAMS_MOCK,
global: false,
remoteCalculation: false,
onError
}}
/>
Expand All @@ -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(
<TestComponent
modelFn={modelFn}
args={{
id: 'test',
dataSource: 'test',
params: PARAMS_MOCK,
global: false,
attemptRemoteCalculation: true,
onError
}}
/>
);

// 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(
<TestComponent
modelFn={modelFn}
args={{
id: 'test',
dataSource: 'test',
params: PARAMS_MOCK,
global: true,
attemptRemoteCalculation: true,
onError
}}
/>
);

// 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
Expand Down
4 changes: 4 additions & 0 deletions packages/react-widgets/__tests__/mockReduxHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
33 changes: 24 additions & 9 deletions packages/react-widgets/__tests__/models/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});

Expand Down
4 changes: 4 additions & 0 deletions packages/react-widgets/src/models/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit b6d0241

Please sign in to comment.