From 78c58ed04f229e921d93652e2d314aebfb8bc848 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Thu, 29 Aug 2024 03:35:57 +0300 Subject: [PATCH] test: use key pressed tests --- .../useEventListener/useEventListener.ts | 17 +++-- .../useKeyPressed/useKeyPressed.spec.ts | 69 +++++++++++++++++++ .../helpers/useKeyPressed/useKeyPressed.ts | 8 ++- .../usePopoverController.ts | 4 +- vitest.config.ts | 1 + 5 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 packages/core/src/helpers/useKeyPressed/useKeyPressed.spec.ts diff --git a/packages/core/src/helpers/useEventListener/useEventListener.ts b/packages/core/src/helpers/useEventListener/useEventListener.ts index 14c92da3..3d891e6a 100644 --- a/packages/core/src/helpers/useEventListener/useEventListener.ts +++ b/packages/core/src/helpers/useEventListener/useEventListener.ts @@ -1,6 +1,6 @@ import { isRef, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'; -import { Arrayable, Maybe } from '../types'; -import { isCallable, normalizeArrayable } from '../utils/common'; +import { Arrayable, Maybe } from '../../types'; +import { isCallable, normalizeArrayable } from '../../utils/common'; interface ListenerOptions { disabled?: MaybeRefOrGetter; @@ -26,7 +26,6 @@ export function useEventListener( } const events = normalizeArrayable(event); - events.forEach(evt => { el.addEventListener(evt, listener as EventListener); }); @@ -43,6 +42,7 @@ export function useEventListener( setup(target); } }, + { immediate: true }, ); onBeforeUnmount(() => { @@ -57,8 +57,17 @@ export function useEventListener( if (isCallable(opts?.disabled) || isRef(opts?.disabled)) { watch(opts.disabled, value => { const target = toValue(targetRef); - if (!value && target) { + if (!target) { + return; + } + + if (!value) { setup(target); + return; + } + + if (value) { + cleanup(target); } }); } diff --git a/packages/core/src/helpers/useKeyPressed/useKeyPressed.spec.ts b/packages/core/src/helpers/useKeyPressed/useKeyPressed.spec.ts new file mode 100644 index 00000000..c8fc1460 --- /dev/null +++ b/packages/core/src/helpers/useKeyPressed/useKeyPressed.spec.ts @@ -0,0 +1,69 @@ +import { renderSetup } from '@test-utils/index'; +import { useKeyPressed } from './useKeyPressed'; +import { fireEvent } from '@testing-library/vue'; +import { nextTick, ref } from 'vue'; + +describe('ref is true as long as the key is held', () => { + test('accepts single key string', async () => { + const { isPressed } = await renderSetup(() => { + return { isPressed: useKeyPressed('ShiftLeft') }; + }); + + expect(isPressed.value).toBe(false); + await fireEvent.keyDown(window, { code: 'ShiftLeft' }); + expect(isPressed.value).toBe(true); + await fireEvent.keyUp(window, { code: 'ShiftLeft' }); + expect(isPressed.value).toBe(false); + }); + + test('accepts multiple key strings', async () => { + const { isPressed } = await renderSetup(() => { + return { isPressed: useKeyPressed(['KeyK', 'KeyL']) }; + }); + + expect(isPressed.value).toBe(false); + await fireEvent.keyDown(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(true); + await fireEvent.keyUp(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(false); + + await fireEvent.keyDown(window, { code: 'KeyL' }); + expect(isPressed.value).toBe(true); + await fireEvent.keyUp(window, { code: 'KeyL' }); + expect(isPressed.value).toBe(false); + }); + + test('accepts a predicate', async () => { + const { isPressed } = await renderSetup(() => { + return { isPressed: useKeyPressed(e => e.code === 'KeyK') }; + }); + + expect(isPressed.value).toBe(false); + await fireEvent.keyDown(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(true); + await fireEvent.keyUp(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(false); + }); +}); + +test('can be disabled', async () => { + const isDisabled = ref(true); + const { isPressed } = await renderSetup(() => { + return { isPressed: useKeyPressed('KeyK', isDisabled) }; + }); + + expect(isPressed.value).toBe(false); + await fireEvent.keyDown(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(false); + await fireEvent.keyUp(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(false); + + isDisabled.value = false; + await nextTick(); + + expect(isPressed.value).toBe(false); + await fireEvent.keyDown(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(true); + await fireEvent.keyUp(window, { code: 'KeyK' }); + expect(isPressed.value).toBe(false); +}); diff --git a/packages/core/src/helpers/useKeyPressed/useKeyPressed.ts b/packages/core/src/helpers/useKeyPressed/useKeyPressed.ts index 311bbefa..7438f0dc 100644 --- a/packages/core/src/helpers/useKeyPressed/useKeyPressed.ts +++ b/packages/core/src/helpers/useKeyPressed/useKeyPressed.ts @@ -1,7 +1,7 @@ -import { useEventListener } from './useEventListener'; import { MaybeRefOrGetter, shallowRef } from 'vue'; -import { Arrayable } from '../types'; -import { isCallable, normalizeArrayable } from '../utils/common'; +import { useEventListener } from '../useEventListener'; +import { Arrayable } from '../../types'; +import { isCallable, normalizeArrayable } from '../../utils/common'; export function useKeyPressed( codes: Arrayable | ((evt: KeyboardEvent) => boolean), @@ -15,6 +15,8 @@ export function useKeyPressed( } } + // We don't care if the multiple keys can be pressed to trigger it initially + // because it's a rare case and it's not worth the complexity, user can split it into multiple hooks function onKeyup(e: KeyboardEvent) { if (predicate(e)) { isPressed.value = false; diff --git a/packages/core/src/helpers/usePopoverController/usePopoverController.ts b/packages/core/src/helpers/usePopoverController/usePopoverController.ts index 5e618a9c..8019ceb5 100644 --- a/packages/core/src/helpers/usePopoverController/usePopoverController.ts +++ b/packages/core/src/helpers/usePopoverController/usePopoverController.ts @@ -1,6 +1,6 @@ import { Ref, shallowRef, watch } from 'vue'; -import { useEventListener } from './useEventListener'; -import { Maybe } from '../types'; +import { useEventListener } from '../useEventListener'; +import { Maybe } from '../../types'; export function usePopoverController(popoverEl: Ref>) { const isOpen = shallowRef(false); diff --git a/vitest.config.ts b/vitest.config.ts index e3400e57..5d5bff90 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ exclude: ['docs/*', ...configDefaults.exclude], coverage: { reporter: ['html', 'json'], + include: [...(configDefaults.coverage.include || [])], exclude: [ '**/*/devtools.ts', 'packages/**/dist/**',