Fix NSFW filter and add tests
This commit is contained in:
parent
2ede07153c
commit
6d210220be
28 changed files with 550 additions and 116 deletions
|
@ -281,6 +281,7 @@
|
|||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"e2e/**/*.ts",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
|
|
29
client/e2e/src/po/admin-config.po.ts
Normal file
29
client/e2e/src/po/admin-config.po.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { browserSleep, go } from '../utils'
|
||||
|
||||
export class AdminConfigPage {
|
||||
|
||||
async navigateTo (tab: 'instance-homepage' | 'basic-configuration' | 'instance-information') {
|
||||
const waitTitles = {
|
||||
'instance-homepage': 'INSTANCE HOMEPAGE',
|
||||
'basic-configuration': 'APPEARANCE',
|
||||
'instance-information': 'INSTANCE'
|
||||
}
|
||||
|
||||
await go('/admin/config/edit-custom#' + tab)
|
||||
|
||||
await $('.inner-form-title=' + waitTitles[tab]).waitForDisplayed()
|
||||
}
|
||||
|
||||
updateNSFWSetting (newValue: 'do_not_list' | 'blur' | 'display') {
|
||||
return $('#instanceDefaultNSFWPolicy').selectByAttribute('value', newValue)
|
||||
}
|
||||
|
||||
updateHomepage (newValue: string) {
|
||||
return $('#instanceCustomHomepageContent').setValue(newValue)
|
||||
}
|
||||
|
||||
async save () {
|
||||
await $('input[type=submit]').click()
|
||||
await browserSleep(200)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { go } from '../utils'
|
||||
|
||||
export class LoginPage {
|
||||
|
||||
async loginAsRootUser () {
|
||||
await go('/login')
|
||||
|
||||
|
@ -8,7 +9,7 @@ export class LoginPage {
|
|||
await browser.execute(`window.localStorage.setItem('no_welcome_modal', 'true')`)
|
||||
|
||||
await $('input#username').setValue('root')
|
||||
await $('input#password').setValue('test1')
|
||||
await $('input#password').setValue('test' + this.getSuffix())
|
||||
|
||||
await browser.pause(1000)
|
||||
|
||||
|
@ -19,7 +20,24 @@ export class LoginPage {
|
|||
await expect(this.getLoggedInInfoElem()).toHaveText('root')
|
||||
}
|
||||
|
||||
async logout () {
|
||||
await $('.logged-in-more').click()
|
||||
|
||||
const logout = () => $('.dropdown-item*=Log out')
|
||||
|
||||
await logout().waitForDisplayed()
|
||||
await logout().click()
|
||||
|
||||
await $('.login-buttons-block').waitForDisplayed()
|
||||
}
|
||||
|
||||
private getLoggedInInfoElem () {
|
||||
return $('.logged-in-display-name')
|
||||
}
|
||||
|
||||
private getSuffix () {
|
||||
return browser.config.baseUrl
|
||||
? browser.config.baseUrl.slice(-1)
|
||||
: '1'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,24 @@ export class MyAccountPage {
|
|||
return $('a[href="/my-library/history/videos"]').click()
|
||||
}
|
||||
|
||||
// Settings
|
||||
|
||||
navigateToMySettings () {
|
||||
return $('a[href="/my-account"]').click()
|
||||
}
|
||||
|
||||
async updateNSFW (newValue: 'do_not_list' | 'blur' | 'display') {
|
||||
const nsfw = $('#nsfwPolicy')
|
||||
|
||||
await nsfw.waitForDisplayed()
|
||||
await nsfw.scrollIntoView(false) // Avoid issues with fixed header on firefox
|
||||
await nsfw.selectByAttribute('value', newValue)
|
||||
|
||||
const submit = $('my-user-video-settings input[type=submit]')
|
||||
await submit.scrollIntoView(false)
|
||||
await submit.click()
|
||||
}
|
||||
|
||||
// My account Videos
|
||||
|
||||
async removeVideo (name: string) {
|
||||
|
|
|
@ -15,6 +15,9 @@ export class PlayerPage {
|
|||
|
||||
waitUntilPlaylistInfo (text: string, maxTime: number) {
|
||||
return browser.waitUntil(async () => {
|
||||
// Without this we have issues on iphone
|
||||
await $('.video-js').click()
|
||||
|
||||
return (await $('.video-js .vjs-playlist-info').getText()).includes(text)
|
||||
}, { timeout: maxTime })
|
||||
}
|
||||
|
@ -42,7 +45,7 @@ export class PlayerPage {
|
|||
await browserSleep(2000)
|
||||
|
||||
await browser.waitUntil(async () => {
|
||||
return (await this.getWatchVideoPlayerCurrentTime()) >= 2
|
||||
return (await this.getWatchVideoPlayerCurrentTime()) >= waitUntilSec
|
||||
})
|
||||
|
||||
await videojsElem().click()
|
||||
|
|
128
client/e2e/src/po/video-list.po.ts
Normal file
128
client/e2e/src/po/video-list.po.ts
Normal file
|
@ -0,0 +1,128 @@
|
|||
import { browserSleep, go } from '../utils'
|
||||
|
||||
export class VideoListPage {
|
||||
|
||||
constructor (private isMobileDevice: boolean, private isSafari: boolean) {
|
||||
|
||||
}
|
||||
|
||||
async goOnVideosList () {
|
||||
let url: string
|
||||
|
||||
// We did not upload a file on a mobile device
|
||||
if (this.isMobileDevice === true || this.isSafari === true) {
|
||||
url = 'https://peertube2.cpy.re/videos/local'
|
||||
} else {
|
||||
url = '/videos/recently-added'
|
||||
}
|
||||
|
||||
await go(url)
|
||||
|
||||
// Waiting the following element does not work on Safari...
|
||||
if (this.isSafari) return browserSleep(3000)
|
||||
|
||||
await this.waitForList()
|
||||
}
|
||||
|
||||
async goOnLocal () {
|
||||
await $('.menu-link[href="/videos/local"]').click()
|
||||
await this.waitForTitle('Local videos')
|
||||
}
|
||||
|
||||
async goOnRecentlyAdded () {
|
||||
await $('.menu-link[href="/videos/recently-added"]').click()
|
||||
await this.waitForTitle('Recently added')
|
||||
}
|
||||
|
||||
async goOnTrending () {
|
||||
await $('.menu-link[href="/videos/trending"]').click()
|
||||
await this.waitForTitle('Trending')
|
||||
}
|
||||
|
||||
async goOnHomepage () {
|
||||
await go('/home')
|
||||
await this.waitForList()
|
||||
}
|
||||
|
||||
async goOnRootChannel () {
|
||||
await go('/c/root_channel/videos')
|
||||
await this.waitForList()
|
||||
}
|
||||
|
||||
async goOnRootAccount () {
|
||||
await go('/a/root/videos')
|
||||
await this.waitForList()
|
||||
}
|
||||
|
||||
async goOnRootAccountChannels () {
|
||||
await go('/a/root/video-channels')
|
||||
await this.waitForList()
|
||||
}
|
||||
|
||||
getNSFWFilter () {
|
||||
return $$('.active-filter').filter(async a => {
|
||||
return (await a.getText()).includes('Sensitive')
|
||||
}).then(f => f[0])
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
videoExists (name: string) {
|
||||
return $('.video-miniature-name=' + name).isDisplayed()
|
||||
}
|
||||
|
||||
async videoIsBlurred (name: string) {
|
||||
const filter = await $('.video-miniature-name=' + name).getCSSProperty('filter')
|
||||
|
||||
return filter.value !== 'none'
|
||||
}
|
||||
|
||||
async clickOnVideo (videoName: string) {
|
||||
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()
|
||||
|
||||
return elem?.isClickable()
|
||||
});
|
||||
|
||||
(await video()).click()
|
||||
|
||||
await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/'))
|
||||
}
|
||||
|
||||
async clickOnFirstVideo () {
|
||||
const video = () => $('.videos .video-miniature .video-thumbnail')
|
||||
const videoName = () => $('.videos .video-miniature .video-miniature-name')
|
||||
|
||||
await video().waitForClickable()
|
||||
|
||||
const textToReturn = await videoName().getText()
|
||||
await video().click()
|
||||
|
||||
await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/'))
|
||||
|
||||
return textToReturn
|
||||
}
|
||||
|
||||
private waitForList () {
|
||||
return $('.videos .video-miniature .video-miniature-name').waitForDisplayed()
|
||||
}
|
||||
|
||||
private waitForTitle (title: string) {
|
||||
return $('h1=' + title).waitForDisplayed()
|
||||
}
|
||||
}
|
11
client/e2e/src/po/video-search.po.ts
Normal file
11
client/e2e/src/po/video-search.po.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export class VideoSearchPage {
|
||||
|
||||
async search (search: string) {
|
||||
await $('#search-video').setValue(search)
|
||||
await $('my-header .icon-search').click()
|
||||
|
||||
await browser.waitUntil(() => {
|
||||
return $('my-video-miniature').isDisplayed()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { join } from 'path'
|
||||
import { clickOnCheckbox } from '../utils'
|
||||
|
||||
export class VideoUploadPage {
|
||||
async navigateTo () {
|
||||
|
@ -30,6 +31,10 @@ export class VideoUploadPage {
|
|||
})
|
||||
}
|
||||
|
||||
setAsNSFW () {
|
||||
return clickOnCheckbox('nsfw')
|
||||
}
|
||||
|
||||
async validSecondUploadStep (videoName: string) {
|
||||
const nameInput = $('input#name')
|
||||
await nameInput.clearValue()
|
||||
|
|
|
@ -1,37 +1,16 @@
|
|||
import { FIXTURE_URLS } from '../urls'
|
||||
import { browserSleep, go } from '../utils'
|
||||
import { browserSleep, FIXTURE_URLS, go } from '../utils'
|
||||
|
||||
export class VideoWatchPage {
|
||||
async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) {
|
||||
let url: string
|
||||
|
||||
// We did not upload a file on a mobile device
|
||||
if (isMobileDevice === true || isSafari === true) {
|
||||
url = 'https://peertube2.cpy.re/videos/local'
|
||||
} else {
|
||||
url = '/videos/recently-added'
|
||||
}
|
||||
constructor (private isMobileDevice: boolean, private isSafari: boolean) {
|
||||
|
||||
await go(url)
|
||||
|
||||
// Waiting the following element does not work on Safari...
|
||||
if (isSafari) return browserSleep(3000)
|
||||
|
||||
await $('.videos .video-miniature .video-miniature-name').waitForDisplayed()
|
||||
}
|
||||
|
||||
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) {
|
||||
if (isSafari) return browserSleep(5000)
|
||||
waitWatchVideoName (videoName: string) {
|
||||
if (this.isSafari) return browserSleep(5000)
|
||||
|
||||
// On mobile we display the first node, on desktop the second
|
||||
const index = isMobileDevice ? 0 : 1
|
||||
const index = this.isMobileDevice ? 0 : 1
|
||||
|
||||
return browser.waitUntil(async () => {
|
||||
return (await $$('.video-info .video-info-name')[index].getText()).includes(videoName)
|
||||
|
@ -58,42 +37,6 @@ export class VideoWatchPage {
|
|||
return go(FIXTURE_URLS.HLS_PLAYLIST_EMBED)
|
||||
}
|
||||
|
||||
async clickOnVideo (videoName: string) {
|
||||
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()
|
||||
|
||||
return elem?.isClickable()
|
||||
});
|
||||
|
||||
(await video()).click()
|
||||
|
||||
await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/'))
|
||||
}
|
||||
|
||||
async clickOnFirstVideo () {
|
||||
const video = () => $('.videos .video-miniature .video-thumbnail')
|
||||
const videoName = () => $('.videos .video-miniature .video-miniature-name')
|
||||
|
||||
await video().waitForClickable()
|
||||
|
||||
const textToReturn = await videoName().getText()
|
||||
await video().click()
|
||||
|
||||
await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/'))
|
||||
|
||||
return textToReturn
|
||||
}
|
||||
|
||||
async clickOnUpdate () {
|
||||
const dropdown = $('my-video-actions-dropdown .action-button')
|
||||
await dropdown.click()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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 { FIXTURE_URLS } from './urls'
|
||||
import { browserSleep, go, isIOS, isMobileDevice, isSafari } from './utils'
|
||||
import { LoginPage } from '../po/login.po'
|
||||
import { MyAccountPage } from '../po/my-account'
|
||||
import { PlayerPage } from '../po/player.po'
|
||||
import { VideoListPage } from '../po/video-list.po'
|
||||
import { VideoUpdatePage } from '../po/video-update.po'
|
||||
import { VideoUploadPage } from '../po/video-upload.po'
|
||||
import { VideoWatchPage } from '../po/video-watch.po'
|
||||
import { FIXTURE_URLS, go, isIOS, isMobileDevice, isSafari, waitServerUp } from '../utils'
|
||||
|
||||
function isUploadUnsupported () {
|
||||
if (isMobileDevice() || isSafari()) {
|
||||
|
@ -16,8 +16,9 @@ function isUploadUnsupported () {
|
|||
return false
|
||||
}
|
||||
|
||||
describe('Videos workflow', () => {
|
||||
describe('Videos all workflow', () => {
|
||||
let videoWatchPage: VideoWatchPage
|
||||
let videoListPage: VideoListPage
|
||||
let videoUploadPage: VideoUploadPage
|
||||
let videoUpdatePage: VideoUpdatePage
|
||||
let myAccountPage: MyAccountPage
|
||||
|
@ -40,21 +41,17 @@ describe('Videos workflow', () => {
|
|||
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
await browser.waitUntil(async () => {
|
||||
await go('/')
|
||||
await browserSleep(500)
|
||||
|
||||
return $('<my-app>').isDisplayed()
|
||||
}, { timeout: 20 * 1000 })
|
||||
await waitServerUp()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
videoWatchPage = new VideoWatchPage()
|
||||
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
|
||||
videoUploadPage = new VideoUploadPage()
|
||||
videoUpdatePage = new VideoUpdatePage()
|
||||
myAccountPage = new MyAccountPage()
|
||||
loginPage = new LoginPage()
|
||||
playerPage = new PlayerPage()
|
||||
videoListPage = new VideoListPage(isMobileDevice(), isSafari())
|
||||
|
||||
if (!isMobileDevice()) {
|
||||
await browser.maximizeWindow()
|
||||
|
@ -80,11 +77,11 @@ describe('Videos workflow', () => {
|
|||
})
|
||||
|
||||
it('Should list videos', async () => {
|
||||
await videoWatchPage.goOnVideosList(isMobileDevice(), isSafari())
|
||||
await videoListPage.goOnVideosList()
|
||||
|
||||
if (isUploadUnsupported()) return
|
||||
|
||||
const videoNames = await videoWatchPage.getVideosListName()
|
||||
const videoNames = await videoListPage.getVideosListName()
|
||||
expect(videoNames).toContain(videoName)
|
||||
})
|
||||
|
||||
|
@ -95,10 +92,10 @@ describe('Videos workflow', () => {
|
|||
await go(FIXTURE_URLS.WEBTORRENT_VIDEO)
|
||||
videoNameToExcept = 'E2E tests'
|
||||
} else {
|
||||
await videoWatchPage.clickOnVideo(videoName)
|
||||
await videoListPage.clickOnVideo(videoName)
|
||||
}
|
||||
|
||||
return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice(), isSafari())
|
||||
return videoWatchPage.waitWatchVideoName(videoNameToExcept)
|
||||
})
|
||||
|
||||
it('Should play the video', async () => {
|
195
client/e2e/src/suites-local/videos-list.e2e-spec.ts
Normal file
195
client/e2e/src/suites-local/videos-list.e2e-spec.ts
Normal file
|
@ -0,0 +1,195 @@
|
|||
import { AdminConfigPage } from '../po/admin-config.po'
|
||||
import { LoginPage } from '../po/login.po'
|
||||
import { MyAccountPage } from '../po/my-account'
|
||||
import { VideoListPage } from '../po/video-list.po'
|
||||
import { VideoSearchPage } from '../po/video-search.po'
|
||||
import { VideoUploadPage } from '../po/video-upload.po'
|
||||
import { NSFWPolicy } from '../types/common'
|
||||
import { isMobileDevice, isSafari, waitServerUp } from '../utils'
|
||||
|
||||
describe('Videos list', () => {
|
||||
let videoListPage: VideoListPage
|
||||
let videoUploadPage: VideoUploadPage
|
||||
let adminConfigPage: AdminConfigPage
|
||||
let loginPage: LoginPage
|
||||
let myAccountPage: MyAccountPage
|
||||
let videoSearchPage: VideoSearchPage
|
||||
|
||||
const seed = Math.random()
|
||||
const nsfwVideo = seed + ' - nsfw'
|
||||
const normalVideo = seed + ' - normal'
|
||||
|
||||
async function checkNormalVideo () {
|
||||
expect(await videoListPage.videoExists(normalVideo)).toBeTruthy()
|
||||
expect(await videoListPage.videoIsBlurred(normalVideo)).toBeFalsy()
|
||||
}
|
||||
|
||||
async function checkNSFWVideo (policy: NSFWPolicy, filterText?: string) {
|
||||
if (policy === 'do_not_list') {
|
||||
if (filterText) expect(filterText).toContain('hidden')
|
||||
|
||||
expect(await videoListPage.videoExists(nsfwVideo)).toBeFalsy()
|
||||
return
|
||||
}
|
||||
|
||||
if (policy === 'blur') {
|
||||
if (filterText) expect(filterText).toContain('blurred')
|
||||
|
||||
expect(await videoListPage.videoExists(nsfwVideo)).toBeTruthy()
|
||||
expect(await videoListPage.videoIsBlurred(nsfwVideo)).toBeTruthy()
|
||||
return
|
||||
}
|
||||
|
||||
// display
|
||||
if (filterText) expect(filterText).toContain('displayed')
|
||||
|
||||
expect(await videoListPage.videoExists(nsfwVideo)).toBeTruthy()
|
||||
expect(await videoListPage.videoIsBlurred(nsfwVideo)).toBeFalsy()
|
||||
}
|
||||
|
||||
async function checkCommonVideoListPages (policy: NSFWPolicy) {
|
||||
const promisesWithFilters = [
|
||||
videoListPage.goOnRootAccount,
|
||||
videoListPage.goOnLocal,
|
||||
videoListPage.goOnRecentlyAdded,
|
||||
videoListPage.goOnTrending,
|
||||
videoListPage.goOnRootChannel
|
||||
]
|
||||
|
||||
for (const p of promisesWithFilters) {
|
||||
await p.call(videoListPage)
|
||||
|
||||
const filter = await videoListPage.getNSFWFilter()
|
||||
const filterText = await filter.getText()
|
||||
|
||||
await checkNormalVideo()
|
||||
await checkNSFWVideo(policy, filterText)
|
||||
}
|
||||
|
||||
const promisesWithoutFilters = [
|
||||
videoListPage.goOnRootAccountChannels,
|
||||
videoListPage.goOnHomepage
|
||||
]
|
||||
for (const p of promisesWithoutFilters) {
|
||||
await p.call(videoListPage)
|
||||
|
||||
await checkNormalVideo()
|
||||
await checkNSFWVideo(policy)
|
||||
}
|
||||
}
|
||||
|
||||
async function checkSearchPage (policy: NSFWPolicy) {
|
||||
await videoSearchPage.search(normalVideo)
|
||||
await checkNormalVideo()
|
||||
|
||||
await videoSearchPage.search(nsfwVideo)
|
||||
await checkNSFWVideo(policy)
|
||||
}
|
||||
|
||||
async function updateAdminNSFW (nsfw: NSFWPolicy) {
|
||||
await adminConfigPage.navigateTo('instance-information')
|
||||
await adminConfigPage.updateNSFWSetting(nsfw)
|
||||
await adminConfigPage.save()
|
||||
}
|
||||
|
||||
async function updateUserNSFW (nsfw: NSFWPolicy) {
|
||||
await myAccountPage.navigateToMySettings()
|
||||
await myAccountPage.updateNSFW(nsfw)
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
await waitServerUp()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
videoListPage = new VideoListPage(isMobileDevice(), isSafari())
|
||||
adminConfigPage = new AdminConfigPage()
|
||||
loginPage = new LoginPage()
|
||||
videoUploadPage = new VideoUploadPage()
|
||||
myAccountPage = new MyAccountPage()
|
||||
videoSearchPage = new VideoSearchPage()
|
||||
|
||||
await browser.maximizeWindow()
|
||||
})
|
||||
|
||||
it('Should login and disable NSFW', async () => {
|
||||
await loginPage.loginAsRootUser()
|
||||
await updateUserNSFW('display')
|
||||
})
|
||||
|
||||
it('Should set the homepage', async () => {
|
||||
await adminConfigPage.navigateTo('instance-homepage')
|
||||
await adminConfigPage.updateHomepage('<peertube-videos-list data-sort="-publishedAt"></peertube-videos-list>')
|
||||
await adminConfigPage.save()
|
||||
})
|
||||
|
||||
it('Should upload 2 videos (NSFW and classic videos)', async () => {
|
||||
await videoUploadPage.navigateTo()
|
||||
await videoUploadPage.uploadVideo()
|
||||
await videoUploadPage.setAsNSFW()
|
||||
await videoUploadPage.validSecondUploadStep(nsfwVideo)
|
||||
|
||||
await videoUploadPage.navigateTo()
|
||||
await videoUploadPage.uploadVideo()
|
||||
await videoUploadPage.validSecondUploadStep(normalVideo)
|
||||
})
|
||||
|
||||
it('Should logout', async function () {
|
||||
await loginPage.logout()
|
||||
})
|
||||
|
||||
describe('Anonymous users', function () {
|
||||
|
||||
it('Should correctly handle do not list', async () => {
|
||||
await loginPage.loginAsRootUser()
|
||||
await updateAdminNSFW('do_not_list')
|
||||
|
||||
await loginPage.logout()
|
||||
await checkCommonVideoListPages('do_not_list')
|
||||
await checkSearchPage('do_not_list')
|
||||
})
|
||||
|
||||
it('Should correctly handle blur', async () => {
|
||||
await loginPage.loginAsRootUser()
|
||||
await updateAdminNSFW('blur')
|
||||
|
||||
await loginPage.logout()
|
||||
await checkCommonVideoListPages('blur')
|
||||
await checkSearchPage('blur')
|
||||
})
|
||||
|
||||
it('Should correctly handle display', async () => {
|
||||
await loginPage.loginAsRootUser()
|
||||
await updateAdminNSFW('display')
|
||||
|
||||
await loginPage.logout()
|
||||
await checkCommonVideoListPages('display')
|
||||
await checkSearchPage('display')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Logged in users', function () {
|
||||
|
||||
before(async () => {
|
||||
await loginPage.loginAsRootUser()
|
||||
})
|
||||
|
||||
it('Should correctly handle do not list', async () => {
|
||||
await updateUserNSFW('do_not_list')
|
||||
await checkCommonVideoListPages('do_not_list')
|
||||
await checkSearchPage('do_not_list')
|
||||
})
|
||||
|
||||
it('Should correctly handle blur', async () => {
|
||||
await updateUserNSFW('blur')
|
||||
await checkCommonVideoListPages('blur')
|
||||
await checkSearchPage('blur')
|
||||
})
|
||||
|
||||
it('Should correctly handle display', async () => {
|
||||
await updateUserNSFW('display')
|
||||
await checkCommonVideoListPages('display')
|
||||
await checkSearchPage('display')
|
||||
})
|
||||
})
|
||||
})
|
1
client/e2e/src/types/common.ts
Normal file
1
client/e2e/src/types/common.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export type NSFWPolicy = 'do_not_list' | 'blur' | 'display'
|
|
@ -28,10 +28,20 @@ async function go (url: string) {
|
|||
})
|
||||
}
|
||||
|
||||
async function waitServerUp () {
|
||||
await browser.waitUntil(async () => {
|
||||
await go('/')
|
||||
await browserSleep(500)
|
||||
|
||||
return $('<my-app>').isDisplayed()
|
||||
}, { timeout: 20 * 1000 })
|
||||
}
|
||||
|
||||
export {
|
||||
isMobileDevice,
|
||||
isSafari,
|
||||
isIOS,
|
||||
waitServerUp,
|
||||
go,
|
||||
browserSleep
|
||||
}
|
7
client/e2e/src/utils/elements.ts
Normal file
7
client/e2e/src/utils/elements.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
function clickOnCheckbox (name: string) {
|
||||
return $(`my-peertube-checkbox[inputname=${name}] label`).click()
|
||||
}
|
||||
|
||||
export {
|
||||
clickOnCheckbox
|
||||
}
|
3
client/e2e/src/utils/index.ts
Normal file
3
client/e2e/src/utils/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './common'
|
||||
export * from './elements'
|
||||
export * from './urls'
|
|
@ -2,6 +2,8 @@
|
|||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true,
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
|
|
|
@ -26,14 +26,16 @@ function buildBStackDesktopOptions (sessionName: string, resolution?: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function buildBStackMobileOptions (sessionName: string, deviceName: string, osVersion: string) {
|
||||
function buildBStackMobileOptions (sessionName: string, deviceName: string, osVersion: string, appiumVersion?: string) {
|
||||
return {
|
||||
'bstack:options': {
|
||||
...buildMainOptions(sessionName),
|
||||
|
||||
realMobile: true,
|
||||
osVersion,
|
||||
deviceName
|
||||
deviceName,
|
||||
|
||||
appiumVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +86,7 @@ module.exports = {
|
|||
{
|
||||
browserName: 'Safari',
|
||||
|
||||
...buildBStackMobileOptions('Safari iPhone', 'iPhone 8 Plus', '11')
|
||||
...buildBStackMobileOptions('Safari iPhone', 'iPhone SE', '11')
|
||||
},
|
||||
{
|
||||
browserName: 'Safari',
|
||||
|
@ -97,17 +99,20 @@ module.exports = {
|
|||
connectionRetryTimeout: 240000,
|
||||
waitforTimeout: 20000,
|
||||
|
||||
specs: [
|
||||
// We don't want to test "local" tests
|
||||
'./src/suites-all/*.e2e-spec.ts'
|
||||
],
|
||||
|
||||
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": ""}}', [])
|
||||
onWorkerStart: function (_cid, capabilities) {
|
||||
if (capabilities['bstack:options'].realMobile === true) {
|
||||
capabilities['bstack:options'].local = false
|
||||
}
|
||||
}
|
||||
} as WebdriverIO.Config
|
||||
|
|
28
client/e2e/wdio.local-test.conf.ts
Normal file
28
client/e2e/wdio.local-test.conf.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { config as mainConfig } from './wdio.main.conf'
|
||||
|
||||
const prefs = {
|
||||
'intl.accept_languages': 'en'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
...mainConfig,
|
||||
|
||||
runner: 'local',
|
||||
|
||||
maxInstances: 1,
|
||||
specFileRetries: 0,
|
||||
|
||||
capabilities: [
|
||||
{
|
||||
browserName: 'chrome',
|
||||
acceptInsecureCerts: true,
|
||||
'goog:chromeOptions': {
|
||||
prefs
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
services: [ 'chromedriver' ]
|
||||
} as WebdriverIO.Config
|
||||
}
|
|
@ -10,12 +10,11 @@ module.exports = {
|
|||
|
||||
runner: 'local',
|
||||
|
||||
maxInstances: 1,
|
||||
maxInstances: 2,
|
||||
|
||||
capabilities: [
|
||||
{
|
||||
browserName: 'chrome',
|
||||
acceptInsecureCerts: true,
|
||||
'goog:chromeOptions': {
|
||||
prefs
|
||||
}
|
||||
|
@ -23,21 +22,20 @@ module.exports = {
|
|||
{
|
||||
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' ]
|
||||
services: [ 'chromedriver', 'geckodriver' ],
|
||||
|
||||
beforeSession: function (config, capabilities) {
|
||||
if (capabilities['browserName'] === 'chrome') {
|
||||
config.baseUrl = 'http://localhost:9001'
|
||||
} else {
|
||||
config.baseUrl = 'http://localhost:9002'
|
||||
}
|
||||
}
|
||||
} as WebdriverIO.Config
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ export const config = {
|
|||
// will be called from there.
|
||||
//
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
'./src/suites-all/*.e2e-spec.ts',
|
||||
'./src/suites-local/*.e2e-spec.ts'
|
||||
],
|
||||
// Patterns to exclude.
|
||||
exclude: [
|
||||
|
@ -79,7 +80,7 @@ export const config = {
|
|||
framework: 'mocha',
|
||||
//
|
||||
// The number of times to retry the entire specfile when it fails as a whole
|
||||
specFileRetries: 2,
|
||||
specFileRetries: 1,
|
||||
//
|
||||
// Delay in seconds between the spec file retry attempts
|
||||
// specFileRetriesDelay: 0,
|
||||
|
@ -105,6 +106,14 @@ export const config = {
|
|||
|
||||
tsNodeOpts: {
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
},
|
||||
|
||||
tsConfigPathsOpts: {
|
||||
baseUrl: './',
|
||||
paths: {
|
||||
'@server/*': [ '../../server/*' ],
|
||||
'@shared/*': [ '../../shared/*' ]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
UserUpdateMe,
|
||||
UserVideoQuota
|
||||
} from '@shared/models'
|
||||
import { ServerService } from '../'
|
||||
import { environment } from '../../../environments/environment'
|
||||
import { RestExtractor, RestPagination, RestService } from '../rest'
|
||||
import { LocalStorageService, SessionStorageService } from '../wrappers/storage.service'
|
||||
|
@ -32,6 +33,7 @@ export class UserService {
|
|||
|
||||
constructor (
|
||||
private authHttp: HttpClient,
|
||||
private server: ServerService,
|
||||
private authService: AuthService,
|
||||
private restExtractor: RestExtractor,
|
||||
private restService: RestService,
|
||||
|
@ -298,9 +300,11 @@ export class UserService {
|
|||
console.error('Cannot parse desired video languages from localStorage.', err)
|
||||
}
|
||||
|
||||
const defaultNSFWPolicy = this.server.getHTMLConfig().instance.defaultNSFWPolicy
|
||||
|
||||
return new User({
|
||||
// local storage keys
|
||||
nsfwPolicy: this.localStorageService.getItem(UserLocalStorageKeys.NSFW_POLICY),
|
||||
nsfwPolicy: this.localStorageService.getItem(UserLocalStorageKeys.NSFW_POLICY) || defaultNSFWPolicy,
|
||||
webTorrentEnabled: this.localStorageService.getItem(UserLocalStorageKeys.WEBTORRENT_ENABLED) !== 'false',
|
||||
theme: this.localStorageService.getItem(UserLocalStorageKeys.THEME) || 'instance-default',
|
||||
videoLanguages,
|
||||
|
|
|
@ -5,7 +5,6 @@ import { FormBuilder, FormGroup } from '@angular/forms'
|
|||
import { AuthService } from '@app/core'
|
||||
import { ServerService } from '@app/core/server/server.service'
|
||||
import { UserRight } from '@shared/models'
|
||||
import { NSFWPolicyType } from '@shared/models/videos'
|
||||
import { PeertubeModalService } from '../shared-main'
|
||||
import { VideoFilters } from './video-filters.model'
|
||||
|
||||
|
@ -18,12 +17,7 @@ const logger = debug('peertube:videos:VideoFiltersHeaderComponent')
|
|||
})
|
||||
export class VideoFiltersHeaderComponent implements OnInit, OnDestroy {
|
||||
@Input() filters: VideoFilters
|
||||
|
||||
@Input() displayModerationBlock = false
|
||||
|
||||
@Input() defaultSort = '-publishedAt'
|
||||
@Input() nsfwPolicy: NSFWPolicyType
|
||||
|
||||
@Input() hideScope = false
|
||||
|
||||
@Output() filtersChanged = new EventEmitter()
|
||||
|
|
|
@ -74,6 +74,8 @@ export class VideoFilters {
|
|||
}
|
||||
|
||||
setNSFWPolicy (nsfwPolicy: NSFWPolicyType) {
|
||||
console.log(nsfwPolicy)
|
||||
|
||||
this.updateDefaultNSFW(nsfwPolicy)
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
<my-video-filters-header
|
||||
*ngIf="displayFilters" [displayModerationBlock]="displayModerationBlock" [hideScope]="hideScopeFilter"
|
||||
[defaultSort]="defaultSort" [filters]="filters"
|
||||
[filters]="filters"
|
||||
(filtersChanged)="onFiltersChanged(true)"
|
||||
></my-video-filters-header>
|
||||
|
||||
|
|
|
@ -6,4 +6,4 @@ npm run clean:server:test
|
|||
|
||||
npm run concurrently -- -k -s first \
|
||||
"cd client/e2e && ../node_modules/.bin/wdio run ./wdio.browserstack.conf.ts" \
|
||||
"NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"log\": { \"level\": \"warn\" }, \"signup\": { \"enabled\": false } }' node dist/server"
|
||||
"NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"rates_limit\": { \"api\": { \"max\": 5000 }, \"login\": { \"max\": 5000 } }, \"log\": { \"level\": \"warn\" }, \"signup\": { \"enabled\": false } }' node dist/server"
|
||||
|
|
|
@ -4,6 +4,14 @@ set -eu
|
|||
|
||||
npm run clean:server:test
|
||||
|
||||
config="{"
|
||||
config+=" \"rates_limit\": { \"api\": { \"max\": 5000 }, \"login\": { \"max\": 5000 } }"
|
||||
config+=", \"log\": { \"level\": \"warn\" }"
|
||||
config+=", \"signup\": { \"enabled\": false }"
|
||||
config+=", \"transcoding\": { \"enabled\": false }"
|
||||
config+="}"
|
||||
|
||||
npm run concurrently -- -k -s first \
|
||||
"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"
|
||||
"NODE_ENV=test NODE_CONFIG='$config' NODE_APP_INSTANCE=1 node dist/server" \
|
||||
"NODE_ENV=test NODE_CONFIG='$config' NODE_APP_INSTANCE=2 node dist/server"
|
||||
|
|
|
@ -70,3 +70,18 @@ To run tests on browser stack:
|
|||
```
|
||||
$ BROWSERSTACK_USER=your_user BROWSERSTACK_KEY=your_key npm run e2e:browserstack
|
||||
```
|
||||
|
||||
### Add E2E tests
|
||||
|
||||
To add E2E tests and quickly run tests using a local Chrome, first create a test instance:
|
||||
|
||||
```
|
||||
$ npm run clean:server:test && NODE_APP_INSTANCE=1 NODE_ENV=test npm start
|
||||
```
|
||||
|
||||
Then, just run your suite using:
|
||||
|
||||
```
|
||||
$ cd client/e2e
|
||||
$ ../node_modules/.bin/wdio wdio.local-test.conf.ts # you can also add --mochaOpts.grep to only run tests you want
|
||||
```
|
||||
|
|
Loading…
Reference in a new issue