123 lines
4.4 KiB
TypeScript
123 lines
4.4 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { isValidYouTubeUrl, extractYouTubeId, isValidYouTubeId, cn, formatDuration } from './utils'
|
|
|
|
describe('isValidYouTubeUrl', () => {
|
|
it('accepts standard youtube.com watch URLs', () => {
|
|
expect(isValidYouTubeUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true)
|
|
expect(isValidYouTubeUrl('http://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true)
|
|
expect(isValidYouTubeUrl('https://youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true)
|
|
})
|
|
|
|
it('accepts youtu.be short URLs', () => {
|
|
expect(isValidYouTubeUrl('https://youtu.be/dQw4w9WgXcQ')).toBe(true)
|
|
expect(isValidYouTubeUrl('http://youtu.be/dQw4w9WgXcQ')).toBe(true)
|
|
})
|
|
|
|
it('accepts URLs without protocol', () => {
|
|
expect(isValidYouTubeUrl('www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true)
|
|
expect(isValidYouTubeUrl('youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true)
|
|
})
|
|
|
|
it('rejects non-YouTube URLs', () => {
|
|
expect(isValidYouTubeUrl('https://vimeo.com/123456')).toBe(false)
|
|
expect(isValidYouTubeUrl('https://google.com')).toBe(false)
|
|
expect(isValidYouTubeUrl('not a url')).toBe(false)
|
|
expect(isValidYouTubeUrl('')).toBe(false)
|
|
})
|
|
|
|
it('rejects YouTube domain without path', () => {
|
|
expect(isValidYouTubeUrl('https://youtube.com')).toBe(false)
|
|
expect(isValidYouTubeUrl('https://youtube.com/')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('extractYouTubeId', () => {
|
|
it('extracts ID from standard watch URLs', () => {
|
|
expect(extractYouTubeId('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
|
|
expect(extractYouTubeId('https://youtube.com/watch?v=abc123XYZ_-')).toBe('abc123XYZ_-')
|
|
})
|
|
|
|
it('extracts ID from youtu.be short URLs', () => {
|
|
expect(extractYouTubeId('https://youtu.be/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
|
|
})
|
|
|
|
it('extracts ID from embed URLs', () => {
|
|
expect(extractYouTubeId('https://www.youtube.com/embed/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
|
|
})
|
|
|
|
it('extracts ID from /v/ URLs', () => {
|
|
expect(extractYouTubeId('https://www.youtube.com/v/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
|
|
})
|
|
|
|
it('handles URLs with extra parameters', () => {
|
|
expect(extractYouTubeId('https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=120')).toBe('dQw4w9WgXcQ')
|
|
expect(extractYouTubeId('https://youtu.be/dQw4w9WgXcQ?t=120')).toBe('dQw4w9WgXcQ')
|
|
})
|
|
|
|
it('returns null for invalid URLs', () => {
|
|
expect(extractYouTubeId('https://vimeo.com/123456')).toBe(null)
|
|
expect(extractYouTubeId('not a url')).toBe(null)
|
|
expect(extractYouTubeId('')).toBe(null)
|
|
})
|
|
})
|
|
|
|
describe('isValidYouTubeId', () => {
|
|
it('accepts valid 11-character IDs', () => {
|
|
expect(isValidYouTubeId('dQw4w9WgXcQ')).toBe(true)
|
|
expect(isValidYouTubeId('abc123XYZ_-')).toBe(true)
|
|
expect(isValidYouTubeId('AAAAAAAAAAA')).toBe(true)
|
|
expect(isValidYouTubeId('00000000000')).toBe(true)
|
|
})
|
|
|
|
it('rejects IDs with wrong length', () => {
|
|
expect(isValidYouTubeId('dQw4w9WgXc')).toBe(false)
|
|
expect(isValidYouTubeId('dQw4w9WgXcQQ')).toBe(false)
|
|
expect(isValidYouTubeId('')).toBe(false)
|
|
})
|
|
|
|
it('rejects IDs with invalid characters', () => {
|
|
expect(isValidYouTubeId('dQw4w9WgXc!')).toBe(false)
|
|
expect(isValidYouTubeId('dQw4w9WgXc@')).toBe(false)
|
|
expect(isValidYouTubeId('dQw4w9 gXcQ')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('cn', () => {
|
|
it('merges class names', () => {
|
|
expect(cn('foo', 'bar')).toBe('foo bar')
|
|
})
|
|
|
|
it('handles conditional classes', () => {
|
|
expect(cn('foo', false && 'bar', 'baz')).toBe('foo baz')
|
|
expect(cn('foo', true && 'bar', 'baz')).toBe('foo bar baz')
|
|
})
|
|
|
|
it('deduplicates tailwind classes', () => {
|
|
expect(cn('p-4', 'p-2')).toBe('p-2')
|
|
expect(cn('text-red-500', 'text-blue-500')).toBe('text-blue-500')
|
|
})
|
|
})
|
|
|
|
describe('formatDuration', () => {
|
|
it('formats seconds into mm:ss', () => {
|
|
expect(formatDuration(0)).toBe('0:00')
|
|
expect(formatDuration(5)).toBe('0:05')
|
|
expect(formatDuration(59)).toBe('0:59')
|
|
expect(formatDuration(60)).toBe('1:00')
|
|
expect(formatDuration(61)).toBe('1:01')
|
|
expect(formatDuration(125)).toBe('2:05')
|
|
})
|
|
|
|
it('handles longer durations', () => {
|
|
expect(formatDuration(600)).toBe('10:00')
|
|
expect(formatDuration(3600)).toBe('60:00')
|
|
expect(formatDuration(3661)).toBe('61:01')
|
|
})
|
|
|
|
it('handles decimal seconds by flooring', () => {
|
|
expect(formatDuration(5.7)).toBe('0:05')
|
|
expect(formatDuration(59.9)).toBe('0:59')
|
|
expect(formatDuration(60.1)).toBe('1:00')
|
|
})
|
|
})
|