diff options
author | Chocobozzz <me@florianbigard.com> | 2021-09-03 10:27:04 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-09-03 16:35:18 +0200 |
commit | 6d210220be0875d63461829d83c6e3a59d05cf7a (patch) | |
tree | 60ec5b596ef06295b70ebb553920a39b549e0f13 /client/e2e | |
parent | 2ede07153ce0282b116345dfee09bff902355a75 (diff) | |
download | PeerTube-6d210220be0875d63461829d83c6e3a59d05cf7a.tar.gz PeerTube-6d210220be0875d63461829d83c6e3a59d05cf7a.tar.zst PeerTube-6d210220be0875d63461829d83c6e3a59d05cf7a.zip |
Fix NSFW filter and add tests
Diffstat (limited to 'client/e2e')
20 files changed, 516 insertions, 106 deletions
diff --git a/client/e2e/src/po/admin-config.po.ts b/client/e2e/src/po/admin-config.po.ts new file mode 100644 index 000000000..a15184781 --- /dev/null +++ b/client/e2e/src/po/admin-config.po.ts | |||
@@ -0,0 +1,29 @@ | |||
1 | import { browserSleep, go } from '../utils' | ||
2 | |||
3 | export class AdminConfigPage { | ||
4 | |||
5 | async navigateTo (tab: 'instance-homepage' | 'basic-configuration' | 'instance-information') { | ||
6 | const waitTitles = { | ||
7 | 'instance-homepage': 'INSTANCE HOMEPAGE', | ||
8 | 'basic-configuration': 'APPEARANCE', | ||
9 | 'instance-information': 'INSTANCE' | ||
10 | } | ||
11 | |||
12 | await go('/admin/config/edit-custom#' + tab) | ||
13 | |||
14 | await $('.inner-form-title=' + waitTitles[tab]).waitForDisplayed() | ||
15 | } | ||
16 | |||
17 | updateNSFWSetting (newValue: 'do_not_list' | 'blur' | 'display') { | ||
18 | return $('#instanceDefaultNSFWPolicy').selectByAttribute('value', newValue) | ||
19 | } | ||
20 | |||
21 | updateHomepage (newValue: string) { | ||
22 | return $('#instanceCustomHomepageContent').setValue(newValue) | ||
23 | } | ||
24 | |||
25 | async save () { | ||
26 | await $('input[type=submit]').click() | ||
27 | await browserSleep(200) | ||
28 | } | ||
29 | } | ||
diff --git a/client/e2e/src/po/login.po.ts b/client/e2e/src/po/login.po.ts index 8e3030e43..486b9a6d8 100644 --- a/client/e2e/src/po/login.po.ts +++ b/client/e2e/src/po/login.po.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { go } from '../utils' | 1 | import { go } from '../utils' |
2 | 2 | ||
3 | export class LoginPage { | 3 | export class LoginPage { |
4 | |||
4 | async loginAsRootUser () { | 5 | async loginAsRootUser () { |
5 | await go('/login') | 6 | await go('/login') |
6 | 7 | ||
@@ -8,7 +9,7 @@ export class LoginPage { | |||
8 | await browser.execute(`window.localStorage.setItem('no_welcome_modal', 'true')`) | 9 | await browser.execute(`window.localStorage.setItem('no_welcome_modal', 'true')`) |
9 | 10 | ||
10 | await $('input#username').setValue('root') | 11 | await $('input#username').setValue('root') |
11 | await $('input#password').setValue('test1') | 12 | await $('input#password').setValue('test' + this.getSuffix()) |
12 | 13 | ||
13 | await browser.pause(1000) | 14 | await browser.pause(1000) |
14 | 15 | ||
@@ -19,7 +20,24 @@ export class LoginPage { | |||
19 | await expect(this.getLoggedInInfoElem()).toHaveText('root') | 20 | await expect(this.getLoggedInInfoElem()).toHaveText('root') |
20 | } | 21 | } |
21 | 22 | ||
23 | async logout () { | ||
24 | await $('.logged-in-more').click() | ||
25 | |||
26 | const logout = () => $('.dropdown-item*=Log out') | ||
27 | |||
28 | await logout().waitForDisplayed() | ||
29 | await logout().click() | ||
30 | |||
31 | await $('.login-buttons-block').waitForDisplayed() | ||
32 | } | ||
33 | |||
22 | private getLoggedInInfoElem () { | 34 | private getLoggedInInfoElem () { |
23 | return $('.logged-in-display-name') | 35 | return $('.logged-in-display-name') |
24 | } | 36 | } |
37 | |||
38 | private getSuffix () { | ||
39 | return browser.config.baseUrl | ||
40 | ? browser.config.baseUrl.slice(-1) | ||
41 | : '1' | ||
42 | } | ||
25 | } | 43 | } |
diff --git a/client/e2e/src/po/my-account.ts b/client/e2e/src/po/my-account.ts index 85dc02805..8b5e79b5e 100644 --- a/client/e2e/src/po/my-account.ts +++ b/client/e2e/src/po/my-account.ts | |||
@@ -14,6 +14,24 @@ export class MyAccountPage { | |||
14 | return $('a[href="/my-library/history/videos"]').click() | 14 | return $('a[href="/my-library/history/videos"]').click() |
15 | } | 15 | } |
16 | 16 | ||
17 | // Settings | ||
18 | |||
19 | navigateToMySettings () { | ||
20 | return $('a[href="/my-account"]').click() | ||
21 | } | ||
22 | |||
23 | async updateNSFW (newValue: 'do_not_list' | 'blur' | 'display') { | ||
24 | const nsfw = $('#nsfwPolicy') | ||
25 | |||
26 | await nsfw.waitForDisplayed() | ||
27 | await nsfw.scrollIntoView(false) // Avoid issues with fixed header on firefox | ||
28 | await nsfw.selectByAttribute('value', newValue) | ||
29 | |||
30 | const submit = $('my-user-video-settings input[type=submit]') | ||
31 | await submit.scrollIntoView(false) | ||
32 | await submit.click() | ||
33 | } | ||
34 | |||
17 | // My account Videos | 35 | // My account Videos |
18 | 36 | ||
19 | async removeVideo (name: string) { | 37 | async removeVideo (name: string) { |
diff --git a/client/e2e/src/po/player.po.ts b/client/e2e/src/po/player.po.ts index 372e8ab20..fca3bcdba 100644 --- a/client/e2e/src/po/player.po.ts +++ b/client/e2e/src/po/player.po.ts | |||
@@ -15,6 +15,9 @@ export class PlayerPage { | |||
15 | 15 | ||
16 | waitUntilPlaylistInfo (text: string, maxTime: number) { | 16 | waitUntilPlaylistInfo (text: string, maxTime: number) { |
17 | return browser.waitUntil(async () => { | 17 | return browser.waitUntil(async () => { |
18 | // Without this we have issues on iphone | ||
19 | await $('.video-js').click() | ||
20 | |||
18 | return (await $('.video-js .vjs-playlist-info').getText()).includes(text) | 21 | return (await $('.video-js .vjs-playlist-info').getText()).includes(text) |
19 | }, { timeout: maxTime }) | 22 | }, { timeout: maxTime }) |
20 | } | 23 | } |
@@ -42,7 +45,7 @@ export class PlayerPage { | |||
42 | await browserSleep(2000) | 45 | await browserSleep(2000) |
43 | 46 | ||
44 | await browser.waitUntil(async () => { | 47 | await browser.waitUntil(async () => { |
45 | return (await this.getWatchVideoPlayerCurrentTime()) >= 2 | 48 | return (await this.getWatchVideoPlayerCurrentTime()) >= waitUntilSec |
46 | }) | 49 | }) |
47 | 50 | ||
48 | await videojsElem().click() | 51 | await videojsElem().click() |
diff --git a/client/e2e/src/po/video-list.po.ts b/client/e2e/src/po/video-list.po.ts new file mode 100644 index 000000000..f62c79adc --- /dev/null +++ b/client/e2e/src/po/video-list.po.ts | |||
@@ -0,0 +1,128 @@ | |||
1 | import { browserSleep, go } from '../utils' | ||
2 | |||
3 | export class VideoListPage { | ||
4 | |||
5 | constructor (private isMobileDevice: boolean, private isSafari: boolean) { | ||
6 | |||
7 | } | ||
8 | |||
9 | async goOnVideosList () { | ||
10 | let url: string | ||
11 | |||
12 | // We did not upload a file on a mobile device | ||
13 | if (this.isMobileDevice === true || this.isSafari === true) { | ||
14 | url = 'https://peertube2.cpy.re/videos/local' | ||
15 | } else { | ||
16 | url = '/videos/recently-added' | ||
17 | } | ||
18 | |||
19 | await go(url) | ||
20 | |||
21 | // Waiting the following element does not work on Safari... | ||
22 | if (this.isSafari) return browserSleep(3000) | ||
23 | |||
24 | await this.waitForList() | ||
25 | } | ||
26 | |||
27 | async goOnLocal () { | ||
28 | await $('.menu-link[href="/videos/local"]').click() | ||
29 | await this.waitForTitle('Local videos') | ||
30 | } | ||
31 | |||
32 | async goOnRecentlyAdded () { | ||
33 | await $('.menu-link[href="/videos/recently-added"]').click() | ||
34 | await this.waitForTitle('Recently added') | ||
35 | } | ||
36 | |||
37 | async goOnTrending () { | ||
38 | await $('.menu-link[href="/videos/trending"]').click() | ||
39 | await this.waitForTitle('Trending') | ||
40 | } | ||
41 | |||
42 | async goOnHomepage () { | ||
43 | await go('/home') | ||
44 | await this.waitForList() | ||
45 | } | ||
46 | |||
47 | async goOnRootChannel () { | ||
48 | await go('/c/root_channel/videos') | ||
49 | await this.waitForList() | ||
50 | } | ||
51 | |||
52 | async goOnRootAccount () { | ||
53 | await go('/a/root/videos') | ||
54 | await this.waitForList() | ||
55 | } | ||
56 | |||
57 | async goOnRootAccountChannels () { | ||
58 | await go('/a/root/video-channels') | ||
59 | await this.waitForList() | ||
60 | } | ||
61 | |||
62 | getNSFWFilter () { | ||
63 | return $$('.active-filter').filter(async a => { | ||
64 | return (await a.getText()).includes('Sensitive') | ||
65 | }).then(f => f[0]) | ||
66 | } | ||
67 | |||
68 | async getVideosListName () { | ||
69 | const elems = await $$('.videos .video-miniature .video-miniature-name') | ||
70 | const texts = await Promise.all(elems.map(e => e.getText())) | ||
71 | |||
72 | return texts.map(t => t.trim()) | ||
73 | } | ||
74 | |||
75 | videoExists (name: string) { | ||
76 | return $('.video-miniature-name=' + name).isDisplayed() | ||
77 | } | ||
78 | |||
79 | async videoIsBlurred (name: string) { | ||
80 | const filter = await $('.video-miniature-name=' + name).getCSSProperty('filter') | ||
81 | |||
82 | return filter.value !== 'none' | ||
83 | } | ||
84 | |||
85 | async clickOnVideo (videoName: string) { | ||
86 | const video = async () => { | ||
87 | const videos = await $$('.videos .video-miniature .video-miniature-name').filter(async e => { | ||
88 | const t = await e.getText() | ||
89 | |||
90 | return t === videoName | ||
91 | }) | ||
92 | |||
93 | return videos[0] | ||
94 | } | ||
95 | |||
96 | await browser.waitUntil(async () => { | ||
97 | const elem = await video() | ||
98 | |||
99 | return elem?.isClickable() | ||
100 | }); | ||
101 | |||
102 | (await video()).click() | ||
103 | |||
104 | await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/')) | ||
105 | } | ||
106 | |||
107 | async clickOnFirstVideo () { | ||
108 | const video = () => $('.videos .video-miniature .video-thumbnail') | ||
109 | const videoName = () => $('.videos .video-miniature .video-miniature-name') | ||
110 | |||
111 | await video().waitForClickable() | ||
112 | |||
113 | const textToReturn = await videoName().getText() | ||
114 | await video().click() | ||
115 | |||
116 | await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/')) | ||
117 | |||
118 | return textToReturn | ||
119 | } | ||
120 | |||
121 | private waitForList () { | ||
122 | return $('.videos .video-miniature .video-miniature-name').waitForDisplayed() | ||
123 | } | ||
124 | |||
125 | private waitForTitle (title: string) { | ||
126 | return $('h1=' + title).waitForDisplayed() | ||
127 | } | ||
128 | } | ||
diff --git a/client/e2e/src/po/video-search.po.ts b/client/e2e/src/po/video-search.po.ts new file mode 100644 index 000000000..5446718d1 --- /dev/null +++ b/client/e2e/src/po/video-search.po.ts | |||
@@ -0,0 +1,11 @@ | |||
1 | export class VideoSearchPage { | ||
2 | |||
3 | async search (search: string) { | ||
4 | await $('#search-video').setValue(search) | ||
5 | await $('my-header .icon-search').click() | ||
6 | |||
7 | await browser.waitUntil(() => { | ||
8 | return $('my-video-miniature').isDisplayed() | ||
9 | }) | ||
10 | } | ||
11 | } | ||
diff --git a/client/e2e/src/po/video-upload.po.ts b/client/e2e/src/po/video-upload.po.ts index 34f916b55..dd437c390 100644 --- a/client/e2e/src/po/video-upload.po.ts +++ b/client/e2e/src/po/video-upload.po.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { join } from 'path' | 1 | import { join } from 'path' |
2 | import { clickOnCheckbox } from '../utils' | ||
2 | 3 | ||
3 | export class VideoUploadPage { | 4 | export class VideoUploadPage { |
4 | async navigateTo () { | 5 | async navigateTo () { |
@@ -30,6 +31,10 @@ export class VideoUploadPage { | |||
30 | }) | 31 | }) |
31 | } | 32 | } |
32 | 33 | ||
34 | setAsNSFW () { | ||
35 | return clickOnCheckbox('nsfw') | ||
36 | } | ||
37 | |||
33 | async validSecondUploadStep (videoName: string) { | 38 | async validSecondUploadStep (videoName: string) { |
34 | const nameInput = $('input#name') | 39 | const nameInput = $('input#name') |
35 | await nameInput.clearValue() | 40 | await nameInput.clearValue() |
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts index c07f4b25f..41425f4d7 100644 --- a/client/e2e/src/po/video-watch.po.ts +++ b/client/e2e/src/po/video-watch.po.ts | |||
@@ -1,37 +1,16 @@ | |||
1 | import { FIXTURE_URLS } from '../urls' | 1 | import { browserSleep, FIXTURE_URLS, go } from '../utils' |
2 | import { browserSleep, go } from '../utils' | ||
3 | 2 | ||
4 | export class VideoWatchPage { | 3 | export class VideoWatchPage { |
5 | async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { | ||
6 | let url: string | ||
7 | |||
8 | // We did not upload a file on a mobile device | ||
9 | if (isMobileDevice === true || isSafari === true) { | ||
10 | url = 'https://peertube2.cpy.re/videos/local' | ||
11 | } else { | ||
12 | url = '/videos/recently-added' | ||
13 | } | ||
14 | |||
15 | await go(url) | ||
16 | |||
17 | // Waiting the following element does not work on Safari... | ||
18 | if (isSafari) return browserSleep(3000) | ||
19 | 4 | ||
20 | await $('.videos .video-miniature .video-miniature-name').waitForDisplayed() | 5 | constructor (private isMobileDevice: boolean, private isSafari: boolean) { |
21 | } | ||
22 | |||
23 | async getVideosListName () { | ||
24 | const elems = await $$('.videos .video-miniature .video-miniature-name') | ||
25 | const texts = await Promise.all(elems.map(e => e.getText())) | ||
26 | 6 | ||
27 | return texts.map(t => t.trim()) | ||
28 | } | 7 | } |
29 | 8 | ||
30 | waitWatchVideoName (videoName: string, isMobileDevice: boolean, isSafari: boolean) { | 9 | waitWatchVideoName (videoName: string) { |
31 | if (isSafari) return browserSleep(5000) | 10 | if (this.isSafari) return browserSleep(5000) |
32 | 11 | ||
33 | // On mobile we display the first node, on desktop the second | 12 | // On mobile we display the first node, on desktop the second |
34 | const index = isMobileDevice ? 0 : 1 | 13 | const index = this.isMobileDevice ? 0 : 1 |
35 | 14 | ||
36 | return browser.waitUntil(async () => { | 15 | return browser.waitUntil(async () => { |
37 | return (await $$('.video-info .video-info-name')[index].getText()).includes(videoName) | 16 | return (await $$('.video-info .video-info-name')[index].getText()).includes(videoName) |
@@ -58,42 +37,6 @@ export class VideoWatchPage { | |||
58 | return go(FIXTURE_URLS.HLS_PLAYLIST_EMBED) | 37 | return go(FIXTURE_URLS.HLS_PLAYLIST_EMBED) |
59 | } | 38 | } |
60 | 39 | ||
61 | async clickOnVideo (videoName: string) { | ||
62 | const video = async () => { | ||
63 | const videos = await $$('.videos .video-miniature .video-miniature-name').filter(async e => { | ||
64 | const t = await e.getText() | ||
65 | |||
66 | return t === videoName | ||
67 | }) | ||
68 | |||
69 | return videos[0] | ||
70 | } | ||
71 | |||
72 | await browser.waitUntil(async () => { | ||
73 | const elem = await video() | ||
74 | |||
75 | return elem?.isClickable() | ||
76 | }); | ||
77 | |||
78 | (await video()).click() | ||
79 | |||
80 | await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/')) | ||
81 | } | ||
82 | |||
83 | async clickOnFirstVideo () { | ||
84 | const video = () => $('.videos .video-miniature .video-thumbnail') | ||
85 | const videoName = () => $('.videos .video-miniature .video-miniature-name') | ||
86 | |||
87 | await video().waitForClickable() | ||
88 | |||
89 | const textToReturn = await videoName().getText() | ||
90 | await video().click() | ||
91 | |||
92 | await browser.waitUntil(async () => (await browser.getUrl()).includes('/w/')) | ||
93 | |||
94 | return textToReturn | ||
95 | } | ||
96 | |||
97 | async clickOnUpdate () { | 40 | async clickOnUpdate () { |
98 | const dropdown = $('my-video-actions-dropdown .action-button') | 41 | const dropdown = $('my-video-actions-dropdown .action-button') |
99 | await dropdown.click() | 42 | await dropdown.click() |
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/suites-all/videos.e2e-spec.ts index e09e8c675..3b8305a25 100644 --- a/client/e2e/src/videos.e2e-spec.ts +++ b/client/e2e/src/suites-all/videos.e2e-spec.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { LoginPage } from './po/login.po' | 1 | import { LoginPage } from '../po/login.po' |
2 | import { MyAccountPage } from './po/my-account' | 2 | import { MyAccountPage } from '../po/my-account' |
3 | import { PlayerPage } from './po/player.po' | 3 | import { PlayerPage } from '../po/player.po' |
4 | import { VideoUpdatePage } from './po/video-update.po' | 4 | import { VideoListPage } from '../po/video-list.po' |
5 | import { VideoUploadPage } from './po/video-upload.po' | 5 | import { VideoUpdatePage } from '../po/video-update.po' |
6 | import { VideoWatchPage } from './po/video-watch.po' | 6 | import { VideoUploadPage } from '../po/video-upload.po' |
7 | import { FIXTURE_URLS } from './urls' | 7 | import { VideoWatchPage } from '../po/video-watch.po' |
8 | import { browserSleep, go, isIOS, isMobileDevice, isSafari } from './utils' | 8 | import { FIXTURE_URLS, go, isIOS, isMobileDevice, isSafari, waitServerUp } from '../utils' |
9 | 9 | ||
10 | function isUploadUnsupported () { | 10 | function isUploadUnsupported () { |
11 | if (isMobileDevice() || isSafari()) { | 11 | if (isMobileDevice() || isSafari()) { |
@@ -16,8 +16,9 @@ function isUploadUnsupported () { | |||
16 | return false | 16 | return false |
17 | } | 17 | } |
18 | 18 | ||
19 | describe('Videos workflow', () => { | 19 | describe('Videos all workflow', () => { |
20 | let videoWatchPage: VideoWatchPage | 20 | let videoWatchPage: VideoWatchPage |
21 | let videoListPage: VideoListPage | ||
21 | let videoUploadPage: VideoUploadPage | 22 | let videoUploadPage: VideoUploadPage |
22 | let videoUpdatePage: VideoUpdatePage | 23 | let videoUpdatePage: VideoUpdatePage |
23 | let myAccountPage: MyAccountPage | 24 | let myAccountPage: MyAccountPage |
@@ -40,21 +41,17 @@ describe('Videos workflow', () => { | |||
40 | 41 | ||
41 | if (isUploadUnsupported()) return | 42 | if (isUploadUnsupported()) return |
42 | 43 | ||
43 | await browser.waitUntil(async () => { | 44 | await waitServerUp() |
44 | await go('/') | ||
45 | await browserSleep(500) | ||
46 | |||
47 | return $('<my-app>').isDisplayed() | ||
48 | }, { timeout: 20 * 1000 }) | ||
49 | }) | 45 | }) |
50 | 46 | ||
51 | beforeEach(async () => { | 47 | beforeEach(async () => { |
52 | videoWatchPage = new VideoWatchPage() | 48 | videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari()) |
53 | videoUploadPage = new VideoUploadPage() | 49 | videoUploadPage = new VideoUploadPage() |
54 | videoUpdatePage = new VideoUpdatePage() | 50 | videoUpdatePage = new VideoUpdatePage() |
55 | myAccountPage = new MyAccountPage() | 51 | myAccountPage = new MyAccountPage() |
56 | loginPage = new LoginPage() | 52 | loginPage = new LoginPage() |
57 | playerPage = new PlayerPage() | 53 | playerPage = new PlayerPage() |
54 | videoListPage = new VideoListPage(isMobileDevice(), isSafari()) | ||
58 | 55 | ||
59 | if (!isMobileDevice()) { | 56 | if (!isMobileDevice()) { |
60 | await browser.maximizeWindow() | 57 | await browser.maximizeWindow() |
@@ -80,11 +77,11 @@ describe('Videos workflow', () => { | |||
80 | }) | 77 | }) |
81 | 78 | ||
82 | it('Should list videos', async () => { | 79 | it('Should list videos', async () => { |
83 | await videoWatchPage.goOnVideosList(isMobileDevice(), isSafari()) | 80 | await videoListPage.goOnVideosList() |
84 | 81 | ||
85 | if (isUploadUnsupported()) return | 82 | if (isUploadUnsupported()) return |
86 | 83 | ||
87 | const videoNames = await videoWatchPage.getVideosListName() | 84 | const videoNames = await videoListPage.getVideosListName() |
88 | expect(videoNames).toContain(videoName) | 85 | expect(videoNames).toContain(videoName) |
89 | }) | 86 | }) |
90 | 87 | ||
@@ -95,10 +92,10 @@ describe('Videos workflow', () => { | |||
95 | await go(FIXTURE_URLS.WEBTORRENT_VIDEO) | 92 | await go(FIXTURE_URLS.WEBTORRENT_VIDEO) |
96 | videoNameToExcept = 'E2E tests' | 93 | videoNameToExcept = 'E2E tests' |
97 | } else { | 94 | } else { |
98 | await videoWatchPage.clickOnVideo(videoName) | 95 | await videoListPage.clickOnVideo(videoName) |
99 | } | 96 | } |
100 | 97 | ||
101 | return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice(), isSafari()) | 98 | return videoWatchPage.waitWatchVideoName(videoNameToExcept) |
102 | }) | 99 | }) |
103 | 100 | ||
104 | it('Should play the video', async () => { | 101 | it('Should play the video', async () => { |
diff --git a/client/e2e/src/suites-local/videos-list.e2e-spec.ts b/client/e2e/src/suites-local/videos-list.e2e-spec.ts new file mode 100644 index 000000000..1e0a88859 --- /dev/null +++ b/client/e2e/src/suites-local/videos-list.e2e-spec.ts | |||
@@ -0,0 +1,195 @@ | |||
1 | import { AdminConfigPage } from '../po/admin-config.po' | ||
2 | import { LoginPage } from '../po/login.po' | ||
3 | import { MyAccountPage } from '../po/my-account' | ||
4 | import { VideoListPage } from '../po/video-list.po' | ||
5 | import { VideoSearchPage } from '../po/video-search.po' | ||
6 | import { VideoUploadPage } from '../po/video-upload.po' | ||
7 | import { NSFWPolicy } from '../types/common' | ||
8 | import { isMobileDevice, isSafari, waitServerUp } from '../utils' | ||
9 | |||
10 | describe('Videos list', () => { | ||
11 | let videoListPage: VideoListPage | ||
12 | let videoUploadPage: VideoUploadPage | ||
13 | let adminConfigPage: AdminConfigPage | ||
14 | let loginPage: LoginPage | ||
15 | let myAccountPage: MyAccountPage | ||
16 | let videoSearchPage: VideoSearchPage | ||
17 | |||
18 | const seed = Math.random() | ||
19 | const nsfwVideo = seed + ' - nsfw' | ||
20 | const normalVideo = seed + ' - normal' | ||
21 | |||
22 | async function checkNormalVideo () { | ||
23 | expect(await videoListPage.videoExists(normalVideo)).toBeTruthy() | ||
24 | expect(await videoListPage.videoIsBlurred(normalVideo)).toBeFalsy() | ||
25 | } | ||
26 | |||
27 | async function checkNSFWVideo (policy: NSFWPolicy, filterText?: string) { | ||
28 | if (policy === 'do_not_list') { | ||
29 | if (filterText) expect(filterText).toContain('hidden') | ||
30 | |||
31 | expect(await videoListPage.videoExists(nsfwVideo)).toBeFalsy() | ||
32 | return | ||
33 | } | ||
34 | |||
35 | if (policy === 'blur') { | ||
36 | if (filterText) expect(filterText).toContain('blurred') | ||
37 | |||
38 | expect(await videoListPage.videoExists(nsfwVideo)).toBeTruthy() | ||
39 | expect(await videoListPage.videoIsBlurred(nsfwVideo)).toBeTruthy() | ||
40 | return | ||
41 | } | ||
42 | |||
43 | // display | ||
44 | if (filterText) expect(filterText).toContain('displayed') | ||
45 | |||
46 | expect(await videoListPage.videoExists(nsfwVideo)).toBeTruthy() | ||
47 | expect(await videoListPage.videoIsBlurred(nsfwVideo)).toBeFalsy() | ||
48 | } | ||
49 | |||
50 | async function checkCommonVideoListPages (policy: NSFWPolicy) { | ||
51 | const promisesWithFilters = [ | ||
52 | videoListPage.goOnRootAccount, | ||
53 | videoListPage.goOnLocal, | ||
54 | videoListPage.goOnRecentlyAdded, | ||
55 | videoListPage.goOnTrending, | ||
56 | videoListPage.goOnRootChannel | ||
57 | ] | ||
58 | |||
59 | for (const p of promisesWithFilters) { | ||
60 | await p.call(videoListPage) | ||
61 | |||
62 | const filter = await videoListPage.getNSFWFilter() | ||
63 | const filterText = await filter.getText() | ||
64 | |||
65 | await checkNormalVideo() | ||
66 | await checkNSFWVideo(policy, filterText) | ||
67 | } | ||
68 | |||
69 | const promisesWithoutFilters = [ | ||
70 | videoListPage.goOnRootAccountChannels, | ||
71 | videoListPage.goOnHomepage | ||
72 | ] | ||
73 | for (const p of promisesWithoutFilters) { | ||
74 | await p.call(videoListPage) | ||
75 | |||
76 | await checkNormalVideo() | ||
77 | await checkNSFWVideo(policy) | ||
78 | } | ||
79 | } | ||
80 | |||
81 | async function checkSearchPage (policy: NSFWPolicy) { | ||
82 | await videoSearchPage.search(normalVideo) | ||
83 | await checkNormalVideo() | ||
84 | |||
85 | await videoSearchPage.search(nsfwVideo) | ||
86 | await checkNSFWVideo(policy) | ||
87 | } | ||
88 | |||
89 | async function updateAdminNSFW (nsfw: NSFWPolicy) { | ||
90 | await adminConfigPage.navigateTo('instance-information') | ||
91 | await adminConfigPage.updateNSFWSetting(nsfw) | ||
92 | await adminConfigPage.save() | ||
93 | } | ||
94 | |||
95 | async function updateUserNSFW (nsfw: NSFWPolicy) { | ||
96 | await myAccountPage.navigateToMySettings() | ||
97 | await myAccountPage.updateNSFW(nsfw) | ||
98 | } | ||
99 | |||
100 | before(async () => { | ||
101 | await waitServerUp() | ||
102 | }) | ||
103 | |||
104 | beforeEach(async () => { | ||
105 | videoListPage = new VideoListPage(isMobileDevice(), isSafari()) | ||
106 | adminConfigPage = new AdminConfigPage() | ||
107 | loginPage = new LoginPage() | ||
108 | videoUploadPage = new VideoUploadPage() | ||
109 | myAccountPage = new MyAccountPage() | ||
110 | videoSearchPage = new VideoSearchPage() | ||
111 | |||
112 | await browser.maximizeWindow() | ||
113 | }) | ||
114 | |||
115 | it('Should login and disable NSFW', async () => { | ||
116 | await loginPage.loginAsRootUser() | ||
117 | await updateUserNSFW('display') | ||
118 | }) | ||
119 | |||
120 | it('Should set the homepage', async () => { | ||
121 | await adminConfigPage.navigateTo('instance-homepage') | ||
122 | await adminConfigPage.updateHomepage('<peertube-videos-list data-sort="-publishedAt"></peertube-videos-list>') | ||
123 | await adminConfigPage.save() | ||
124 | }) | ||
125 | |||
126 | it('Should upload 2 videos (NSFW and classic videos)', async () => { | ||
127 | await videoUploadPage.navigateTo() | ||
128 | await videoUploadPage.uploadVideo() | ||
129 | await videoUploadPage.setAsNSFW() | ||
130 | await videoUploadPage.validSecondUploadStep(nsfwVideo) | ||
131 | |||
132 | await videoUploadPage.navigateTo() | ||
133 | await videoUploadPage.uploadVideo() | ||
134 | await videoUploadPage.validSecondUploadStep(normalVideo) | ||
135 | }) | ||
136 | |||
137 | it('Should logout', async function () { | ||
138 | await loginPage.logout() | ||
139 | }) | ||
140 | |||
141 | describe('Anonymous users', function () { | ||
142 | |||
143 | it('Should correctly handle do not list', async () => { | ||
144 | await loginPage.loginAsRootUser() | ||
145 | await updateAdminNSFW('do_not_list') | ||
146 | |||
147 | await loginPage.logout() | ||
148 | await checkCommonVideoListPages('do_not_list') | ||
149 | await checkSearchPage('do_not_list') | ||
150 | }) | ||
151 | |||
152 | it('Should correctly handle blur', async () => { | ||
153 | await loginPage.loginAsRootUser() | ||
154 | await updateAdminNSFW('blur') | ||
155 | |||
156 | await loginPage.logout() | ||
157 | await checkCommonVideoListPages('blur') | ||
158 | await checkSearchPage('blur') | ||
159 | }) | ||
160 | |||
161 | it('Should correctly handle display', async () => { | ||
162 | await loginPage.loginAsRootUser() | ||
163 | await updateAdminNSFW('display') | ||
164 | |||
165 | await loginPage.logout() | ||
166 | await checkCommonVideoListPages('display') | ||
167 | await checkSearchPage('display') | ||
168 | }) | ||
169 | }) | ||
170 | |||
171 | describe('Logged in users', function () { | ||
172 | |||
173 | before(async () => { | ||
174 | await loginPage.loginAsRootUser() | ||
175 | }) | ||
176 | |||
177 | it('Should correctly handle do not list', async () => { | ||
178 | await updateUserNSFW('do_not_list') | ||
179 | await checkCommonVideoListPages('do_not_list') | ||
180 | await checkSearchPage('do_not_list') | ||
181 | }) | ||
182 | |||
183 | it('Should correctly handle blur', async () => { | ||
184 | await updateUserNSFW('blur') | ||
185 | await checkCommonVideoListPages('blur') | ||
186 | await checkSearchPage('blur') | ||
187 | }) | ||
188 | |||
189 | it('Should correctly handle display', async () => { | ||
190 | await updateUserNSFW('display') | ||
191 | await checkCommonVideoListPages('display') | ||
192 | await checkSearchPage('display') | ||
193 | }) | ||
194 | }) | ||
195 | }) | ||
diff --git a/client/e2e/src/types/common.ts b/client/e2e/src/types/common.ts new file mode 100644 index 000000000..c0b59d297 --- /dev/null +++ b/client/e2e/src/types/common.ts | |||
@@ -0,0 +1 @@ | |||
export type NSFWPolicy = 'do_not_list' | 'blur' | 'display' | |||
diff --git a/client/e2e/src/utils.ts b/client/e2e/src/utils/common.ts index df1c29238..eb5f6b450 100644 --- a/client/e2e/src/utils.ts +++ b/client/e2e/src/utils/common.ts | |||
@@ -28,10 +28,20 @@ async function go (url: string) { | |||
28 | }) | 28 | }) |
29 | } | 29 | } |
30 | 30 | ||
31 | async function waitServerUp () { | ||
32 | await browser.waitUntil(async () => { | ||
33 | await go('/') | ||
34 | await browserSleep(500) | ||
35 | |||
36 | return $('<my-app>').isDisplayed() | ||
37 | }, { timeout: 20 * 1000 }) | ||
38 | } | ||
39 | |||
31 | export { | 40 | export { |
32 | isMobileDevice, | 41 | isMobileDevice, |
33 | isSafari, | 42 | isSafari, |
34 | isIOS, | 43 | isIOS, |
44 | waitServerUp, | ||
35 | go, | 45 | go, |
36 | browserSleep | 46 | browserSleep |
37 | } | 47 | } |
diff --git a/client/e2e/src/utils/elements.ts b/client/e2e/src/utils/elements.ts new file mode 100644 index 000000000..cadc46cce --- /dev/null +++ b/client/e2e/src/utils/elements.ts | |||
@@ -0,0 +1,7 @@ | |||
1 | function clickOnCheckbox (name: string) { | ||
2 | return $(`my-peertube-checkbox[inputname=${name}] label`).click() | ||
3 | } | ||
4 | |||
5 | export { | ||
6 | clickOnCheckbox | ||
7 | } | ||
diff --git a/client/e2e/src/utils/index.ts b/client/e2e/src/utils/index.ts new file mode 100644 index 000000000..5da1ad517 --- /dev/null +++ b/client/e2e/src/utils/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './common' | ||
2 | export * from './elements' | ||
3 | export * from './urls' | ||
diff --git a/client/e2e/src/urls.ts b/client/e2e/src/utils/urls.ts index 664c65931..664c65931 100644 --- a/client/e2e/src/urls.ts +++ b/client/e2e/src/utils/urls.ts | |||
diff --git a/client/e2e/tsconfig.json b/client/e2e/tsconfig.json index f42206621..c72e1ed4c 100644 --- a/client/e2e/tsconfig.json +++ b/client/e2e/tsconfig.json | |||
@@ -2,6 +2,8 @@ | |||
2 | "extends": "../tsconfig.json", | 2 | "extends": "../tsconfig.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "outDir": "../out-tsc/app", | 4 | "outDir": "../out-tsc/app", |
5 | "noImplicitAny": false, | ||
6 | "esModuleInterop": true, | ||
5 | "module": "commonjs", | 7 | "module": "commonjs", |
6 | "target": "es5", | 8 | "target": "es5", |
7 | "types": [ | 9 | "types": [ |
diff --git a/client/e2e/wdio.browserstack.conf.ts b/client/e2e/wdio.browserstack.conf.ts index af3a454fc..43614a862 100644 --- a/client/e2e/wdio.browserstack.conf.ts +++ b/client/e2e/wdio.browserstack.conf.ts | |||
@@ -26,14 +26,16 @@ function buildBStackDesktopOptions (sessionName: string, resolution?: string) { | |||
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | function buildBStackMobileOptions (sessionName: string, deviceName: string, osVersion: string) { | 29 | function buildBStackMobileOptions (sessionName: string, deviceName: string, osVersion: string, appiumVersion?: string) { |
30 | return { | 30 | return { |
31 | 'bstack:options': { | 31 | 'bstack:options': { |
32 | ...buildMainOptions(sessionName), | 32 | ...buildMainOptions(sessionName), |
33 | 33 | ||
34 | realMobile: true, | 34 | realMobile: true, |
35 | osVersion, | 35 | osVersion, |
36 | deviceName | 36 | deviceName, |
37 | |||
38 | appiumVersion | ||
37 | } | 39 | } |
38 | } | 40 | } |
39 | } | 41 | } |
@@ -84,7 +86,7 @@ module.exports = { | |||
84 | { | 86 | { |
85 | browserName: 'Safari', | 87 | browserName: 'Safari', |
86 | 88 | ||
87 | ...buildBStackMobileOptions('Safari iPhone', 'iPhone 8 Plus', '11') | 89 | ...buildBStackMobileOptions('Safari iPhone', 'iPhone SE', '11') |
88 | }, | 90 | }, |
89 | { | 91 | { |
90 | browserName: 'Safari', | 92 | browserName: 'Safari', |
@@ -97,17 +99,20 @@ module.exports = { | |||
97 | connectionRetryTimeout: 240000, | 99 | connectionRetryTimeout: 240000, |
98 | waitforTimeout: 20000, | 100 | waitforTimeout: 20000, |
99 | 101 | ||
102 | specs: [ | ||
103 | // We don't want to test "local" tests | ||
104 | './src/suites-all/*.e2e-spec.ts' | ||
105 | ], | ||
106 | |||
100 | services: [ | 107 | services: [ |
101 | [ | 108 | [ |
102 | 'browserstack', { browserstackLocal: true } | 109 | 'browserstack', { browserstackLocal: true } |
103 | ] | 110 | ] |
104 | ], | 111 | ], |
105 | 112 | ||
106 | after: function (result) { | 113 | onWorkerStart: function (_cid, capabilities) { |
107 | if (result === 0) { | 114 | if (capabilities['bstack:options'].realMobile === true) { |
108 | browser.executeScript('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed","reason": ""}}', []) | 115 | capabilities['bstack:options'].local = false |
109 | } else { | ||
110 | browser.executeScript('browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed","reason": ""}}', []) | ||
111 | } | 116 | } |
112 | } | 117 | } |
113 | } as WebdriverIO.Config | 118 | } as WebdriverIO.Config |
diff --git a/client/e2e/wdio.local-test.conf.ts b/client/e2e/wdio.local-test.conf.ts new file mode 100644 index 000000000..6ae426322 --- /dev/null +++ b/client/e2e/wdio.local-test.conf.ts | |||
@@ -0,0 +1,28 @@ | |||
1 | import { config as mainConfig } from './wdio.main.conf' | ||
2 | |||
3 | const prefs = { | ||
4 | 'intl.accept_languages': 'en' | ||
5 | } | ||
6 | |||
7 | module.exports = { | ||
8 | config: { | ||
9 | ...mainConfig, | ||
10 | |||
11 | runner: 'local', | ||
12 | |||
13 | maxInstances: 1, | ||
14 | specFileRetries: 0, | ||
15 | |||
16 | capabilities: [ | ||
17 | { | ||
18 | browserName: 'chrome', | ||
19 | acceptInsecureCerts: true, | ||
20 | 'goog:chromeOptions': { | ||
21 | prefs | ||
22 | } | ||
23 | } | ||
24 | ], | ||
25 | |||
26 | services: [ 'chromedriver' ] | ||
27 | } as WebdriverIO.Config | ||
28 | } | ||
diff --git a/client/e2e/wdio.local.conf.ts b/client/e2e/wdio.local.conf.ts index 4071aa249..a4c517f5e 100644 --- a/client/e2e/wdio.local.conf.ts +++ b/client/e2e/wdio.local.conf.ts | |||
@@ -10,12 +10,11 @@ module.exports = { | |||
10 | 10 | ||
11 | runner: 'local', | 11 | runner: 'local', |
12 | 12 | ||
13 | maxInstances: 1, | 13 | maxInstances: 2, |
14 | 14 | ||
15 | capabilities: [ | 15 | capabilities: [ |
16 | { | 16 | { |
17 | browserName: 'chrome', | 17 | browserName: 'chrome', |
18 | acceptInsecureCerts: true, | ||
19 | 'goog:chromeOptions': { | 18 | 'goog:chromeOptions': { |
20 | prefs | 19 | prefs |
21 | } | 20 | } |
@@ -23,21 +22,20 @@ module.exports = { | |||
23 | { | 22 | { |
24 | browserName: 'firefox', | 23 | browserName: 'firefox', |
25 | 'moz:firefoxOptions': { | 24 | 'moz:firefoxOptions': { |
26 | // args: [ '-headless' ], | ||
27 | binary: '/usr/bin/firefox-developer-edition', | 25 | binary: '/usr/bin/firefox-developer-edition', |
28 | prefs | 26 | prefs |
29 | } | 27 | } |
30 | }, | ||
31 | { | ||
32 | browserName: 'firefox', | ||
33 | 'moz:firefoxOptions': { | ||
34 | // args: [ '-headless' ], | ||
35 | binary: '/usr/bin/firefox-esr', | ||
36 | prefs | ||
37 | } | ||
38 | } | 28 | } |
39 | ], | 29 | ], |
40 | 30 | ||
41 | services: [ 'chromedriver', 'geckodriver' ] | 31 | services: [ 'chromedriver', 'geckodriver' ], |
32 | |||
33 | beforeSession: function (config, capabilities) { | ||
34 | if (capabilities['browserName'] === 'chrome') { | ||
35 | config.baseUrl = 'http://localhost:9001' | ||
36 | } else { | ||
37 | config.baseUrl = 'http://localhost:9002' | ||
38 | } | ||
39 | } | ||
42 | } as WebdriverIO.Config | 40 | } as WebdriverIO.Config |
43 | } | 41 | } |
diff --git a/client/e2e/wdio.main.conf.ts b/client/e2e/wdio.main.conf.ts index 7f4c7f7ee..29afdbdc0 100644 --- a/client/e2e/wdio.main.conf.ts +++ b/client/e2e/wdio.main.conf.ts | |||
@@ -21,7 +21,8 @@ export const config = { | |||
21 | // will be called from there. | 21 | // will be called from there. |
22 | // | 22 | // |
23 | specs: [ | 23 | specs: [ |
24 | './src/**/*.e2e-spec.ts' | 24 | './src/suites-all/*.e2e-spec.ts', |
25 | './src/suites-local/*.e2e-spec.ts' | ||
25 | ], | 26 | ], |
26 | // Patterns to exclude. | 27 | // Patterns to exclude. |
27 | exclude: [ | 28 | exclude: [ |
@@ -79,7 +80,7 @@ export const config = { | |||
79 | framework: 'mocha', | 80 | framework: 'mocha', |
80 | // | 81 | // |
81 | // The number of times to retry the entire specfile when it fails as a whole | 82 | // The number of times to retry the entire specfile when it fails as a whole |
82 | specFileRetries: 2, | 83 | specFileRetries: 1, |
83 | // | 84 | // |
84 | // Delay in seconds between the spec file retry attempts | 85 | // Delay in seconds between the spec file retry attempts |
85 | // specFileRetriesDelay: 0, | 86 | // specFileRetriesDelay: 0, |
@@ -105,6 +106,14 @@ export const config = { | |||
105 | 106 | ||
106 | tsNodeOpts: { | 107 | tsNodeOpts: { |
107 | project: require('path').join(__dirname, './tsconfig.json') | 108 | project: require('path').join(__dirname, './tsconfig.json') |
109 | }, | ||
110 | |||
111 | tsConfigPathsOpts: { | ||
112 | baseUrl: './', | ||
113 | paths: { | ||
114 | '@server/*': [ '../../server/*' ], | ||
115 | '@shared/*': [ '../../shared/*' ] | ||
116 | } | ||
108 | } | 117 | } |
109 | }, | 118 | }, |
110 | 119 | ||