diff --git a/package.json b/package.json
index 4a3b34cd20..dedec73edb 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
"@matrix-org/react-sdk-module-api": "^0.0.3",
"@sentry/browser": "^6.11.0",
"@sentry/tracing": "^6.11.0",
+ "@testing-library/react-hooks": "^8.0.1",
"@types/geojson": "^7946.0.8",
"@types/ua-parser-js": "^0.7.36",
"await-lock": "^2.1.0",
diff --git a/test/hooks/useDebouncedCallback-test.tsx b/test/hooks/useDebouncedCallback-test.tsx
index a9b8e04e95..d0428358f0 100644
--- a/test/hooks/useDebouncedCallback-test.tsx
+++ b/test/hooks/useDebouncedCallback-test.tsx
@@ -14,70 +14,85 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// eslint-disable-next-line deprecate/import
-import { mount } from "enzyme";
-import { sleep } from "matrix-js-sdk/src/utils";
-import React from "react";
-import { act } from "react-dom/test-utils";
+import { renderHook } from "@testing-library/react-hooks";
import { useDebouncedCallback } from "../../src/hooks/spotlight/useDebouncedCallback";
-function DebouncedCallbackComponent({ enabled, params, callback }) {
- useDebouncedCallback(enabled, callback, params);
- return
- { JSON.stringify(params) }
-
;
-}
-
describe("useDebouncedCallback", () => {
+ beforeAll(() => jest.useFakeTimers());
+ afterAll(() => jest.useRealTimers());
+
+ function render(enabled: boolean, callback: (...params: any) => void, params: any) {
+ return renderHook(
+ ({ enabled, callback, params }) => useDebouncedCallback(enabled, callback, params),
+ { initialProps: {
+ enabled,
+ callback,
+ params,
+ } });
+ }
+
it("should be able to handle empty parameters", async () => {
+ // When
const params = [];
const callback = jest.fn();
+ render(true, callback, params);
+ jest.advanceTimersByTime(1);
- const wrapper = mount();
- await act(async () => {
- await sleep(1);
- wrapper.setProps({ enabled: true, params, callback });
- return act(() => sleep(500));
- });
+ // Then
+ expect(callback).toHaveBeenCalledTimes(0);
- expect(wrapper.text()).toContain(JSON.stringify(params));
+ // When
+ jest.advanceTimersByTime(500);
+
+ // Then
expect(callback).toHaveBeenCalledTimes(1);
});
it("should call the callback with the parameters", async () => {
+ // When
const params = ["USER NAME"];
const callback = jest.fn();
+ render(true, callback, params);
+ jest.advanceTimersByTime(500);
- const wrapper = mount();
- await act(async () => {
- await sleep(1);
- wrapper.setProps({ enabled: true, params, callback });
- return act(() => sleep(500));
- });
+ // Then
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback).toHaveBeenCalledWith(...params);
+ });
- expect(wrapper.text()).toContain(JSON.stringify(params));
+ it("should call the callback with the parameters when parameters change during the timeout", async () => {
+ // When
+ const params = ["USER NAME"];
+ const callback = jest.fn();
+ const { rerender } = render(true, callback, []);
+
+ jest.advanceTimersByTime(1);
+ rerender({ enabled: true, callback, params });
+ jest.advanceTimersByTime(500);
+
+ // Then
expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith(...params);
});
it("should handle multiple parameters", async () => {
+ // When
const params = [4, 8, 15, 16, 23, 42];
const callback = jest.fn();
+ const { rerender } = render(true, callback, []);
- const wrapper = mount();
- await act(async () => {
- await sleep(1);
- wrapper.setProps({ enabled: true, params, callback });
- return act(() => sleep(500));
- });
+ jest.advanceTimersByTime(1);
+ rerender({ enabled: true, callback, params });
+ jest.advanceTimersByTime(500);
- expect(wrapper.text()).toContain(JSON.stringify(params));
+ // Then
expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith(...params);
});
it("should debounce quick changes", async () => {
+ // When
const queries = [
"U",
"US",
@@ -95,23 +110,24 @@ describe("useDebouncedCallback", () => {
];
const callback = jest.fn();
- const wrapper = mount();
- await act(async () => {
- await sleep(1);
- for (const query of queries) {
- wrapper.setProps({ enabled: true, params: [query], callback });
- await sleep(50);
- }
- return act(() => sleep(500));
- });
+ const { rerender } = render(true, callback, []);
+ jest.advanceTimersByTime(1);
+ for (const query of queries) {
+ rerender({ enabled: true, callback, params: [query] });
+ jest.advanceTimersByTime(50);
+ }
+
+ jest.advanceTimersByTime(500);
+
+ // Then
const query = queries[queries.length - 1];
- expect(wrapper.text()).toContain(JSON.stringify(query));
expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith(query);
});
it("should not debounce slow changes", async () => {
+ // When
const queries = [
"U",
"US",
@@ -129,23 +145,23 @@ describe("useDebouncedCallback", () => {
];
const callback = jest.fn();
- const wrapper = mount();
- await act(async () => {
- await sleep(1);
- for (const query of queries) {
- wrapper.setProps({ enabled: true, params: [query], callback });
- await sleep(200);
- }
- return act(() => sleep(500));
- });
+ const { rerender } = render(true, callback, []);
+ jest.advanceTimersByTime(1);
+ for (const query of queries) {
+ rerender({ enabled: true, callback, params: [query] });
+ jest.advanceTimersByTime(200);
+ }
+ jest.advanceTimersByTime(500);
+
+ // Then
const query = queries[queries.length - 1];
- expect(wrapper.text()).toContain(JSON.stringify(query));
expect(callback).toHaveBeenCalledTimes(queries.length);
expect(callback).toHaveBeenCalledWith(query);
});
it("should not call the callback if it’s disabled", async () => {
+ // When
const queries = [
"U",
"US",
@@ -163,18 +179,16 @@ describe("useDebouncedCallback", () => {
];
const callback = jest.fn();
- const wrapper = mount();
- await act(async () => {
- await sleep(1);
- for (const query of queries) {
- wrapper.setProps({ enabled: false, params: [query], callback });
- await sleep(200);
- }
- return act(() => sleep(500));
- });
+ const { rerender } = render(false, callback, []);
+ jest.advanceTimersByTime(1);
+ for (const query of queries) {
+ rerender({ enabled: false, callback, params: [query] });
+ jest.advanceTimersByTime(200);
+ }
- const query = queries[queries.length - 1];
- expect(wrapper.text()).toContain(JSON.stringify(query));
+ jest.advanceTimersByTime(500);
+
+ // Then
expect(callback).toHaveBeenCalledTimes(0);
});
});
diff --git a/yarn.lock b/yarn.lock
index 647b29a0b6..f538e16acd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2205,6 +2205,14 @@
lodash "^4.17.15"
redent "^3.0.0"
+"@testing-library/react-hooks@^8.0.1":
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12"
+ integrity sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ react-error-boundary "^3.1.0"
+
"@testing-library/react@^12.1.5":
version "12.1.5"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.5.tgz#bb248f72f02a5ac9d949dea07279095fa577963b"
@@ -8185,6 +8193,13 @@ react-dom@17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
+react-error-boundary@^3.1.0:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
+ integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
react-focus-lock@^2.5.1:
version "2.9.1"
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.1.tgz#094cfc19b4f334122c73bb0bff65d77a0c92dd16"