aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/e2e/src/po/my-account.ts72
-rw-r--r--client/e2e/src/po/video-update.po.ts20
-rw-r--r--client/e2e/src/po/video-watch.po.ts43
-rw-r--r--client/e2e/src/videos.e2e-spec.ts159
4 files changed, 264 insertions, 30 deletions
diff --git a/client/e2e/src/po/my-account.ts b/client/e2e/src/po/my-account.ts
new file mode 100644
index 000000000..e49372983
--- /dev/null
+++ b/client/e2e/src/po/my-account.ts
@@ -0,0 +1,72 @@
1import { by, element } from 'protractor'
2
3export class MyAccountPage {
4
5 navigateToMyVideos () {
6 return element(by.css('a[href="/my-account/videos"]')).click()
7 }
8
9 navigateToMyPlaylists () {
10 return element(by.css('a[href="/my-account/video-playlists"]')).click()
11 }
12
13 navigateToMyHistory () {
14 return element(by.css('a[href="/my-account/history/videos"]')).click()
15 }
16
17 // My account Videos
18
19 getLastVideoName () {
20 return this.getAllVideoNameElements().first().getText()
21 }
22
23 removeLastVideo () {
24 return this.getLastVideoElement().element(by.css('my-delete-button')).click()
25 }
26
27 validRemove () {
28 return element(by.css('.action-button-submit')).click()
29 }
30
31 countVideos () {
32 return this.getAllVideoNameElements().count()
33 }
34
35 // My account playlists
36
37 getLastUpdatedPlaylistName () {
38 return this.getLastUpdatedPlaylist().element(by.css('.miniature-name')).getText()
39 }
40
41 getLastUpdatedPlaylistVideosText () {
42 return this.getLastUpdatedPlaylist().element(by.css('.miniature-playlist-info-overlay')).getText()
43 }
44
45 clickOnLastUpdatedPlaylist () {
46 return this.getLastUpdatedPlaylist().element(by.css('.miniature-thumbnail')).click()
47 }
48
49 countTotalPlaylistElements () {
50 return element.all(by.css('my-video-playlist-element-miniature')).count()
51 }
52
53 playPlaylist () {
54 return element(by.css('.playlist-info .miniature-thumbnail')).click()
55 }
56
57 // My account Videos
58
59 private getLastVideoElement () {
60 return element.all(by.css('.video')).first()
61 }
62
63 private getAllVideoNameElements () {
64 return element.all(by.css('.video-miniature-name'))
65 }
66
67 // My account playlists
68
69 private getLastUpdatedPlaylist () {
70 return element.all(by.css('my-video-playlist-miniature')).first()
71 }
72}
diff --git a/client/e2e/src/po/video-update.po.ts b/client/e2e/src/po/video-update.po.ts
new file mode 100644
index 000000000..4de3b1b1d
--- /dev/null
+++ b/client/e2e/src/po/video-update.po.ts
@@ -0,0 +1,20 @@
1import { by, element } from 'protractor'
2
3export class VideoUpdatePage {
4
5 async updateName (videoName: string) {
6 const nameInput = element(by.css('input#name'))
7 await nameInput.clear()
8 await nameInput.sendKeys(videoName)
9 }
10
11 async validUpdate () {
12 const submitButton = await this.getSubmitButton()
13
14 return submitButton.click()
15 }
16
17 private getSubmitButton () {
18 return element(by.css('.submit-button:not(.disabled) input'))
19 }
20}
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts
index 5f61d5668..9bb0a3919 100644
--- a/client/e2e/src/po/video-watch.po.ts
+++ b/client/e2e/src/po/video-watch.po.ts
@@ -1,4 +1,4 @@
1import { browser, by, element } from 'protractor' 1import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor'
2 2
3export class VideoWatchPage { 3export class VideoWatchPage {
4 async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { 4 async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) {
@@ -44,6 +44,10 @@ export class VideoWatchPage {
44 .then(seconds => parseInt(seconds, 10)) 44 .then(seconds => parseInt(seconds, 10))
45 } 45 }
46 46
47 getVideoName () {
48 return this.getVideoNameElement().getText()
49 }
50
47 async playAndPauseVideo (isAutoplay: boolean, isMobileDevice: boolean) { 51 async playAndPauseVideo (isAutoplay: boolean, isMobileDevice: boolean) {
48 if (isAutoplay === false) { 52 if (isAutoplay === false) {
49 const playButton = element(by.css('.vjs-big-play-button')) 53 const playButton = element(by.css('.vjs-big-play-button'))
@@ -101,4 +105,41 @@ export class VideoWatchPage {
101 async goOnP2PMediaLoaderEmbed () { 105 async goOnP2PMediaLoaderEmbed () {
102 return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50?mode=p2p-media-loader') 106 return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50?mode=p2p-media-loader')
103 } 107 }
108
109 async clickOnUpdate () {
110 const dropdown = element(by.css('my-video-actions-dropdown .action-button'))
111 await dropdown.click()
112
113 const items: ElementFinder[] = await element.all(by.css('my-video-actions-dropdown .dropdown-menu .dropdown-item'))
114
115 for (const item of items) {
116 const href = await item.getAttribute('href')
117
118 if (href && href.includes('/update/')) {
119 await item.click()
120 return
121 }
122 }
123 }
124
125 async clickOnSave () {
126 return element(by.css('.action-button-save')).click()
127 }
128
129 async saveToWatchLater () {
130 return element.all(by.css('my-video-add-to-playlist .playlist')).first().click()
131 }
132
133 waitUntilVideoName (name: string, maxTime: number) {
134 const elem = this.getVideoNameElement()
135
136 return browser.wait(ExpectedConditions.textToBePresentInElement(elem, name), maxTime)
137 }
138
139 private getVideoNameElement () {
140 // We have 2 video info name block, pick the first that is not empty
141 return element.all(by.css('.video-bottom .video-info-name'))
142 .filter(e => e.getText().then(t => !!t))
143 .first()
144 }
104} 145}
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts
index 25521cad9..c19ab3092 100644
--- a/client/e2e/src/videos.e2e-spec.ts
+++ b/client/e2e/src/videos.e2e-spec.ts
@@ -2,35 +2,56 @@ import { VideoWatchPage } from './po/video-watch.po'
2import { VideoUploadPage } from './po/video-upload.po' 2import { VideoUploadPage } from './po/video-upload.po'
3import { LoginPage } from './po/login.po' 3import { LoginPage } from './po/login.po'
4import { browser } from 'protractor' 4import { browser } from 'protractor'
5import { VideoUpdatePage } from './po/video-update.po'
6import { MyAccountPage } from './po/my-account'
7
8async function skipIfUploadNotSupported () {
9 if (await isMobileDevice() || await isSafari()) {
10 console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.')
11 return true
12 }
13
14 return false
15}
16
17async function isMobileDevice () {
18 const caps = await browser.getCapabilities()
19 return caps.get('realMobile') === 'true' || caps.get('realMobile') === true
20}
21
22async function isSafari () {
23 const caps = await browser.getCapabilities()
24 return caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari'
25}
5 26
6describe('Videos workflow', () => { 27describe('Videos workflow', () => {
7 let videoWatchPage: VideoWatchPage 28 let videoWatchPage: VideoWatchPage
8 let pageUploadPage: VideoUploadPage 29 let videoUploadPage: VideoUploadPage
30 let videoUpdatePage: VideoUpdatePage
31 let myAccountPage: MyAccountPage
9 let loginPage: LoginPage 32 let loginPage: LoginPage
33
10 const videoName = new Date().getTime() + ' video' 34 const videoName = new Date().getTime() + ' video'
11 let isMobileDevice = false 35 let videoWatchUrl: string
12 let isSafari = false
13 36
14 beforeEach(async () => { 37 beforeEach(async () => {
15 videoWatchPage = new VideoWatchPage() 38 videoWatchPage = new VideoWatchPage()
16 pageUploadPage = new VideoUploadPage() 39 videoUploadPage = new VideoUploadPage()
40 videoUpdatePage = new VideoUpdatePage()
41 myAccountPage = new MyAccountPage()
17 loginPage = new LoginPage() 42 loginPage = new LoginPage()
18 43
19 const caps = await browser.getCapabilities() 44 if (await isMobileDevice()) {
20 isMobileDevice = caps.get('realMobile') === 'true' || caps.get('realMobile') === true
21 isSafari = caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari'
22
23 if (isMobileDevice) {
24 console.log('Mobile device detected.') 45 console.log('Mobile device detected.')
25 } 46 }
26 47
27 if (isSafari) { 48 if (await isSafari()) {
28 console.log('Safari detected.') 49 console.log('Safari detected.')
29 } 50 }
30 }) 51 })
31 52
32 it('Should log in', () => { 53 it('Should log in', async () => {
33 if (isMobileDevice || isSafari) { 54 if (await isMobileDevice() || await isSafari()) {
34 console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') 55 console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.')
35 return 56 return
36 } 57 }
@@ -39,24 +60,18 @@ describe('Videos workflow', () => {
39 }) 60 })
40 61
41 it('Should upload a video', async () => { 62 it('Should upload a video', async () => {
42 if (isMobileDevice || isSafari) { 63 if (await skipIfUploadNotSupported()) return
43 console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.')
44 return
45 }
46 64
47 await pageUploadPage.navigateTo() 65 await videoUploadPage.navigateTo()
48 66
49 await pageUploadPage.uploadVideo() 67 await videoUploadPage.uploadVideo()
50 return pageUploadPage.validSecondUploadStep(videoName) 68 return videoUploadPage.validSecondUploadStep(videoName)
51 }) 69 })
52 70
53 it('Should list videos', async () => { 71 it('Should list videos', async () => {
54 await videoWatchPage.goOnVideosList(isMobileDevice, isSafari) 72 await videoWatchPage.goOnVideosList(await isMobileDevice(), await isSafari())
55 73
56 if (isMobileDevice || isSafari) { 74 if (await skipIfUploadNotSupported()) return
57 console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.')
58 return
59 }
60 75
61 const videoNames = videoWatchPage.getVideosListName() 76 const videoNames = videoWatchPage.getVideosListName()
62 expect(videoNames).toContain(videoName) 77 expect(videoNames).toContain(videoName)
@@ -65,14 +80,16 @@ describe('Videos workflow', () => {
65 it('Should go on video watch page', async () => { 80 it('Should go on video watch page', async () => {
66 let videoNameToExcept = videoName 81 let videoNameToExcept = videoName
67 82
68 if (isMobileDevice || isSafari) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() 83 if (await isMobileDevice() || await isSafari()) videoNameToExcept = await videoWatchPage.clickOnFirstVideo()
69 else await videoWatchPage.clickOnVideo(videoName) 84 else await videoWatchPage.clickOnVideo(videoName)
70 85
71 return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice, isSafari) 86 return videoWatchPage.waitWatchVideoName(videoNameToExcept, await isMobileDevice(), await isSafari())
72 }) 87 })
73 88
74 it('Should play the video', async () => { 89 it('Should play the video', async () => {
75 await videoWatchPage.playAndPauseVideo(true, isMobileDevice) 90 videoWatchUrl = await browser.getCurrentUrl()
91
92 await videoWatchPage.playAndPauseVideo(true, await isMobileDevice())
76 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 93 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
77 }) 94 })
78 95
@@ -81,7 +98,7 @@ describe('Videos workflow', () => {
81 98
82 await videoWatchPage.goOnAssociatedEmbed() 99 await videoWatchPage.goOnAssociatedEmbed()
83 100
84 await videoWatchPage.playAndPauseVideo(false, isMobileDevice) 101 await videoWatchPage.playAndPauseVideo(false, await isMobileDevice())
85 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 102 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
86 103
87 await browser.waitForAngularEnabled(true) 104 await browser.waitForAngularEnabled(true)
@@ -92,9 +109,93 @@ describe('Videos workflow', () => {
92 109
93 await videoWatchPage.goOnP2PMediaLoaderEmbed() 110 await videoWatchPage.goOnP2PMediaLoaderEmbed()
94 111
95 await videoWatchPage.playAndPauseVideo(false, isMobileDevice) 112 await videoWatchPage.playAndPauseVideo(false, await isMobileDevice())
96 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) 113 expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
97 114
98 await browser.waitForAngularEnabled(true) 115 await browser.waitForAngularEnabled(true)
99 }) 116 })
117
118 it('Should update the video', async () => {
119 if (await skipIfUploadNotSupported()) return
120
121 await browser.get(videoWatchUrl)
122
123 await videoWatchPage.clickOnUpdate()
124
125 await videoUpdatePage.updateName('my new name')
126
127 await videoUpdatePage.validUpdate()
128
129 const name = await videoWatchPage.getVideoName()
130 expect(name).toEqual('my new name')
131 })
132
133 it('Should add the video in my playlist', async () => {
134 if (await skipIfUploadNotSupported()) return
135
136 await videoWatchPage.clickOnSave()
137 await videoWatchPage.saveToWatchLater()
138
139 await videoUploadPage.navigateTo()
140
141 await videoUploadPage.uploadVideo()
142 await videoUploadPage.validSecondUploadStep('second video')
143
144 await videoWatchPage.clickOnSave()
145 await videoWatchPage.saveToWatchLater()
146 })
147
148 it('Should have the watch later playlist in my account', async () => {
149 if (await skipIfUploadNotSupported()) return
150
151 await myAccountPage.navigateToMyPlaylists()
152
153 const name = await myAccountPage.getLastUpdatedPlaylistName()
154 expect(name).toEqual('Watch later')
155
156 const videosNumberText = await myAccountPage.getLastUpdatedPlaylistVideosText()
157 expect(videosNumberText).toEqual('2 videos')
158
159 await myAccountPage.clickOnLastUpdatedPlaylist()
160
161 const count = await myAccountPage.countTotalPlaylistElements()
162 expect(count).toEqual(2)
163 })
164
165 it('Should watch the playlist', async () => {
166 if (await skipIfUploadNotSupported()) return
167
168 await myAccountPage.playPlaylist()
169
170 await videoWatchPage.waitUntilVideoName('second video', 20000 * 1000)
171 })
172
173 it('Should have the video in my account', async () => {
174 if (await skipIfUploadNotSupported()) return
175
176 await myAccountPage.navigateToMyVideos()
177
178 const lastVideoName = await myAccountPage.getLastVideoName()
179 expect(lastVideoName).toEqual('second video')
180 })
181
182 it('Should delete the last video', async () => {
183 if (await skipIfUploadNotSupported()) return
184
185 await myAccountPage.removeLastVideo()
186 await myAccountPage.validRemove()
187
188 const count = await myAccountPage.countVideos()
189 expect(count).toEqual(1)
190 })
191
192 it('Should delete the first video', async () => {
193 if (await skipIfUploadNotSupported()) return
194
195 await myAccountPage.removeLastVideo()
196 await myAccountPage.validRemove()
197
198 const count = await myAccountPage.countVideos()
199 expect(count).toEqual(0)
200 })
100}) 201})