aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorWicklow <123956049+wickloww@users.noreply.github.com>2023-07-17 09:31:42 +0000
committerGitHub <noreply@github.com>2023-07-17 11:31:42 +0200
commitcbe06f779f485935b227ccbb48a4493e4acda725 (patch)
tree93556507650a20ee544e1eb0a51588318156732f
parent260242decdd740bfee8b9f7c9536d98a6a951bcf (diff)
downloadPeerTube-cbe06f779f485935b227ccbb48a4493e4acda725.tar.gz
PeerTube-cbe06f779f485935b227ccbb48a4493e4acda725.tar.zst
PeerTube-cbe06f779f485935b227ccbb48a4493e4acda725.zip
Add e2e tests for password protected videos (#5860)
-rw-r--r--client/e2e/src/po/my-account.po.ts21
-rw-r--r--client/e2e/src/po/player.po.ts11
-rw-r--r--client/e2e/src/po/signup.po.ts22
-rw-r--r--client/e2e/src/po/video-upload.po.ts9
-rw-r--r--client/e2e/src/po/video-watch.po.ts81
-rw-r--r--client/e2e/src/suites-local/video-password.e2e-spec.ts226
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html6
7 files changed, 370 insertions, 6 deletions
diff --git a/client/e2e/src/po/my-account.po.ts b/client/e2e/src/po/my-account.po.ts
index 5188eca11..73eb6162c 100644
--- a/client/e2e/src/po/my-account.po.ts
+++ b/client/e2e/src/po/my-account.po.ts
@@ -1,4 +1,4 @@
1import { getCheckbox, go } from '../utils' 1import { getCheckbox, go, selectCustomSelect } from '../utils'
2 2
3export class MyAccountPage { 3export class MyAccountPage {
4 4
@@ -117,6 +117,25 @@ export class MyAccountPage {
117 return go(url) 117 return go(url)
118 } 118 }
119 119
120 async updatePlaylistPrivacy (playlistUUID: string, privacy: 'Public' | 'Private' | 'Unlisted') {
121 go('/my-library/video-playlists/update/' + playlistUUID)
122
123 await browser.waitUntil(async () => {
124 return (await $('form .video-playlist-title').getText() === 'PLAYLIST')
125 })
126
127 await selectCustomSelect('videoChannelId', 'Main root channel')
128 await selectCustomSelect('privacy', privacy)
129
130 const submit = await $('form input[type=submit]')
131 submit.waitForClickable()
132 await submit.click()
133
134 return browser.waitUntil(async () => {
135 return (await browser.getUrl()).includes('my-library/video-playlists')
136 })
137 }
138
120 // My account Videos 139 // My account Videos
121 140
122 private async getVideoElement (name: string) { 141 private async getVideoElement (name: string) {
diff --git a/client/e2e/src/po/player.po.ts b/client/e2e/src/po/player.po.ts
index a20e683bc..33719da25 100644
--- a/client/e2e/src/po/player.po.ts
+++ b/client/e2e/src/po/player.po.ts
@@ -61,4 +61,15 @@ export class PlayerPage {
61 await playButton().waitForClickable() 61 await playButton().waitForClickable()
62 await playButton().click() 62 await playButton().click()
63 } 63 }
64
65 async fillEmbedVideoPassword (videoPassword: string) {
66 const videoPasswordInput = $('input#video-password-input')
67 const confirmButton = await $('button#video-password-submit')
68
69 await videoPasswordInput.clearValue()
70 await videoPasswordInput.setValue(videoPassword)
71 await confirmButton.waitForClickable()
72
73 return confirmButton.click()
74 }
64} 75}
diff --git a/client/e2e/src/po/signup.po.ts b/client/e2e/src/po/signup.po.ts
index 84a7a1847..4da35a7d4 100644
--- a/client/e2e/src/po/signup.po.ts
+++ b/client/e2e/src/po/signup.po.ts
@@ -62,4 +62,26 @@ export class SignupPage {
62 await $('#displayName').setValue(options.displayName || `${options.name} channel display name`) 62 await $('#displayName').setValue(options.displayName || `${options.name} channel display name`)
63 await $('#name').setValue(options.name) 63 await $('#name').setValue(options.name)
64 } 64 }
65
66 async fullSignup ({ accountInfo, channelInfo }: {
67 accountInfo: {
68 username: string
69 password?: string
70 displayName?: string
71 email?: string
72 }
73 channelInfo: {
74 name: string
75 }
76 }) {
77 await this.clickOnRegisterInMenu()
78 await this.validateStep()
79 await this.checkTerms()
80 await this.validateStep()
81 await this.fillAccountStep(accountInfo)
82 await this.validateStep()
83 await this.fillChannelStep(channelInfo)
84 await this.validateStep()
85 await this.getEndMessage()
86 }
65} 87}
diff --git a/client/e2e/src/po/video-upload.po.ts b/client/e2e/src/po/video-upload.po.ts
index 7e7989763..ff3841a02 100644
--- a/client/e2e/src/po/video-upload.po.ts
+++ b/client/e2e/src/po/video-upload.po.ts
@@ -64,6 +64,15 @@ export class VideoUploadPage {
64 return selectCustomSelect('privacy', 'Private') 64 return selectCustomSelect('privacy', 'Private')
65 } 65 }
66 66
67 async setAsPasswordProtected (videoPassword: string) {
68 selectCustomSelect('privacy', 'Password protected')
69
70 const videoPasswordInput = $('input#videoPassword')
71 await videoPasswordInput.clearValue()
72
73 return videoPasswordInput.setValue(videoPassword)
74 }
75
67 private getSecondStepSubmitButton () { 76 private getSecondStepSubmitButton () {
68 return $('.submit-container my-button') 77 return $('.submit-container my-button')
69 } 78 }
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts
index 982c90908..56870511d 100644
--- a/client/e2e/src/po/video-watch.po.ts
+++ b/client/e2e/src/po/video-watch.po.ts
@@ -43,19 +43,25 @@ export class VideoWatchPage {
43 return $('my-privacy-concerns').isDisplayed() 43 return $('my-privacy-concerns').isDisplayed()
44 } 44 }
45 45
46 async goOnAssociatedEmbed () { 46 async goOnAssociatedEmbed (passwordProtected = false) {
47 let url = await browser.getUrl() 47 let url = await browser.getUrl()
48 url = url.replace('/w/', '/videos/embed/') 48 url = url.replace('/w/', '/videos/embed/')
49 url = url.replace(':3333', ':9001') 49 url = url.replace(':3333', ':9001')
50 50
51 await go(url) 51 await go(url)
52 await this.waitEmbedForDisplayed() 52
53 if (passwordProtected) await this.waitEmbedForVideoPasswordForm()
54 else await this.waitEmbedForDisplayed()
53 } 55 }
54 56
55 waitEmbedForDisplayed () { 57 waitEmbedForDisplayed () {
56 return $('.vjs-big-play-button').waitForDisplayed() 58 return $('.vjs-big-play-button').waitForDisplayed()
57 } 59 }
58 60
61 waitEmbedForVideoPasswordForm () {
62 return $('#video-password-input').waitForDisplayed()
63 }
64
59 isEmbedWarningDisplayed () { 65 isEmbedWarningDisplayed () {
60 return $('.peertube-dock-description').isDisplayed() 66 return $('.peertube-dock-description').isDisplayed()
61 } 67 }
@@ -138,4 +144,75 @@ export class VideoWatchPage {
138 144
139 return elem() 145 return elem()
140 } 146 }
147
148 isPasswordProtected () {
149 return $('#confirmInput').isExisting()
150 }
151
152 async fillVideoPassword (videoPassword: string) {
153 const videoPasswordInput = $('input#confirmInput')
154 const confirmButton = await $('input[value="Confirm"]')
155
156 await videoPasswordInput.clearValue()
157 await videoPasswordInput.setValue(videoPassword)
158 await confirmButton.waitForClickable()
159
160 return confirmButton.click()
161 }
162
163 async like () {
164 const likeButton = await $('.action-button-like')
165 const isActivated = (await likeButton.getAttribute('class')).includes('activated')
166
167 let count: number
168 try {
169 count = parseInt(await $('.action-button-like > .count').getText())
170 } catch (error) {
171 count = 0
172 }
173
174 await likeButton.waitForClickable()
175 await likeButton.click()
176
177 if (isActivated) {
178 if (count === 1) {
179 return expect(!await $('.action-button-like > .count').isExisting())
180 } else {
181 return expect(parseInt(await $('.action-button-like > .count').getText())).toBe(count - 1)
182 }
183 } else {
184 return expect(parseInt(await $('.action-button-like > .count').getText())).toBe(count + 1)
185 }
186 }
187
188 async createThread (comment: string) {
189 const textarea = await $('my-video-comment-add textarea')
190
191 await textarea.setValue(comment)
192
193 const confirmButton = await $('.comment-buttons .orange-button')
194 await confirmButton.waitForClickable()
195 await confirmButton.click()
196
197 const createdComment = await (await $('.comment-html p')).getText()
198
199 return expect(createdComment).toBe(comment)
200 }
201
202 async createReply (comment: string) {
203 const replyButton = await $('button.comment-action-reply')
204
205 await replyButton.click()
206 const textarea = await $('my-video-comment my-video-comment-add textarea')
207
208 await textarea.setValue(comment)
209
210 const confirmButton = await $('my-video-comment .comment-buttons .orange-button')
211 await confirmButton.waitForClickable()
212 await confirmButton.click()
213
214 const createdComment = await (await $('.is-child .comment-html p')).getText()
215
216 return expect(createdComment).toBe(comment)
217 }
141} 218}
diff --git a/client/e2e/src/suites-local/video-password.e2e-spec.ts b/client/e2e/src/suites-local/video-password.e2e-spec.ts
new file mode 100644
index 000000000..f4d836c05
--- /dev/null
+++ b/client/e2e/src/suites-local/video-password.e2e-spec.ts
@@ -0,0 +1,226 @@
1import { LoginPage } from '../po/login.po'
2import { SignupPage } from '../po/signup.po'
3import { PlayerPage } from '../po/player.po'
4import { VideoUploadPage } from '../po/video-upload.po'
5import { VideoWatchPage } from '../po/video-watch.po'
6import { go, isMobileDevice, isSafari, waitServerUp } from '../utils'
7import { MyAccountPage } from '../po/my-account.po'
8
9describe('Password protected videos', () => {
10 let videoUploadPage: VideoUploadPage
11 let loginPage: LoginPage
12 let videoWatchPage: VideoWatchPage
13 let signupPage: SignupPage
14 let playerPage: PlayerPage
15 let myAccountPage: MyAccountPage
16 let passwordProtectedVideoUrl: string
17 let playlistUrl: string
18
19 const seed = Math.random()
20 const passwordProtectedVideoName = seed + ' - password protected'
21 const publicVideoName1 = seed + ' - public 1'
22 const publicVideoName2 = seed + ' - public 2'
23 const videoPassword = 'password'
24 const regularUsername = 'user_1'
25 const regularUserPassword = 'user password'
26 const playlistName = seed + ' - playlist'
27
28 function testRateAndComment () {
29 it('Should add and remove like on video', async function () {
30 await videoWatchPage.like()
31 await videoWatchPage.like()
32 })
33
34 it('Should create thread on video', async function () {
35 await videoWatchPage.createThread('My first comment')
36 })
37
38 it('Should reply to thread on video', async function () {
39 await videoWatchPage.createReply('My first reply')
40 })
41 }
42
43 before(async () => {
44 await waitServerUp()
45 })
46
47 beforeEach(async () => {
48 loginPage = new LoginPage(isMobileDevice())
49 videoUploadPage = new VideoUploadPage()
50 videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
51 signupPage = new SignupPage()
52 playerPage = new PlayerPage()
53 myAccountPage = new MyAccountPage()
54
55 await browser.maximizeWindow()
56 })
57
58 describe('Owner', function () {
59 before(async () => {
60 await loginPage.loginAsRootUser()
61 })
62
63 it('Should login, upload a public video and save it to a playlist', async () => {
64 await videoUploadPage.navigateTo()
65 await videoUploadPage.uploadVideo('video.mp4')
66 await videoUploadPage.validSecondUploadStep(publicVideoName1)
67
68 await videoWatchPage.clickOnSave()
69
70 await videoWatchPage.createPlaylist(playlistName)
71
72 await videoWatchPage.saveToPlaylist(playlistName)
73 await browser.pause(5000)
74
75 })
76
77 it('Should upload a password protected video', async () => {
78 await videoUploadPage.navigateTo()
79 await videoUploadPage.uploadVideo('video2.mp4')
80 await videoUploadPage.setAsPasswordProtected(videoPassword)
81 await videoUploadPage.validSecondUploadStep(passwordProtectedVideoName)
82
83 await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
84
85 passwordProtectedVideoUrl = await browser.getUrl()
86 })
87
88 it('Should save to playlist the password protected video', async () => {
89 await videoWatchPage.clickOnSave()
90 await videoWatchPage.saveToPlaylist(playlistName)
91 })
92
93 it('Should upload a second public video and save it to playlist', async () => {
94 await videoUploadPage.navigateTo()
95
96 await videoUploadPage.uploadVideo('video3.mp4')
97 await videoUploadPage.validSecondUploadStep(publicVideoName2)
98
99 await videoWatchPage.clickOnSave()
100 await videoWatchPage.saveToPlaylist(playlistName)
101 })
102
103 it('Should play video without password', async function () {
104 await go(passwordProtectedVideoUrl)
105
106 expect(!await videoWatchPage.isPasswordProtected())
107
108 await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
109
110 expect(await videoWatchPage.getPrivacy()).toBe('Password protected')
111 await playerPage.playAndPauseVideo(false, 2)
112 })
113
114 testRateAndComment()
115
116 it('Should play video on embed without password', async function () {
117 await videoWatchPage.goOnAssociatedEmbed()
118 await playerPage.playAndPauseVideo(false, 2)
119 })
120
121 it('Should have the playlist in my account', async function () {
122 await go('/')
123 await myAccountPage.navigateToMyPlaylists()
124 const videosNumberText = await myAccountPage.getPlaylistVideosText(playlistName)
125
126 expect(videosNumberText).toEqual('3 videos')
127 await myAccountPage.clickOnPlaylist(playlistName)
128
129 const count = await myAccountPage.countTotalPlaylistElements()
130 expect(count).toEqual(3)
131 })
132
133 it('Should update the playlist to public', async () => {
134 const url = await browser.getUrl()
135 const regex = /\/([a-f0-9-]+)$/i
136 const match = url.match(regex)
137 const uuid = match ? match[1] : null
138
139 await myAccountPage.updatePlaylistPrivacy(uuid, 'Public')
140 })
141
142 it('Should watch the playlist', async () => {
143 await myAccountPage.clickOnPlaylist(playlistName)
144 await myAccountPage.playPlaylist()
145 playlistUrl = await browser.getUrl()
146
147 await videoWatchPage.waitUntilVideoName(publicVideoName1, 40 * 1000)
148 await videoWatchPage.waitUntilVideoName(passwordProtectedVideoName, 40 * 1000)
149 await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000)
150 })
151
152 after(async () => {
153 await loginPage.logout()
154 })
155 })
156
157 describe('Regular users', function () {
158 before(async () => {
159 await signupPage.fullSignup({
160 accountInfo: {
161 username: regularUsername,
162 password: regularUserPassword
163 },
164 channelInfo: {
165 name: 'user_1_channel'
166 }
167 })
168 })
169
170 it('Should requires password to play video', async function () {
171 await go(passwordProtectedVideoUrl)
172
173 expect(await videoWatchPage.isPasswordProtected())
174
175 await videoWatchPage.fillVideoPassword(videoPassword)
176 await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
177
178 expect(await videoWatchPage.getPrivacy()).toBe('Password protected')
179 await playerPage.playAndPauseVideo(true, 2)
180 })
181
182 testRateAndComment()
183
184 it('Should requires password to play video on embed', async function () {
185 await videoWatchPage.goOnAssociatedEmbed(true)
186 await playerPage.fillEmbedVideoPassword(videoPassword)
187 await playerPage.playAndPauseVideo(false, 2)
188 })
189
190 it('Should watch the playlist without password protected video', async () => {
191 await go(playlistUrl)
192 await playerPage.playVideo()
193 await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000)
194 })
195
196 after(async () => {
197 await loginPage.logout()
198 })
199 })
200
201 describe('Anonymous users', function () {
202 it('Should requires password to play video', async function () {
203 await go(passwordProtectedVideoUrl)
204
205 expect(await videoWatchPage.isPasswordProtected())
206
207 await videoWatchPage.fillVideoPassword(videoPassword)
208 await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName)
209
210 expect(await videoWatchPage.getPrivacy()).toBe('Password protected')
211 await playerPage.playAndPauseVideo(true, 2)
212 })
213
214 it('Should requires password to play video on embed', async function () {
215 await videoWatchPage.goOnAssociatedEmbed(true)
216 await playerPage.fillEmbedVideoPassword(videoPassword)
217 await playerPage.playAndPauseVideo(false, 2)
218 })
219
220 it('Should watch the playlist without password protected video', async () => {
221 await go(playlistUrl)
222 await playerPage.playVideo()
223 await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000)
224 })
225 })
226})
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html b/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html
index a3c2aab44..9475820ac 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html
@@ -50,9 +50,9 @@
50 <div class="form-group"> 50 <div class="form-group">
51 <label i18n for="privacy">Privacy</label> 51 <label i18n for="privacy">Privacy</label>
52 <div class="peertube-select-container"> 52 <div class="peertube-select-container">
53 <select id="privacy" formControlName="privacy" class="form-control"> 53 <my-select-options
54 <option *ngFor="let privacy of videoPlaylistPrivacies" [value]="privacy.id">{{ privacy.label }}</option> 54 labelForId="privacy" [items]="videoPlaylistPrivacies" formControlName="privacy" [clearable]="false"
55 </select> 55 ></my-select-options>
56 </div> 56 </div>
57 57
58 <div *ngIf="formErrors.privacy" class="form-error"> 58 <div *ngIf="formErrors.privacy" class="form-error">