From 85f8e3b67bce027e2d03f3f6872b9e03cbcdc76a Mon Sep 17 00:00:00 2001 From: Tyler Gray Date: Sat, 16 May 2026 10:34:17 -0400 Subject: [PATCH] =?UTF-8?q?fix(types):=20close=206=20svelte-check=20errors?= =?UTF-8?q?=20=E2=80=94=20keybindings=20test=20Input=20cast=20(#214=20Grou?= =?UTF-8?q?p=20E)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the #214 cleanup. Brings `npm run check` from 53 -> 47 errors (closes 6). Test-only change, no production behavior. ## What was wrong `keybindingsLibrary.test.ts` mocks `$lib/types` (lines 4-21) to provide a minimal universe with an extra `'Input'` context and a `'newline'` action — that's how the conflict-detection tests have something cross-context to exercise (e.g. `detectConflicts('Global', 'Shift+Enter')` expects an `Input` conflict, where `newline` defaults to `Shift+Enter`). `vi.mock` is runtime-only, so TypeScript still reads the real `KeybindingContext` union from `$lib/types`, which doesn't include `'Input'`. The store methods are typed `(context: KeybindingContext, ...)` so the 6 test sites passing `'Input'` errored. ## Fix Imported `KeybindingContext` and added one cast alias at the top of the file: const Input = 'Input' as unknown as KeybindingContext; Replaced the 6 `'Input'` literals at call sites typed against `KeybindingContext` (setBinding, detectConflicts, Map.has, binding.context comparison). Comment explains why the cast is needed so future readers don't try to delete it. NOT adding `'Input'` to the production `KeybindingContext` union — that would be a phantom value (nothing in real `KEYBINDING_CONTEXTS` or `KEYBINDING_ACTIONS` uses it; it only exists in this test's mock). Same principle as #221's spinnerverbs decision. ## Test plan - [x] `npm run check` — 47 errors (down from 53 on `main`) - [x] `npx vitest run keybindingsLibrary` — 31/31 pass Co-Authored-By: Claude Opus 4.7 (1M context) --- src/tests/stores/keybindingsLibrary.test.ts | 22 ++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/tests/stores/keybindingsLibrary.test.ts b/src/tests/stores/keybindingsLibrary.test.ts index 9a87d0fc..0739ecf3 100644 --- a/src/tests/stores/keybindingsLibrary.test.ts +++ b/src/tests/stores/keybindingsLibrary.test.ts @@ -1,5 +1,13 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { invoke } from '@tauri-apps/api/core'; +import type { KeybindingContext } from '$lib/types'; + +// The vi.mock below extends the real KEYBINDING_CONTEXTS / KEYBINDING_ACTIONS +// universe with an "Input" context + a "newline" action so the conflict-detection +// tests have something cross-context to exercise. TypeScript only sees the real +// $lib/types (mocks are runtime-only), so 'Input' needs an explicit cast where +// it's passed to store methods typed as KeybindingContext. +const Input = 'Input' as unknown as KeybindingContext; vi.mock('$lib/types', () => { const contexts = [ @@ -89,8 +97,8 @@ describe('Keybindings Library Store', () => { it('should create new context block if needed', async () => { const { keybindingsLibrary } = await import('$lib/stores/keybindingsLibrary.svelte'); - keybindingsLibrary.setBinding('Input', 'Ctrl+A', 'newline'); - const block = keybindingsLibrary.overrides.find((b) => b.context === 'Input'); + keybindingsLibrary.setBinding(Input, 'Ctrl+A', 'newline'); + const block = keybindingsLibrary.overrides.find((b) => b.context === Input); expect(block?.bindings['Ctrl+A']).toBe('newline'); }); }); @@ -134,7 +142,7 @@ describe('Keybindings Library Store', () => { it('should clear all overrides', async () => { const { keybindingsLibrary } = await import('$lib/stores/keybindingsLibrary.svelte'); keybindingsLibrary.setBinding('Global', 'Ctrl+K', 'cancel'); - keybindingsLibrary.setBinding('Input', 'Ctrl+A', 'newline'); + keybindingsLibrary.setBinding(Input, 'Ctrl+A', 'newline'); keybindingsLibrary.resetAll(); expect(keybindingsLibrary.overrides).toEqual([]); }); @@ -145,7 +153,7 @@ describe('Keybindings Library Store', () => { const { keybindingsLibrary } = await import('$lib/stores/keybindingsLibrary.svelte'); keybindingsLibrary.setBinding('Global', 'Ctrl+K', 'cancel'); keybindingsLibrary.setBinding('Global', 'Ctrl+S', 'submit'); - keybindingsLibrary.setBinding('Input', 'Ctrl+A', 'newline'); + keybindingsLibrary.setBinding(Input, 'Ctrl+A', 'newline'); expect(keybindingsLibrary.overrideCount).toBe(3); }); }); @@ -191,7 +199,7 @@ describe('Keybindings Library Store', () => { it('should check Global context for non-global contexts', async () => { const { keybindingsLibrary } = await import('$lib/stores/keybindingsLibrary.svelte'); - const conflicts = keybindingsLibrary.detectConflicts('Input', 'Enter'); + const conflicts = keybindingsLibrary.detectConflicts(Input, 'Enter'); // Should find conflict with Global's 'submit' action on Enter const globalConflict = conflicts.find((c) => c.context === 'Global'); expect(globalConflict).toBeDefined(); @@ -201,7 +209,7 @@ describe('Keybindings Library Store', () => { const { keybindingsLibrary } = await import('$lib/stores/keybindingsLibrary.svelte'); const conflicts = keybindingsLibrary.detectConflicts('Global', 'Shift+Enter'); // Shift+Enter is default for 'newline' in Input context - const inputConflict = conflicts.find((c) => c.context === 'Input'); + const inputConflict = conflicts.find((c) => c.context === Input); expect(inputConflict).toBeDefined(); }); }); @@ -302,7 +310,7 @@ describe('Keybindings Library Store', () => { keybindingsLibrary.searchQuery = 'newline'; const filtered = keybindingsLibrary.filteredByContext; expect(filtered.has('Global')).toBe(false); - expect(filtered.has('Input')).toBe(true); + expect(filtered.has(Input)).toBe(true); }); }); });