diff --git a/packages/hooks/__tests__/use-timeout.spec.ts b/packages/hooks/__tests__/use-timeout.spec.ts new file mode 100644 index 0000000000..9bcd0ba191 --- /dev/null +++ b/packages/hooks/__tests__/use-timeout.spec.ts @@ -0,0 +1,56 @@ +import { mount } from '@vue/test-utils' +import useTimeout from '../use-timeout' + +const _mount = (cb: () => void) => { + return mount({ + setup() { + const { cancelTimeout, registerTimeout } = useTimeout() + registerTimeout(cb, 0) + + return { + cancelTimeout, + } + }, + render() { + return null + }, + }) +} + +jest.useFakeTimers() + +describe('use-timeout', () => { + + let wrapper + const cb = jest.fn() + beforeEach(() => { + cb.mockClear() + wrapper = _mount(cb) + }) + + it('should register timeout correctly', async () => { + expect(cb).not.toHaveBeenCalled() + jest.runOnlyPendingTimers() + expect(cb).toHaveBeenCalled() + wrapper.unmount() + }) + + it('should cancel the timeout correctly', async () => { + + wrapper.vm.cancelTimeout() + + jest.runOnlyPendingTimers() + + expect(cb).not.toHaveBeenCalled() + wrapper.unmount() + }) + + it('should cancel timeout before unmount', () => { + expect(cb).not.toHaveBeenCalled() + + wrapper.unmount() + jest.runOnlyPendingTimers() + + expect(cb).not.toHaveBeenCalled() + }) +}) diff --git a/packages/hooks/index.ts b/packages/hooks/index.ts index acbd5cf4fe..36fdce4a0e 100644 --- a/packages/hooks/index.ts +++ b/packages/hooks/index.ts @@ -8,4 +8,5 @@ export { default as useFocus } from './use-focus' export { default as useThrottleRender } from './use-throttle-render' export { default as usePreventGlobal } from './use-prevent-global' export { default as useTeleport } from './use-teleport' +export { default as useTimeout } from './use-timeout' export * from './use-model-toggle' diff --git a/packages/hooks/use-timeout/index.ts b/packages/hooks/use-timeout/index.ts new file mode 100644 index 0000000000..680b3add40 --- /dev/null +++ b/packages/hooks/use-timeout/index.ts @@ -0,0 +1,20 @@ +import { onBeforeUnmount } from 'vue' + +export default function () { + let timeoutHandle: ReturnType + + onBeforeUnmount(() => { + clearTimeout(timeoutHandle) + }) + + return { + registerTimeout: (fn: (...args: any[]) => unknown, delay: number) => { + clearTimeout(timeoutHandle) + timeoutHandle = setTimeout(fn, delay) + }, + + cancelTimeout: () => { + clearTimeout(timeoutHandle) + }, + } +}