Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Handle undefined DashboardData props #1726

Merged
merged 6 commits into from
Jan 22, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Error handling
  • Loading branch information
bmingles committed Jan 19, 2024
commit c2b029ced23ebf4686d23c104bafe5835a82457b
56 changes: 53 additions & 3 deletions packages/react-hooks/src/useAsyncInterval.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
import { renderHook, act } from '@testing-library/react-hooks';
import Log from '@deephaven/log';
import { TestUtils } from '@deephaven/utils';
import useAsyncInterval from './useAsyncInterval';

jest.mock('@deephaven/log', () => {
const logger = {
error: jest.fn(),
};
return {
__esModule: true,
default: {
module: jest.fn(() => logger),
},
};
});

const { asMock } = TestUtils;

const mockLoggerInstance = Log.module('mock.logger');

beforeEach(() => {
jest.clearAllMocks();
expect.hasAssertions();
@@ -16,12 +31,22 @@ afterAll(() => {
});

describe('useAsyncInterval', () => {
function createCallback(ms: number) {
/**
* Creates a callback function that resolves after the given number of
* milliseconds. Accepts an optional array of booleans that determine whether
* calls to the callback will reject instead of resolve. They are mapped by
* index to the order in which the callback is called.
*/
function createCallback(ms: number, rejectWith: (Error | undefined)[] = []) {
return jest
.fn(
async (): Promise<void> =>
new Promise(resolve => {
setTimeout(resolve, ms);
new Promise((resolve, reject) => {
const rejectArg = rejectWith.shift();
setTimeout(
rejectArg == null ? resolve : () => reject(rejectArg),
ms
);

// Don't track the above call to `setTimeout`
asMock(setTimeout).mock.calls.pop();
@@ -155,4 +180,29 @@ describe('useAsyncInterval', () => {

expect(window.setTimeout).not.toHaveBeenCalled();
});

it('should handle tick errors', async () => {
const callbackDelayMs = 50;
const mockError = new Error('mock.error');
const callback = createCallback(callbackDelayMs, [mockError, undefined]);

renderHook(() => useAsyncInterval(callback, targetIntervalMs));

// First callback fires immediately
expect(callback).toHaveBeenCalledTimes(1);

// Mimick the callback Promise rejecting
act(() => jest.advanceTimersByTime(callbackDelayMs));
await TestUtils.flushPromises();

expect(mockLoggerInstance.error).toHaveBeenCalledWith(
'A tick error occurred:',
mockError
);

// Advance to next interval
act(() => jest.advanceTimersByTime(targetIntervalMs));

expect(callback).toHaveBeenCalledTimes(2);
});
});
9 changes: 8 additions & 1 deletion packages/react-hooks/src/useAsyncInterval.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useCallback, useEffect, useRef } from 'react';
import Log from '@deephaven/log';
import { useIsMountedRef } from './useIsMountedRef';

const log = Log.module('useAsyncInterval');

/**
* Calls the given async callback at a target interval.
*
@@ -40,7 +43,11 @@ export function useAsyncInterval(

trackingStartedRef.current = now;

await callback();
try {
await callback();
} catch (err) {
log.error('A tick error occurred:', err);
}

if (!isMountedRef.current) {
return;
Loading