diff --git a/change/office-ui-fabric-react-2020-03-03-15-35-01-jg-fix-infinite-timers.json b/change/office-ui-fabric-react-2020-03-03-15-35-01-jg-fix-infinite-timers.json new file mode 100644 index 0000000000000..b8b8273b4d3ee --- /dev/null +++ b/change/office-ui-fabric-react-2020-03-03-15-35-01-jg-fix-infinite-timers.json @@ -0,0 +1,9 @@ +{ + "type": "none", + "comment": "Add mock for Async to prevent spurious infinite timer issue.", + "packageName": "office-ui-fabric-react", + "email": "jagore@microsoft.com", + "commit": "5c78a6866573bcfa7096bc625c795c3205d69e89", + "dependentChangeType": "patch", + "date": "2020-03-03T23:35:01.016Z" +} diff --git a/packages/office-ui-fabric-react/__mocks__/@uifabric/utilities.ts b/packages/office-ui-fabric-react/__mocks__/@uifabric/utilities.ts new file mode 100644 index 0000000000000..f3bb0950abf4e --- /dev/null +++ b/packages/office-ui-fabric-react/__mocks__/@uifabric/utilities.ts @@ -0,0 +1,37 @@ +export * from '@uifabric/utilities'; +import { Async } from '@uifabric/utilities'; + +declare function setTimeout(cb: Function, delay: number): number; + +// Known issue with jest's runAllTimers and debounce implementations resulting in +// "Ran 100000 timers, and there are still more! Assuming we've hit an infinite recursion and bailing out..." +// https://github.com/facebook/jest/issues/3465 +// Mock impl inspired from issue. +class MockAsync extends Async { + public debounce(callback: Function, timeout: number) { + let timeoutId: number | null = null; + const debounced = (...args: any[]) => { + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = null; + } + // Callback functions throughout repo aren't binding properly, so we have to access + // Async's private _parent member and invoke callbacks the same way Async.debounce does. + const invokeFunction = () => callback.apply((this as any)._parent, args); + timeoutId = setTimeout(invokeFunction, timeout); + }; + + const cancel = () => { + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = null; + } + }; + + (debounced as any).cancel = cancel; + + return debounced as any; + } +} + +export { MockAsync as Async };