aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/e2e/protractor.conf.js35
-rw-r--r--client/e2e/src/po/video-upload.po.ts16
-rw-r--r--client/e2e/src/po/video-watch.po.ts49
-rw-r--r--client/e2e/src/videos.e2e-spec.ts19
-rw-r--r--client/src/assets/player/peertube-player.ts16
-rw-r--r--client/src/assets/player/peertube-videojs-plugin.ts14
-rw-r--r--client/src/assets/player/utils.ts5
-rw-r--r--client/src/standalone/videos/embed.ts15
8 files changed, 99 insertions, 70 deletions
diff --git a/client/e2e/protractor.conf.js b/client/e2e/protractor.conf.js
index a4fd12473..5dcd77284 100644
--- a/client/e2e/protractor.conf.js
+++ b/client/e2e/protractor.conf.js
@@ -5,16 +5,14 @@ const {SpecReporter} = require('jasmine-spec-reporter')
5 5
6exports.config = { 6exports.config = {
7 allScriptsTimeout: 25000, 7 allScriptsTimeout: 25000,
8 specs: [ 8 specs: ['./src/**/*.e2e-spec.ts'],
9 './src/**/*.e2e-spec.ts'
10 ],
11 9
12 seleniumAddress: 'http://hub-cloud.browserstack.com/wd/hub', 10 seleniumAddress: 'http://hub-cloud.browserstack.com/wd/hub',
13 commonCapabilities: { 11 commonCapabilities: {
14 'browserstack.user': process.env.BROWSERSTACK_USER, 12 'browserstack.user': process.env.BROWSERSTACK_USER,
15 'browserstack.key': process.env.BROWSERSTACK_KEY, 13 'browserstack.key': process.env.BROWSERSTACK_KEY,
16 'browserstack.local': true, 14 'browserstack.local': true,
17 'project': 'PeerTube' 15 projec: 'PeerTube'
18 }, 16 },
19 17
20 multiCapabilities: [ 18 multiCapabilities: [
@@ -24,7 +22,8 @@ exports.config = {
24 }, 22 },
25 { 23 {
26 browserName: 'Safari', 24 browserName: 'Safari',
27 version: '11.1' 25 version: '11.1',
26 resolution: '1920x1080'
28 }, 27 },
29 { 28 {
30 browserName: 'Firefox', 29 browserName: 'Firefox',
@@ -44,35 +43,29 @@ exports.config = {
44 realMobile: 'true', 43 realMobile: 'true',
45 os_version: '5.0' 44 os_version: '5.0'
46 }, 45 },
47 // { 46 {
48 // browserName: 'Safari', 47 browserName: 'Safari',
49 // device: 'iPhone 6s', 48 device: 'iPhone SE',
50 // realMobile: 'true', 49 realMobile: 'true',
51 // os_version: '9.0' 50 os_version: '11.2'
52 // }, 51 }
53 // {
54 // browserName: 'Safari',
55 // device: 'iPhone SE',
56 // realMobile: 'true',
57 // os_version: '11.2'
58 // }
59 ], 52 ],
60 53
61 maxSessions: 1, 54 // maxSessions: 1,
62 // BrowserStack compatible ports: https://www.browserstack.com/question/664 55 // BrowserStack compatible ports: https://www.browserstack.com/question/664
63 baseUrl: 'http://localhost:3333/', 56 baseUrl: 'http://localhost:3333/',
64 framework: 'jasmine', 57 framework: 'jasmine',
65 jasmineNodeOpts: { 58 jasmineNodeOpts: {
66 showColors: true, 59 showColors: true,
67 defaultTimeoutInterval: 45000, 60 defaultTimeoutInterval: 45000,
68 print: function () {} 61 print: function() {}
69 }, 62 },
70 63
71 onPrepare () { 64 onPrepare() {
72 require('ts-node').register({ 65 require('ts-node').register({
73 project: require('path').join(__dirname, './tsconfig.e2e.json') 66 project: require('path').join(__dirname, './tsconfig.e2e.json')
74 }) 67 })
75 jasmine.getEnv().addReporter(new SpecReporter({spec: {displayStacktrace: true}})) 68 jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }))
76 } 69 }
77} 70}
78 71
diff --git a/client/e2e/src/po/video-upload.po.ts b/client/e2e/src/po/video-upload.po.ts
index 1ac696107..1978707e3 100644
--- a/client/e2e/src/po/video-upload.po.ts
+++ b/client/e2e/src/po/video-upload.po.ts
@@ -3,16 +3,26 @@ import { FileDetector } from 'selenium-webdriver/remote'
3import { join } from 'path' 3import { join } from 'path'
4 4
5export class VideoUploadPage { 5export class VideoUploadPage {
6 navigateTo () { 6 async navigateTo () {
7 return browser.get('/videos/upload') 7 await element(by.css('.header .upload-button')).click()
8
9 return browser.wait(browser.ExpectedConditions.visibilityOf(element(by.css('.upload-video-container'))))
8 } 10 }
9 11
10 async uploadVideo () { 12 async uploadVideo () {
11 browser.setFileDetector(new FileDetector()) 13 browser.setFileDetector(new FileDetector())
12 14
13 const fileToUpload = join(__dirname, '../../fixtures/video.mp4') 15 const fileToUpload = join(__dirname, '../../fixtures/video.mp4')
16 const fileInputSelector = '.upload-video-container input[type=file]'
17 const parentFileInput = '.upload-video .button-file'
18
19 // Avoid sending keys on non visible element
20 await browser.executeScript(`document.querySelector('${fileInputSelector}').style.opacity = 1`)
21 // await browser.executeScript(`document.querySelector('${fileInputSelector}').style.opacity = 1`)
22 await browser.executeScript(`document.querySelector('${parentFileInput}').style.overflow = 'initial'`)
14 23
15 await element(by.css('.upload-video-container input[type=file]')).sendKeys(fileToUpload) 24 const elem = element(by.css(fileInputSelector))
25 await elem.sendKeys(fileToUpload)
16 26
17 // Wait for the upload to finish 27 // Wait for the upload to finish
18 await browser.wait(browser.ExpectedConditions.elementToBeClickable(this.getSecondStepSubmitButton())) 28 await browser.wait(browser.ExpectedConditions.elementToBeClickable(this.getSecondStepSubmitButton()))
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts
index 0f37e3e33..19d02ff51 100644
--- a/client/e2e/src/po/video-watch.po.ts
+++ b/client/e2e/src/po/video-watch.po.ts
@@ -1,7 +1,7 @@
1import { by, element, browser } from 'protractor' 1import { by, element, browser } from 'protractor'
2 2
3export class VideoWatchPage { 3export class VideoWatchPage {
4 async goOnVideosList (isIphoneDevice: boolean) { 4 async goOnVideosList (isIphoneDevice: boolean, isSafari: boolean) {
5 let url: string 5 let url: string
6 6
7 if (isIphoneDevice === true) { 7 if (isIphoneDevice === true) {
@@ -12,11 +12,16 @@ export class VideoWatchPage {
12 } 12 }
13 13
14 await browser.get(url) 14 await browser.get(url)
15 return browser.wait(browser.ExpectedConditions.elementToBeClickable(element(this.getFirstVideoListSelector()))) 15
16 // Waiting the following element does not work on Safari...
17 if (isSafari === true) return browser.sleep(3000)
18
19 const elem = element.all(by.css('.videos .video-miniature .video-miniature-name')).first()
20 return browser.wait(browser.ExpectedConditions.visibilityOf(elem))
16 } 21 }
17 22
18 getVideosListName () { 23 getVideosListName () {
19 return element.all(this.getFirstVideoListSelector()) 24 return element.all(by.css('.videos .video-miniature .video-miniature-name'))
20 .getText() 25 .getText()
21 .then((texts: any) => texts.map(t => t.trim())) 26 .then((texts: any) => texts.map(t => t.trim()))
22 } 27 }
@@ -33,19 +38,19 @@ export class VideoWatchPage {
33 .then(seconds => parseInt(seconds, 10)) 38 .then(seconds => parseInt(seconds, 10))
34 } 39 }
35 40
36 async pauseVideo (pauseAfterMs: number, isMobileDevice: boolean, isIphoneDevice: boolean) { 41 async pauseVideo (pauseAfterMs: number, isAutoplay: boolean, isSafari: boolean) {
37 if (isMobileDevice === true) { 42 if (isAutoplay === false) {
38 if (isIphoneDevice === false) { 43 const playButton = element(by.css('.vjs-big-play-button'))
39 const playButton = element(by.css('.vjs-big-play-button')) 44 await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton))
40 await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton)) 45 await playButton.click()
41 await playButton.click() 46 }
42 } else { 47
43 const playButton = element(by.css('video')) 48 if (isSafari === true) {
44 await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton)) 49 await browser.sleep(1000)
45 await playButton.click() 50 await element(by.css('.vjs-play-control')).click()
46 }
47 } 51 }
48 52
53 await browser.sleep(1000)
49 await browser.wait(browser.ExpectedConditions.invisibilityOf(element(by.css('.vjs-loading-spinner')))) 54 await browser.wait(browser.ExpectedConditions.invisibilityOf(element(by.css('.vjs-loading-spinner'))))
50 55
51 const el = element(by.css('div.video-js')) 56 const el = element(by.css('div.video-js'))
@@ -53,11 +58,7 @@ export class VideoWatchPage {
53 58
54 await browser.sleep(pauseAfterMs) 59 await browser.sleep(pauseAfterMs)
55 60
56 if (isIphoneDevice === true) { 61 return el.click()
57 // document.webkitCancelFullScreen()
58 } else {
59 return el.click()
60 }
61 } 62 }
62 63
63 async clickOnVideo (videoName: string) { 64 async clickOnVideo (videoName: string) {
@@ -69,7 +70,7 @@ export class VideoWatchPage {
69 } 70 }
70 71
71 async clickOnFirstVideo () { 72 async clickOnFirstVideo () {
72 const video = element(by.css('.videos .video-miniature:first-child .video-miniature-name')) 73 const video = element.all(by.css('.videos .video-miniature .video-miniature-name')).first()
73 await browser.wait(browser.ExpectedConditions.elementToBeClickable(video)) 74 await browser.wait(browser.ExpectedConditions.elementToBeClickable(video))
74 const textToReturn = video.getText() 75 const textToReturn = video.getText()
75 76
@@ -79,7 +80,11 @@ export class VideoWatchPage {
79 return textToReturn 80 return textToReturn
80 } 81 }
81 82
82 private getFirstVideoListSelector () { 83 async goOnAssociatedEmbed () {
83 return by.css('.videos .video-miniature-name') 84 let url = await browser.getCurrentUrl()
85 url = url.replace('/watch/', '/embed/')
86 url = url.replace(':3333', ':9001')
87
88 return browser.get(url)
84 } 89 }
85} 90}
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts
index c21bc163e..f216f8dd1 100644
--- a/client/e2e/src/videos.e2e-spec.ts
+++ b/client/e2e/src/videos.e2e-spec.ts
@@ -10,6 +10,7 @@ describe('Videos workflow', () => {
10 const videoName = new Date().getTime() + ' video' 10 const videoName = new Date().getTime() + ' video'
11 let isMobileDevice = false 11 let isMobileDevice = false
12 let isIphoneDevice = false 12 let isIphoneDevice = false
13 let isSafari = false
13 14
14 beforeEach(async () => { 15 beforeEach(async () => {
15 browser.waitForAngularEnabled(false) 16 browser.waitForAngularEnabled(false)
@@ -21,6 +22,7 @@ describe('Videos workflow', () => {
21 const caps = await browser.getCapabilities() 22 const caps = await browser.getCapabilities()
22 isMobileDevice = caps.get('realMobile') === 'true' || caps.get('realMobile') === true 23 isMobileDevice = caps.get('realMobile') === 'true' || caps.get('realMobile') === true
23 isIphoneDevice = caps.get('device') === 'iphone' 24 isIphoneDevice = caps.get('device') === 'iphone'
25 isSafari = caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari'
24 }) 26 })
25 27
26 it('Should log in', () => { 28 it('Should log in', () => {
@@ -38,14 +40,14 @@ describe('Videos workflow', () => {
38 return 40 return
39 } 41 }
40 42
41 pageUploadPage.navigateTo() 43 await pageUploadPage.navigateTo()
42 44
43 await pageUploadPage.uploadVideo() 45 await pageUploadPage.uploadVideo()
44 return pageUploadPage.validSecondUploadStep(videoName) 46 return pageUploadPage.validSecondUploadStep(videoName)
45 }) 47 })
46 48
47 it('Should list the video', async () => { 49 it('Should list the video', async () => {
48 await videoWatchPage.goOnVideosList(isIphoneDevice) 50 await videoWatchPage.goOnVideosList(isIphoneDevice, isSafari)
49 51
50 if (isMobileDevice) { 52 if (isMobileDevice) {
51 console.log('Skipping because we are on a real device and BrowserStack does not support file upload.') 53 console.log('Skipping because we are on a real device and BrowserStack does not support file upload.')
@@ -59,16 +61,21 @@ describe('Videos workflow', () => {
59 it('Should go on video watch page', async () => { 61 it('Should go on video watch page', async () => {
60 let videoNameToExcept = videoName 62 let videoNameToExcept = videoName
61 63
62 if (isMobileDevice && isIphoneDevice) videoNameToExcept = 'PeerTube_Mobile.v.1' 64 if (isMobileDevice) videoNameToExcept = await videoWatchPage.clickOnFirstVideo()
63
64 if (isMobileDevice && isIphoneDevice === false) videoNameToExcept = await videoWatchPage.clickOnFirstVideo()
65 else await videoWatchPage.clickOnVideo(videoName) 65 else await videoWatchPage.clickOnVideo(videoName)
66 66
67 return videoWatchPage.waitWatchVideoName(videoNameToExcept) 67 return videoWatchPage.waitWatchVideoName(videoNameToExcept)
68 }) 68 })
69 69
70 it('Should play the video', async () => { 70 it('Should play the video', async () => {
71 await videoWatchPage.pauseVideo(7000, isMobileDevice, isIphoneDevice) 71 await videoWatchPage.pauseVideo(7000, !isMobileDevice, isSafari)
72 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
73 })
74
75 it('Should watch the associated embed video', async () => {
76 await videoWatchPage.goOnAssociatedEmbed()
77
78 await videoWatchPage.pauseVideo(7000, false, isSafari)
72 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 79 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
73 }) 80 })
74}) 81})
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts
index 2e77a973f..f419d58fc 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/assets/player/peertube-player.ts
@@ -1,21 +1,5 @@
1import { VideoFile } from '../../../../shared/models/videos' 1import { VideoFile } from '../../../../shared/models/videos'
2 2
3import 'core-js/es6/symbol';
4import 'core-js/es6/object';
5import 'core-js/es6/function';
6import 'core-js/es6/parse-int';
7import 'core-js/es6/parse-float';
8import 'core-js/es6/number';
9import 'core-js/es6/math';
10import 'core-js/es6/string';
11import 'core-js/es6/date';
12import 'core-js/es6/array';
13import 'core-js/es6/regexp';
14import 'core-js/es6/map';
15import 'core-js/es6/weak-map';
16import 'core-js/es6/set';
17import 'core-js/es7/object';
18
19import 'videojs-hotkeys' 3import 'videojs-hotkeys'
20import 'videojs-dock' 4import 'videojs-dock'
21import './peertube-link-button' 5import './peertube-link-button'
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts
index 5789641fe..1e68100d1 100644
--- a/client/src/assets/player/peertube-videojs-plugin.ts
+++ b/client/src/assets/player/peertube-videojs-plugin.ts
@@ -4,7 +4,15 @@ import { VideoFile } from '../../../../shared/models/videos/video.model'
4import { renderVideo } from './video-renderer' 4import { renderVideo } from './video-renderer'
5import './settings-menu-button' 5import './settings-menu-button'
6import { PeertubePluginOptions, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 6import { PeertubePluginOptions, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
7import { getAverageBandwidth, getStoredMute, getStoredVolume, saveAverageBandwidth, saveMuteInStore, saveVolumeInStore } from './utils' 7import {
8 getAverageBandwidth,
9 getStoredMute,
10 getStoredVolume,
11 isMobile,
12 saveAverageBandwidth,
13 saveMuteInStore,
14 saveVolumeInStore
15} from './utils'
8import minBy from 'lodash-es/minBy' 16import minBy from 'lodash-es/minBy'
9import maxBy from 'lodash-es/maxBy' 17import maxBy from 'lodash-es/maxBy'
10import * as CacheChunkStore from 'cache-chunk-store' 18import * as CacheChunkStore from 'cache-chunk-store'
@@ -262,7 +270,6 @@ class PeerTubePlugin extends Plugin {
262 270
263 private tryToPlay (done?: Function) { 271 private tryToPlay (done?: Function) {
264 if (!done) done = function () { /* empty */ } 272 if (!done) done = function () { /* empty */ }
265
266 const playPromise = this.player.play() 273 const playPromise = this.player.play()
267 if (playPromise !== undefined) { 274 if (playPromise !== undefined) {
268 return playPromise.then(done) 275 return playPromise.then(done)
@@ -348,6 +355,9 @@ class PeerTubePlugin extends Plugin {
348 // Proxy first play 355 // Proxy first play
349 const oldPlay = this.player.play.bind(this.player) 356 const oldPlay = this.player.play.bind(this.player)
350 this.player.play = () => { 357 this.player.play = () => {
358 // Avoid issue new play policy on mobiles
359 if (isMobile()) oldPlay()
360
351 this.player.addClass('vjs-has-big-play-button-clicked') 361 this.player.addClass('vjs-has-big-play-button-clicked')
352 this.player.play = oldPlay 362 this.player.play = oldPlay
353 363
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts
index f5407ef60..1df39d4e4 100644
--- a/client/src/assets/player/utils.ts
+++ b/client/src/assets/player/utils.ts
@@ -60,6 +60,10 @@ function saveAverageBandwidth (value: number) {
60 return setLocalStorage('average-bandwidth', value.toString()) 60 return setLocalStorage('average-bandwidth', value.toString())
61} 61}
62 62
63function isMobile () {
64 return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
65}
66
63export { 67export {
64 toTitleCase, 68 toTitleCase,
65 getStoredVolume, 69 getStoredVolume,
@@ -68,6 +72,7 @@ export {
68 getAverageBandwidth, 72 getAverageBandwidth,
69 saveMuteInStore, 73 saveMuteInStore,
70 getStoredMute, 74 getStoredMute,
75 isMobile,
71 bytes 76 bytes
72} 77}
73 78
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index c88219242..ba906cc32 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -1,5 +1,20 @@
1import './embed.scss' 1import './embed.scss'
2 2
3import 'core-js/es6/symbol'
4import 'core-js/es6/object'
5import 'core-js/es6/function'
6import 'core-js/es6/parse-int'
7import 'core-js/es6/parse-float'
8import 'core-js/es6/number'
9import 'core-js/es6/math'
10import 'core-js/es6/string'
11import 'core-js/es6/date'
12import 'core-js/es6/array'
13import 'core-js/es6/regexp'
14import 'core-js/es6/map'
15import 'core-js/es6/weak-map'
16import 'core-js/es6/set'
17
3// For google bot that uses Chrome 41 and does not understand fetch 18// For google bot that uses Chrome 41 and does not understand fetch
4import 'whatwg-fetch' 19import 'whatwg-fetch'
5 20