Migrate to webdriverio
This commit is contained in:
parent
2a4c9669d2
commit
3419e0e1fe
|
@ -22,6 +22,8 @@
|
|||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"jsdoc/newline-after-description": "off",
|
||||
"jsdoc/check-alignment": "off",
|
||||
"lines-between-class-members": "off",
|
||||
"@typescript-eslint/lines-between-class-members": [ "off" ],
|
||||
"arrow-body-style": "off",
|
||||
|
|
|
@ -8,3 +8,4 @@
|
|||
/src/locale/target/iso639_*.xml
|
||||
/src/locale/target/player_*.xml
|
||||
/src/locale/target/server_*.xml
|
||||
/e2e/local.log
|
||||
|
|
|
@ -233,21 +233,6 @@
|
|||
"with": "src/environments/environment.hmr.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"e2e": {
|
||||
"localize": false,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.e2e.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -266,10 +251,6 @@
|
|||
},
|
||||
"ar-locale": {
|
||||
"browserTarget": "PeerTube:build:ar-locale"
|
||||
},
|
||||
"e2e": {
|
||||
"browserTarget": "PeerTube:build:e2e",
|
||||
"proxyConfig": "e2e/proxy.config.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -361,25 +342,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PeerTube-e2e": {
|
||||
"root": "e2e/",
|
||||
"sourceRoot": "",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "PeerTube:serve:e2e"
|
||||
},
|
||||
"configurations": {
|
||||
"local": {
|
||||
"protractorConfig": "e2e/local-protractor.conf.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "PeerTube",
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const {SpecReporter} = require('jasmine-spec-reporter')
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 25000,
|
||||
specs: ['./src/**/*.e2e-spec.ts'],
|
||||
|
||||
directConnect: true,
|
||||
|
||||
multiCapabilities: [
|
||||
{
|
||||
'browserName': 'firefox',
|
||||
'name': 'Firefox',
|
||||
'moz:firefoxOptions': {
|
||||
binary: '/usr/bin/firefox-developer-edition',
|
||||
// args: ["-headless"],
|
||||
log: {
|
||||
"level": "info" // default is "info"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'browserName': 'firefox',
|
||||
'name': 'Firefox ESR',
|
||||
'moz:firefoxOptions': {
|
||||
binary: '/usr/bin/firefox-esr',
|
||||
// args: ["-headless"],
|
||||
log: {
|
||||
"level": "info" // default is "info"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'browserName': 'chrome',
|
||||
'name': 'Chromium'
|
||||
}
|
||||
],
|
||||
|
||||
maxSessions: 1,
|
||||
baseUrl: 'http://localhost:3000/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 45000,
|
||||
print: function() {}
|
||||
},
|
||||
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
})
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }))
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const {SpecReporter} = require('jasmine-spec-reporter')
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 25000,
|
||||
specs: [ './src/**/*.e2e-spec.ts' ],
|
||||
|
||||
seleniumAddress: 'http://hub-cloud.browserstack.com/wd/hub',
|
||||
commonCapabilities: {
|
||||
'browserstack.user': process.env.BROWSERSTACK_USER,
|
||||
'browserstack.key': process.env.BROWSERSTACK_KEY,
|
||||
'browserstack.local': true,
|
||||
'browserstack.console': 'verbose',
|
||||
'browserstack.networkLogs': true,
|
||||
'browserstack.debug': true,
|
||||
project: 'PeerTube',
|
||||
build: 'Main',
|
||||
name: 'Bstack-[Protractor] Parallel Test'
|
||||
},
|
||||
|
||||
multiCapabilities: [
|
||||
{
|
||||
browserName: 'Safari',
|
||||
version: '11.1',
|
||||
name: 'Safari Desktop',
|
||||
resolution: '1280x1024'
|
||||
},
|
||||
{
|
||||
browserName: 'Chrome',
|
||||
name: 'Latest Chrome Desktop',
|
||||
resolution: '1280x1024'
|
||||
},
|
||||
{
|
||||
browserName: 'Firefox',
|
||||
version: '68', // ESR
|
||||
name: 'Firefox ESR Desktop',
|
||||
resolution: '1280x1024'
|
||||
},
|
||||
{
|
||||
browserName: 'Firefox',
|
||||
name: 'Latest Firefox Desktop',
|
||||
resolution: '1280x1024'
|
||||
},
|
||||
{
|
||||
browserName: 'Edge',
|
||||
name: 'Latest Edge Desktop',
|
||||
resolution: '1280x1024'
|
||||
},
|
||||
{
|
||||
browserName: 'Chrome',
|
||||
device: 'Google Nexus 6',
|
||||
real_mobile: 'true',
|
||||
os_version: '5.0',
|
||||
name: 'Latest Chrome Android'
|
||||
},
|
||||
{
|
||||
browserName: 'Safari',
|
||||
device: 'iPhone 8 Plus',
|
||||
real_mobile: 'true',
|
||||
os_version: '11',
|
||||
name: 'Safari iPhone'
|
||||
},
|
||||
{
|
||||
browserName: 'Safari',
|
||||
device: 'iPad 7th',
|
||||
real_mobile: 'true',
|
||||
os_version: '13',
|
||||
name: 'Safari iPad'
|
||||
}
|
||||
],
|
||||
|
||||
// maxSessions: 1,
|
||||
// BrowserStack compatible ports: https://www.browserstack.com/question/664
|
||||
baseUrl: 'http://localhost:3333/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 45000,
|
||||
print: function() {}
|
||||
},
|
||||
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
})
|
||||
jasmine.getEnv().addReporter(new SpecReporter({
|
||||
spec: { displayStacktrace: 'raw' }
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
exports.config.multiCapabilities.forEach(function (caps) {
|
||||
for (var i in exports.config.commonCapabilities) caps[i] = caps[i] || exports.config.commonCapabilities[i]
|
||||
})
|
|
@ -1,37 +0,0 @@
|
|||
{
|
||||
"/api": {
|
||||
"target": "http://localhost:9000",
|
||||
"secure": false
|
||||
},
|
||||
"/plugins": {
|
||||
"target": "http://localhost:9000",
|
||||
"secure": false
|
||||
},
|
||||
"/themes": {
|
||||
"target": "http://localhost:9000",
|
||||
"secure": false
|
||||
},
|
||||
"/static": {
|
||||
"target": "http://localhost:9000",
|
||||
"secure": false
|
||||
},
|
||||
"/lazy-static": {
|
||||
"target": "http://localhost:9000",
|
||||
"secure": false
|
||||
},
|
||||
"/socket.io": {
|
||||
"target": "ws://localhost:9000",
|
||||
"secure": false,
|
||||
"ws": true
|
||||
},
|
||||
"/!(client)**": {
|
||||
"target": "http://localhost:3333/client/index.html",
|
||||
"secure": false,
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"/!(client)**/**": {
|
||||
"target": "http://localhost:3333/client/index.html",
|
||||
"secure": false,
|
||||
"logLevel": "debug"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
browser.addCommand('chooseFile', async function (this: WebdriverIO.Element, localFilePath: string) {
|
||||
try {
|
||||
const remoteFile = await browser.uploadFile(localFilePath)
|
||||
|
||||
return this.addValue(remoteFile)
|
||||
} catch {
|
||||
console.log('Cannot upload file, fallback to add value.')
|
||||
|
||||
// Firefox does not support upload file, but if we're running the test in local we don't really need it
|
||||
return this.addValue(localFilePath)
|
||||
}
|
||||
}, true)
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 $('<my-video-playlist-element-miniature>').waitForDisplayed()
|
||||
|
||||
return $$('<my-video-playlist-element-miniature>').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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
return elem.getProperty('currentTime')
|
||||
}
|
||||
|
||||
waitUntilPlaylistInfo (text: string) {
|
||||
const elem = element(by.css('.video-js .vjs-playlist-info'))
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
await browser.wait(browser.ExpectedConditions.elementToBeClickable(video))
|
||||
await video.click()
|
||||
return t === videoName
|
||||
})
|
||||
|
||||
await browser.wait(browser.ExpectedConditions.urlContains('/w/'))
|
||||
return videos[0]
|
||||
}
|
||||
|
||||
await browser.waitUntil(async () => {
|
||||
const elem = await video()
|
||||
|
||||
return elem?.isClickable()
|
||||
});
|
||||
|
||||
(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')
|
||||
|
||||
// Don't know why but the expectation fails on Safari
|
||||
await browser.wait(browser.ExpectedConditions.elementToBeClickable(video))
|
||||
await video().waitForClickable()
|
||||
|
||||
const textToReturn = videoName.getText()
|
||||
await video.click()
|
||||
const textToReturn = await 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 element(by.css('#displayName')).sendKeys(name)
|
||||
await newPlaylistButton().waitForClickable()
|
||||
await newPlaylistButton().click()
|
||||
|
||||
return element(by.css('.new-playlist-block input[type=submit]')).click()
|
||||
const displayName = () => $('#displayName')
|
||||
|
||||
await displayName().waitForDisplayed()
|
||||
await displayName().setValue(name)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
declare namespace WebdriverIO {
|
||||
interface Element {
|
||||
chooseFile: (path: string) => Promise<void>
|
||||
}
|
||||
}
|
|
@ -1,34 +1,37 @@
|
|||
import { browser } from 'protractor'
|
||||
|
||||
async function browserSleep (amount: number) {
|
||||
const oldValue = await browser.waitForAngularEnabled()
|
||||
|
||||
// iOS does not seem to work with protractor
|
||||
// https://github.com/angular/protractor/issues/2840
|
||||
if (await isIOS()) browser.waitForAngularEnabled(true)
|
||||
|
||||
await browser.sleep(amount)
|
||||
|
||||
if (await isIOS()) browser.waitForAngularEnabled(oldValue)
|
||||
await browser.pause(amount)
|
||||
}
|
||||
|
||||
async function isMobileDevice () {
|
||||
const caps = await browser.getCapabilities()
|
||||
return caps.get('realMobile') === 'true' || caps.get('realMobile') === true
|
||||
function isMobileDevice () {
|
||||
const platformName = (browser.capabilities['platformName'] || '').toLowerCase()
|
||||
|
||||
return platformName === 'android' || platformName === 'ios'
|
||||
}
|
||||
|
||||
async function isSafari () {
|
||||
const caps = await browser.getCapabilities()
|
||||
return caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari'
|
||||
function isSafari () {
|
||||
return browser.capabilities['browserName'] &&
|
||||
browser.capabilities['browserName'].toLowerCase() === 'safari'
|
||||
}
|
||||
|
||||
async function isIOS () {
|
||||
return await isMobileDevice() && await isSafari()
|
||||
function isIOS () {
|
||||
return isMobileDevice() && isSafari()
|
||||
}
|
||||
|
||||
export {
|
||||
async function go (url: string) {
|
||||
await browser.url(url)
|
||||
|
||||
// Hide notifications that could fail tests when hiding buttons
|
||||
await browser.execute(() => {
|
||||
const style = document.createElement('style')
|
||||
style.innerHTML = 'p-toast { display: none }'
|
||||
document.head.appendChild(style)
|
||||
})
|
||||
}
|
||||
|
||||
export {
|
||||
isMobileDevice,
|
||||
isSafari,
|
||||
isIOS,
|
||||
go,
|
||||
browserSleep
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { browser } from 'protractor'
|
||||
import { LoginPage } from './po/login.po'
|
||||
import { MyAccountPage } from './po/my-account'
|
||||
import { PlayerPage } from './po/player.po'
|
||||
import { VideoUpdatePage } from './po/video-update.po'
|
||||
import { VideoUploadPage } from './po/video-upload.po'
|
||||
import { VideoWatchPage } from './po/video-watch.po'
|
||||
import { isIOS, isMobileDevice, isSafari } from './utils'
|
||||
import { browserSleep, go, isIOS, isMobileDevice, isSafari } from './utils'
|
||||
|
||||
async function skipIfUploadNotSupported () {
|
||||
if (await isMobileDevice() || await isSafari()) {
|
||||
function isUploadUnsupported () {
|
||||
if (isMobileDevice() || isSafari()) {
|
||||
console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.')
|
||||
return true
|
||||
}
|
||||
|
@ -24,11 +23,30 @@ describe('Videos workflow', () => {
|
|||
let loginPage: LoginPage
|
||||
let playerPage: PlayerPage
|
||||
|
||||
let videoName = new Date().getTime() + ' video'
|
||||
const video2Name = new Date().getTime() + ' second video'
|
||||
const playlistName = new Date().getTime() + ' playlist'
|
||||
let videoName = Math.random() + ' video'
|
||||
const video2Name = Math.random() + ' second video'
|
||||
const playlistName = Math.random() + ' playlist'
|
||||
let videoWatchUrl: string
|
||||
|
||||
before(async () => {
|
||||
if (isIOS()) {
|
||||
console.log('iOS detected')
|
||||
} else if (isMobileDevice()) {
|
||||
console.log('Android detected.')
|
||||
} else if (isSafari()) {
|
||||
console.log('Safari detected.')
|
||||
}
|
||||
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await browser.waitUntil(async () => {
|
||||
await go('/')
|
||||
await browserSleep(500)
|
||||
|
||||
return $('<my-app>').isDisplayed()
|
||||
}, { timeout: 20 * 1000 })
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
videoWatchPage = new VideoWatchPage()
|
||||
videoUploadPage = new VideoUploadPage()
|
||||
|
@ -37,25 +55,13 @@ describe('Videos workflow', () => {
|
|||
loginPage = new LoginPage()
|
||||
playerPage = new PlayerPage()
|
||||
|
||||
if (await isIOS()) {
|
||||
// iOS does not seem to work with protractor
|
||||
// https://github.com/angular/protractor/issues/2840
|
||||
browser.waitForAngularEnabled(false)
|
||||
|
||||
console.log('iOS detected')
|
||||
} else if (await isMobileDevice()) {
|
||||
console.log('Android detected.')
|
||||
} else if (await isSafari()) {
|
||||
console.log('Safari detected.')
|
||||
}
|
||||
|
||||
if (!await isMobileDevice()) {
|
||||
await browser.driver.manage().window().maximize()
|
||||
if (!isMobileDevice()) {
|
||||
await browser.maximizeWindow()
|
||||
}
|
||||
})
|
||||
|
||||
it('Should log in', async () => {
|
||||
if (await isMobileDevice() || await isSafari()) {
|
||||
if (isMobileDevice() || isSafari()) {
|
||||
console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.')
|
||||
return
|
||||
}
|
||||
|
@ -64,7 +70,7 @@ describe('Videos workflow', () => {
|
|||
})
|
||||
|
||||
it('Should upload a video', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await videoUploadPage.navigateTo()
|
||||
|
||||
|
@ -73,62 +79,52 @@ describe('Videos workflow', () => {
|
|||
})
|
||||
|
||||
it('Should list videos', async () => {
|
||||
await videoWatchPage.goOnVideosList(await isMobileDevice(), await isSafari())
|
||||
await videoWatchPage.goOnVideosList(isMobileDevice(), isSafari())
|
||||
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
const videoNames = videoWatchPage.getVideosListName()
|
||||
const videoNames = await videoWatchPage.getVideosListName()
|
||||
expect(videoNames).toContain(videoName)
|
||||
})
|
||||
|
||||
it('Should go on video watch page', async () => {
|
||||
let videoNameToExcept = videoName
|
||||
|
||||
if (await isMobileDevice() || await isSafari()) {
|
||||
await browser.get('https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e')
|
||||
if (isMobileDevice() || isSafari()) {
|
||||
await go('https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e')
|
||||
videoNameToExcept = 'E2E tests'
|
||||
} else {
|
||||
await videoWatchPage.clickOnVideo(videoName)
|
||||
}
|
||||
|
||||
return videoWatchPage.waitWatchVideoName(videoNameToExcept, await isMobileDevice(), await isSafari())
|
||||
return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice(), isSafari())
|
||||
})
|
||||
|
||||
it('Should play the video', async () => {
|
||||
videoWatchUrl = await browser.getCurrentUrl()
|
||||
videoWatchUrl = await browser.getUrl()
|
||||
|
||||
await playerPage.playAndPauseVideo(true)
|
||||
expect(playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
|
||||
expect(await playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
|
||||
it('Should watch the associated embed video', async () => {
|
||||
const oldValue = await browser.waitForAngularEnabled()
|
||||
await browser.waitForAngularEnabled(false)
|
||||
|
||||
await videoWatchPage.goOnAssociatedEmbed()
|
||||
|
||||
await playerPage.playAndPauseVideo(false)
|
||||
expect(playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
|
||||
|
||||
await browser.waitForAngularEnabled(oldValue)
|
||||
expect(await playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
|
||||
it('Should watch the p2p media loader embed video', async () => {
|
||||
const oldValue = await browser.waitForAngularEnabled()
|
||||
await browser.waitForAngularEnabled(false)
|
||||
|
||||
await videoWatchPage.goOnP2PMediaLoaderEmbed()
|
||||
|
||||
await playerPage.playAndPauseVideo(false)
|
||||
expect(playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
|
||||
|
||||
await browser.waitForAngularEnabled(oldValue)
|
||||
expect(await playerPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
|
||||
it('Should update the video', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await browser.get(videoWatchUrl)
|
||||
await go(videoWatchUrl)
|
||||
|
||||
await videoWatchPage.clickOnUpdate()
|
||||
|
||||
|
@ -142,14 +138,14 @@ describe('Videos workflow', () => {
|
|||
})
|
||||
|
||||
it('Should add the video in my playlist', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await videoWatchPage.clickOnSave()
|
||||
|
||||
await videoWatchPage.createPlaylist(playlistName)
|
||||
|
||||
await videoWatchPage.saveToPlaylist(playlistName)
|
||||
await browser.sleep(5000)
|
||||
await browser.pause(5000)
|
||||
|
||||
await videoUploadPage.navigateTo()
|
||||
|
||||
|
@ -161,7 +157,7 @@ describe('Videos workflow', () => {
|
|||
})
|
||||
|
||||
it('Should have the playlist in my account', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await myAccountPage.navigateToMyPlaylists()
|
||||
|
||||
|
@ -175,26 +171,18 @@ describe('Videos workflow', () => {
|
|||
})
|
||||
|
||||
it('Should watch the playlist', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await myAccountPage.playPlaylist()
|
||||
|
||||
const oldValue = await browser.waitForAngularEnabled()
|
||||
await browser.waitForAngularEnabled(false)
|
||||
|
||||
await videoWatchPage.waitUntilVideoName(video2Name, 20000 * 1000)
|
||||
|
||||
await browser.waitForAngularEnabled(oldValue)
|
||||
await videoWatchPage.waitUntilVideoName(video2Name, 30 * 1000)
|
||||
})
|
||||
|
||||
it('Should watch the webtorrent playlist in the embed', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
const accessToken = await browser.executeScript(`return window.localStorage.getItem('access_token');`)
|
||||
const refreshToken = await browser.executeScript(`return window.localStorage.getItem('refresh_token');`)
|
||||
|
||||
const oldValue = await browser.waitForAngularEnabled()
|
||||
await browser.waitForAngularEnabled(false)
|
||||
const accessToken = await browser.execute(`return window.localStorage.getItem('access_token');`)
|
||||
const refreshToken = await browser.execute(`return window.localStorage.getItem('refresh_token');`)
|
||||
|
||||
await myAccountPage.goOnAssociatedPlaylistEmbed()
|
||||
|
||||
|
@ -202,49 +190,45 @@ describe('Videos workflow', () => {
|
|||
|
||||
console.log('Will set %s and %s tokens in local storage.', accessToken, refreshToken)
|
||||
|
||||
await browser.executeScript(`window.localStorage.setItem('access_token', '${accessToken}');`)
|
||||
await browser.executeScript(`window.localStorage.setItem('refresh_token', '${refreshToken}');`)
|
||||
await browser.executeScript(`window.localStorage.setItem('token_type', 'Bearer');`)
|
||||
await browser.execute(`window.localStorage.setItem('access_token', '${accessToken}');`)
|
||||
await browser.execute(`window.localStorage.setItem('refresh_token', '${refreshToken}');`)
|
||||
await browser.execute(`window.localStorage.setItem('token_type', 'Bearer');`)
|
||||
|
||||
await browser.refresh()
|
||||
|
||||
await playerPage.playVideo()
|
||||
|
||||
await playerPage.waitUntilPlaylistInfo('2/2')
|
||||
|
||||
await browser.waitForAngularEnabled(oldValue)
|
||||
await playerPage.waitUntilPlaylistInfo('2/2', 30 * 1000)
|
||||
})
|
||||
|
||||
it('Should watch the HLS playlist in the embed', async () => {
|
||||
const oldValue = await browser.waitForAngularEnabled()
|
||||
await browser.waitForAngularEnabled(false)
|
||||
|
||||
await videoWatchPage.goOnP2PMediaLoaderPlaylistEmbed()
|
||||
|
||||
await playerPage.playVideo()
|
||||
|
||||
await playerPage.waitUntilPlaylistInfo('2/2')
|
||||
|
||||
await browser.waitForAngularEnabled(oldValue)
|
||||
await playerPage.waitUntilPlaylistInfo('2/2', 30 * 1000)
|
||||
})
|
||||
|
||||
it('Should delete the video 2', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
// Go to the dev website
|
||||
await browser.get(videoWatchUrl)
|
||||
await go(videoWatchUrl)
|
||||
|
||||
await myAccountPage.navigateToMyVideos()
|
||||
|
||||
await myAccountPage.removeVideo(video2Name)
|
||||
await myAccountPage.validRemove()
|
||||
|
||||
const count = await myAccountPage.countVideos([ videoName, video2Name ])
|
||||
expect(count).toEqual(1)
|
||||
await browser.waitUntil(async () => {
|
||||
const count = await myAccountPage.countVideos([ videoName, video2Name ])
|
||||
|
||||
return count === 1
|
||||
})
|
||||
})
|
||||
|
||||
it('Should delete the first video', async () => {
|
||||
if (await skipIfUploadNotSupported()) return
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await myAccountPage.removeVideo(videoName)
|
||||
await myAccountPage.validRemove()
|
||||
|
|
|
@ -5,9 +5,14 @@
|
|||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
"node",
|
||||
"webdriverio/async",
|
||||
"@wdio/mocha-framework",
|
||||
"expect-webdriverio"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"./*.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
import { config as mainConfig } from './wdio.main.conf'
|
||||
|
||||
const user = process.env.BROWSERSTACK_USER
|
||||
const key = process.env.BROWSERSTACK_KEY
|
||||
|
||||
if (!user) throw new Error('Miss browser stack user')
|
||||
if (!key) throw new Error('Miss browser stack key')
|
||||
|
||||
function buildMainOptions (sessionName: string) {
|
||||
return {
|
||||
projectName: 'PeerTube',
|
||||
buildName: 'Main E2E - ' + new Date().toISOString().split('T')[0],
|
||||
sessionName,
|
||||
consoleLogs: 'info',
|
||||
networkLogs: true
|
||||
}
|
||||
}
|
||||
|
||||
function buildBStackDesktopOptions (sessionName: string, resolution?: string) {
|
||||
return {
|
||||
'bstack:options': {
|
||||
...buildMainOptions(sessionName),
|
||||
|
||||
resolution
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildBStackMobileOptions (sessionName: string, deviceName: string, osVersion: string) {
|
||||
return {
|
||||
'bstack:options': {
|
||||
...buildMainOptions(sessionName),
|
||||
|
||||
realMobile: true,
|
||||
osVersion,
|
||||
deviceName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
...mainConfig,
|
||||
|
||||
user,
|
||||
key,
|
||||
|
||||
maxInstances: 5,
|
||||
|
||||
capabilities: [
|
||||
{
|
||||
browserName: 'Chrome',
|
||||
|
||||
...buildBStackDesktopOptions('Latest Chrome Desktop', '1280x1024')
|
||||
},
|
||||
{
|
||||
browserName: 'Firefox',
|
||||
browserVersion: '68', // ESR
|
||||
|
||||
...buildBStackDesktopOptions('Firefox ESR Desktop', '1280x1024')
|
||||
},
|
||||
{
|
||||
browserName: 'Safari',
|
||||
browserVersion: '11.1',
|
||||
|
||||
...buildBStackDesktopOptions('Safari Desktop', '1280x1024')
|
||||
},
|
||||
{
|
||||
browserName: 'Firefox',
|
||||
|
||||
...buildBStackDesktopOptions('Firefox Latest', '1280x1024')
|
||||
},
|
||||
{
|
||||
browserName: 'Edge',
|
||||
|
||||
...buildBStackDesktopOptions('Edge Latest', '1280x1024')
|
||||
},
|
||||
|
||||
{
|
||||
browserName: 'Chrome',
|
||||
|
||||
...buildBStackMobileOptions('Latest Chrome Android', 'Samsung Galaxy S6', '5.0')
|
||||
},
|
||||
{
|
||||
browserName: 'Safari',
|
||||
|
||||
...buildBStackMobileOptions('Safari iPhone', 'iPhone 8 Plus', '11')
|
||||
},
|
||||
{
|
||||
browserName: 'Safari',
|
||||
|
||||
...buildBStackMobileOptions('Safari iPad', 'iPad 7th', '13')
|
||||
}
|
||||
],
|
||||
|
||||
host: 'hub-cloud.browserstack.com',
|
||||
connectionRetryTimeout: 240000,
|
||||
waitforTimeout: 20000,
|
||||
|
||||
services: [
|
||||
[
|
||||
'browserstack', { browserstackLocal: true }
|
||||
]
|
||||
],
|
||||
|
||||
after: function (result) {
|
||||
if (result === 0) {
|
||||
browser.executeScript('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed","reason": ""}}', [])
|
||||
} else {
|
||||
browser.executeScript('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed","reason": ""}}', [])
|
||||
}
|
||||
}
|
||||
} as WebdriverIO.Config
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import { config as mainConfig } from './wdio.main.conf'
|
||||
|
||||
const prefs = {
|
||||
'intl.accept_languages': 'en'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
...mainConfig,
|
||||
|
||||
runner: 'local',
|
||||
|
||||
maxInstances: 1,
|
||||
|
||||
capabilities: [
|
||||
{
|
||||
browserName: 'chrome',
|
||||
acceptInsecureCerts: true,
|
||||
'goog:chromeOptions': {
|
||||
prefs
|
||||
}
|
||||
},
|
||||
{
|
||||
browserName: 'firefox',
|
||||
'moz:firefoxOptions': {
|
||||
// args: [ '-headless' ],
|
||||
binary: '/usr/bin/firefox-developer-edition',
|
||||
prefs
|
||||
}
|
||||
},
|
||||
{
|
||||
browserName: 'firefox',
|
||||
'moz:firefoxOptions': {
|
||||
// args: [ '-headless' ],
|
||||
binary: '/usr/bin/firefox-esr',
|
||||
prefs
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
services: [ 'chromedriver', 'geckodriver' ]
|
||||
} as WebdriverIO.Config
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
export const config = {
|
||||
//
|
||||
// ====================
|
||||
// Runner Configuration
|
||||
// ====================
|
||||
//
|
||||
//
|
||||
// ==================
|
||||
// Specify Test Files
|
||||
// ==================
|
||||
// Define which test specs should run. The pattern is relative to the directory
|
||||
// from which `wdio` was called.
|
||||
//
|
||||
// The specs are defined as an array of spec files (optionally using wildcards
|
||||
// that will be expanded). The test for each spec file will be run in a separate
|
||||
// worker process. In order to have a group of spec files run in the same worker
|
||||
// process simply enclose them in an array within the specs array.
|
||||
//
|
||||
// If you are calling `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script),
|
||||
// then the current working directory is where your `package.json` resides, so `wdio`
|
||||
// will be called from there.
|
||||
//
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
// Patterns to exclude.
|
||||
exclude: [
|
||||
// 'path/to/excluded/files'
|
||||
],
|
||||
//
|
||||
// ===================
|
||||
// Test Configurations
|
||||
// ===================
|
||||
// Define all options that are relevant for the WebdriverIO instance here
|
||||
//
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
logLevel: 'info',
|
||||
//
|
||||
// Set specific log levels per logger
|
||||
// loggers:
|
||||
// - webdriver, webdriverio
|
||||
// - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
|
||||
// - @wdio/mocha-framework, @wdio/jasmine-framework
|
||||
// - @wdio/local-runner
|
||||
// - @wdio/sumologic-reporter
|
||||
// - @wdio/cli, @wdio/config, @wdio/utils
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
// logLevels: {
|
||||
// webdriver: 'info',
|
||||
// '@wdio/appium-service': 'info'
|
||||
// },
|
||||
//
|
||||
// If you only want to run your tests until a specific amount of tests have failed use
|
||||
// bail (default is 0 - don't bail, run all tests).
|
||||
bail: 1,
|
||||
//
|
||||
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
|
||||
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
|
||||
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
|
||||
// gets prepended directly.
|
||||
baseUrl: 'http://localhost:9001',
|
||||
//
|
||||
// Default timeout for all waitFor* commands.
|
||||
waitforTimeout: 5000,
|
||||
//
|
||||
// Default timeout in milliseconds for request
|
||||
// if browser driver or grid doesn't send response
|
||||
connectionRetryTimeout: 120000,
|
||||
//
|
||||
// Default request retries count
|
||||
connectionRetryCount: 3,
|
||||
|
||||
// Framework you want to run your specs with.
|
||||
// The following are supported: Mocha, Jasmine, and Cucumber
|
||||
// see also: https://webdriver.io/docs/frameworks
|
||||
//
|
||||
// Make sure you have the wdio adapter package for the specific framework installed
|
||||
// before running any tests.
|
||||
framework: 'mocha',
|
||||
//
|
||||
// The number of times to retry the entire specfile when it fails as a whole
|
||||
// specFileRetries: 1,
|
||||
//
|
||||
// Delay in seconds between the spec file retry attempts
|
||||
// specFileRetriesDelay: 0,
|
||||
//
|
||||
// Whether or not retried specfiles should be retried immediately or deferred to the end of the queue
|
||||
// specFileRetriesDeferred: false,
|
||||
//
|
||||
// Test reporter for stdout.
|
||||
// The only one supported by default is 'dot'
|
||||
// see also: https://webdriver.io/docs/dot-reporter
|
||||
reporters: [ 'spec' ],
|
||||
|
||||
//
|
||||
// Options to be passed to Mocha.
|
||||
// See the full list at http://mochajs.org/
|
||||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
timeout: 60000
|
||||
},
|
||||
|
||||
autoCompileOpts: {
|
||||
autoCompile: true,
|
||||
|
||||
tsNodeOpts: {
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
}
|
||||
},
|
||||
|
||||
before: function () {
|
||||
require('expect-webdriverio')
|
||||
require('./src/commands/upload')
|
||||
}
|
||||
} as Partial<WebdriverIO.Config>
|
|
@ -58,8 +58,6 @@
|
|||
"@types/chart.js": "^2.9.16",
|
||||
"@types/core-js": "^2.5.2",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/jasmine": "^3.3.15",
|
||||
"@types/jasminewd2": "^2.0.3",
|
||||
"@types/jschannel": "^1.0.0",
|
||||
"@types/linkifyjs": "^2.1.2",
|
||||
"@types/lodash-es": "^4.17.0",
|
||||
|
@ -71,12 +69,19 @@
|
|||
"@types/webtorrent": "^0.109.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.29.3",
|
||||
"@typescript-eslint/parser": "4.29.3",
|
||||
"@wdio/browserstack-service": "^7.11.1",
|
||||
"@wdio/cli": "^7.11.1",
|
||||
"@wdio/codemod": "^0.9.0",
|
||||
"@wdio/local-runner": "^7.11.1",
|
||||
"@wdio/mocha-framework": "^7.11.1",
|
||||
"@wdio/spec-reporter": "^7.10.1",
|
||||
"angular2-hotkeys": "^2.1.2",
|
||||
"angularx-qrcode": "11.0.0",
|
||||
"bootstrap": "^4.1.3",
|
||||
"buffer": "^6.0.3",
|
||||
"cache-chunk-store": "^3.0.0",
|
||||
"chart.js": "^3.5.1",
|
||||
"chromedriver": "^92.0.1",
|
||||
"core-js": "^3.1.4",
|
||||
"css-loader": "^6.2.0",
|
||||
"debug": "^4.3.1",
|
||||
|
@ -85,19 +90,15 @@
|
|||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-jsdoc": "^36.0.8",
|
||||
"eslint-plugin-prefer-arrow": "latest",
|
||||
"expect": "^27.1.0",
|
||||
"expect-webdriverio": "^3.1.2",
|
||||
"focus-visible": "^5.0.2",
|
||||
"geckodriver": "^2.0.3",
|
||||
"hls.js": "^1.0.7",
|
||||
"html-loader": "^2.1.2",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"https-browserify": "^1.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"jschannel": "^1.0.2",
|
||||
"karma": "~6.3.2",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"linkifyjs": "^2.1.5",
|
||||
"lodash-es": "^4.17.4",
|
||||
"markdown-it": "12.2.0",
|
||||
|
@ -106,7 +107,6 @@
|
|||
"path-browserify": "^1.0.0",
|
||||
"primeng": "^12.0.0-rc.1",
|
||||
"process": "^0.11.10",
|
||||
"protractor": "~7.0.0",
|
||||
"purify-css": "^1.2.5",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rxjs": "^7.3.0",
|
||||
|
@ -129,6 +129,8 @@
|
|||
"videojs-dock": "^2.0.2",
|
||||
"videojs-hotkeys": "^0.2.27",
|
||||
"videostream": "~3.2.1",
|
||||
"wdio-chromedriver-service": "^7.2.0",
|
||||
"wdio-geckodriver-service": "^2.0.3",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webtorrent": "^1.3.8",
|
||||
|
|
2463
client/yarn.lock
2463
client/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -4,12 +4,6 @@ set -eu
|
|||
|
||||
npm run clean:server:test
|
||||
|
||||
(
|
||||
cd client
|
||||
npm run webdriver-manager -- update
|
||||
npm run webpack -- --config webpack/webpack.video-embed.js --mode development
|
||||
)
|
||||
|
||||
npm run concurrently -- -k -s first \
|
||||
"cd client && npm run ng -- e2e --port 3333 -c local" \
|
||||
"cd client/e2e && ../node_modules/.bin/wdio run ./wdio.local.conf.ts" \
|
||||
"NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"log\": { \"level\": \"warn\" }, \"signup\": { \"enabled\": false } }' node dist/server"
|
||||
|
|
|
@ -197,9 +197,6 @@ async function addVideo (options: {
|
|||
}, sequelizeOptions)
|
||||
}
|
||||
|
||||
// Channel has a new content, set as updated
|
||||
await videoCreated.VideoChannel.setAsUpdated(t)
|
||||
|
||||
await autoBlacklistVideoIfNeeded({
|
||||
video,
|
||||
user,
|
||||
|
@ -214,6 +211,9 @@ async function addVideo (options: {
|
|||
return { videoCreated }
|
||||
})
|
||||
|
||||
// Channel has a new content, set as updated
|
||||
await videoCreated.VideoChannel.setAsUpdated()
|
||||
|
||||
createTorrentFederate(video, videoFile)
|
||||
.then(() => {
|
||||
if (video.state === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE) {
|
||||
|
|
|
@ -753,7 +753,7 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
|
|||
return this.Actor.isOutdated()
|
||||
}
|
||||
|
||||
setAsUpdated (transaction: Transaction) {
|
||||
setAsUpdated (transaction?: Transaction) {
|
||||
return setAsUpdated('videoChannel', this.id, transaction)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue