diff options
author | Chocobozzz <me@florianbigard.com> | 2020-08-07 10:25:07 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2020-08-07 11:12:59 +0200 |
commit | 7f90579c04383ca883083548f40782352605d778 (patch) | |
tree | 7abeba248d6621b2df324c4def4271b9469288ee | |
parent | 5ab7fd9da92463ade6b31d49bdc0f559174b4c57 (diff) | |
download | PeerTube-7f90579c04383ca883083548f40782352605d778.tar.gz PeerTube-7f90579c04383ca883083548f40782352605d778.tar.zst PeerTube-7f90579c04383ca883083548f40782352605d778.zip |
Add playlist embed E2E test
-rw-r--r-- | client/e2e/src/po/player.po.ts | 54 | ||||
-rw-r--r-- | client/e2e/src/po/video-watch.po.ts | 55 | ||||
-rw-r--r-- | client/e2e/src/videos.e2e-spec.ts | 47 | ||||
-rw-r--r-- | client/src/assets/player/playlist/playlist-menu.ts | 5 |
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 @@ | |||
1 | import { browser, by, element, ExpectedConditions } from 'protractor' | ||
2 | import { browserSleep, isIOS, isMobileDevice } from '../utils' | ||
3 | |||
4 | export 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 @@ | |||
1 | import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor' | 1 | import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor' |
2 | import { browserSleep, isIOS, isMobileDevice } from '../utils' | 2 | import { browserSleep, isMobileDevice } from '../utils' |
3 | 3 | ||
4 | export class VideoWatchPage { | 4 | export 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' | |||
2 | import { AppPage } from './po/app.po' | 2 | import { AppPage } from './po/app.po' |
3 | import { LoginPage } from './po/login.po' | 3 | import { LoginPage } from './po/login.po' |
4 | import { MyAccountPage } from './po/my-account' | 4 | import { MyAccountPage } from './po/my-account' |
5 | import { PlayerPage } from './po/player.po' | ||
5 | import { VideoUpdatePage } from './po/video-update.po' | 6 | import { VideoUpdatePage } from './po/video-update.po' |
6 | import { VideoUploadPage } from './po/video-upload.po' | 7 | import { VideoUploadPage } from './po/video-upload.po' |
7 | import { VideoWatchPage } from './po/video-watch.po' | 8 | import { 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 | ||