use-async-effekt-hooks
Version:
React hooks for async effects and memoization with proper dependency tracking and linting support
770 lines (769 loc) • 38 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import React from "react";
import { renderHook, act, waitFor } from "./test-utils";
import { useAsyncMemo } from "../useAsyncMemo";
describe("useAsyncMemo", function () {
beforeEach(function () {
jest.clearAllMocks();
jest.clearAllTimers();
jest.useRealTimers();
});
afterEach(function () {
jest.useRealTimers();
});
it("should return undefined initially and then the computed value", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
computeFn = jest.fn().mockResolvedValue("test-value");
result = renderHook(function () { return useAsyncMemo(computeFn, []); }).result;
expect(result.current).toBeUndefined();
expect(computeFn).toHaveBeenCalledTimes(1);
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("test-value");
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should recompute when dependencies change", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
computeFn = jest
.fn()
.mockResolvedValueOnce("value-1")
.mockResolvedValueOnce("value-2");
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(computeFn, [dep]);
}, { initialProps: { dep: "dep1" } }), result = _a.result, rerender = _a.rerender;
expect(result.current).toBeUndefined();
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("value-1");
})];
case 1:
_b.sent();
act(function () {
rerender({ dep: "dep2" });
});
// useAsyncMemo keeps the previous value during recomputation
expect(result.current).toBe("value-1");
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("value-2");
})];
case 2:
_b.sent();
expect(computeFn).toHaveBeenCalledTimes(2);
return [2 /*return*/];
}
});
}); });
it("should not recompute when dependencies are the same", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
computeFn = jest.fn().mockResolvedValue("test-value");
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(computeFn, [dep]);
}, { initialProps: { dep: "same-dep" } }), result = _a.result, rerender = _a.rerender;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("test-value");
})];
case 1:
_b.sent();
act(function () {
rerender({ dep: "same-dep" });
});
expect(computeFn).toHaveBeenCalledTimes(1);
expect(result.current).toBe("test-value");
return [2 /*return*/];
}
});
}); });
it("should handle errors and keep the last successful value", function () { return __awaiter(void 0, void 0, void 0, function () {
var mockConsoleError, computeFn, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
mockConsoleError = jest
.spyOn(console, "error")
.mockImplementation(function () { });
computeFn = jest
.fn()
.mockResolvedValueOnce("success-value")
.mockRejectedValueOnce(new Error("computation error"));
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(computeFn, [dep]);
}, { initialProps: { dep: "dep1" } }), result = _a.result, rerender = _a.rerender;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("success-value");
})];
case 1:
_b.sent();
act(function () {
rerender({ dep: "dep2" });
});
// Should keep the last successful value on error
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("success-value");
})];
case 2:
// Should keep the last successful value on error
_b.sent();
expect(computeFn).toHaveBeenCalledTimes(2);
mockConsoleError.mockRestore();
return [2 /*return*/];
}
});
}); });
it("should handle initial error by returning undefined", function () { return __awaiter(void 0, void 0, void 0, function () {
var mockConsoleError, computeFn, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
mockConsoleError = jest
.spyOn(console, "error")
.mockImplementation(function () { });
computeFn = jest.fn().mockRejectedValue(new Error("initial error"));
result = renderHook(function () { return useAsyncMemo(computeFn, []); }).result;
expect(result.current).toBeUndefined();
// Wait a bit to ensure the error is handled
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10); })];
case 1:
// Wait a bit to ensure the error is handled
_a.sent();
expect(result.current).toBeUndefined();
expect(computeFn).toHaveBeenCalledTimes(1);
mockConsoleError.mockRestore();
return [2 /*return*/];
}
});
}); });
it("should cancel previous computation when dependencies change", function () { return __awaiter(void 0, void 0, void 0, function () {
var resolveFirst, resolveSecond, firstPromise, secondPromise, computeFn, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
firstPromise = new Promise(function (resolve) {
resolveFirst = resolve;
});
secondPromise = new Promise(function (resolve) {
resolveSecond = resolve;
});
computeFn = jest
.fn()
.mockReturnValueOnce(firstPromise)
.mockReturnValueOnce(secondPromise);
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(computeFn, [dep]);
}, { initialProps: { dep: "dep1" } }), result = _a.result, rerender = _a.rerender;
expect(result.current).toBeUndefined();
// Change dependencies before first computation completes
act(function () {
rerender({ dep: "dep2" });
});
// Resolve both promises
return [4 /*yield*/, act(function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
resolveFirst("first-value");
resolveSecond("second-value");
return [4 /*yield*/, Promise.all([firstPromise, secondPromise])];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); })];
case 1:
// Resolve both promises
_b.sent();
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("second-value");
})];
case 2:
_b.sent();
expect(computeFn).toHaveBeenCalledTimes(2);
return [2 /*return*/];
}
});
}); });
it("should handle rapid dependency changes", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
computeFn = jest
.fn()
.mockResolvedValueOnce("value-1")
.mockResolvedValueOnce("value-2")
.mockResolvedValueOnce("value-3");
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(computeFn, [dep]);
}, { initialProps: { dep: "dep1" } }), result = _a.result, rerender = _a.rerender;
// Wait for first value
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("value-1");
})];
case 1:
// Wait for first value
_b.sent();
// Rapidly change dependencies
act(function () {
rerender({ dep: "dep2" });
rerender({ dep: "dep3" });
});
// Wait for the final computation to complete
// Due to cancellation, we might get value-2 or value-3
return [4 /*yield*/, waitFor(function () {
expect(["value-2", "value-3"]).toContain(result.current);
})];
case 2:
// Wait for the final computation to complete
// Due to cancellation, we might get value-2 or value-3
_b.sent();
// Due to rapid changes and cancellation, we might get fewer calls than expected
expect(computeFn).toHaveBeenCalledTimes(2);
return [2 /*return*/];
}
});
}); });
it("should handle null, zero, and empty string values correctly", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
computeFn = jest
.fn()
.mockResolvedValueOnce(null)
.mockResolvedValueOnce(0)
.mockResolvedValueOnce("");
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(computeFn, [dep]);
}, { initialProps: { dep: "null" } }), result = _a.result, rerender = _a.rerender;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBeNull();
})];
case 1:
_b.sent();
act(function () {
rerender({ dep: "zero" });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe(0);
})];
case 2:
_b.sent();
act(function () {
rerender({ dep: "empty" });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("");
})];
case 3:
_b.sent();
expect(computeFn).toHaveBeenCalledTimes(3);
return [2 /*return*/];
}
});
}); });
it("should cleanup on unmount", function () { return __awaiter(void 0, void 0, void 0, function () {
var resolveComputation, computationPromise, computeFn, _a, result, unmount;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
computationPromise = new Promise(function (resolve) {
resolveComputation = resolve;
});
computeFn = jest.fn().mockReturnValue(computationPromise);
_a = renderHook(function () { return useAsyncMemo(computeFn, []); }), result = _a.result, unmount = _a.unmount;
expect(result.current).toBeUndefined();
unmount();
// Resolve after unmount - should not cause any issues
return [4 /*yield*/, act(function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
resolveComputation("test-value");
return [4 /*yield*/, computationPromise];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); })];
case 1:
// Resolve after unmount - should not cause any issues
_b.sent();
expect(computeFn).toHaveBeenCalledTimes(1);
return [2 /*return*/];
}
});
}); });
it("should work with complex dependencies", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, obj1, obj2, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
computeFn = jest
.fn()
.mockResolvedValueOnce("result-1")
.mockResolvedValueOnce("result-2");
obj1 = { id: 1, name: "test" };
obj2 = { id: 2, name: "test2" };
_a = renderHook(function (_a) {
var obj = _a.obj, num = _a.num;
return useAsyncMemo(computeFn, [obj.id, obj.name, num]);
}, { initialProps: { obj: obj1, num: 42 } }), result = _a.result, rerender = _a.rerender;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("result-1");
})];
case 1:
_b.sent();
act(function () {
rerender({ obj: obj2, num: 42 });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("result-2");
})];
case 2:
_b.sent();
expect(computeFn).toHaveBeenCalledTimes(2);
return [2 /*return*/];
}
});
}); });
it("should handle StrictMode double invocation", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
computeFn = jest.fn().mockResolvedValue("test-value");
result = renderHook(function () { return useAsyncMemo(computeFn, []); }, {
wrapper: function (_a) {
var children = _a.children;
return React.createElement(React.StrictMode, null, children);
},
}).result;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("test-value");
})];
case 1:
_a.sent();
// In StrictMode, effects may run twice, but the final result should be correct
expect(result.current).toBe("test-value");
return [2 /*return*/];
}
});
}); });
it("should handle synchronous computation functions", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
computeFn = jest.fn().mockReturnValue("sync-value");
result = renderHook(function () { return useAsyncMemo(computeFn, []); }).result;
expect(result.current).toBeUndefined();
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("sync-value");
})];
case 1:
_a.sent();
expect(computeFn).toHaveBeenCalledTimes(1);
return [2 /*return*/];
}
});
}); });
it("should handle delayed async operations with proper timing", function () { return __awaiter(void 0, void 0, void 0, function () {
var computeFn, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
jest.useFakeTimers();
computeFn = jest
.fn()
.mockImplementation(function () {
return new Promise(function (resolve) {
return setTimeout(function () { return resolve("test-value"); }, 1000);
});
});
result = renderHook(function () { return useAsyncMemo(computeFn, []); }).result;
expect(result.current).toBeUndefined();
return [4 /*yield*/, act(function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
jest.advanceTimersByTime(1000);
return [4 /*yield*/, Promise.resolve()];
case 1:
_a.sent(); // Allow promises to resolve
return [2 /*return*/];
}
});
}); })];
case 1:
_a.sent();
expect(result.current).toBe("test-value");
jest.useRealTimers();
return [2 /*return*/];
}
});
}); });
it("should handle synchronous factory function", function () { return __awaiter(void 0, void 0, void 0, function () {
var syncFactory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
syncFactory = jest.fn().mockReturnValue("sync-value");
result = renderHook(function () { return useAsyncMemo(syncFactory, []); }).result;
expect(result.current).toBeUndefined();
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("sync-value");
})];
case 1:
_a.sent();
expect(syncFactory).toHaveBeenCalledTimes(1);
expect(syncFactory).toHaveBeenCalledWith(expect.any(Function));
return [2 /*return*/];
}
});
}); });
it("should handle factory function that checks isMounted", function () { return __awaiter(void 0, void 0, void 0, function () {
var isMountedFn, factory, _a, result, unmount;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
factory = jest.fn().mockImplementation(function (isMounted) {
isMountedFn = isMounted;
return Promise.resolve("test-value");
});
_a = renderHook(function () { return useAsyncMemo(factory, []); }), result = _a.result, unmount = _a.unmount;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("test-value");
})];
case 1:
_b.sent();
expect(isMountedFn).toBeDefined();
expect(isMountedFn()).toBe(true);
unmount();
expect(isMountedFn()).toBe(false);
return [2 /*return*/];
}
});
}); });
it("should not update state if component unmounts before async operation completes", function () { return __awaiter(void 0, void 0, void 0, function () {
var resolveFactory, factory, _a, result, unmount;
return __generator(this, function (_b) {
factory = jest.fn().mockImplementation(function () {
return new Promise(function (resolve) {
resolveFactory = resolve;
});
});
_a = renderHook(function () { return useAsyncMemo(factory, []); }), result = _a.result, unmount = _a.unmount;
expect(result.current).toBeUndefined();
expect(factory).toHaveBeenCalledTimes(1);
// Unmount before resolving
unmount();
// Now resolve the promise
act(function () {
resolveFactory("late-value");
});
// Should still be undefined since component was unmounted
expect(result.current).toBeUndefined();
return [2 /*return*/];
});
}); });
it("should handle factory function returning null", function () { return __awaiter(void 0, void 0, void 0, function () {
var factory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
factory = jest.fn().mockResolvedValue(null);
result = renderHook(function () { return useAsyncMemo(factory, []); }).result;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBeNull();
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should handle factory function returning undefined", function () { return __awaiter(void 0, void 0, void 0, function () {
var factory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
factory = jest.fn().mockResolvedValue(undefined);
result = renderHook(function () { return useAsyncMemo(factory, []); }).result;
// Should remain undefined, but factory should have been called
expect(result.current).toBeUndefined();
expect(factory).toHaveBeenCalledTimes(1);
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBeUndefined();
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should handle factory function returning 0", function () { return __awaiter(void 0, void 0, void 0, function () {
var factory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
factory = jest.fn().mockResolvedValue(0);
result = renderHook(function () { return useAsyncMemo(factory, []); }).result;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe(0);
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should handle factory function returning false", function () { return __awaiter(void 0, void 0, void 0, function () {
var factory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
factory = jest.fn().mockResolvedValue(false);
result = renderHook(function () { return useAsyncMemo(factory, []); }).result;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe(false);
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should handle factory function returning empty string", function () { return __awaiter(void 0, void 0, void 0, function () {
var factory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
factory = jest.fn().mockResolvedValue("");
result = renderHook(function () { return useAsyncMemo(factory, []); }).result;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("");
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should preserve last successful value through multiple errors", function () { return __awaiter(void 0, void 0, void 0, function () {
var mockConsoleError, factory, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
mockConsoleError = jest
.spyOn(console, "error")
.mockImplementation(function () { });
factory = jest
.fn()
.mockResolvedValueOnce("success-1")
.mockRejectedValueOnce(new Error("error-1"))
.mockRejectedValueOnce(new Error("error-2"))
.mockResolvedValueOnce("success-2");
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(factory, [dep]);
}, { initialProps: { dep: 1 } }), result = _a.result, rerender = _a.rerender;
// First success
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("success-1");
})];
case 1:
// First success
_b.sent();
// First error - should keep last successful value
act(function () {
rerender({ dep: 2 });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("success-1");
})];
case 2:
_b.sent();
// Second error - should still keep last successful value
act(function () {
rerender({ dep: 3 });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("success-1");
})];
case 3:
_b.sent();
// Second success - should update to new value
act(function () {
rerender({ dep: 4 });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("success-2");
})];
case 4:
_b.sent();
expect(mockConsoleError).toHaveBeenCalledTimes(2);
mockConsoleError.mockRestore();
return [2 /*return*/];
}
});
}); });
it("should handle complex object values", function () { return __awaiter(void 0, void 0, void 0, function () {
var complexValue, factory, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
complexValue = {
id: 1,
name: "test",
nested: { value: "nested-test" },
array: [1, 2, 3],
};
factory = jest.fn().mockResolvedValue(complexValue);
result = renderHook(function () { return useAsyncMemo(factory, []); }).result;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toEqual(complexValue);
expect(result.current).toBe(complexValue); // Same reference
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it("should handle factory that uses isMounted to prevent state updates", function () { return __awaiter(void 0, void 0, void 0, function () {
var shouldComplete, factory, _a, result, rerender;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
shouldComplete = false;
factory = jest.fn().mockImplementation(function (isMounted) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
// Simulate some async work
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10); })];
case 1:
// Simulate some async work
_a.sent();
if (!isMounted()) {
return [2 /*return*/, "should-not-be-used"];
}
return [2 /*return*/, shouldComplete ? "completed" : "initial"];
}
});
}); });
_a = renderHook(function (_a) {
var trigger = _a.trigger;
return useAsyncMemo(factory, [trigger]);
}, { initialProps: { trigger: false } }), result = _a.result, rerender = _a.rerender;
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("initial");
})];
case 1:
_b.sent();
shouldComplete = true;
act(function () {
rerender({ trigger: true });
});
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("completed");
})];
case 2:
_b.sent();
expect(factory).toHaveBeenCalledTimes(2);
return [2 /*return*/];
}
});
}); });
it("should handle very rapid dependency changes", function () { return __awaiter(void 0, void 0, void 0, function () {
var factory, _a, result, rerender, _loop_1, i;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
factory = jest
.fn()
.mockResolvedValueOnce("value-1")
.mockResolvedValueOnce("value-2")
.mockResolvedValueOnce("value-3")
.mockResolvedValueOnce("value-4")
.mockResolvedValueOnce("value-5");
_a = renderHook(function (_a) {
var dep = _a.dep;
return useAsyncMemo(factory, [dep]);
}, { initialProps: { dep: 1 } }), result = _a.result, rerender = _a.rerender;
_loop_1 = function (i) {
act(function () {
rerender({ dep: i });
});
};
// Rapid changes
for (i = 2; i <= 5; i++) {
_loop_1(i);
}
// Should eventually settle on the last value
return [4 /*yield*/, waitFor(function () {
expect(result.current).toBe("value-5");
})];
case 1:
// Should eventually settle on the last value
_b.sent();
expect(factory).toHaveBeenCalledTimes(5);
return [2 /*return*/];
}
});
}); });
});