video.test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. jest.setTimeout(60000);
  2. const platformInfo = process.env.uniTestPlatformInfo.toLocaleLowerCase()
  3. const isAndroid = platformInfo.startsWith('android')
  4. const isHarmony = platformInfo.startsWith('harmony')
  5. const isIOS = platformInfo.startsWith('ios')
  6. const isMP = platformInfo.startsWith('mp')
  7. const isWeb = platformInfo.startsWith('web')
  8. const isAppWebView = process.env.UNI_AUTOMATOR_APP_WEBVIEW == 'true'
  9. describe('component-native-video', () => {
  10. if (isWeb || isAppWebView) {
  11. // TODO: web 端暂不支持测试
  12. it('web', async () => {
  13. expect(1).toBe(1)
  14. })
  15. return
  16. }
  17. let page;
  18. let start = 0;
  19. beforeAll(async () => {
  20. page = await program.reLaunch('/pages/component/video/video');
  21. if (isWeb) {
  22. await page.setData({
  23. muted: true
  24. });
  25. }
  26. await page.$('.video');
  27. });
  28. it('screenshot', async () => {
  29. // 等待视频封面图加载完成
  30. await page.waitFor(2000);
  31. const image = await program.screenshot({ fullPage: true });
  32. expect(image).toSaveImageSnapshot();
  33. });
  34. it('test play pause', async () => {
  35. expect(await page.data('isError')).toBe(false);
  36. // play
  37. await page.callMethod('play');
  38. await page.waitFor(3000);
  39. expect(await page.data('isPlaying')).toBe(true);
  40. // pause
  41. await page.callMethod('pause');
  42. await page.waitFor(3000);
  43. expect(await page.data('isPause')).toBe(true);
  44. });
  45. if (!isMP) {
  46. it('test download source', async () => {
  47. await page.setData({
  48. autoTest: true,
  49. isError: false
  50. });
  51. const oldSrc = await page.data('src');
  52. await page.callMethod('downloadSource');
  53. await page.waitFor(5000);
  54. expect(await page.data('isError')).toBe(false);
  55. await page.setData({
  56. src: oldSrc
  57. });
  58. // 在性能差一些的 harmony 机器上,设置 src 后再次播放可能需要等待一段时间
  59. await page.waitFor(2000);
  60. });
  61. it('test video local mp4', async () => {
  62. await page.setData({
  63. autoTest: true,
  64. isError: false
  65. });
  66. const oldSrc = await page.data('src');
  67. await page.setData({
  68. src: '/static/test-video/10second-demo.mp4'
  69. });
  70. await page.waitFor(1000);
  71. expect(await page.data('isError')).toBe(false);
  72. await page.setData({
  73. src: oldSrc
  74. });
  75. // 在性能差一些的 harmony 机器上,设置 src 后再次播放可能需要等待一段时间
  76. await page.waitFor(2000);
  77. })
  78. // 鸿蒙不播放本地 m3u8
  79. if (!isHarmony) {
  80. it('test video local m3u8', async () => {
  81. await page.setData({
  82. autoTest: true,
  83. isError: false
  84. });
  85. const oldSrc = await page.data('src');
  86. await page.setData({
  87. src: '/static/test-video/2minute-demo.m3u8'
  88. });
  89. await page.waitFor(100);
  90. expect(await page.data('isError')).toBe(false);
  91. await page.setData({
  92. src: oldSrc
  93. });
  94. })
  95. }
  96. if (isAndroid) {
  97. it('android test assets path', async () => {
  98. const oldSrc = await page.data('src');
  99. await page.setData({
  100. isError: false,
  101. src: 'file:///android_asset/uni-autoTest/demo10s.mp4'
  102. });
  103. await page.waitFor(500);
  104. expect(await page.data('isError')).toBe(false);
  105. await page.setData({
  106. src: oldSrc
  107. });
  108. });
  109. }
  110. }
  111. it('test event play pause controls toggle', async () => {
  112. await page.setData({
  113. isPause: false,
  114. isPlaying: false,
  115. autoTest: true,
  116. });
  117. await page.callMethod('play');
  118. start = Date.now();
  119. await page.waitFor(async () => {
  120. return (await page.data('isPlaying')) || (Date.now() - start > 3000);
  121. });
  122. start = Date.now();
  123. await page.waitFor(async () => {
  124. return (await page.data('eventPlay')) || (Date.now() - start > 500);
  125. });
  126. if (!isIOS) {
  127. expect(await page.data('eventPlay')).toEqual({
  128. tagName: 'VIDEO',
  129. type: 'play'
  130. });
  131. }
  132. await page.callMethod('pause');
  133. start = Date.now();
  134. await page.waitFor(async () => {
  135. return (await page.data('isPause')) || (Date.now() - start > 3000);
  136. });
  137. start = Date.now();
  138. await page.waitFor(async () => {
  139. return (await page.data('eventPause')) || (Date.now() - start > 1000);
  140. });
  141. if (!isIOS) {
  142. expect(await page.data('eventPause')).toEqual({
  143. tagName: 'VIDEO',
  144. type: 'pause'
  145. });
  146. }
  147. if (isAndroid || isIOS) {
  148. /**
  149. * app端video组件controlstoggle事件会在controls显示和隐藏触发(播放、暂停等操作都会触发)。
  150. * 微信小程序、web、鸿蒙播放暂停或者一些其他的操作也会影响controls的显隐,但是不会触发controlstoggle, 只有controls属性变化的时候才会触发
  151. */
  152. await page.callMethod('play');
  153. start = Date.now();
  154. await page.waitFor(async () => {
  155. return (await page.data('eventControlstoggle')) || (Date.now() - start > 1000);
  156. });
  157. if (process.env.uniTestPlatformInfo.toLowerCase().startsWith('ios')) {
  158. // expect(await page.data('eventControlstoggle')).toEqual({
  159. // tagName: 'VIDEO',
  160. // type: 'controlstoggle',
  161. // show: true
  162. // });
  163. } else {
  164. expect(await page.data('eventControlstoggle')).toEqual({
  165. tagName: 'VIDEO',
  166. type: 'controlstoggle',
  167. show: true
  168. });
  169. }
  170. }
  171. });
  172. if (isAndroid || isHarmony) {
  173. if (isAndroid) {
  174. it('test event waiting progress', async () => {
  175. await page.callMethod('seek', 10);
  176. start = Date.now();
  177. await page.waitFor(async () => {
  178. return ((await page.data('eventWaiting')) && (await page.data('eventProgress'))) || (Date.now() - start > 1000);
  179. });
  180. expect(await page.data('eventWaiting')).toEqual({
  181. tagName: 'VIDEO',
  182. type: 'waiting'
  183. });
  184. expect(await page.data('eventProgress')).toEqual({
  185. tagName: 'VIDEO',
  186. type: 'progress',
  187. isBufferedValid: true
  188. });
  189. });
  190. }
  191. it('test event fullscreenchange fullscreenclick', async () => {
  192. await page.callMethod('requestFullScreen');
  193. start = Date.now();
  194. await page.waitFor(async () => {
  195. return (await page.data('eventFullscreenchange')) || (Date.now() - start > 1000);
  196. });
  197. expect(await page.data('eventFullscreenchange')).toEqual({
  198. tagName: 'VIDEO',
  199. type: 'fullscreenchange',
  200. fullScreen: true,
  201. direction: 'horizontal'
  202. });
  203. const infos = process.env.uniTestPlatformInfo.split(' ');
  204. const version = parseInt(infos[infos.length - 1]);
  205. if (isAndroid && version >5) { // android5.1模拟器全屏时会弹出系统提示框,无法响应adb tap命令
  206. await page.waitFor(5000);
  207. await program.adbCommand('input tap 10 10');
  208. start = Date.now();
  209. await page.waitFor(async () => {
  210. return (await page.data('eventFullscreenclick')) || (Date.now() - start > 1000);
  211. });
  212. const res = await program.adbCommand('wm size');
  213. const width = res.data.split(' ').at(-1).split('x')[0];
  214. const height = res.data.split(' ').at(-1).split('x')[1];
  215. const res2 = await program.adbCommand('wm density');
  216. const scale = res2.data.split(' ').at(-1) / 160;
  217. expect(await page.data('eventFullscreenclick')).toEqual({
  218. tagName: 'VIDEO',
  219. type: 'fullscreenclick',
  220. screenX: parseInt(10 / scale),
  221. screenY: parseInt(10 / scale),
  222. screenWidth: parseInt(height / scale),
  223. screenHeight: parseInt(width / scale)
  224. });
  225. }
  226. await page.callMethod('exitFullScreen');
  227. });
  228. it('test event ended timeupdate', async () => {
  229. await page.callMethod('seek', 120);
  230. if (isAndroid) {
  231. start = Date.now();
  232. await page.waitFor(async () => {
  233. return (await page.data('eventEnded')) || (Date.now() - start > 30000);
  234. });
  235. expect(await page.data('eventEnded')).toEqual({
  236. tagName: 'VIDEO',
  237. type: 'ended'
  238. });
  239. }
  240. await page.waitFor(3000);
  241. const infos = process.env.uniTestPlatformInfo.split(' ');
  242. const version = parseInt(infos[infos.length - 1]);
  243. if ((isAndroid && version > 5) || isHarmony) {
  244. let currentTime = 121
  245. if (isHarmony) currentTime = 120
  246. start = Date.now();
  247. await page.waitFor(async () => {
  248. return (await page.data('eventTimeupdate')) || (Date.now() - start > 500);
  249. });
  250. expect(await page.data('eventTimeupdate')).toEqual({
  251. tagName: 'VIDEO',
  252. type: 'timeupdate',
  253. currentTime,
  254. duration: 121
  255. });
  256. }
  257. });
  258. it('test event error', async () => {
  259. const oldSrc = await page.data('src');
  260. await page.setData({
  261. src: 'invalid url'
  262. });
  263. start = Date.now();
  264. await page.waitFor(async () => {
  265. return (await page.data('eventError')) || (Date.now() - start > 1000);
  266. });
  267. const eventError = await page.data('eventError')
  268. expect(eventError.tagName).toEqual('VIDEO')
  269. expect(eventError.type).toEqual('error')
  270. if (!isHarmony) {
  271. expect(eventError.errCode).toEqual(300001)
  272. } else {
  273. // 鸿蒙 video onError 没有错误信息,恒为 200001 内部错误
  274. expect(eventError.errCode).toEqual(200001)
  275. }
  276. await page.setData({
  277. autoTest: false,
  278. src: oldSrc
  279. });
  280. });
  281. if (isAndroid) {
  282. it('test sub component', async () => {
  283. await page.setData({
  284. subCompEnable: true,
  285. subCompShow: true
  286. });
  287. await page.waitFor(100);
  288. expect(await page.callMethod('hasSubComponent')).toBe(true);
  289. });
  290. }
  291. it('test enable-danmu', async () => {
  292. await page.callMethod('play');
  293. await page.waitFor(5000);
  294. await page.setData({
  295. enableDanmu: false
  296. });
  297. const windowInfo = await program.callUniMethod('getWindowInfo');
  298. const image = await program.screenshot({
  299. deviceShot: true,
  300. area: {
  301. x: 0,
  302. y: windowInfo.statusBarHeight + 44
  303. }
  304. });
  305. expect(image).toSaveImageSnapshot();
  306. });
  307. }
  308. it('test format', async () => {
  309. page = await program.navigateTo('/pages/component/video/video-format');
  310. await page.waitFor(1000);
  311. expect((await page.data('isError')).value).toBe(false);
  312. });
  313. });