diff --git a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts index f79502fb6ef..2abb260230a 100644 --- a/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts +++ b/apps/cowswap-frontend/src/modules/advancedOrders/hooks/useAdvancedOrdersActions.ts @@ -36,7 +36,7 @@ export function useAdvancedOrdersActions() { const onUserInput = useCallback( (field: Field, typedValue: string) => { - debouncedTradeAmountAnalytics([field, Number(typedValue)]) + debouncedTradeAmountAnalytics(field, Number(typedValue)) updateCurrencyAmount({ amount: { isTyped: true, value: typedValue }, currency: inputCurrency, diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/hooks/useLimitOrdersWidgetActions.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/hooks/useLimitOrdersWidgetActions.ts index bed42b9851e..cfcbafd24e1 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/hooks/useLimitOrdersWidgetActions.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/hooks/useLimitOrdersWidgetActions.ts @@ -37,7 +37,7 @@ export function useLimitOrdersWidgetActions(): TradeWidgetActions { const value = tryParseCurrencyAmount(typedValue, currency) - debouncedTradeAmountAnalytics([field, Number(typedValue)]) + debouncedTradeAmountAnalytics(field, Number(typedValue)) updateCurrencyAmount({ activeRate, diff --git a/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts b/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts index 07dcd28b225..38b2e89128b 100644 --- a/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts +++ b/apps/cowswap-frontend/src/modules/trade/utils/analytics.ts @@ -11,7 +11,7 @@ import { CowSwapAnalyticsCategory } from 'common/analytics/types' // TODO: Add proper return type annotation // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createDebouncedTradeAmountAnalytics(cowAnalytics: CowAnalytics) { - return debounce(([field, amount]: [Field, number]) => { + return debounce((field: Field, amount: number) => { cowAnalytics.sendEvent({ category: CowSwapAnalyticsCategory.TRADE, action: `Change ${field} amount`, diff --git a/libs/common-utils/src/misc.test.ts b/libs/common-utils/src/misc.test.ts index 78ad2005cc6..167ca9d67e0 100644 --- a/libs/common-utils/src/misc.test.ts +++ b/libs/common-utils/src/misc.test.ts @@ -1,4 +1,50 @@ -import { isRejectRequestProviderError, TimeoutError, withTimeout } from './misc' +import { debounce, isRejectRequestProviderError, TimeoutError, withTimeout } from './misc' + +describe('debounce', () => { + beforeEach(() => { + jest.useFakeTimers() + }) + + afterEach(() => { + jest.useRealTimers() + }) + + it('forwards the original arguments to the wrapped function', () => { + const func = jest.fn() + const debounced = debounce(func, 100) + + debounced('/swap?chain=mainnet', ['param'], 'CoW Swap') + jest.advanceTimersByTime(100) + + // Regression: the wrapped function used to receive a single array argument + // (['/swap?chain=mainnet', ['param'], 'CoW Swap']) instead of the original arguments + expect(func).toHaveBeenCalledTimes(1) + expect(func).toHaveBeenCalledWith('/swap?chain=mainnet', ['param'], 'CoW Swap') + }) + + it('invokes the wrapped function only once with the latest arguments', () => { + const func = jest.fn() + const debounced = debounce(func, 100) + + debounced('first') + jest.advanceTimersByTime(50) + debounced('second') + jest.advanceTimersByTime(100) + + expect(func).toHaveBeenCalledTimes(1) + expect(func).toHaveBeenCalledWith('second') + }) + + it('does not invoke the wrapped function before the wait time elapses', () => { + const func = jest.fn() + const debounced = debounce(func, 100) + + debounced() + jest.advanceTimersByTime(99) + + expect(func).not.toHaveBeenCalled() + }) +}) describe('withTimeout', () => { it('resolves when the promise settles before the timeout', async () => { diff --git a/libs/common-utils/src/misc.ts b/libs/common-utils/src/misc.ts index 4a763323861..0c83a526286 100644 --- a/libs/common-utils/src/misc.ts +++ b/libs/common-utils/src/misc.ts @@ -45,7 +45,7 @@ export function debounce any>(func: F, wait = 200) { // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-function-return-type const debounced = (...args: any) => { clearTimeout(timeout) - timeout = setTimeout(() => func(args), wait) + timeout = setTimeout(() => func(...args), wait) } return debounced