From bb5fa4bd63eb8eae4c38a1baf0d64e31a0d96f41 Mon Sep 17 00:00:00 2001 From: cottongin Date: Tue, 22 Sep 2026 19:03:46 -0400 Subject: [PATCH] feat: add SpeedSelector popup component Co-authored-by: Cursor --- src/lib/components/SpeedSelector.svelte | 89 ++++++++++++++++++++++ tests/lib/components/SpeedSelector.test.ts | 35 +++++++++ vite.config.ts | 4 +- 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/lib/components/SpeedSelector.svelte create mode 100644 tests/lib/components/SpeedSelector.test.ts diff --git a/src/lib/components/SpeedSelector.svelte b/src/lib/components/SpeedSelector.svelte new file mode 100644 index 0000000..5ca7316 --- /dev/null +++ b/src/lib/components/SpeedSelector.svelte @@ -0,0 +1,89 @@ + + + + + + + diff --git a/tests/lib/components/SpeedSelector.test.ts b/tests/lib/components/SpeedSelector.test.ts new file mode 100644 index 0000000..a2207de --- /dev/null +++ b/tests/lib/components/SpeedSelector.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect, vi } from 'vitest'; +import { render, fireEvent } from '@testing-library/svelte'; +import SpeedSelector from '$lib/components/SpeedSelector.svelte'; + +describe('SpeedSelector', () => { + it('renders all speed options', () => { + const { getByText } = render(SpeedSelector, { + props: { currentRate: 1, onSelect: vi.fn(), onClose: vi.fn() }, + }); + expect(getByText('0.5×')).toBeTruthy(); + expect(getByText('0.75×')).toBeTruthy(); + expect(getByText('1×')).toBeTruthy(); + expect(getByText('1.25×')).toBeTruthy(); + expect(getByText('1.5×')).toBeTruthy(); + expect(getByText('2×')).toBeTruthy(); + }); + + it('highlights the current rate', () => { + const { container } = render(SpeedSelector, { + props: { currentRate: 1.5, onSelect: vi.fn(), onClose: vi.fn() }, + }); + const activeBtn = container.querySelector('.speed-option.active'); + expect(activeBtn).toBeTruthy(); + expect(activeBtn!.textContent).toContain('1.5×'); + }); + + it('calls onSelect when an option is clicked', async () => { + const onSelect = vi.fn(); + const { getByText } = render(SpeedSelector, { + props: { currentRate: 1, onSelect, onClose: vi.fn() }, + }); + await fireEvent.click(getByText('2×')); + expect(onSelect).toHaveBeenCalledWith(2); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 9d1e3e9..301fb32 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,17 +3,19 @@ import process from 'node:process'; import { fileURLToPath } from 'node:url'; import { defineConfig } from 'vitest/config'; import { svelte } from '@sveltejs/vite-plugin-svelte'; +import { svelteTesting } from '@testing-library/svelte/vite'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const host = process.env.TAURI_DEV_HOST; const libAlias = path.resolve(__dirname, 'src/lib'); export default defineConfig({ - plugins: [svelte()], + plugins: [svelte(), svelteTesting()], resolve: { alias: { $lib: libAlias, }, + ...(process.env.VITEST ? { conditions: ['browser'] } : {}), }, clearScreen: false, server: {