aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/e2e/src/po/player.po.ts54
-rw-r--r--client/e2e/src/po/video-watch.po.ts55
-rw-r--r--client/e2e/src/videos.e2e-spec.ts47
-rw-r--r--client/src/assets/player/playlist/playlist-menu.ts5
4 files changed, 109 insertions, 52 deletions
diff --git a/client/e2e/src/po/player.po.ts b/client/e2e/src/po/player.po.ts
new file mode 100644
index 000000000..c03f20c68
--- /dev/null
+++ b/client/e2e/src/po/player.po.ts
@@ -0,0 +1,54 @@
1import { browser, by, element, ExpectedConditions } from 'protractor'
2import { browserSleep, isIOS, isMobileDevice } from '../utils'
3
4export class PlayerPage {
5
6 getWatchVideoPlayerCurrentTime () {
7 return element(by.css('.video-js .vjs-current-time-display'))
8 .getText()
9 .then((t: string) => t.split(':')[1])
10 .then(seconds => parseInt(seconds, 10))
11 }
12
13 waitUntilPlaylistInfo (text: string) {
14 const elem = element(by.css('.video-js .vjs-playlist-info'))
15
16 return browser.wait(browser.ExpectedConditions.textToBePresentInElement(elem, text))
17 }
18
19 async playAndPauseVideo (isAutoplay: boolean) {
20 // Autoplay is disabled on iOS
21 if (isAutoplay === false || await isIOS()) {
22 await this.clickOnPlayButton()
23 }
24
25 await browserSleep(2000)
26 await browser.wait(browser.ExpectedConditions.invisibilityOf(element(by.css('.vjs-loading-spinner'))))
27
28 const videojsEl = element(by.css('div.video-js'))
29 await browser.wait(browser.ExpectedConditions.elementToBeClickable(videojsEl))
30
31 // On Android, we need to click twice on "play" (BrowserStack particularity)
32 if (await isMobileDevice()) {
33 await browserSleep(5000)
34
35 await videojsEl.click()
36 }
37
38 browser.ignoreSynchronization = false
39 await browserSleep(7000)
40 browser.ignoreSynchronization = true
41
42 await videojsEl.click()
43 }
44
45 async playVideo () {
46 return this.clickOnPlayButton()
47 }
48
49 private async clickOnPlayButton () {
50 const playButton = element(by.css('.vjs-big-play-button'))
51 await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton))
52 await playButton.click()
53 }
54}
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts
index 35ec773af..fb9c3a000 100644
--- a/client/e2e/src/po/video-watch.po.ts
+++ b/client/e2e/src/po/video-watch.po.ts
@@ -1,5 +1,5 @@
1import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor' 1import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor'
2import { browserSleep, isIOS, isMobileDevice } from '../utils' 2import { browserSleep, isMobileDevice } from '../utils'
3 3
4export class VideoWatchPage { 4export class VideoWatchPage {
5 async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { 5 async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) {
@@ -37,43 +37,24 @@ export class VideoWatchPage {
37 return browser.wait(browser.ExpectedConditions.textToBePresentInElement(elem, videoName)) 37 return browser.wait(browser.ExpectedConditions.textToBePresentInElement(elem, videoName))
38 } 38 }
39 39
40 getWatchVideoPlayerCurrentTime () {
41 return element(by.css('.video-js .vjs-current-time-display'))
42 .getText()
43 .then((t: string) => t.split(':')[1])
44 .then(seconds => parseInt(seconds, 10))
45 }
46
47 getVideoName () { 40 getVideoName () {
48 return this.getVideoNameElement().getText() 41 return this.getVideoNameElement().getText()
49 } 42 }
50 43
51 async playAndPauseVideo (isAutoplay: boolean) { 44 async goOnAssociatedEmbed () {
52 // Autoplay is disabled on iOS 45 let url = await browser.getCurrentUrl()
53 if (isAutoplay === false || await isIOS()) { 46 url = url.replace('/watch/', '/embed/')
54 const playButton = element(by.css('.vjs-big-play-button')) 47 url = url.replace(':3333', ':9001')
55 await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton))
56 await playButton.click()
57 }
58
59 await browserSleep(2000)
60 await browser.wait(browser.ExpectedConditions.invisibilityOf(element(by.css('.vjs-loading-spinner'))))
61
62 const videojsEl = element(by.css('div.video-js'))
63 await browser.wait(browser.ExpectedConditions.elementToBeClickable(videojsEl))
64
65 // On Android, we need to click twice on "play" (BrowserStack particularity)
66 if (await isMobileDevice()) {
67 await browserSleep(5000)
68 48
69 await videojsEl.click() 49 return browser.get(url)
70 } 50 }
71 51
72 browser.ignoreSynchronization = false 52 async goOnP2PMediaLoaderEmbed () {
73 await browserSleep(7000) 53 return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50')
74 browser.ignoreSynchronization = true 54 }
75 55
76 await videojsEl.click() 56 async goOnP2PMediaLoaderPlaylistEmbed () {
57 return browser.get('https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
77 } 58 }
78 59
79 async clickOnVideo (videoName: string) { 60 async clickOnVideo (videoName: string) {
@@ -101,18 +82,6 @@ export class VideoWatchPage {
101 return textToReturn 82 return textToReturn
102 } 83 }
103 84
104 async goOnAssociatedEmbed () {
105 let url = await browser.getCurrentUrl()
106 url = url.replace('/watch/', '/embed/')
107 url = url.replace(':3333', ':9001')
108
109 return browser.get(url)
110 }
111
112 async goOnP2PMediaLoaderEmbed () {
113 return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50')
114 }
115
116 async clickOnUpdate () { 85 async clickOnUpdate () {
117 const dropdown = element(by.css('my-video-actions-dropdown .action-button')) 86 const dropdown = element(by.css('my-video-actions-dropdown .action-button'))
118 await dropdown.click() 87 await dropdown.click()
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts
index 75fa89e28..97d1b827c 100644
--- a/client/e2e/src/videos.e2e-spec.ts
+++ b/client/e2e/src/videos.e2e-spec.ts
@@ -2,6 +2,7 @@ import { browser } from 'protractor'
2import { AppPage } from './po/app.po' 2import { AppPage } from './po/app.po'
3import { LoginPage } from './po/login.po' 3import { LoginPage } from './po/login.po'
4import { MyAccountPage } from './po/my-account' 4import { MyAccountPage } from './po/my-account'
5import { PlayerPage } from './po/player.po'
5import { VideoUpdatePage } from './po/video-update.po' 6import { VideoUpdatePage } from './po/video-update.po'
6import { VideoUploadPage } from './po/video-upload.po' 7import { VideoUploadPage } from './po/video-upload.po'
7import { VideoWatchPage } from './po/video-watch.po' 8import { VideoWatchPage } from './po/video-watch.po'
@@ -23,6 +24,7 @@ describe('Videos workflow', () => {
23 let myAccountPage: MyAccountPage 24 let myAccountPage: MyAccountPage
24 let loginPage: LoginPage 25 let loginPage: LoginPage
25 let appPage: AppPage 26 let appPage: AppPage
27 let playerPage: PlayerPage
26 28
27 let videoName = new Date().getTime() + ' video' 29 let videoName = new Date().getTime() + ' video'
28 const video2Name = new Date().getTime() + ' second video' 30 const video2Name = new Date().getTime() + ' second video'
@@ -36,6 +38,7 @@ describe('Videos workflow', () => {
36 myAccountPage = new MyAccountPage() 38 myAccountPage = new MyAccountPage()
37 loginPage = new LoginPage() 39 loginPage = new LoginPage()
38 appPage = new AppPage() 40 appPage = new AppPage()
41 playerPage = new PlayerPage()
39 42
40 if (await isIOS()) { 43 if (await isIOS()) {
41 // iOS does not seem to work with protractor 44 // iOS does not seem to work with protractor
@@ -99,8 +102,8 @@ describe('Videos workflow', () => {
99 it('Should play the video', async () => { 102 it('Should play the video', async () => {
100 videoWatchUrl = await browser.getCurrentUrl() 103 videoWatchUrl = await browser.getCurrentUrl()
101 104
102 await videoWatchPage.playAndPauseVideo(true) 105 await playerPage.playAndPauseVideo(true)
103 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 106 expect(playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
104 }) 107 })
105 108
106 it('Should watch the associated embed video', async () => { 109 it('Should watch the associated embed video', async () => {
@@ -108,8 +111,8 @@ describe('Videos workflow', () => {
108 111
109 await videoWatchPage.goOnAssociatedEmbed() 112 await videoWatchPage.goOnAssociatedEmbed()
110 113
111 await videoWatchPage.playAndPauseVideo(false) 114 await playerPage.playAndPauseVideo(false)
112 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 115 expect(playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
113 116
114 await browser.waitForAngularEnabled(true) 117 await browser.waitForAngularEnabled(true)
115 }) 118 })
@@ -119,8 +122,8 @@ describe('Videos workflow', () => {
119 122
120 await videoWatchPage.goOnP2PMediaLoaderEmbed() 123 await videoWatchPage.goOnP2PMediaLoaderEmbed()
121 124
122 await videoWatchPage.playAndPauseVideo(false) 125 await playerPage.playAndPauseVideo(false)
123 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 126 expect(playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
124 127
125 await browser.waitForAngularEnabled(true) 128 await browser.waitForAngularEnabled(true)
126 }) 129 })
@@ -178,19 +181,44 @@ describe('Videos workflow', () => {
178 181
179 await myAccountPage.playPlaylist() 182 await myAccountPage.playPlaylist()
180 183
184 await browser.waitForAngularEnabled(false)
185
181 await videoWatchPage.waitUntilVideoName(video2Name, 20000 * 1000) 186 await videoWatchPage.waitUntilVideoName(video2Name, 20000 * 1000)
187
188 await browser.waitForAngularEnabled(true)
182 }) 189 })
183 190
184 it('Should watch the webtorrent playlist in the embed', async () => { 191 it('Should watch the webtorrent playlist in the embed', async () => {
185 if (await skipIfUploadNotSupported()) return 192 if (await skipIfUploadNotSupported()) return
186 193
194 const accessToken = await browser.executeScript(`return window.localStorage.getItem('access_token');`)
195 const refreshToken = await browser.executeScript(`return window.localStorage.getItem('refresh_token');`)
196
187 await browser.waitForAngularEnabled(false) 197 await browser.waitForAngularEnabled(false)
188 198
189 await myAccountPage.goOnAssociatedPlaylistEmbed() 199 await myAccountPage.goOnAssociatedPlaylistEmbed()
190 200
191 await videoWatchPage.playAndPauseVideo(false) 201 await browser.executeScript(`window.localStorage.setItem('access_token', '${accessToken}');`)
202 await browser.executeScript(`window.localStorage.setItem('refresh_token', '${refreshToken}');`)
203 await browser.executeScript(`window.localStorage.setItem('token_type', 'Bearer');`)
192 204
193 await videoWatchPage.waitUntilVideoName(video2Name, 20000 * 1000) 205 await browser.refresh()
206
207 await playerPage.playVideo()
208
209 await playerPage.waitUntilPlaylistInfo('2/2')
210
211 await browser.waitForAngularEnabled(true)
212 })
213
214 it('Should watch the HLS playlist in the embed', async () => {
215 await browser.waitForAngularEnabled(false)
216
217 await videoWatchPage.goOnP2PMediaLoaderPlaylistEmbed()
218
219 await playerPage.playVideo()
220
221 await playerPage.waitUntilPlaylistInfo('2/2')
194 222
195 await browser.waitForAngularEnabled(true) 223 await browser.waitForAngularEnabled(true)
196 }) 224 })
@@ -198,6 +226,9 @@ describe('Videos workflow', () => {
198 it('Should delete the video 2', async () => { 226 it('Should delete the video 2', async () => {
199 if (await skipIfUploadNotSupported()) return 227 if (await skipIfUploadNotSupported()) return
200 228
229 // Go to the dev website
230 await browser.get(videoWatchUrl)
231
201 await myAccountPage.navigateToMyVideos() 232 await myAccountPage.navigateToMyVideos()
202 233
203 await myAccountPage.removeVideo(video2Name) 234 await myAccountPage.removeVideo(video2Name)
diff --git a/client/src/assets/player/playlist/playlist-menu.ts b/client/src/assets/player/playlist/playlist-menu.ts
index 37284fb44..a2583047b 100644
--- a/client/src/assets/player/playlist/playlist-menu.ts
+++ b/client/src/assets/player/playlist/playlist-menu.ts
@@ -65,8 +65,11 @@ class PlaylistMenu extends Component {
65 className: 'title' 65 className: 'title'
66 }) 66 })
67 67
68 const playlistChannel = options.playlist.videoChannel
68 const leftSubtitle = super.createEl('div', { 69 const leftSubtitle = super.createEl('div', {
69 innerHTML: this.player().localize('By {1}', [ options.playlist.videoChannel.displayName ]), 70 innerHTML: playlistChannel
71 ? this.player().localize('By {1}', [ playlistChannel.displayName ])
72 : '',
70 className: 'channel' 73 className: 'channel'
71 }) 74 })
72 75