From 739ad1c87b42cbb14bf249c8335e784529d98323 Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 26 Mar 2025 12:54:44 +0100 Subject: [PATCH 1/3] feat: tests for the debounce util function --- vis/test/utils/debounce.test.ts | 131 ++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 vis/test/utils/debounce.test.ts diff --git a/vis/test/utils/debounce.test.ts b/vis/test/utils/debounce.test.ts new file mode 100644 index 000000000..df0a6433e --- /dev/null +++ b/vis/test/utils/debounce.test.ts @@ -0,0 +1,131 @@ +import { describe, it, expect, vi } from "vitest"; +import debounce from "../../js/utils/debounce"; + +describe("Debounce function", () => { + const getDelayTimeouts = () => { + const BASE_DELAY = 100; + const DELAY_WITH_TIMEOUT = BASE_DELAY + 50; + const TIMEOUT_BELOW_BASE_DELAY = BASE_DELAY - 50; + + return { BASE_DELAY, DELAY_WITH_TIMEOUT, TIMEOUT_BELOW_BASE_DELAY }; + }; + + it("Should call a callback after delay timeout", async () => { + // Getting delay values + const { BASE_DELAY, DELAY_WITH_TIMEOUT } = getDelayTimeouts(); + + // Mocking callback function to check + // how many times it would be called + const mockFunc = vi.fn(); + + // Create debounced function + const debouncedFunc = debounce(mockFunc, BASE_DELAY, false); + + // Call function two times (without delay) + debouncedFunc(); + debouncedFunc(); + + // Check that function was not called immediately + expect(mockFunc).not.toHaveBeenCalled(); + + // Waiting more then delay was configured + await new Promise((resolve) => setTimeout(resolve, DELAY_WITH_TIMEOUT)); + + // Check that mocked callback function was called once + expect(mockFunc).toHaveBeenCalledTimes(1); + }); + + it("Callback function must be called immediately if immediate is true", async () => { + // Getting delay values + const { BASE_DELAY, DELAY_WITH_TIMEOUT } = getDelayTimeouts(); + + // Mocking callback function to check + // how many times it would be called + const mockFunc = vi.fn(); + + // Create debounced function + const debouncedFunc = debounce(mockFunc, BASE_DELAY, true); + + // Call function + debouncedFunc(); + + // Check that function was called immediately + expect(mockFunc).toHaveBeenCalledTimes(1); + + // Waiting more then delay was configured + await new Promise((resolve) => setTimeout(resolve, DELAY_WITH_TIMEOUT)); + + // Check that mocked callback function was called once + expect(mockFunc).toHaveBeenCalledTimes(1); + }); + + it("Callback function should be called during a delay time", async () => { + // Getting delay values + const { BASE_DELAY, TIMEOUT_BELOW_BASE_DELAY } = getDelayTimeouts(); + + // Mocking callback function to check + // how many times it would be called + const mockFunc = vi.fn(); + + // Create debounced function + const debouncedFunc = debounce(mockFunc, BASE_DELAY, false); + + // Call function two times (without delay) + debouncedFunc(); + debouncedFunc(); + + // Waiting less the delay was configured + await new Promise((resolve) => + setTimeout(resolve, TIMEOUT_BELOW_BASE_DELAY) + ); + + // Check that mocked callback function was NOT called + expect(mockFunc).not.toHaveBeenCalled(); + + // Waiting until the end of delay + await new Promise((resolve) => setTimeout(resolve, BASE_DELAY)); + + // Check that mocked callback function was called once + expect(mockFunc).toHaveBeenCalledTimes(1); + }); + + it("Maintaining the context of this", async () => { + // Getting delay values + const { BASE_DELAY, DELAY_WITH_TIMEOUT } = getDelayTimeouts(); + + // Defining context value + const VALUE = 5; + + // Mock object to test that this is working correctly + const MOCK_OBJECT_WITH_CONTEXT = { value: VALUE }; + + // Mocking callback function to check + // how many times it would be called + const mockFunc = vi.fn(function () { + // @ts-ignore + return this.value; + }); + + // Create debounced function + const debouncedFunc = debounce( + mockFunc.bind(MOCK_OBJECT_WITH_CONTEXT), + BASE_DELAY, + false + ); + + // Calling function once + debouncedFunc(); + + // Function must not been called + expect(mockFunc).not.toHaveBeenCalled(); + + // Waiting until the end of delay + await new Promise((resolve) => setTimeout(resolve, DELAY_WITH_TIMEOUT)); + + // Check that callback function was called once + expect(mockFunc).toHaveBeenCalledTimes(1); + + // Check that callback function was called with correct context + expect(mockFunc).toHaveReturnedWith(VALUE); + }); +}); From 5561d27e5bab04b399c131caa451277b4129c124 Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 26 Mar 2025 12:55:38 +0100 Subject: [PATCH 2/3] refactor: add default values for args in the debounce --- vis/js/utils/debounce.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vis/js/utils/debounce.ts b/vis/js/utils/debounce.ts index 51ffbb3d5..8dba024ee 100644 --- a/vis/js/utils/debounce.ts +++ b/vis/js/utils/debounce.ts @@ -2,10 +2,10 @@ /** * Debounce any function - * + * * Copied from helpers.js */ -export default function debounce(func, wait, immediate) { +export default function debounce(func, wait = 300, immediate = false) { var timeout; return function () { let context = this, From 2e8b75f4176299bf658fb55d6590d4bce32f9555 Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 26 Mar 2025 13:02:41 +0100 Subject: [PATCH 3/3] refactor: resolve typescript error with this typing --- vis/test/utils/debounce.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vis/test/utils/debounce.test.ts b/vis/test/utils/debounce.test.ts index df0a6433e..2918db946 100644 --- a/vis/test/utils/debounce.test.ts +++ b/vis/test/utils/debounce.test.ts @@ -101,8 +101,7 @@ describe("Debounce function", () => { // Mocking callback function to check // how many times it would be called - const mockFunc = vi.fn(function () { - // @ts-ignore + const mockFunc = vi.fn(function (this: { value: number }) { return this.value; });