diff --git a/apps/web/package.json b/apps/web/package.json
index fe97c66a..a794741d 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -7,8 +7,6 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
- "test": "vitest",
- "test:run": "vitest run",
"lint": "biome check src/",
"lint:fix": "biome check src/ --write",
"format": "biome format src/ --write",
@@ -76,9 +74,6 @@
"devDependencies": {
"@tailwindcss/postcss": "^4.1.11",
"@tailwindcss/typography": "^0.5.16",
- "@testing-library/jest-dom": "^6.4.0",
- "@testing-library/react": "^15.0.7",
- "@testing-library/user-event": "^14.5.2",
"@types/bun": "latest",
"@types/node": "^24.2.1",
"@types/pg": "^8.15.4",
@@ -86,11 +81,9 @@
"@types/react-dom": "^18.2.18",
"cross-env": "^7.0.3",
"drizzle-kit": "^0.31.4",
- "jsdom": "^26.0.0",
"postcss": "^8",
"tailwindcss": "^4.1.11",
"tsx": "^4.7.1",
- "typescript": "^5.8.3",
- "vitest": "^2.1.8"
+ "typescript": "^5.8.3"
}
}
diff --git a/apps/web/src/components/editor/timeline/__tests__/TimelineToolbar.test.tsx b/apps/web/src/components/editor/timeline/__tests__/TimelineToolbar.test.tsx
deleted file mode 100644
index 9a8ef666..00000000
--- a/apps/web/src/components/editor/timeline/__tests__/TimelineToolbar.test.tsx
+++ /dev/null
@@ -1,217 +0,0 @@
-import React from 'react'
-import { describe, it, expect, vi, beforeEach } from 'vitest'
-import { render, screen, fireEvent } from '@testing-library/react'
-import { Timeline } from '../index'
-
-// Mock the stores and hooks
-vi.mock('@/stores/timeline-store', () => ({
- useTimelineStore: () => ({
- tracks: [],
- addTrack: vi.fn(),
- addElementToTrack: vi.fn(),
- removeElementFromTrack: vi.fn(),
- removeElementFromTrackWithRipple: vi.fn(),
- selectedElements: [],
- clearSelectedElements: vi.fn(),
- splitElement: vi.fn(),
- splitAndKeepLeft: vi.fn(),
- splitAndKeepRight: vi.fn(),
- separateAudio: vi.fn(),
- snappingEnabled: false,
- toggleSnapping: vi.fn(),
- deleteElements: vi.fn(),
- duplicateElement: vi.fn(),
- selectAll: vi.fn(),
- zoomLevel: 1,
- setZoomLevel: vi.fn(),
- dragState: { isDragging: false, draggedElement: null, dragOffset: { x: 0, y: 0 } },
- getTotalDuration: () => 100,
- setSelectedElements: vi.fn(),
- toggleTrackMute: vi.fn(),
- })
-}))
-
-vi.mock('@/stores/media-store', () => ({
- useMediaStore: () => ({
- mediaItems: [],
- addMediaItem: vi.fn(),
- })
-}))
-
-vi.mock('@/stores/project-store', () => ({
- useProjectStore: () => ({
- activeProject: null,
- })
-}))
-
-const mockSeek = vi.fn()
-
-vi.mock('@/stores/playback-store', () => ({
- usePlaybackStore: () => ({
- currentTime: 0,
- duration: 100,
- seek: mockSeek,
- setDuration: vi.fn(),
- isPlaying: false,
- toggle: vi.fn(),
- }),
-}))
-
-// Mock the timeline playhead hook
-vi.mock('@/hooks/use-timeline-playhead', () => ({
- useTimelinePlayhead: () => ({
- playheadRef: { current: null },
- updatePlayheadPosition: vi.fn(),
- onPlayheadDrag: vi.fn(),
- })
-}))
-
-vi.mock('@/hooks/use-editor-actions', () => ({
- useEditorActions: () => ({})
-}))
-
-vi.mock('@/hooks/use-timeline-context-menu', () => ({
- useTimelineContextMenu: () => ({
- contextMenu: null,
- handleContextMenu: vi.fn(),
- closeContextMenu: vi.fn(),
- })
-}))
-
-vi.mock('@/hooks/use-timeline-selection', () => ({
- useTimelineSelection: () => ({
- isSelecting: false,
- selectionBox: null,
- handleMouseDown: vi.fn(),
- })
-}))
-
-vi.mock('@/hooks/use-timeline-drag-drop', () => ({
- useTimelineDragDrop: () => ({
- dragProps: {},
- })
-}))
-
-// Mock UI components to avoid dependency issues
-vi.mock('../../ui/tooltip', () => ({
- Tooltip: ({ children }: any) => children,
- TooltipTrigger: ({ children }: any) => children,
- TooltipContent: ({ children }: any) =>
{children}
,
- TooltipProvider: ({ children }: any) => children,
-}))
-
-vi.mock('../../ui/button', () => ({
- Button: ({ children, onClick, ...props }: any) => (
-
- ),
-}))
-
-vi.mock('../../ui/scroll-area', () => ({
- ScrollArea: ({ children }: any) => {children}
,
-}))
-
-vi.mock('lucide-react', () => ({
- SkipBack: () => ,
- Play: () => ,
- Pause: () => ,
- Scissors: () => ,
- ArrowLeftToLine: () => ,
- ArrowRightToLine: () => ,
- Trash2: () => ,
- Snowflake: () => ,
- Copy: () => ,
- SplitSquareHorizontal: () => ,
- Video: () => ,
- Music: () => ,
- TypeIcon: () => ,
- Magnet: () => ,
- Link: () => ,
- ZoomIn: () => ,
- ZoomOut: () => ,
-}))
-
-vi.mock('@/constants/timeline', () => ({
- TIMELINE_CONSTANTS: {
- DEFAULT_TEXT_DURATION: 5,
- }
-}))
-
-vi.mock('@/lib/utils', () => ({
- cn: (...args: any[]) => args.join(' '),
- snapTimeToFrame: (time: number) => time,
-}))
-
-// Mock timeline utilities
-vi.mock('@/lib/timeline-utils', () => ({
- getTotalDuration: () => 100,
- getCurrentSnapPoint: () => null,
-}))
-
-// Mock context menu components
-vi.mock('../../ui/context-menu', () => ({
- ContextMenu: ({ children }: any) => children,
- ContextMenuTrigger: ({ children }: any) => children,
- ContextMenuContent: ({ children }: any) => {children}
,
- ContextMenuItem: ({ children }: any) => {children}
,
- ContextMenuSeparator: () => ,
-}))
-
-// Mock dialog components
-vi.mock('../../ui/dialog', () => ({
- Dialog: ({ children }: any) => children,
- DialogContent: ({ children }: any) => {children}
,
- DialogHeader: ({ children }: any) => {children}
,
- DialogTitle: ({ children }: any) => {children}
,
-}))
-
-describe('Timeline - Return to Start Button', () => {
- beforeEach(() => {
- mockSeek.mockClear()
- })
-
- it('should render Return to Start button', () => {
- render()
-
- // Look for the SkipBack icon which indicates our button
- const skipBackIcon = screen.getByTestId('skip-back-icon')
- expect(skipBackIcon).toBeInTheDocument()
- })
-
- it('should call seek(0) when Return to Start button is clicked', () => {
- render()
-
- // Find the button that contains the SkipBack icon
- const skipBackIcon = screen.getByTestId('skip-back-icon')
- const button = skipBackIcon.closest('button')
-
- expect(button).toBeInTheDocument()
- fireEvent.click(button!)
-
- expect(mockSeek).toHaveBeenCalledWith(0)
- })
-
- it('should have tooltip structure for Return to Start button', () => {
- render()
-
- // Find the skip back button and verify it's wrapped in tooltip components
- const skipBackIcon = screen.getByTestId('skip-back-icon')
- const button = skipBackIcon.closest('button')
-
- expect(button).toBeInTheDocument()
- // The button should exist and be clickable, which means the tooltip structure is in place
- expect(button).toHaveAttribute('data-state', 'closed') // Tooltip trigger state
- })
-
- it('should have SkipBack icon in Return to Start button', () => {
- render()
-
- const skipBackIcon = screen.getByTestId('skip-back-icon')
- expect(skipBackIcon).toBeInTheDocument()
-
- // Verify it's inside a button
- const button = skipBackIcon.closest('button')
- expect(button).toBeInTheDocument()
- })
-})
\ No newline at end of file
diff --git a/apps/web/src/components/editor/timeline/index.tsx b/apps/web/src/components/editor/timeline/index.tsx
index 669d556c..d8261d9b 100644
--- a/apps/web/src/components/editor/timeline/index.tsx
+++ b/apps/web/src/components/editor/timeline/index.tsx
@@ -1,6 +1,5 @@
"use client";
-import React from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "../../ui/button";
import {
@@ -609,7 +608,11 @@ export function Timeline() {
onMouseEnter={() => setIsInTimeline(true)}
onMouseLeave={() => setIsInTimeline(false)}
>
-
+
{/* Timeline Container */}
{
if (selectedElements.length === 0) return;
let splitCount = 0;
@@ -1075,7 +1077,6 @@ function TimelineToolbar({
clearSelectedElements();
};
- // Zoom handlers
const handleZoomIn = () => {
setZoomLevel(Math.min(4, zoomLevel + 0.25));
};
@@ -1092,13 +1093,11 @@ function TimelineToolbar({
await toggleBookmark(currentTime);
};
- // Check if the current time is bookmarked
const currentBookmarked = isBookmarked(currentTime);
return (
- {/* Play/Pause Button */}
- {/* Return to Start Button - Seeks timeline to 00:00:00 */}
-
- Return to Start (Home / Enter)
-
+ Return to Start (Home / Enter)
- {/* Time Display */}
{currentTime.toFixed(1)}s / {duration.toFixed(1)}s
- {/* Test Clip Button - for debugging */}
{tracks.length === 0 && (
<>
diff --git a/apps/web/src/components/editor/timeline/timeline-playhead.tsx b/apps/web/src/components/editor/timeline/timeline-playhead.tsx
index 48c60596..a1be5b26 100644
--- a/apps/web/src/components/editor/timeline/timeline-playhead.tsx
+++ b/apps/web/src/components/editor/timeline/timeline-playhead.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useRef, useState, useEffect } from "react";
+import { useRef, useState, useEffect } from "react";
import { TimelineTrack } from "@/types/timeline";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { useTimelinePlayhead } from "@/hooks/use-timeline-playhead";
diff --git a/apps/web/src/hooks/__tests__/use-keyboard-shortcuts-help.test.ts b/apps/web/src/hooks/__tests__/use-keyboard-shortcuts-help.test.ts
deleted file mode 100644
index 52c7dcd6..00000000
--- a/apps/web/src/hooks/__tests__/use-keyboard-shortcuts-help.test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { describe, it, expect, beforeEach } from 'vitest'
-import { renderHook } from '@testing-library/react'
-import { useKeyboardShortcutsHelp } from '../use-keyboard-shortcuts-help'
-import { useKeybindingsStore } from '../../stores/keybindings-store'
-
-describe('useKeyboardShortcutsHelp', () => {
- beforeEach(() => {
- // Reset store to default state before each test
- useKeybindingsStore.getState().resetToDefaults()
- })
-
- it('should format Enter key correctly in shortcuts', () => {
- const { result } = renderHook(() => useKeyboardShortcutsHelp())
-
- // Find the goto-start action in shortcuts
- const gotoStartShortcut = result.current.shortcuts.find(
- shortcut => shortcut.action === 'goto-start'
- )
-
- expect(gotoStartShortcut).toBeDefined()
- expect(gotoStartShortcut?.keys).toContain('Enter')
- expect(gotoStartShortcut?.keys).toContain('Home')
- })
-
- it('should include goto-start action with correct description', () => {
- const { result } = renderHook(() => useKeyboardShortcutsHelp())
-
- const gotoStartShortcut = result.current.shortcuts.find(
- shortcut => shortcut.action === 'goto-start'
- )
-
- expect(gotoStartShortcut).toBeDefined()
- expect(gotoStartShortcut?.description).toBe('Go to timeline start')
- expect(gotoStartShortcut?.category).toBe('Navigation')
- })
-
- it('should have multiple keys for goto-start action', () => {
- const { result } = renderHook(() => useKeyboardShortcutsHelp())
-
- const gotoStartShortcut = result.current.shortcuts.find(
- shortcut => shortcut.action === 'goto-start'
- )
-
- expect(gotoStartShortcut?.keys.length).toBeGreaterThanOrEqual(2)
- })
-})
\ No newline at end of file
diff --git a/apps/web/src/hooks/use-keyboard-shortcuts-help.ts b/apps/web/src/hooks/use-keyboard-shortcuts-help.ts
index 98810cb1..e2cde3b4 100644
--- a/apps/web/src/hooks/use-keyboard-shortcuts-help.ts
+++ b/apps/web/src/hooks/use-keyboard-shortcuts-help.ts
@@ -77,7 +77,7 @@ const formatKey = (key: string): string => {
.replace("down", "↓")
.replace("space", "Space")
.replace("home", "Home")
- .replace("enter", "Enter") // Format Enter key for display in help dialog
+ .replace("enter", "Enter")
.replace("end", "End")
.replace("delete", "Delete")
.replace("backspace", "Backspace")
diff --git a/apps/web/src/stores/keybindings-store.ts b/apps/web/src/stores/keybindings-store.ts
index 740a5855..4c11cfde 100644
--- a/apps/web/src/stores/keybindings-store.ts
+++ b/apps/web/src/stores/keybindings-store.ts
@@ -17,7 +17,7 @@ export const defaultKeybindings: KeybindingConfig = {
"shift+left": "jump-backward",
"shift+right": "jump-forward",
home: "goto-start",
- enter: "goto-start", // More intuitive alternative to Home key for timeline navigation
+ enter: "goto-start",
end: "goto-end",
s: "split-element",
n: "toggle-snapping",
diff --git a/apps/web/src/test/setup.ts b/apps/web/src/test/setup.ts
deleted file mode 100644
index e53f09dd..00000000
--- a/apps/web/src/test/setup.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import '@testing-library/jest-dom'
-
-// Mock ResizeObserver
-global.ResizeObserver = class ResizeObserver {
- observe() {}
- unobserve() {}
- disconnect() {}
-}
\ No newline at end of file
diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts
deleted file mode 100644
index cb1133fb..00000000
--- a/apps/web/vitest.config.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { defineConfig } from 'vitest/config'
-import { resolve } from 'path'
-
-export default defineConfig({
- test: {
- environment: 'jsdom',
- setupFiles: ['./src/test/setup.ts'],
- globals: true,
- },
- resolve: {
- alias: {
- '@': resolve(__dirname, './src'),
- },
- },
-})
\ No newline at end of file