From d1bd87e066633b8a66266b280327ec828980916b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 22 May 2018 16:02:29 +0200 Subject: [PATCH] Make it works with new autoplay policy --- client/e2e/protractor.conf.js | 35 ++++++------- client/e2e/src/po/video-upload.po.ts | 16 ++++-- client/e2e/src/po/video-watch.po.ts | 49 ++++++++++--------- client/e2e/src/videos.e2e-spec.ts | 19 ++++--- client/src/assets/player/peertube-player.ts | 16 ------ .../assets/player/peertube-videojs-plugin.ts | 14 +++++- client/src/assets/player/utils.ts | 5 ++ client/src/standalone/videos/embed.ts | 15 ++++++ package.json | 2 +- scripts/e2e.sh | 1 + 10 files changed, 101 insertions(+), 71 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') exports.config = { allScriptsTimeout: 25000, - specs: [ - './src/**/*.e2e-spec.ts' - ], + specs: ['./src/**/*.e2e-spec.ts'], seleniumAddress: 'http://hub-cloud.browserstack.com/wd/hub', commonCapabilities: { 'browserstack.user': process.env.BROWSERSTACK_USER, 'browserstack.key': process.env.BROWSERSTACK_KEY, 'browserstack.local': true, - 'project': 'PeerTube' + projec: 'PeerTube' }, multiCapabilities: [ @@ -24,7 +22,8 @@ exports.config = { }, { browserName: 'Safari', - version: '11.1' + version: '11.1', + resolution: '1920x1080' }, { browserName: 'Firefox', @@ -44,35 +43,29 @@ exports.config = { realMobile: 'true', os_version: '5.0' }, - // { - // browserName: 'Safari', - // device: 'iPhone 6s', - // realMobile: 'true', - // os_version: '9.0' - // }, - // { - // browserName: 'Safari', - // device: 'iPhone SE', - // realMobile: 'true', - // os_version: '11.2' - // } + { + browserName: 'Safari', + device: 'iPhone SE', + realMobile: 'true', + os_version: '11.2' + } ], - maxSessions: 1, + // maxSessions: 1, // BrowserStack compatible ports: https://www.browserstack.com/question/664 baseUrl: 'http://localhost:3333/', framework: 'jasmine', jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 45000, - print: function () {} + print: function() {} }, - onPrepare () { + onPrepare() { require('ts-node').register({ project: require('path').join(__dirname, './tsconfig.e2e.json') }) - jasmine.getEnv().addReporter(new SpecReporter({spec: {displayStacktrace: true}})) + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })) } } 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' import { join } from 'path' export class VideoUploadPage { - navigateTo () { - return browser.get('/videos/upload') + async navigateTo () { + await element(by.css('.header .upload-button')).click() + + return browser.wait(browser.ExpectedConditions.visibilityOf(element(by.css('.upload-video-container')))) } async uploadVideo () { browser.setFileDetector(new FileDetector()) const fileToUpload = join(__dirname, '../../fixtures/video.mp4') + const fileInputSelector = '.upload-video-container input[type=file]' + const parentFileInput = '.upload-video .button-file' - await element(by.css('.upload-video-container input[type=file]')).sendKeys(fileToUpload) + // Avoid sending keys on non visible element + await browser.executeScript(`document.querySelector('${fileInputSelector}').style.opacity = 1`) + // await browser.executeScript(`document.querySelector('${fileInputSelector}').style.opacity = 1`) + await browser.executeScript(`document.querySelector('${parentFileInput}').style.overflow = 'initial'`) + + const elem = element(by.css(fileInputSelector)) + await elem.sendKeys(fileToUpload) // Wait for the upload to finish 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 @@ import { by, element, browser } from 'protractor' export class VideoWatchPage { - async goOnVideosList (isIphoneDevice: boolean) { + async goOnVideosList (isIphoneDevice: boolean, isSafari: boolean) { let url: string if (isIphoneDevice === true) { @@ -12,11 +12,16 @@ export class VideoWatchPage { } await browser.get(url) - return browser.wait(browser.ExpectedConditions.elementToBeClickable(element(this.getFirstVideoListSelector()))) + + // Waiting the following element does not work on Safari... + if (isSafari === true) return browser.sleep(3000) + + const elem = element.all(by.css('.videos .video-miniature .video-miniature-name')).first() + return browser.wait(browser.ExpectedConditions.visibilityOf(elem)) } getVideosListName () { - return element.all(this.getFirstVideoListSelector()) + return element.all(by.css('.videos .video-miniature .video-miniature-name')) .getText() .then((texts: any) => texts.map(t => t.trim())) } @@ -33,19 +38,19 @@ export class VideoWatchPage { .then(seconds => parseInt(seconds, 10)) } - async pauseVideo (pauseAfterMs: number, isMobileDevice: boolean, isIphoneDevice: boolean) { - if (isMobileDevice === true) { - if (isIphoneDevice === false) { - const playButton = element(by.css('.vjs-big-play-button')) - await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton)) - await playButton.click() - } else { - const playButton = element(by.css('video')) - await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton)) - await playButton.click() - } + async pauseVideo (pauseAfterMs: number, isAutoplay: boolean, isSafari: boolean) { + if (isAutoplay === false) { + const playButton = element(by.css('.vjs-big-play-button')) + await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton)) + await playButton.click() } + if (isSafari === true) { + await browser.sleep(1000) + await element(by.css('.vjs-play-control')).click() + } + + await browser.sleep(1000) await browser.wait(browser.ExpectedConditions.invisibilityOf(element(by.css('.vjs-loading-spinner')))) const el = element(by.css('div.video-js')) @@ -53,11 +58,7 @@ export class VideoWatchPage { await browser.sleep(pauseAfterMs) - if (isIphoneDevice === true) { - // document.webkitCancelFullScreen() - } else { - return el.click() - } + return el.click() } async clickOnVideo (videoName: string) { @@ -69,7 +70,7 @@ export class VideoWatchPage { } async clickOnFirstVideo () { - const video = element(by.css('.videos .video-miniature:first-child .video-miniature-name')) + const video = element.all(by.css('.videos .video-miniature .video-miniature-name')).first() await browser.wait(browser.ExpectedConditions.elementToBeClickable(video)) const textToReturn = video.getText() @@ -79,7 +80,11 @@ export class VideoWatchPage { return textToReturn } - private getFirstVideoListSelector () { - return by.css('.videos .video-miniature-name') + async goOnAssociatedEmbed () { + let url = await browser.getCurrentUrl() + url = url.replace('/watch/', '/embed/') + url = url.replace(':3333', ':9001') + + return browser.get(url) } } 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', () => { const videoName = new Date().getTime() + ' video' let isMobileDevice = false let isIphoneDevice = false + let isSafari = false beforeEach(async () => { browser.waitForAngularEnabled(false) @@ -21,6 +22,7 @@ describe('Videos workflow', () => { const caps = await browser.getCapabilities() isMobileDevice = caps.get('realMobile') === 'true' || caps.get('realMobile') === true isIphoneDevice = caps.get('device') === 'iphone' + isSafari = caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari' }) it('Should log in', () => { @@ -38,14 +40,14 @@ describe('Videos workflow', () => { return } - pageUploadPage.navigateTo() + await pageUploadPage.navigateTo() await pageUploadPage.uploadVideo() return pageUploadPage.validSecondUploadStep(videoName) }) it('Should list the video', async () => { - await videoWatchPage.goOnVideosList(isIphoneDevice) + await videoWatchPage.goOnVideosList(isIphoneDevice, isSafari) if (isMobileDevice) { console.log('Skipping because we are on a real device and BrowserStack does not support file upload.') @@ -59,16 +61,21 @@ describe('Videos workflow', () => { it('Should go on video watch page', async () => { let videoNameToExcept = videoName - if (isMobileDevice && isIphoneDevice) videoNameToExcept = 'PeerTube_Mobile.v.1' - - if (isMobileDevice && isIphoneDevice === false) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() + if (isMobileDevice) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() else await videoWatchPage.clickOnVideo(videoName) return videoWatchPage.waitWatchVideoName(videoNameToExcept) }) it('Should play the video', async () => { - await videoWatchPage.pauseVideo(7000, isMobileDevice, isIphoneDevice) + await videoWatchPage.pauseVideo(7000, !isMobileDevice, isSafari) + expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) + }) + + it('Should watch the associated embed video', async () => { + await videoWatchPage.goOnAssociatedEmbed() + + await videoWatchPage.pauseVideo(7000, false, isSafari) expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) }) }) 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 @@ import { VideoFile } from '../../../../shared/models/videos' -import 'core-js/es6/symbol'; -import 'core-js/es6/object'; -import 'core-js/es6/function'; -import 'core-js/es6/parse-int'; -import 'core-js/es6/parse-float'; -import 'core-js/es6/number'; -import 'core-js/es6/math'; -import 'core-js/es6/string'; -import 'core-js/es6/date'; -import 'core-js/es6/array'; -import 'core-js/es6/regexp'; -import 'core-js/es6/map'; -import 'core-js/es6/weak-map'; -import 'core-js/es6/set'; -import 'core-js/es7/object'; - import 'videojs-hotkeys' import 'videojs-dock' import './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' import { renderVideo } from './video-renderer' import './settings-menu-button' import { PeertubePluginOptions, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' -import { getAverageBandwidth, getStoredMute, getStoredVolume, saveAverageBandwidth, saveMuteInStore, saveVolumeInStore } from './utils' +import { + getAverageBandwidth, + getStoredMute, + getStoredVolume, + isMobile, + saveAverageBandwidth, + saveMuteInStore, + saveVolumeInStore +} from './utils' import minBy from 'lodash-es/minBy' import maxBy from 'lodash-es/maxBy' import * as CacheChunkStore from 'cache-chunk-store' @@ -262,7 +270,6 @@ class PeerTubePlugin extends Plugin { private tryToPlay (done?: Function) { if (!done) done = function () { /* empty */ } - const playPromise = this.player.play() if (playPromise !== undefined) { return playPromise.then(done) @@ -348,6 +355,9 @@ class PeerTubePlugin extends Plugin { // Proxy first play const oldPlay = this.player.play.bind(this.player) this.player.play = () => { + // Avoid issue new play policy on mobiles + if (isMobile()) oldPlay() + this.player.addClass('vjs-has-big-play-button-clicked') this.player.play = oldPlay 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) { return setLocalStorage('average-bandwidth', value.toString()) } +function isMobile () { + return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) +} + export { toTitleCase, getStoredVolume, @@ -68,6 +72,7 @@ export { getAverageBandwidth, saveMuteInStore, getStoredMute, + isMobile, bytes } 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 @@ import './embed.scss' +import 'core-js/es6/symbol' +import 'core-js/es6/object' +import 'core-js/es6/function' +import 'core-js/es6/parse-int' +import 'core-js/es6/parse-float' +import 'core-js/es6/number' +import 'core-js/es6/math' +import 'core-js/es6/string' +import 'core-js/es6/date' +import 'core-js/es6/array' +import 'core-js/es6/regexp' +import 'core-js/es6/map' +import 'core-js/es6/weak-map' +import 'core-js/es6/set' + // For google bot that uses Chrome 41 and does not understand fetch import 'whatwg-fetch' diff --git a/package.json b/package.json index 16ef248e2..9ed15982a 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "jsonld": "^1.0.1", "jsonld-signatures": "https://github.com/Chocobozzz/jsonld-signatures#rsa2017", "kue": "^0.11.6", - "lodash": "^4.11.1", + "lodash": "^4.17.10", "magnet-uri": "^5.1.4", "mkdirp": "^0.5.1", "morgan": "^1.5.3", diff --git a/scripts/e2e.sh b/scripts/e2e.sh index 17c8f68ef..0e70e6e51 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -7,6 +7,7 @@ npm run clean:server:test ( cd client npm run webdriver-manager update + npm run webpack -- --config webpack/webpack.video-embed.js --mode development ) concurrently -k -s first \