From cbe06f779f485935b227ccbb48a4493e4acda725 Mon Sep 17 00:00:00 2001 From: Wicklow <123956049+wickloww@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:31:42 +0000 Subject: [PATCH] Add e2e tests for password protected videos (#5860) --- client/e2e/src/po/my-account.po.ts | 21 +- client/e2e/src/po/player.po.ts | 11 + client/e2e/src/po/signup.po.ts | 22 ++ client/e2e/src/po/video-upload.po.ts | 9 + client/e2e/src/po/video-watch.po.ts | 81 ++++++- .../suites-local/video-password.e2e-spec.ts | 226 ++++++++++++++++++ .../my-video-playlist-edit.component.html | 6 +- 7 files changed, 370 insertions(+), 6 deletions(-) create mode 100644 client/e2e/src/suites-local/video-password.e2e-spec.ts 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 @@ -import { getCheckbox, go } from '../utils' +import { getCheckbox, go, selectCustomSelect } from '../utils' export class MyAccountPage { @@ -117,6 +117,25 @@ export class MyAccountPage { return go(url) } + async updatePlaylistPrivacy (playlistUUID: string, privacy: 'Public' | 'Private' | 'Unlisted') { + go('/my-library/video-playlists/update/' + playlistUUID) + + await browser.waitUntil(async () => { + return (await $('form .video-playlist-title').getText() === 'PLAYLIST') + }) + + await selectCustomSelect('videoChannelId', 'Main root channel') + await selectCustomSelect('privacy', privacy) + + const submit = await $('form input[type=submit]') + submit.waitForClickable() + await submit.click() + + return browser.waitUntil(async () => { + return (await browser.getUrl()).includes('my-library/video-playlists') + }) + } + // My account Videos 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 { await playButton().waitForClickable() await playButton().click() } + + async fillEmbedVideoPassword (videoPassword: string) { + const videoPasswordInput = $('input#video-password-input') + const confirmButton = await $('button#video-password-submit') + + await videoPasswordInput.clearValue() + await videoPasswordInput.setValue(videoPassword) + await confirmButton.waitForClickable() + + return confirmButton.click() + } } 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 { await $('#displayName').setValue(options.displayName || `${options.name} channel display name`) await $('#name').setValue(options.name) } + + async fullSignup ({ accountInfo, channelInfo }: { + accountInfo: { + username: string + password?: string + displayName?: string + email?: string + } + channelInfo: { + name: string + } + }) { + await this.clickOnRegisterInMenu() + await this.validateStep() + await this.checkTerms() + await this.validateStep() + await this.fillAccountStep(accountInfo) + await this.validateStep() + await this.fillChannelStep(channelInfo) + await this.validateStep() + await this.getEndMessage() + } } 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 { return selectCustomSelect('privacy', 'Private') } + async setAsPasswordProtected (videoPassword: string) { + selectCustomSelect('privacy', 'Password protected') + + const videoPasswordInput = $('input#videoPassword') + await videoPasswordInput.clearValue() + + return videoPasswordInput.setValue(videoPassword) + } + private getSecondStepSubmitButton () { return $('.submit-container my-button') } 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 { return $('my-privacy-concerns').isDisplayed() } - async goOnAssociatedEmbed () { + async goOnAssociatedEmbed (passwordProtected = false) { let url = await browser.getUrl() url = url.replace('/w/', '/videos/embed/') url = url.replace(':3333', ':9001') await go(url) - await this.waitEmbedForDisplayed() + + if (passwordProtected) await this.waitEmbedForVideoPasswordForm() + else await this.waitEmbedForDisplayed() } waitEmbedForDisplayed () { return $('.vjs-big-play-button').waitForDisplayed() } + waitEmbedForVideoPasswordForm () { + return $('#video-password-input').waitForDisplayed() + } + isEmbedWarningDisplayed () { return $('.peertube-dock-description').isDisplayed() } @@ -138,4 +144,75 @@ export class VideoWatchPage { return elem() } + + isPasswordProtected () { + return $('#confirmInput').isExisting() + } + + async fillVideoPassword (videoPassword: string) { + const videoPasswordInput = $('input#confirmInput') + const confirmButton = await $('input[value="Confirm"]') + + await videoPasswordInput.clearValue() + await videoPasswordInput.setValue(videoPassword) + await confirmButton.waitForClickable() + + return confirmButton.click() + } + + async like () { + const likeButton = await $('.action-button-like') + const isActivated = (await likeButton.getAttribute('class')).includes('activated') + + let count: number + try { + count = parseInt(await $('.action-button-like > .count').getText()) + } catch (error) { + count = 0 + } + + await likeButton.waitForClickable() + await likeButton.click() + + if (isActivated) { + if (count === 1) { + return expect(!await $('.action-button-like > .count').isExisting()) + } else { + return expect(parseInt(await $('.action-button-like > .count').getText())).toBe(count - 1) + } + } else { + return expect(parseInt(await $('.action-button-like > .count').getText())).toBe(count + 1) + } + } + + async createThread (comment: string) { + const textarea = await $('my-video-comment-add textarea') + + await textarea.setValue(comment) + + const confirmButton = await $('.comment-buttons .orange-button') + await confirmButton.waitForClickable() + await confirmButton.click() + + const createdComment = await (await $('.comment-html p')).getText() + + return expect(createdComment).toBe(comment) + } + + async createReply (comment: string) { + const replyButton = await $('button.comment-action-reply') + + await replyButton.click() + const textarea = await $('my-video-comment my-video-comment-add textarea') + + await textarea.setValue(comment) + + const confirmButton = await $('my-video-comment .comment-buttons .orange-button') + await confirmButton.waitForClickable() + await confirmButton.click() + + const createdComment = await (await $('.is-child .comment-html p')).getText() + + return expect(createdComment).toBe(comment) + } } 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 @@ +import { LoginPage } from '../po/login.po' +import { SignupPage } from '../po/signup.po' +import { PlayerPage } from '../po/player.po' +import { VideoUploadPage } from '../po/video-upload.po' +import { VideoWatchPage } from '../po/video-watch.po' +import { go, isMobileDevice, isSafari, waitServerUp } from '../utils' +import { MyAccountPage } from '../po/my-account.po' + +describe('Password protected videos', () => { + let videoUploadPage: VideoUploadPage + let loginPage: LoginPage + let videoWatchPage: VideoWatchPage + let signupPage: SignupPage + let playerPage: PlayerPage + let myAccountPage: MyAccountPage + let passwordProtectedVideoUrl: string + let playlistUrl: string + + const seed = Math.random() + const passwordProtectedVideoName = seed + ' - password protected' + const publicVideoName1 = seed + ' - public 1' + const publicVideoName2 = seed + ' - public 2' + const videoPassword = 'password' + const regularUsername = 'user_1' + const regularUserPassword = 'user password' + const playlistName = seed + ' - playlist' + + function testRateAndComment () { + it('Should add and remove like on video', async function () { + await videoWatchPage.like() + await videoWatchPage.like() + }) + + it('Should create thread on video', async function () { + await videoWatchPage.createThread('My first comment') + }) + + it('Should reply to thread on video', async function () { + await videoWatchPage.createReply('My first reply') + }) + } + + before(async () => { + await waitServerUp() + }) + + beforeEach(async () => { + loginPage = new LoginPage(isMobileDevice()) + videoUploadPage = new VideoUploadPage() + videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari()) + signupPage = new SignupPage() + playerPage = new PlayerPage() + myAccountPage = new MyAccountPage() + + await browser.maximizeWindow() + }) + + describe('Owner', function () { + before(async () => { + await loginPage.loginAsRootUser() + }) + + it('Should login, upload a public video and save it to a playlist', async () => { + await videoUploadPage.navigateTo() + await videoUploadPage.uploadVideo('video.mp4') + await videoUploadPage.validSecondUploadStep(publicVideoName1) + + await videoWatchPage.clickOnSave() + + await videoWatchPage.createPlaylist(playlistName) + + await videoWatchPage.saveToPlaylist(playlistName) + await browser.pause(5000) + + }) + + it('Should upload a password protected video', async () => { + await videoUploadPage.navigateTo() + await videoUploadPage.uploadVideo('video2.mp4') + await videoUploadPage.setAsPasswordProtected(videoPassword) + await videoUploadPage.validSecondUploadStep(passwordProtectedVideoName) + + await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName) + + passwordProtectedVideoUrl = await browser.getUrl() + }) + + it('Should save to playlist the password protected video', async () => { + await videoWatchPage.clickOnSave() + await videoWatchPage.saveToPlaylist(playlistName) + }) + + it('Should upload a second public video and save it to playlist', async () => { + await videoUploadPage.navigateTo() + + await videoUploadPage.uploadVideo('video3.mp4') + await videoUploadPage.validSecondUploadStep(publicVideoName2) + + await videoWatchPage.clickOnSave() + await videoWatchPage.saveToPlaylist(playlistName) + }) + + it('Should play video without password', async function () { + await go(passwordProtectedVideoUrl) + + expect(!await videoWatchPage.isPasswordProtected()) + + await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName) + + expect(await videoWatchPage.getPrivacy()).toBe('Password protected') + await playerPage.playAndPauseVideo(false, 2) + }) + + testRateAndComment() + + it('Should play video on embed without password', async function () { + await videoWatchPage.goOnAssociatedEmbed() + await playerPage.playAndPauseVideo(false, 2) + }) + + it('Should have the playlist in my account', async function () { + await go('/') + await myAccountPage.navigateToMyPlaylists() + const videosNumberText = await myAccountPage.getPlaylistVideosText(playlistName) + + expect(videosNumberText).toEqual('3 videos') + await myAccountPage.clickOnPlaylist(playlistName) + + const count = await myAccountPage.countTotalPlaylistElements() + expect(count).toEqual(3) + }) + + it('Should update the playlist to public', async () => { + const url = await browser.getUrl() + const regex = /\/([a-f0-9-]+)$/i + const match = url.match(regex) + const uuid = match ? match[1] : null + + await myAccountPage.updatePlaylistPrivacy(uuid, 'Public') + }) + + it('Should watch the playlist', async () => { + await myAccountPage.clickOnPlaylist(playlistName) + await myAccountPage.playPlaylist() + playlistUrl = await browser.getUrl() + + await videoWatchPage.waitUntilVideoName(publicVideoName1, 40 * 1000) + await videoWatchPage.waitUntilVideoName(passwordProtectedVideoName, 40 * 1000) + await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000) + }) + + after(async () => { + await loginPage.logout() + }) + }) + + describe('Regular users', function () { + before(async () => { + await signupPage.fullSignup({ + accountInfo: { + username: regularUsername, + password: regularUserPassword + }, + channelInfo: { + name: 'user_1_channel' + } + }) + }) + + it('Should requires password to play video', async function () { + await go(passwordProtectedVideoUrl) + + expect(await videoWatchPage.isPasswordProtected()) + + await videoWatchPage.fillVideoPassword(videoPassword) + await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName) + + expect(await videoWatchPage.getPrivacy()).toBe('Password protected') + await playerPage.playAndPauseVideo(true, 2) + }) + + testRateAndComment() + + it('Should requires password to play video on embed', async function () { + await videoWatchPage.goOnAssociatedEmbed(true) + await playerPage.fillEmbedVideoPassword(videoPassword) + await playerPage.playAndPauseVideo(false, 2) + }) + + it('Should watch the playlist without password protected video', async () => { + await go(playlistUrl) + await playerPage.playVideo() + await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000) + }) + + after(async () => { + await loginPage.logout() + }) + }) + + describe('Anonymous users', function () { + it('Should requires password to play video', async function () { + await go(passwordProtectedVideoUrl) + + expect(await videoWatchPage.isPasswordProtected()) + + await videoWatchPage.fillVideoPassword(videoPassword) + await videoWatchPage.waitWatchVideoName(passwordProtectedVideoName) + + expect(await videoWatchPage.getPrivacy()).toBe('Password protected') + await playerPage.playAndPauseVideo(true, 2) + }) + + it('Should requires password to play video on embed', async function () { + await videoWatchPage.goOnAssociatedEmbed(true) + await playerPage.fillEmbedVideoPassword(videoPassword) + await playerPage.playAndPauseVideo(false, 2) + }) + + it('Should watch the playlist without password protected video', async () => { + await go(playlistUrl) + await playerPage.playVideo() + await videoWatchPage.waitUntilVideoName(publicVideoName2, 40 * 1000) + }) + }) +}) 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 @@