1
0
Fork 0

Fix NSFW filter and add tests

This commit is contained in:
Chocobozzz 2021-09-03 10:27:04 +02:00
parent 2ede07153c
commit 6d210220be
No known key found for this signature in database
GPG key ID: 583A612D890159BE
28 changed files with 550 additions and 116 deletions

View file

@ -281,6 +281,7 @@
"builder": "@angular-eslint/builder:lint", "builder": "@angular-eslint/builder:lint",
"options": { "options": {
"lintFilePatterns": [ "lintFilePatterns": [
"e2e/**/*.ts",
"src/**/*.ts", "src/**/*.ts",
"src/**/*.html" "src/**/*.html"
] ]

View 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)
}
}

View file

@ -1,6 +1,7 @@
import { go } from '../utils' import { go } from '../utils'
export class LoginPage { export class LoginPage {
async loginAsRootUser () { async loginAsRootUser () {
await go('/login') await go('/login')
@ -8,7 +9,7 @@ export class LoginPage {
await browser.execute(`window.localStorage.setItem('no_welcome_modal', 'true')`) await browser.execute(`window.localStorage.setItem('no_welcome_modal', 'true')`)
await $('input#username').setValue('root') await $('input#username').setValue('root')
await $('input#password').setValue('test1') await $('input#password').setValue('test' + this.getSuffix())
await browser.pause(1000) await browser.pause(1000)
@ -19,7 +20,24 @@ export class LoginPage {
await expect(this.getLoggedInInfoElem()).toHaveText('root') 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 () { private getLoggedInInfoElem () {
return $('.logged-in-display-name') return $('.logged-in-display-name')
} }
private getSuffix () {
return browser.config.baseUrl
? browser.config.baseUrl.slice(-1)
: '1'
}
} }

View file

@ -14,6 +14,24 @@ export class MyAccountPage {
return $('a[href="/my-library/history/videos"]').click() 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 // My account Videos
async removeVideo (name: string) { async removeVideo (name: string) {

View file

@ -15,6 +15,9 @@ export class PlayerPage {
waitUntilPlaylistInfo (text: string, maxTime: number) { waitUntilPlaylistInfo (text: string, maxTime: number) {
return browser.waitUntil(async () => { 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) return (await $('.video-js .vjs-playlist-info').getText()).includes(text)
}, { timeout: maxTime }) }, { timeout: maxTime })
} }
@ -42,7 +45,7 @@ export class PlayerPage {
await browserSleep(2000) await browserSleep(2000)
await browser.waitUntil(async () => { await browser.waitUntil(async () => {
return (await this.getWatchVideoPlayerCurrentTime()) >= 2 return (await this.getWatchVideoPlayerCurrentTime()) >= waitUntilSec
}) })
await videojsElem().click() await videojsElem().click()

View 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()
}
}

View 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()
})
}
}

View file

@ -1,4 +1,5 @@
import { join } from 'path' import { join } from 'path'
import { clickOnCheckbox } from '../utils'
export class VideoUploadPage { export class VideoUploadPage {
async navigateTo () { async navigateTo () {
@ -30,6 +31,10 @@ export class VideoUploadPage {
}) })
} }
setAsNSFW () {
return clickOnCheckbox('nsfw')
}
async validSecondUploadStep (videoName: string) { async validSecondUploadStep (videoName: string) {
const nameInput = $('input#name') const nameInput = $('input#name')
await nameInput.clearValue() await nameInput.clearValue()

View file

@ -1,37 +1,16 @@
import { FIXTURE_URLS } from '../urls' import { browserSleep, FIXTURE_URLS, go } from '../utils'
import { browserSleep, go } from '../utils'
export class VideoWatchPage { export class VideoWatchPage {
async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) {
let url: string
// We did not upload a file on a mobile device constructor (private isMobileDevice: boolean, private isSafari: boolean) {
if (isMobileDevice === true || 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 (isSafari) return browserSleep(3000)
await $('.videos .video-miniature .video-miniature-name').waitForDisplayed()
} }
async getVideosListName () { waitWatchVideoName (videoName: string) {
const elems = await $$('.videos .video-miniature .video-miniature-name') if (this.isSafari) return browserSleep(5000)
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)
// On mobile we display the first node, on desktop the second // 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 browser.waitUntil(async () => {
return (await $$('.video-info .video-info-name')[index].getText()).includes(videoName) 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) 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 () { async clickOnUpdate () {
const dropdown = $('my-video-actions-dropdown .action-button') const dropdown = $('my-video-actions-dropdown .action-button')
await dropdown.click() await dropdown.click()

View file

@ -1,11 +1,11 @@
import { LoginPage } from './po/login.po' import { LoginPage } from '../po/login.po'
import { MyAccountPage } from './po/my-account' import { MyAccountPage } from '../po/my-account'
import { PlayerPage } from './po/player.po' import { PlayerPage } from '../po/player.po'
import { VideoUpdatePage } from './po/video-update.po' import { VideoListPage } from '../po/video-list.po'
import { VideoUploadPage } from './po/video-upload.po' import { VideoUpdatePage } from '../po/video-update.po'
import { VideoWatchPage } from './po/video-watch.po' import { VideoUploadPage } from '../po/video-upload.po'
import { FIXTURE_URLS } from './urls' import { VideoWatchPage } from '../po/video-watch.po'
import { browserSleep, go, isIOS, isMobileDevice, isSafari } from './utils' import { FIXTURE_URLS, go, isIOS, isMobileDevice, isSafari, waitServerUp } from '../utils'
function isUploadUnsupported () { function isUploadUnsupported () {
if (isMobileDevice() || isSafari()) { if (isMobileDevice() || isSafari()) {
@ -16,8 +16,9 @@ function isUploadUnsupported () {
return false return false
} }
describe('Videos workflow', () => { describe('Videos all workflow', () => {
let videoWatchPage: VideoWatchPage let videoWatchPage: VideoWatchPage
let videoListPage: VideoListPage
let videoUploadPage: VideoUploadPage let videoUploadPage: VideoUploadPage
let videoUpdatePage: VideoUpdatePage let videoUpdatePage: VideoUpdatePage
let myAccountPage: MyAccountPage let myAccountPage: MyAccountPage
@ -40,21 +41,17 @@ describe('Videos workflow', () => {
if (isUploadUnsupported()) return if (isUploadUnsupported()) return
await browser.waitUntil(async () => { await waitServerUp()
await go('/')
await browserSleep(500)
return $('<my-app>').isDisplayed()
}, { timeout: 20 * 1000 })
}) })
beforeEach(async () => { beforeEach(async () => {
videoWatchPage = new VideoWatchPage() videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
videoUploadPage = new VideoUploadPage() videoUploadPage = new VideoUploadPage()
videoUpdatePage = new VideoUpdatePage() videoUpdatePage = new VideoUpdatePage()
myAccountPage = new MyAccountPage() myAccountPage = new MyAccountPage()
loginPage = new LoginPage() loginPage = new LoginPage()
playerPage = new PlayerPage() playerPage = new PlayerPage()
videoListPage = new VideoListPage(isMobileDevice(), isSafari())
if (!isMobileDevice()) { if (!isMobileDevice()) {
await browser.maximizeWindow() await browser.maximizeWindow()
@ -80,11 +77,11 @@ describe('Videos workflow', () => {
}) })
it('Should list videos', async () => { it('Should list videos', async () => {
await videoWatchPage.goOnVideosList(isMobileDevice(), isSafari()) await videoListPage.goOnVideosList()
if (isUploadUnsupported()) return if (isUploadUnsupported()) return
const videoNames = await videoWatchPage.getVideosListName() const videoNames = await videoListPage.getVideosListName()
expect(videoNames).toContain(videoName) expect(videoNames).toContain(videoName)
}) })
@ -95,10 +92,10 @@ describe('Videos workflow', () => {
await go(FIXTURE_URLS.WEBTORRENT_VIDEO) await go(FIXTURE_URLS.WEBTORRENT_VIDEO)
videoNameToExcept = 'E2E tests' videoNameToExcept = 'E2E tests'
} else { } 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 () => { it('Should play the video', async () => {

View 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')
})
})
})

View file

@ -0,0 +1 @@
export type NSFWPolicy = 'do_not_list' | 'blur' | 'display'

View file

@ -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 { export {
isMobileDevice, isMobileDevice,
isSafari, isSafari,
isIOS, isIOS,
waitServerUp,
go, go,
browserSleep browserSleep
} }

View file

@ -0,0 +1,7 @@
function clickOnCheckbox (name: string) {
return $(`my-peertube-checkbox[inputname=${name}] label`).click()
}
export {
clickOnCheckbox
}

View file

@ -0,0 +1,3 @@
export * from './common'
export * from './elements'
export * from './urls'

View file

@ -2,6 +2,8 @@
"extends": "../tsconfig.json", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/app", "outDir": "../out-tsc/app",
"noImplicitAny": false,
"esModuleInterop": true,
"module": "commonjs", "module": "commonjs",
"target": "es5", "target": "es5",
"types": [ "types": [

View file

@ -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 { return {
'bstack:options': { 'bstack:options': {
...buildMainOptions(sessionName), ...buildMainOptions(sessionName),
realMobile: true, realMobile: true,
osVersion, osVersion,
deviceName deviceName,
appiumVersion
} }
} }
} }
@ -84,7 +86,7 @@ module.exports = {
{ {
browserName: 'Safari', browserName: 'Safari',
...buildBStackMobileOptions('Safari iPhone', 'iPhone 8 Plus', '11') ...buildBStackMobileOptions('Safari iPhone', 'iPhone SE', '11')
}, },
{ {
browserName: 'Safari', browserName: 'Safari',
@ -97,17 +99,20 @@ module.exports = {
connectionRetryTimeout: 240000, connectionRetryTimeout: 240000,
waitforTimeout: 20000, waitforTimeout: 20000,
specs: [
// We don't want to test "local" tests
'./src/suites-all/*.e2e-spec.ts'
],
services: [ services: [
[ [
'browserstack', { browserstackLocal: true } 'browserstack', { browserstackLocal: true }
] ]
], ],
after: function (result) { onWorkerStart: function (_cid, capabilities) {
if (result === 0) { if (capabilities['bstack:options'].realMobile === true) {
browser.executeScript('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed","reason": ""}}', []) capabilities['bstack:options'].local = false
} else {
browser.executeScript('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed","reason": ""}}', [])
} }
} }
} as WebdriverIO.Config } as WebdriverIO.Config

View 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
}

View file

@ -10,12 +10,11 @@ module.exports = {
runner: 'local', runner: 'local',
maxInstances: 1, maxInstances: 2,
capabilities: [ capabilities: [
{ {
browserName: 'chrome', browserName: 'chrome',
acceptInsecureCerts: true,
'goog:chromeOptions': { 'goog:chromeOptions': {
prefs prefs
} }
@ -23,21 +22,20 @@ module.exports = {
{ {
browserName: 'firefox', browserName: 'firefox',
'moz:firefoxOptions': { 'moz:firefoxOptions': {
// args: [ '-headless' ],
binary: '/usr/bin/firefox-developer-edition', binary: '/usr/bin/firefox-developer-edition',
prefs 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 } as WebdriverIO.Config
} }

View file

@ -21,7 +21,8 @@ export const config = {
// will be called from there. // will be called from there.
// //
specs: [ specs: [
'./src/**/*.e2e-spec.ts' './src/suites-all/*.e2e-spec.ts',
'./src/suites-local/*.e2e-spec.ts'
], ],
// Patterns to exclude. // Patterns to exclude.
exclude: [ exclude: [
@ -79,7 +80,7 @@ export const config = {
framework: 'mocha', framework: 'mocha',
// //
// The number of times to retry the entire specfile when it fails as a whole // 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 // Delay in seconds between the spec file retry attempts
// specFileRetriesDelay: 0, // specFileRetriesDelay: 0,
@ -105,6 +106,14 @@ export const config = {
tsNodeOpts: { tsNodeOpts: {
project: require('path').join(__dirname, './tsconfig.json') project: require('path').join(__dirname, './tsconfig.json')
},
tsConfigPathsOpts: {
baseUrl: './',
paths: {
'@server/*': [ '../../server/*' ],
'@shared/*': [ '../../shared/*' ]
}
} }
}, },

View file

@ -17,6 +17,7 @@ import {
UserUpdateMe, UserUpdateMe,
UserVideoQuota UserVideoQuota
} from '@shared/models' } from '@shared/models'
import { ServerService } from '../'
import { environment } from '../../../environments/environment' import { environment } from '../../../environments/environment'
import { RestExtractor, RestPagination, RestService } from '../rest' import { RestExtractor, RestPagination, RestService } from '../rest'
import { LocalStorageService, SessionStorageService } from '../wrappers/storage.service' import { LocalStorageService, SessionStorageService } from '../wrappers/storage.service'
@ -32,6 +33,7 @@ export class UserService {
constructor ( constructor (
private authHttp: HttpClient, private authHttp: HttpClient,
private server: ServerService,
private authService: AuthService, private authService: AuthService,
private restExtractor: RestExtractor, private restExtractor: RestExtractor,
private restService: RestService, private restService: RestService,
@ -298,9 +300,11 @@ export class UserService {
console.error('Cannot parse desired video languages from localStorage.', err) console.error('Cannot parse desired video languages from localStorage.', err)
} }
const defaultNSFWPolicy = this.server.getHTMLConfig().instance.defaultNSFWPolicy
return new User({ return new User({
// local storage keys // 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', webTorrentEnabled: this.localStorageService.getItem(UserLocalStorageKeys.WEBTORRENT_ENABLED) !== 'false',
theme: this.localStorageService.getItem(UserLocalStorageKeys.THEME) || 'instance-default', theme: this.localStorageService.getItem(UserLocalStorageKeys.THEME) || 'instance-default',
videoLanguages, videoLanguages,

View file

@ -5,7 +5,6 @@ import { FormBuilder, FormGroup } from '@angular/forms'
import { AuthService } from '@app/core' import { AuthService } from '@app/core'
import { ServerService } from '@app/core/server/server.service' import { ServerService } from '@app/core/server/server.service'
import { UserRight } from '@shared/models' import { UserRight } from '@shared/models'
import { NSFWPolicyType } from '@shared/models/videos'
import { PeertubeModalService } from '../shared-main' import { PeertubeModalService } from '../shared-main'
import { VideoFilters } from './video-filters.model' import { VideoFilters } from './video-filters.model'
@ -18,12 +17,7 @@ const logger = debug('peertube:videos:VideoFiltersHeaderComponent')
}) })
export class VideoFiltersHeaderComponent implements OnInit, OnDestroy { export class VideoFiltersHeaderComponent implements OnInit, OnDestroy {
@Input() filters: VideoFilters @Input() filters: VideoFilters
@Input() displayModerationBlock = false @Input() displayModerationBlock = false
@Input() defaultSort = '-publishedAt'
@Input() nsfwPolicy: NSFWPolicyType
@Input() hideScope = false @Input() hideScope = false
@Output() filtersChanged = new EventEmitter() @Output() filtersChanged = new EventEmitter()

View file

@ -74,6 +74,8 @@ export class VideoFilters {
} }
setNSFWPolicy (nsfwPolicy: NSFWPolicyType) { setNSFWPolicy (nsfwPolicy: NSFWPolicyType) {
console.log(nsfwPolicy)
this.updateDefaultNSFW(nsfwPolicy) this.updateDefaultNSFW(nsfwPolicy)
} }

View file

@ -34,7 +34,7 @@
<my-video-filters-header <my-video-filters-header
*ngIf="displayFilters" [displayModerationBlock]="displayModerationBlock" [hideScope]="hideScopeFilter" *ngIf="displayFilters" [displayModerationBlock]="displayModerationBlock" [hideScope]="hideScopeFilter"
[defaultSort]="defaultSort" [filters]="filters" [filters]="filters"
(filtersChanged)="onFiltersChanged(true)" (filtersChanged)="onFiltersChanged(true)"
></my-video-filters-header> ></my-video-filters-header>

View file

@ -6,4 +6,4 @@ npm run clean:server:test
npm run concurrently -- -k -s first \ npm run concurrently -- -k -s first \
"cd client/e2e && ../node_modules/.bin/wdio run ./wdio.browserstack.conf.ts" \ "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"

View file

@ -4,6 +4,14 @@ set -eu
npm run clean:server:test 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 \ npm run concurrently -- -k -s first \
"cd client/e2e && ../node_modules/.bin/wdio run ./wdio.local.conf.ts" \ "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"

View file

@ -70,3 +70,18 @@ To run tests on browser stack:
``` ```
$ BROWSERSTACK_USER=your_user BROWSERSTACK_KEY=your_key npm run e2e:browserstack $ 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
```