mirror of https://github.com/Chocobozzz/PeerTube
				
				
				
			Add e2e tests for password protected videos (#5860)
							parent
							
								
									260242decd
								
							
						
					
					
						commit
						cbe06f779f
					
				| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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')
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -50,9 +50,9 @@
 | 
			
		|||
        <div class="form-group">
 | 
			
		||||
          <label i18n for="privacy">Privacy</label>
 | 
			
		||||
          <div class="peertube-select-container">
 | 
			
		||||
            <select id="privacy" formControlName="privacy" class="form-control">
 | 
			
		||||
              <option *ngFor="let privacy of videoPlaylistPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
            <my-select-options
 | 
			
		||||
            labelForId="privacy" [items]="videoPlaylistPrivacies" formControlName="privacy" [clearable]="false"
 | 
			
		||||
          ></my-select-options>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div *ngIf="formErrors.privacy" class="form-error">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue