|
|
@@ -0,0 +1,310 @@
|
|
|
+import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
+import { mount } from '@vue/test-utils'
|
|
|
+import VideoPlayer from '@/components/VideoPlayer.vue'
|
|
|
+
|
|
|
+// Mock hls.js
|
|
|
+vi.mock('hls.js', () => ({
|
|
|
+ default: class MockHls {
|
|
|
+ static isSupported() {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ static Events = {
|
|
|
+ MANIFEST_PARSED: 'hlsManifestParsed',
|
|
|
+ ERROR: 'hlsError'
|
|
|
+ }
|
|
|
+ static ErrorTypes = {
|
|
|
+ NETWORK_ERROR: 'networkError',
|
|
|
+ MEDIA_ERROR: 'mediaError'
|
|
|
+ }
|
|
|
+ loadSource = vi.fn()
|
|
|
+ attachMedia = vi.fn()
|
|
|
+ on = vi.fn()
|
|
|
+ destroy = vi.fn()
|
|
|
+ startLoad = vi.fn()
|
|
|
+ recoverMediaError = vi.fn()
|
|
|
+ }
|
|
|
+}))
|
|
|
+
|
|
|
+describe('VideoPlayer', () => {
|
|
|
+ beforeEach(() => {
|
|
|
+ vi.clearAllMocks()
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('Native Video Player', () => {
|
|
|
+ it('should render native video element by default', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').exists()).toBe(true)
|
|
|
+ expect(wrapper.find('video').attributes('src')).toBe('https://example.com/video.mp4')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should pass controls prop to video element', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native',
|
|
|
+ controls: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('controls')).toBeDefined()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should pass autoplay prop to video element', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native',
|
|
|
+ autoplay: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('autoplay')).toBeDefined()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should pass muted prop to video element', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native',
|
|
|
+ muted: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('muted')).toBeDefined()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should pass loop prop to video element', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native',
|
|
|
+ loop: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('loop')).toBeDefined()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should pass poster prop to video element', () => {
|
|
|
+ const poster = 'https://example.com/poster.jpg'
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native',
|
|
|
+ poster
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('poster')).toBe(poster)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('Cloudflare Stream Player', () => {
|
|
|
+ it('should render iframe for cloudflare player type', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ videoId: 'test-video-id',
|
|
|
+ playerType: 'cloudflare'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('iframe').exists()).toBe(true)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should generate correct iframe src', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ videoId: 'test-video-id',
|
|
|
+ playerType: 'cloudflare',
|
|
|
+ customerDomain: 'example.cloudflarestream.com'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const iframeSrc = wrapper.find('iframe').attributes('src')
|
|
|
+ expect(iframeSrc).toContain('https://example.cloudflarestream.com/test-video-id/iframe')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should include autoplay in iframe src when enabled', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ videoId: 'test-video-id',
|
|
|
+ playerType: 'cloudflare',
|
|
|
+ autoplay: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const iframeSrc = wrapper.find('iframe').attributes('src')
|
|
|
+ expect(iframeSrc).toContain('autoplay=true')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should include muted in iframe src when enabled', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ videoId: 'test-video-id',
|
|
|
+ playerType: 'cloudflare',
|
|
|
+ muted: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const iframeSrc = wrapper.find('iframe').attributes('src')
|
|
|
+ expect(iframeSrc).toContain('muted=true')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should include loop in iframe src when enabled', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ videoId: 'test-video-id',
|
|
|
+ playerType: 'cloudflare',
|
|
|
+ loop: true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const iframeSrc = wrapper.find('iframe').attributes('src')
|
|
|
+ expect(iframeSrc).toContain('loop=true')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('HLS Player', () => {
|
|
|
+ it('should render video element for HLS player type', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/stream.m3u8',
|
|
|
+ playerType: 'hls'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').exists()).toBe(true)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('Default Props', () => {
|
|
|
+ it('should have default controls as true', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('controls')).toBeDefined()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should have default muted as true', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('video').attributes('muted')).toBeDefined()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should have default playerType as native', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // Should render video element directly, not iframe
|
|
|
+ expect(wrapper.find('video').exists()).toBe(true)
|
|
|
+ expect(wrapper.find('iframe').exists()).toBe(false)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('Exposed Methods', () => {
|
|
|
+ it('should expose play method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.play).toBe('function')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should expose pause method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.pause).toBe('function')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should expose stop method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.stop).toBe('function')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should expose setVolume method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.setVolume).toBe('function')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should expose setMuted method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.setMuted).toBe('function')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should expose screenshot method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.screenshot).toBe('function')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should expose fullscreen method', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4',
|
|
|
+ playerType: 'native'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(typeof wrapper.vm.fullscreen).toBe('function')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('Wrapper Element', () => {
|
|
|
+ it('should have video-player-wrapper class', () => {
|
|
|
+ const wrapper = mount(VideoPlayer, {
|
|
|
+ props: {
|
|
|
+ src: 'https://example.com/video.mp4'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(wrapper.find('.video-player-wrapper').exists()).toBe(true)
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|