From 3419e0e1fe8e48a08b63ca0ded31087f913eb2b6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 30 Aug 2021 16:24:25 +0200 Subject: Migrate to webdriverio --- client/e2e/src/po/login.po.ts | 24 ++++--- client/e2e/src/po/my-account.ts | 102 +++++++++++++++++---------- client/e2e/src/po/player.po.ts | 52 ++++++++------ client/e2e/src/po/video-update.po.ts | 12 ++-- client/e2e/src/po/video-upload.po.ts | 34 +++++---- client/e2e/src/po/video-watch.po.ts | 132 ++++++++++++++++++++++------------- 6 files changed, 216 insertions(+), 140 deletions(-) (limited to 'client/e2e/src/po') diff --git a/client/e2e/src/po/login.po.ts b/client/e2e/src/po/login.po.ts index 20412ee0d..8e3030e43 100644 --- a/client/e2e/src/po/login.po.ts +++ b/client/e2e/src/po/login.po.ts @@ -1,23 +1,25 @@ -import { browser, element, by } from 'protractor' +import { go } from '../utils' export class LoginPage { async loginAsRootUser () { - await browser.get('/login') + await go('/login') - await browser.executeScript(`window.localStorage.setItem('no_instance_config_warning_modal', 'true')`) - await browser.executeScript(`window.localStorage.setItem('no_welcome_modal', 'true')`) + await browser.execute(`window.localStorage.setItem('no_instance_config_warning_modal', 'true')`) + await browser.execute(`window.localStorage.setItem('no_welcome_modal', 'true')`) - element(by.css('input#username')).sendKeys('root') - element(by.css('input#password')).sendKeys('test1') + await $('input#username').setValue('root') + await $('input#password').setValue('test1') - await browser.sleep(1000) + await browser.pause(1000) - await element(by.css('form input[type=submit]')).click() + await $('form input[type=submit]').click() - expect(this.getLoggedInInfo().getText()).toContain('root') + await this.getLoggedInInfoElem().waitForExist() + + await expect(this.getLoggedInInfoElem()).toHaveText('root') } - private getLoggedInInfo () { - return element(by.css('.logged-in-display-name')) + private getLoggedInInfoElem () { + return $('.logged-in-display-name') } } diff --git a/client/e2e/src/po/my-account.ts b/client/e2e/src/po/my-account.ts index 9866953e9..85dc02805 100644 --- a/client/e2e/src/po/my-account.ts +++ b/client/e2e/src/po/my-account.ts @@ -1,85 +1,117 @@ -import { by, element, browser } from 'protractor' +import { go } from '../utils' export class MyAccountPage { navigateToMyVideos () { - return element(by.css('a[href="/my-library/videos"]')).click() + return $('a[href="/my-library/videos"]').click() } navigateToMyPlaylists () { - return element(by.css('a[href="/my-library/video-playlists"]')).click() + return $('a[href="/my-library/video-playlists"]').click() } navigateToMyHistory () { - return element(by.css('a[href="/my-library/history/videos"]')).click() + return $('a[href="/my-library/history/videos"]').click() } // My account Videos async removeVideo (name: string) { - const container = this.getVideoElement(name) + const container = await this.getVideoElement(name) - await container.element(by.css('.dropdown-toggle')).click() + await container.$('.dropdown-toggle').click() - const dropdownMenu = container.element(by.css('.dropdown-menu .dropdown-item:nth-child(2)')) - await browser.wait(browser.ExpectedConditions.presenceOf(dropdownMenu)) + const dropdownMenu = () => container.$('.dropdown-menu .dropdown-item:nth-child(2)') - return dropdownMenu.click() + await dropdownMenu().waitForDisplayed() + return dropdownMenu().click() } validRemove () { - return element(by.css('input[type=submit]')).click() + return $('input[type=submit]').click() } - countVideos (names: string[]) { - return element.all(by.css('.video')) - .filter(e => { - return e.element(by.css('.video-miniature-name')) - .getText() - .then(t => names.some(n => t.includes(n))) - }) - .count() + async countVideos (names: string[]) { + const elements = await $$('.video').filter(async e => { + const t = await e.$('.video-miniature-name').getText() + + return names.some(n => t.includes(n)) + }) + + return elements.length } // My account playlists - getPlaylistVideosText (name: string) { - return this.getPlaylist(name).element(by.css('.miniature-playlist-info-overlay')).getText() + async getPlaylistVideosText (name: string) { + const elem = await this.getPlaylist(name) + + return elem.$('.miniature-playlist-info-overlay').getText() } - clickOnPlaylist (name: string) { - return this.getPlaylist(name).element(by.css('.miniature-thumbnail')).click() + async clickOnPlaylist (name: string) { + const elem = await this.getPlaylist(name) + + return elem.$('.miniature-thumbnail').click() } - countTotalPlaylistElements () { - return element.all(by.css('my-video-playlist-element-miniature')).count() + async countTotalPlaylistElements () { + await $('').waitForDisplayed() + + return $$('').length } playPlaylist () { - return element(by.css('.playlist-info .miniature-thumbnail')).click() + return $('.playlist-info .miniature-thumbnail').click() } async goOnAssociatedPlaylistEmbed () { - let url = await browser.getCurrentUrl() + let url = await browser.getUrl() url = url.replace('/w/p/', '/video-playlists/embed/') url = url.replace(':3333', ':9001') - return browser.get(url) + return go(url) } // My account Videos - private getVideoElement (name: string) { - return element.all(by.css('.video')) - .filter(e => e.element(by.css('.video-miniature-name')).getText().then(t => t.includes(name))) - .first() + private async getVideoElement (name: string) { + const video = async () => { + const videos = await $$('.video').filter(async e => { + const t = await e.$('.video-miniature-name').getText() + + return t.includes(name) + }) + + return videos[0] + } + + await browser.waitUntil(async () => { + return (await video()).isDisplayed() + }) + + return video() } // My account playlists - private getPlaylist (name: string) { - return element.all(by.css('my-video-playlist-miniature')) - .filter(e => e.element(by.css('.miniature-name')).getText().then(t => t.includes(name))) - .first() + private async getPlaylist (name: string) { + const playlist = () => { + return $$('my-video-playlist-miniature') + .filter(async e => { + const t = await e.$('.miniature-name').getText() + + return t.includes(name) + }) + .then(elems => elems[0]) + } + + await browser.waitUntil(async () => { + const el = await playlist() + + return el?.isDisplayed() + }) + + return playlist() } } diff --git a/client/e2e/src/po/player.po.ts b/client/e2e/src/po/player.po.ts index cb148a003..9d6e21009 100644 --- a/client/e2e/src/po/player.po.ts +++ b/client/e2e/src/po/player.po.ts @@ -1,45 +1,54 @@ -import { browser, by, element } from 'protractor' import { browserSleep, isIOS, isMobileDevice, isSafari } from '../utils' export class PlayerPage { - async getWatchVideoPlayerCurrentTime () { - const elem = element(by.css('video')) + getWatchVideoPlayerCurrentTime () { + const elem = $('video') - return elem.getAttribute('currentTime') - } + if (isIOS()) { + return elem.getAttribute('currentTime') + .then(t => parseInt(t, 10)) + .then(t => Math.round(t)) + } - waitUntilPlaylistInfo (text: string) { - const elem = element(by.css('.video-js .vjs-playlist-info')) + return elem.getProperty('currentTime') + } - return browser.wait(browser.ExpectedConditions.textToBePresentInElement(elem, text)) + waitUntilPlaylistInfo (text: string, maxTime: number) { + return browser.waitUntil(async () => { + return (await $('.video-js .vjs-playlist-info').getText()).includes(text) + }, { timeout: maxTime }) } waitUntilPlayerWrapper () { - const elem = element(by.css('#placeholder-preview')) - - return browser.wait(browser.ExpectedConditions.presenceOf(elem)) + return browser.waitUntil(async () => { + return !!(await $('#placeholder-preview')) + }) } async playAndPauseVideo (isAutoplay: boolean) { - const videojsEl = element(by.css('div.video-js')) - await browser.wait(browser.ExpectedConditions.elementToBeClickable(videojsEl)) + const videojsElem = () => $('div.video-js') + + await videojsElem().waitForExist() // Autoplay is disabled on iOS and Safari - if (await isIOS() || await isSafari() || await isMobileDevice()) { + if (isIOS() || isSafari() || isMobileDevice()) { // We can't play the video using protractor if it is not muted - await browser.executeScript(`document.querySelector('video').muted = true`) + await browser.execute(`document.querySelector('video').muted = true`) await this.clickOnPlayButton() } else if (isAutoplay === false) { await this.clickOnPlayButton() } await browserSleep(2000) - await browser.wait(browser.ExpectedConditions.invisibilityOf(element(by.css('.vjs-loading-spinner')))) - await browserSleep(2000) + await browser.waitUntil(async () => { + return !await $('.vjs-loading-spinner').isDisplayedInViewport() + }, { timeout: 20 * 1000 }) - await videojsEl.click() + await browserSleep(4000) + + await videojsElem().click() } async playVideo () { @@ -47,8 +56,9 @@ export class PlayerPage { } private async clickOnPlayButton () { - const playButton = element(by.css('.vjs-big-play-button')) - await browser.wait(browser.ExpectedConditions.elementToBeClickable(playButton)) - await playButton.click() + const playButton = () => $('.vjs-big-play-button') + + await playButton().waitForClickable() + await playButton().click() } } diff --git a/client/e2e/src/po/video-update.po.ts b/client/e2e/src/po/video-update.po.ts index 752741378..3ffb7ba57 100644 --- a/client/e2e/src/po/video-update.po.ts +++ b/client/e2e/src/po/video-update.po.ts @@ -1,11 +1,11 @@ -import { by, element } from 'protractor' - export class VideoUpdatePage { async updateName (videoName: string) { - const nameInput = element(by.css('input#name')) - await nameInput.clear() - await nameInput.sendKeys(videoName) + const nameInput = $('input#name') + + await nameInput.waitForDisplayed() + await nameInput.clearValue() + await nameInput.setValue(videoName) } async validUpdate () { @@ -15,6 +15,6 @@ export class VideoUpdatePage { } private getSubmitButton () { - return element(by.css('.submit-container .action-button')) + return $('.submit-container .action-button') } } diff --git a/client/e2e/src/po/video-upload.po.ts b/client/e2e/src/po/video-upload.po.ts index a248912ed..34f916b55 100644 --- a/client/e2e/src/po/video-upload.po.ts +++ b/client/e2e/src/po/video-upload.po.ts @@ -1,33 +1,29 @@ -import { browser, by, element } from 'protractor' -import { FileDetector } from 'selenium-webdriver/remote' import { join } from 'path' export class VideoUploadPage { async navigateTo () { - await element(by.css('.header .publish-button')).click() + await $('.header .publish-button').click() - return browser.wait(browser.ExpectedConditions.visibilityOf(element(by.css('.upload-video-container')))) + await $('.upload-video-container').waitForDisplayed() } async uploadVideo () { - browser.setFileDetector(new FileDetector()) - const fileToUpload = join(__dirname, '../../fixtures/video.mp4') const fileInputSelector = '.upload-video-container input[type=file]' const parentFileInput = '.upload-video-container .button-file' // Avoid sending keys on non visible element - await browser.executeScript(`document.querySelector('${fileInputSelector}').style.opacity = 1`) - await browser.executeScript(`document.querySelector('${parentFileInput}').style.overflow = 'initial'`) + await browser.execute(`document.querySelector('${fileInputSelector}').style.opacity = 1`) + await browser.execute(`document.querySelector('${parentFileInput}').style.overflow = 'initial'`) - await browser.sleep(1000) + await browser.pause(1000) - const elem = element(by.css(fileInputSelector)) - await elem.sendKeys(fileToUpload) + const elem = await $(fileInputSelector) + await elem.chooseFile(fileToUpload) // Wait for the upload to finish - await browser.wait(async () => { - const actionButton = this.getSecondStepSubmitButton().element(by.css('.action-button')) + await browser.waitUntil(async () => { + const actionButton = this.getSecondStepSubmitButton().$('.action-button') const klass = await actionButton.getAttribute('class') return !klass.includes('disabled') @@ -35,16 +31,18 @@ export class VideoUploadPage { } async validSecondUploadStep (videoName: string) { - const nameInput = element(by.css('input#name')) - await nameInput.clear() - await nameInput.sendKeys(videoName) + const nameInput = $('input#name') + await nameInput.clearValue() + await nameInput.setValue(videoName) await this.getSecondStepSubmitButton().click() - return browser.wait(browser.ExpectedConditions.urlContains('/w/')) + return browser.waitUntil(async () => { + return (await browser.getUrl()).includes('/w/') + }) } private getSecondStepSubmitButton () { - return element(by.css('.submit-container my-button')) + 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 c875d5854..01061d5d4 100644 --- a/client/e2e/src/po/video-watch.po.ts +++ b/client/e2e/src/po/video-watch.po.ts @@ -1,5 +1,4 @@ -import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor' -import { browserSleep, isMobileDevice } from '../utils' +import { browserSleep, go } from '../utils' export class VideoWatchPage { async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { @@ -12,19 +11,19 @@ export class VideoWatchPage { url = '/videos/recently-added' } - await browser.get(url, 20000) + await go(url) // Waiting the following element does not work on Safari... if (isSafari) return browserSleep(3000) - const elem = element.all(by.css('.videos .video-miniature .video-miniature-name')).first() - return browser.wait(browser.ExpectedConditions.visibilityOf(elem)) + await $('.videos .video-miniature .video-miniature-name').waitForDisplayed() } - getVideosListName () { - return element.all(by.css('.videos .video-miniature .video-miniature-name')) - .getText() - .then((texts: any) => texts.map((t: any) => t.trim())) + async getVideosListName () { + const elems = await $$('.videos .video-miniature .video-miniature-name') + const texts = await Promise.all(elems.map(e => e.getText())) + + return texts.map(t => t.trim()) } waitWatchVideoName (videoName: string, isMobileDevice: boolean, isSafari: boolean) { @@ -33,99 +32,134 @@ export class VideoWatchPage { // On mobile we display the first node, on desktop the second const index = isMobileDevice ? 0 : 1 - const elem = element.all(by.css('.video-info .video-info-name')).get(index) - return browser.wait(browser.ExpectedConditions.textToBePresentInElement(elem, videoName)) + return browser.waitUntil(async () => { + return (await $$('.video-info .video-info-name')[index].getText()).includes(videoName) + }) } getVideoName () { - return this.getVideoNameElement().getText() + return this.getVideoNameElement().then(e => e.getText()) } async goOnAssociatedEmbed () { - let url = await browser.getCurrentUrl() + let url = await browser.getUrl() url = url.replace('/w/', '/videos/embed/') url = url.replace(':3333', ':9001') - return browser.get(url) + return go(url) } - async goOnP2PMediaLoaderEmbed () { - return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50') + goOnP2PMediaLoaderEmbed () { + return go( + 'https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50' + ) } - async goOnP2PMediaLoaderPlaylistEmbed () { - return browser.get('https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') + goOnP2PMediaLoaderPlaylistEmbed () { + return go( + 'https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a' + ) } async clickOnVideo (videoName: string) { - const video = element.all(by.css('.videos .video-miniature .video-miniature-name')) - .filter(e => e.getText().then(t => t === videoName )) - .first() + const video = async () => { + const videos = await $$('.videos .video-miniature .video-miniature-name').filter(async e => { + const t = await e.getText() + + return t === videoName + }) + + return videos[0] + } + + await browser.waitUntil(async () => { + const elem = await video() - await browser.wait(browser.ExpectedConditions.elementToBeClickable(video)) - await video.click() + return elem?.isClickable() + }); - await browser.wait(browser.ExpectedConditions.urlContains('/w/')) + (await video()).click() + + await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/')) } async clickOnFirstVideo () { - const video = element.all(by.css('.videos .video-miniature .video-thumbnail')).first() - const videoName = element.all(by.css('.videos .video-miniature .video-miniature-name')).first() + const video = () => $('.videos .video-miniature .video-thumbnail') + const videoName = () => $('.videos .video-miniature .video-miniature-name') + + await video().waitForClickable() - // Don't know why but the expectation fails on Safari - await browser.wait(browser.ExpectedConditions.elementToBeClickable(video)) + const textToReturn = await videoName().getText() + await video().click() - const textToReturn = videoName.getText() - await video.click() + await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/')) - await browser.wait(browser.ExpectedConditions.urlContains('/w/')) return textToReturn } async clickOnUpdate () { - const dropdown = element(by.css('my-video-actions-dropdown .action-button')) + const dropdown = $('my-video-actions-dropdown .action-button') await dropdown.click() - const items: ElementFinder[] = await element.all(by.css('.dropdown-menu.show .dropdown-item')) + await $('.dropdown-menu.show .dropdown-item').waitForDisplayed() + const items = await $$('.dropdown-menu.show .dropdown-item') for (const item of items) { const href = await item.getAttribute('href') - if (href && href.includes('/update/')) { + if (href?.includes('/update/')) { await item.click() return } } } - async clickOnSave () { - return element(by.css('.action-button-save')).click() + clickOnSave () { + return $('.action-button-save').click() } async createPlaylist (name: string) { - await element(by.css('.new-playlist-button')).click() + const newPlaylistButton = () => $('.new-playlist-button') + + await newPlaylistButton().waitForClickable() + await newPlaylistButton().click() + + const displayName = () => $('#displayName') - await element(by.css('#displayName')).sendKeys(name) + await displayName().waitForDisplayed() + await displayName().setValue(name) - return element(by.css('.new-playlist-block input[type=submit]')).click() + return $('.new-playlist-block input[type=submit]').click() } async saveToPlaylist (name: string) { - return element.all(by.css('my-video-add-to-playlist .playlist')) - .filter(p => p.getText().then(t => t === name)) - .click() + const playlist = () => $('my-video-add-to-playlist').$(`.playlist=${name}`) + + await playlist().waitForDisplayed() + + return playlist().click() } waitUntilVideoName (name: string, maxTime: number) { - const elem = this.getVideoNameElement() - - return browser.wait(ExpectedConditions.textToBePresentInElement(elem, name), maxTime) + return browser.waitUntil(async () => { + return (await this.getVideoName()) === name + }, { timeout: maxTime }) } - private getVideoNameElement () { + private async getVideoNameElement () { // We have 2 video info name block, pick the first that is not empty - return element.all(by.css('.video-info-first-row .video-info-name')) - .filter(e => e.getText().then(t => !!t)) - .first() + const elem = async () => { + const elems = await $$('.video-info-first-row .video-info-name').filter(e => e.isDisplayed()) + + return elems[0] + } + + await browser.waitUntil(async () => { + const e = await elem() + + return e?.isDisplayed() + }) + + return elem() } } -- cgit v1.2.3