视频播放器仓库

video.test.js 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import React from 'react';
  2. import { mount, shallow } from 'enzyme';
  3. import video from './video';
  4. import { EVENTS } from './constants';
  5. const TestControl = ({ duration }) => {
  6. return (
  7. <div>
  8. { duration }
  9. </div>
  10. );
  11. };
  12. const TestVideo = ({ video, ...restProps }) => {
  13. // Remove `videoEl` so we do not spread an unsupported
  14. // prop onto a DOM element.
  15. delete restProps.videoEl;
  16. return (
  17. <div>
  18. <video {...restProps}>
  19. <source src="1" />
  20. </video>
  21. <TestControl {...video} />
  22. </div>
  23. );
  24. };
  25. describe('video', () => {
  26. let Component;
  27. let component;
  28. beforeAll(() => {
  29. Component = video(TestVideo);
  30. });
  31. describe('the wrapped component', () => {
  32. beforeEach(() => {
  33. component = mount(
  34. <Component autoPlay />
  35. );
  36. });
  37. describe('HTMLMediaElement API as props', () => {
  38. let testControl;
  39. beforeEach(() => {
  40. component = mount(
  41. <Component autoPlay />
  42. );
  43. testControl = component.find(TestControl);
  44. expect(testControl.props()).toEqual({});
  45. });
  46. it('should be provided when a video event is triggered', () => {
  47. component.find('video').node.dispatchEvent(new Event('play'));
  48. });
  49. it('should be provided when an error occurs on last source element', () => {
  50. component.find('source').node.dispatchEvent(new Event('error'));
  51. });
  52. afterEach(() => {
  53. // Only matching a subset is sufficient.
  54. expect(testControl.props()).toMatchObject({
  55. controller: undefined,
  56. autoPlay: undefined,
  57. controls: false,
  58. currentSrc: '',
  59. currentTime: 0,
  60. defaultMuted: false,
  61. defaultPlaybackRate: 1,
  62. duration: 0,
  63. ended: false,
  64. error: undefined,
  65. loop: false,
  66. mediaGroup: undefined,
  67. muted: false,
  68. networkState: 0,
  69. paused: true,
  70. playbackRate: 1,
  71. preload: '',
  72. readyState: 0,
  73. seeking: false,
  74. src: '',
  75. startDate: undefined,
  76. volume: 1
  77. });
  78. });
  79. });
  80. it('should remove all event listeners from the video element when unmounted', () => {
  81. const removeEventListenerSpy = jest.fn();
  82. component = mount(
  83. <Component autoPlay />
  84. );
  85. const updateState = component.instance().updateState;
  86. component.find('video').node.removeEventListener = removeEventListenerSpy;
  87. expect(removeEventListenerSpy).not.toHaveBeenCalled();
  88. component.unmount();
  89. EVENTS.forEach((event) => {
  90. expect(removeEventListenerSpy).toHaveBeenCalledWith(event.toLowerCase(), updateState);
  91. });
  92. });
  93. it('should remove "error" event listener from the source element when unmounted', () => {
  94. const removeEventListenerSpy = jest.fn();
  95. component = mount(
  96. <Component autoPlay />
  97. );
  98. const updateState = component.instance().updateState;
  99. component.find('source').node.removeEventListener = removeEventListenerSpy;
  100. expect(removeEventListenerSpy).not.toHaveBeenCalled();
  101. component.unmount();
  102. expect(removeEventListenerSpy).toHaveBeenCalledWith('error', updateState);
  103. });
  104. });
  105. describe('mapping to props', () => {
  106. let videoEl = {};
  107. beforeAll(() => {
  108. component = shallow(
  109. <Component autoPlay />
  110. );
  111. // Emulate videoEl being present
  112. // e.g. componentDidMount fired.
  113. component.instance().videoEl = videoEl;
  114. component.instance().forceUpdate();
  115. });
  116. beforeEach(() => {
  117. // Reset spy
  118. videoEl.play = jest.fn();
  119. });
  120. it('returns a component with it\'s ownProps', () => {
  121. expect(component.find(TestVideo).prop('autoPlay'))
  122. .toBe(true);
  123. });
  124. it('returns a component with a videoEl prop', () => {
  125. expect(component.find(TestVideo).prop('videoEl'))
  126. .toBe(videoEl);
  127. });
  128. it('returns a component with all of its state on the `video` prop', () => {
  129. const state = {
  130. html5: '1',
  131. dom: 2,
  132. properties: function() {
  133. return 3;
  134. }
  135. };
  136. component.setState(state);
  137. expect(component.find(TestVideo).prop('video'))
  138. .toEqual(state);
  139. });
  140. it('can customise the mapping of props using mapToProps', () => {
  141. const Component = video(TestVideo, (state, ownProps) => {
  142. return {
  143. state,
  144. ownProps
  145. };
  146. });
  147. const component = shallow(
  148. <Component autoPlay />
  149. );
  150. component.setState({
  151. paused: true
  152. });
  153. expect(component.find(TestVideo).prop('state').paused)
  154. .toBe(true);
  155. expect(component.find(TestVideo).prop('ownProps').autoPlay)
  156. .toBe(true);
  157. });
  158. it('can map videoEl to props for creating custom API methods', () => {
  159. const Component = video(TestVideo, undefined, (el, state, ownProps) => {
  160. return {
  161. togglePlay: () => {
  162. el.play(ownProps.testProp);
  163. }
  164. }
  165. });
  166. const component = shallow(
  167. <Component autoPlay testProp="testValue" />
  168. );
  169. component.instance().videoEl = videoEl;
  170. component.instance().forceUpdate();
  171. component.find(TestVideo).prop('togglePlay')();
  172. expect(videoEl.play).toHaveBeenCalledWith('testValue');
  173. });
  174. it('allows mapVideoElToProps to take precedence over mapStateToProps', () => {
  175. const Component = video(TestVideo, () => ({
  176. duplicateKey: 'mapStateToProps'
  177. }), () => ({
  178. duplicateKey: 'mapVideoElToProps'
  179. }));
  180. const component = shallow(
  181. <Component />
  182. );
  183. expect(component.find(TestVideo).prop('duplicateKey')).toBe('mapVideoElToProps');
  184. });
  185. it('allows ownProps to take precedence over mapVideoElToProps and mapStateToProps', () => {
  186. const Component = video(TestVideo, () => ({
  187. duplicateKey: 'mapStateToProps'
  188. }), () => ({
  189. duplicateKey: 'mapVideoElToProps'
  190. }));
  191. const component = shallow(
  192. <Component duplicateKey="ownProps" />
  193. );
  194. expect(component.find(TestVideo).prop('duplicateKey')).toBe('ownProps');
  195. });
  196. it('allows cusomtisation of merging ownProps, mapVideoElToProps and mapStateToProps to change the merging precedence', () => {
  197. const Component = video(TestVideo, () => ({
  198. duplicateKey: 'mapStateToProps'
  199. }), () => ({
  200. duplicateKey: 'mapVideoElToProps'
  201. }), (stateProps, videoElProps, ownProps) =>
  202. Object.assign({}, ownProps, stateProps, videoElProps));
  203. const component = shallow(
  204. <Component duplicateKey="ownProps" />
  205. );
  206. expect(component.find(TestVideo).prop('duplicateKey')).toBe('mapVideoElToProps');
  207. });
  208. });
  209. });