Skip to content

Commit

Permalink
Cb 5757 unit tests for core utils and core blocks (#2961)
Browse files Browse the repository at this point in the history
* CB-5757 adds unit tests for getDomainFromUrl helper

* CB-5757 adds unit tests for getTextFileReadingProcess helper

* CB-5757 adds unit tests for TextTools helper

* CB-5757 adds unit tests for downloadFromURL helper

* CB-5757 adds unit tests for Deferred and PromiseExecutor

* CB-5757 adds unit tests for core-blocks hooks

* CB-5757 fixes the tests
  • Loading branch information
sergeyteleshev authored Oct 18, 2024
1 parent 115cfb3 commit ffe0a18
Show file tree
Hide file tree
Showing 10 changed files with 621 additions and 37 deletions.
1 change: 0 additions & 1 deletion webapp/packages/core-blocks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ export * from './useClipboard.js';
export * from './useCombinedHandler.js';
export * from './useCombinedRef.js';
export * from './useExecutor.js';
export * from './useFn.js';
export * from './useFocus.js';
export * from './useFormValidator.js';
export * from './ResourcesHooks/useOffsetPagination.js';
Expand Down
159 changes: 159 additions & 0 deletions webapp/packages/core-blocks/src/useActivationDelay.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';
import { act, renderHook } from '@testing-library/react';

import { useActivationDelay } from './useActivationDelay.js';

describe('useActivationDelay', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});

it('should initially return false', () => {
const { result } = renderHook(() => useActivationDelay(false, 1000));
expect(result.current).toBe(false);
});

it('should not change state before delay when activated', () => {
const { result } = renderHook(() => useActivationDelay(true, 1000));

expect(result.current).toBe(false);

act(() => {
jest.advanceTimersByTime(500);
});

expect(result.current).toBe(false);
});

it('should change state after delay when activated', () => {
const { result } = renderHook(() => useActivationDelay(true, 1000));

act(() => {
jest.advanceTimersByTime(1000);
});

expect(result.current).toBe(true);
});

it('should fire callback after delay when activated', () => {
const callback = jest.fn();
renderHook(() => useActivationDelay(true, 1000, callback));

expect(callback).not.toHaveBeenCalled();

act(() => {
jest.advanceTimersByTime(1000);
});

expect(callback).toHaveBeenCalledTimes(1);
});

it('should handle callback changes', () => {
const initialCallback = jest.fn();
const newCallback = jest.fn();

const { rerender } = renderHook(({ callback }) => useActivationDelay(true, 1000, callback), { initialProps: { callback: initialCallback } });

rerender({ callback: newCallback });

act(() => {
jest.advanceTimersByTime(1000);
});

expect(initialCallback).not.toHaveBeenCalled();
expect(newCallback).toHaveBeenCalledTimes(1);
});

it('should clear timeout on unmount', () => {
const callback = jest.fn();
const { unmount } = renderHook(() => useActivationDelay(true, 1000, callback));

unmount();

act(() => {
jest.advanceTimersByTime(1000);
});

expect(callback).not.toHaveBeenCalled();
});

it('should not fire callback if delay changed', () => {
const callback = jest.fn();
const { rerender } = renderHook(({ delay }) => useActivationDelay(true, delay, callback), { initialProps: { delay: 1000 } });

act(() => {
jest.advanceTimersByTime(500);
});

rerender({ delay: 2000 });

act(() => {
jest.advanceTimersByTime(1500);
});

expect(callback).toHaveBeenCalledTimes(0);
});

it('should not fire callback when state changed to false', () => {
const callback = jest.fn();
const { rerender } = renderHook(({ state }) => useActivationDelay(state, 1000, callback), { initialProps: { state: true } });

act(() => {
jest.advanceTimersByTime(500);
});

rerender({ state: false });

act(() => {
jest.advanceTimersByTime(500);
});

expect(callback).toHaveBeenCalledTimes(0);
});

it('should handle rapid state changes', () => {
const callback = jest.fn();
const { rerender } = renderHook(({ state }) => useActivationDelay(state, 1000, callback), { initialProps: { state: true } });

act(() => {
jest.advanceTimersByTime(500);
});

rerender({ state: false });

act(() => {
jest.advanceTimersByTime(100);
});

rerender({ state: true });

act(() => {
jest.advanceTimersByTime(1000);
});

expect(callback).toHaveBeenCalledTimes(1);
});

it('should work with zero delay', () => {
const callback = jest.fn();
renderHook(() => useActivationDelay(true, 0, callback));

act(() => {
jest.advanceTimersByTime(0);
});

expect(callback).toHaveBeenCalledTimes(1);
});
});
69 changes: 69 additions & 0 deletions webapp/packages/core-blocks/src/useCombinedHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { describe, expect, jest, test } from '@jest/globals';
import { renderHook } from '@testing-library/react';

import { useCombinedHandler } from './useCombinedHandler.js';

jest.mock('./useObjectRef', () => ({
useObjectRef: jest.fn(value => value),
}));

describe('useCombinedHandler', () => {
test('should call all provided handlers', () => {
const handler1 = jest.fn();
const handler2 = jest.fn();

const { result } = renderHook(() => useCombinedHandler(handler1, handler2));

result.current('arg1', 'arg2');

expect(handler1).toHaveBeenCalledWith('arg1', 'arg2');
expect(handler2).toHaveBeenCalledWith('arg1', 'arg2');
});

test('should handle null and undefined handlers', () => {
const { result } = renderHook(() => useCombinedHandler(null, undefined));

expect(() => result.current('testArg')).not.toThrow();
});

test('should not fail when no handlers are provided', () => {
const { result } = renderHook(() => useCombinedHandler());

expect(() => result.current()).not.toThrow();
});

test('should allow the combined handler to be called multiple times', () => {
const handler1 = jest.fn();
const handler2 = jest.fn();

const { result } = renderHook(() => useCombinedHandler(handler1, handler2));

result.current('firstCall');
result.current('secondCall');

expect(handler1).toHaveBeenNthCalledWith(1, 'firstCall');
expect(handler1).toHaveBeenNthCalledWith(2, 'secondCall');

expect(handler2).toHaveBeenNthCalledWith(1, 'firstCall');
expect(handler2).toHaveBeenNthCalledWith(2, 'secondCall');
});

test('should work with asynchronous handlers', async () => {
const handler1 = jest.fn(async arg => await Promise.resolve(arg));
const handler2 = jest.fn(async arg => await Promise.resolve(arg));

const { result } = renderHook(() => useCombinedHandler(handler1, handler2));

result.current('asyncArg');

expect(handler1).toHaveBeenCalledWith('asyncArg');
expect(handler2).toHaveBeenCalledWith('asyncArg');
});
});
69 changes: 69 additions & 0 deletions webapp/packages/core-blocks/src/useCombinedRef.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { describe, expect, it, jest } from '@jest/globals';
import { act, renderHook } from '@testing-library/react';
import React from 'react';

import { useCombinedRef } from './useCombinedRef.js';

describe('useCombinedRef', () => {
it('should handle ref as function', () => {
const callbackRef = jest.fn();
const { result } = renderHook(() => useCombinedRef(callbackRef));

const testInstance = { test: true };

act(() => {
result.current(testInstance);
});

expect(callbackRef).toHaveBeenCalledWith(testInstance);
});

it('should handle ref as RefObject', () => {
const mutableRef = React.createRef();
const { result } = renderHook(() => useCombinedRef(mutableRef));

const testInstance = { test: true };

act(() => {
result.current(testInstance);
});

expect(mutableRef.current).toBe(testInstance);
});

it('should handle ref as null', () => {
const { result } = renderHook(() => useCombinedRef(null));

const testInstance = { test: true };

expect(() => {
act(() => {
result.current(testInstance);
});
}).not.toThrow();
});

it('should handle multiple refs', () => {
const callbackRef = jest.fn();
const mutableRef = React.createRef();
const anotherMutableRef = React.createRef();
const { result } = renderHook(() => useCombinedRef(callbackRef, mutableRef, anotherMutableRef));

const testInstance = { test: true };

act(() => {
result.current(testInstance);
});

expect(callbackRef).toHaveBeenCalledWith(testInstance);
expect(mutableRef.current).toBe(testInstance);
expect(anotherMutableRef.current).toBe(testInstance);
});
});
17 changes: 0 additions & 17 deletions webapp/packages/core-blocks/src/useFn.ts

This file was deleted.

19 changes: 0 additions & 19 deletions webapp/packages/core-utils/src/Promises/Deferred.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
*/
import { action, computed, makeObservable, observable } from 'mobx';

import { errorOf } from '../errorOf.js';
import { PromiseCancelledError } from './PromiseCancelledError.js';
import { PromiseExecutor } from './PromiseExecutor.js';

export enum EDeferredState {
Expand Down Expand Up @@ -111,20 +109,3 @@ export class Deferred<T> {
}
}
}

export class DeferredFromPromise<T> extends Deferred<T> {
constructor(promise: Promise<T>) {
super();
promise.then(
value => this.toResolved(value),
err => {
const promiseCancelledError = errorOf(err, PromiseCancelledError);
if (promiseCancelledError) {
this.toCancelled(promiseCancelledError.cause);
} else {
this.toRejected(err);
}
},
);
}
}
Loading

0 comments on commit ffe0a18

Please sign in to comment.