VideoPlayer.spec.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. import { describe, it, expect, vi, beforeEach } from 'vitest'
  2. import { mount } from '@vue/test-utils'
  3. import VideoPlayer from '@/components/VideoPlayer.vue'
  4. // Mock hls.js
  5. vi.mock('hls.js', () => ({
  6. default: class MockHls {
  7. static isSupported() {
  8. return true
  9. }
  10. static Events = {
  11. MANIFEST_PARSED: 'hlsManifestParsed',
  12. ERROR: 'hlsError'
  13. }
  14. static ErrorTypes = {
  15. NETWORK_ERROR: 'networkError',
  16. MEDIA_ERROR: 'mediaError'
  17. }
  18. loadSource = vi.fn()
  19. attachMedia = vi.fn()
  20. on = vi.fn()
  21. destroy = vi.fn()
  22. startLoad = vi.fn()
  23. recoverMediaError = vi.fn()
  24. }
  25. }))
  26. describe('VideoPlayer', () => {
  27. beforeEach(() => {
  28. vi.clearAllMocks()
  29. })
  30. describe('Native Video Player', () => {
  31. it('should render native video element by default', () => {
  32. const wrapper = mount(VideoPlayer, {
  33. props: {
  34. src: 'https://example.com/video.mp4',
  35. playerType: 'native'
  36. }
  37. })
  38. expect(wrapper.find('video').exists()).toBe(true)
  39. expect(wrapper.find('video').attributes('src')).toBe('https://example.com/video.mp4')
  40. })
  41. it('should pass controls prop to video element', () => {
  42. const wrapper = mount(VideoPlayer, {
  43. props: {
  44. src: 'https://example.com/video.mp4',
  45. playerType: 'native',
  46. controls: true
  47. }
  48. })
  49. expect(wrapper.find('video').attributes('controls')).toBeDefined()
  50. })
  51. it('should pass autoplay prop to video element', () => {
  52. const wrapper = mount(VideoPlayer, {
  53. props: {
  54. src: 'https://example.com/video.mp4',
  55. playerType: 'native',
  56. autoplay: true
  57. }
  58. })
  59. expect(wrapper.find('video').attributes('autoplay')).toBeDefined()
  60. })
  61. it('should pass muted prop to video element', () => {
  62. const wrapper = mount(VideoPlayer, {
  63. props: {
  64. src: 'https://example.com/video.mp4',
  65. playerType: 'native',
  66. muted: true
  67. }
  68. })
  69. expect(wrapper.find('video').attributes('muted')).toBeDefined()
  70. })
  71. it('should pass loop prop to video element', () => {
  72. const wrapper = mount(VideoPlayer, {
  73. props: {
  74. src: 'https://example.com/video.mp4',
  75. playerType: 'native',
  76. loop: true
  77. }
  78. })
  79. expect(wrapper.find('video').attributes('loop')).toBeDefined()
  80. })
  81. it('should pass poster prop to video element', () => {
  82. const poster = 'https://example.com/poster.jpg'
  83. const wrapper = mount(VideoPlayer, {
  84. props: {
  85. src: 'https://example.com/video.mp4',
  86. playerType: 'native',
  87. poster
  88. }
  89. })
  90. expect(wrapper.find('video').attributes('poster')).toBe(poster)
  91. })
  92. })
  93. describe('Cloudflare Stream Player', () => {
  94. it('should render iframe for cloudflare player type', () => {
  95. const wrapper = mount(VideoPlayer, {
  96. props: {
  97. videoId: 'test-video-id',
  98. playerType: 'cloudflare'
  99. }
  100. })
  101. expect(wrapper.find('iframe').exists()).toBe(true)
  102. })
  103. it('should generate correct iframe src', () => {
  104. const wrapper = mount(VideoPlayer, {
  105. props: {
  106. videoId: 'test-video-id',
  107. playerType: 'cloudflare',
  108. customerDomain: 'example.cloudflarestream.com'
  109. }
  110. })
  111. const iframeSrc = wrapper.find('iframe').attributes('src')
  112. expect(iframeSrc).toContain('https://example.cloudflarestream.com/test-video-id/iframe')
  113. })
  114. it('should include autoplay in iframe src when enabled', () => {
  115. const wrapper = mount(VideoPlayer, {
  116. props: {
  117. videoId: 'test-video-id',
  118. playerType: 'cloudflare',
  119. autoplay: true
  120. }
  121. })
  122. const iframeSrc = wrapper.find('iframe').attributes('src')
  123. expect(iframeSrc).toContain('autoplay=true')
  124. })
  125. it('should include muted in iframe src when enabled', () => {
  126. const wrapper = mount(VideoPlayer, {
  127. props: {
  128. videoId: 'test-video-id',
  129. playerType: 'cloudflare',
  130. muted: true
  131. }
  132. })
  133. const iframeSrc = wrapper.find('iframe').attributes('src')
  134. expect(iframeSrc).toContain('muted=true')
  135. })
  136. it('should include loop in iframe src when enabled', () => {
  137. const wrapper = mount(VideoPlayer, {
  138. props: {
  139. videoId: 'test-video-id',
  140. playerType: 'cloudflare',
  141. loop: true
  142. }
  143. })
  144. const iframeSrc = wrapper.find('iframe').attributes('src')
  145. expect(iframeSrc).toContain('loop=true')
  146. })
  147. })
  148. describe('HLS Player', () => {
  149. it('should render video element for HLS player type', () => {
  150. const wrapper = mount(VideoPlayer, {
  151. props: {
  152. src: 'https://example.com/stream.m3u8',
  153. playerType: 'hls'
  154. }
  155. })
  156. expect(wrapper.find('video').exists()).toBe(true)
  157. })
  158. })
  159. describe('Default Props', () => {
  160. it('should have default controls as true', () => {
  161. const wrapper = mount(VideoPlayer, {
  162. props: {
  163. src: 'https://example.com/video.mp4'
  164. }
  165. })
  166. expect(wrapper.find('video').attributes('controls')).toBeDefined()
  167. })
  168. it('should have default muted as true', () => {
  169. const wrapper = mount(VideoPlayer, {
  170. props: {
  171. src: 'https://example.com/video.mp4'
  172. }
  173. })
  174. expect(wrapper.find('video').attributes('muted')).toBeDefined()
  175. })
  176. it('should have default playerType as native', () => {
  177. const wrapper = mount(VideoPlayer, {
  178. props: {
  179. src: 'https://example.com/video.mp4'
  180. }
  181. })
  182. // Should render video element directly, not iframe
  183. expect(wrapper.find('video').exists()).toBe(true)
  184. expect(wrapper.find('iframe').exists()).toBe(false)
  185. })
  186. })
  187. describe('Exposed Methods', () => {
  188. it('should expose play method', () => {
  189. const wrapper = mount(VideoPlayer, {
  190. props: {
  191. src: 'https://example.com/video.mp4',
  192. playerType: 'native'
  193. }
  194. })
  195. expect(typeof wrapper.vm.play).toBe('function')
  196. })
  197. it('should expose pause method', () => {
  198. const wrapper = mount(VideoPlayer, {
  199. props: {
  200. src: 'https://example.com/video.mp4',
  201. playerType: 'native'
  202. }
  203. })
  204. expect(typeof wrapper.vm.pause).toBe('function')
  205. })
  206. it('should expose stop method', () => {
  207. const wrapper = mount(VideoPlayer, {
  208. props: {
  209. src: 'https://example.com/video.mp4',
  210. playerType: 'native'
  211. }
  212. })
  213. expect(typeof wrapper.vm.stop).toBe('function')
  214. })
  215. it('should expose setVolume method', () => {
  216. const wrapper = mount(VideoPlayer, {
  217. props: {
  218. src: 'https://example.com/video.mp4',
  219. playerType: 'native'
  220. }
  221. })
  222. expect(typeof wrapper.vm.setVolume).toBe('function')
  223. })
  224. it('should expose setMuted method', () => {
  225. const wrapper = mount(VideoPlayer, {
  226. props: {
  227. src: 'https://example.com/video.mp4',
  228. playerType: 'native'
  229. }
  230. })
  231. expect(typeof wrapper.vm.setMuted).toBe('function')
  232. })
  233. it('should expose screenshot method', () => {
  234. const wrapper = mount(VideoPlayer, {
  235. props: {
  236. src: 'https://example.com/video.mp4',
  237. playerType: 'native'
  238. }
  239. })
  240. expect(typeof wrapper.vm.screenshot).toBe('function')
  241. })
  242. it('should expose fullscreen method', () => {
  243. const wrapper = mount(VideoPlayer, {
  244. props: {
  245. src: 'https://example.com/video.mp4',
  246. playerType: 'native'
  247. }
  248. })
  249. expect(typeof wrapper.vm.fullscreen).toBe('function')
  250. })
  251. })
  252. describe('Wrapper Element', () => {
  253. it('should have video-player-wrapper class', () => {
  254. const wrapper = mount(VideoPlayer, {
  255. props: {
  256. src: 'https://example.com/video.mp4'
  257. }
  258. })
  259. expect(wrapper.find('.video-player-wrapper').exists()).toBe(true)
  260. })
  261. })
  262. })