diff options
author | Chocobozzz <me@florianbigard.com> | 2019-06-17 08:11:25 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-06-17 08:16:09 +0200 |
commit | e69cb173ba63d0e556d4af6cbaf18b11f16af3a9 (patch) | |
tree | d75c666b2a66f667db1e9dce7f9f606a6b30cfcb /client/e2e/src | |
parent | 6b226c32782ea7779ced56c1e1090d8b51c5c504 (diff) | |
download | PeerTube-e69cb173ba63d0e556d4af6cbaf18b11f16af3a9.tar.gz PeerTube-e69cb173ba63d0e556d4af6cbaf18b11f16af3a9.tar.zst PeerTube-e69cb173ba63d0e556d4af6cbaf18b11f16af3a9.zip |
Add more e2e tests
Diffstat (limited to 'client/e2e/src')
-rw-r--r-- | client/e2e/src/po/my-account.ts | 72 | ||||
-rw-r--r-- | client/e2e/src/po/video-update.po.ts | 20 | ||||
-rw-r--r-- | client/e2e/src/po/video-watch.po.ts | 43 | ||||
-rw-r--r-- | client/e2e/src/videos.e2e-spec.ts | 159 |
4 files changed, 264 insertions, 30 deletions
diff --git a/client/e2e/src/po/my-account.ts b/client/e2e/src/po/my-account.ts new file mode 100644 index 000000000..e49372983 --- /dev/null +++ b/client/e2e/src/po/my-account.ts | |||
@@ -0,0 +1,72 @@ | |||
1 | import { by, element } from 'protractor' | ||
2 | |||
3 | export class MyAccountPage { | ||
4 | |||
5 | navigateToMyVideos () { | ||
6 | return element(by.css('a[href="/my-account/videos"]')).click() | ||
7 | } | ||
8 | |||
9 | navigateToMyPlaylists () { | ||
10 | return element(by.css('a[href="/my-account/video-playlists"]')).click() | ||
11 | } | ||
12 | |||
13 | navigateToMyHistory () { | ||
14 | return element(by.css('a[href="/my-account/history/videos"]')).click() | ||
15 | } | ||
16 | |||
17 | // My account Videos | ||
18 | |||
19 | getLastVideoName () { | ||
20 | return this.getAllVideoNameElements().first().getText() | ||
21 | } | ||
22 | |||
23 | removeLastVideo () { | ||
24 | return this.getLastVideoElement().element(by.css('my-delete-button')).click() | ||
25 | } | ||
26 | |||
27 | validRemove () { | ||
28 | return element(by.css('.action-button-submit')).click() | ||
29 | } | ||
30 | |||
31 | countVideos () { | ||
32 | return this.getAllVideoNameElements().count() | ||
33 | } | ||
34 | |||
35 | // My account playlists | ||
36 | |||
37 | getLastUpdatedPlaylistName () { | ||
38 | return this.getLastUpdatedPlaylist().element(by.css('.miniature-name')).getText() | ||
39 | } | ||
40 | |||
41 | getLastUpdatedPlaylistVideosText () { | ||
42 | return this.getLastUpdatedPlaylist().element(by.css('.miniature-playlist-info-overlay')).getText() | ||
43 | } | ||
44 | |||
45 | clickOnLastUpdatedPlaylist () { | ||
46 | return this.getLastUpdatedPlaylist().element(by.css('.miniature-thumbnail')).click() | ||
47 | } | ||
48 | |||
49 | countTotalPlaylistElements () { | ||
50 | return element.all(by.css('my-video-playlist-element-miniature')).count() | ||
51 | } | ||
52 | |||
53 | playPlaylist () { | ||
54 | return element(by.css('.playlist-info .miniature-thumbnail')).click() | ||
55 | } | ||
56 | |||
57 | // My account Videos | ||
58 | |||
59 | private getLastVideoElement () { | ||
60 | return element.all(by.css('.video')).first() | ||
61 | } | ||
62 | |||
63 | private getAllVideoNameElements () { | ||
64 | return element.all(by.css('.video-miniature-name')) | ||
65 | } | ||
66 | |||
67 | // My account playlists | ||
68 | |||
69 | private getLastUpdatedPlaylist () { | ||
70 | return element.all(by.css('my-video-playlist-miniature')).first() | ||
71 | } | ||
72 | } | ||
diff --git a/client/e2e/src/po/video-update.po.ts b/client/e2e/src/po/video-update.po.ts new file mode 100644 index 000000000..4de3b1b1d --- /dev/null +++ b/client/e2e/src/po/video-update.po.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import { by, element } from 'protractor' | ||
2 | |||
3 | export class VideoUpdatePage { | ||
4 | |||
5 | async updateName (videoName: string) { | ||
6 | const nameInput = element(by.css('input#name')) | ||
7 | await nameInput.clear() | ||
8 | await nameInput.sendKeys(videoName) | ||
9 | } | ||
10 | |||
11 | async validUpdate () { | ||
12 | const submitButton = await this.getSubmitButton() | ||
13 | |||
14 | return submitButton.click() | ||
15 | } | ||
16 | |||
17 | private getSubmitButton () { | ||
18 | return element(by.css('.submit-button:not(.disabled) input')) | ||
19 | } | ||
20 | } | ||
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts index 5f61d5668..9bb0a3919 100644 --- a/client/e2e/src/po/video-watch.po.ts +++ b/client/e2e/src/po/video-watch.po.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { browser, by, element } from 'protractor' | 1 | import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor' |
2 | 2 | ||
3 | export class VideoWatchPage { | 3 | export class VideoWatchPage { |
4 | async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { | 4 | async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { |
@@ -44,6 +44,10 @@ export class VideoWatchPage { | |||
44 | .then(seconds => parseInt(seconds, 10)) | 44 | .then(seconds => parseInt(seconds, 10)) |
45 | } | 45 | } |
46 | 46 | ||
47 | getVideoName () { | ||
48 | return this.getVideoNameElement().getText() | ||
49 | } | ||
50 | |||
47 | async playAndPauseVideo (isAutoplay: boolean, isMobileDevice: boolean) { | 51 | async playAndPauseVideo (isAutoplay: boolean, isMobileDevice: boolean) { |
48 | if (isAutoplay === false) { | 52 | if (isAutoplay === false) { |
49 | const playButton = element(by.css('.vjs-big-play-button')) | 53 | const playButton = element(by.css('.vjs-big-play-button')) |
@@ -101,4 +105,41 @@ export class VideoWatchPage { | |||
101 | async goOnP2PMediaLoaderEmbed () { | 105 | async goOnP2PMediaLoaderEmbed () { |
102 | return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50?mode=p2p-media-loader') | 106 | return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50?mode=p2p-media-loader') |
103 | } | 107 | } |
108 | |||
109 | async clickOnUpdate () { | ||
110 | const dropdown = element(by.css('my-video-actions-dropdown .action-button')) | ||
111 | await dropdown.click() | ||
112 | |||
113 | const items: ElementFinder[] = await element.all(by.css('my-video-actions-dropdown .dropdown-menu .dropdown-item')) | ||
114 | |||
115 | for (const item of items) { | ||
116 | const href = await item.getAttribute('href') | ||
117 | |||
118 | if (href && href.includes('/update/')) { | ||
119 | await item.click() | ||
120 | return | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | async clickOnSave () { | ||
126 | return element(by.css('.action-button-save')).click() | ||
127 | } | ||
128 | |||
129 | async saveToWatchLater () { | ||
130 | return element.all(by.css('my-video-add-to-playlist .playlist')).first().click() | ||
131 | } | ||
132 | |||
133 | waitUntilVideoName (name: string, maxTime: number) { | ||
134 | const elem = this.getVideoNameElement() | ||
135 | |||
136 | return browser.wait(ExpectedConditions.textToBePresentInElement(elem, name), maxTime) | ||
137 | } | ||
138 | |||
139 | private getVideoNameElement () { | ||
140 | // We have 2 video info name block, pick the first that is not empty | ||
141 | return element.all(by.css('.video-bottom .video-info-name')) | ||
142 | .filter(e => e.getText().then(t => !!t)) | ||
143 | .first() | ||
144 | } | ||
104 | } | 145 | } |
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts index 25521cad9..c19ab3092 100644 --- a/client/e2e/src/videos.e2e-spec.ts +++ b/client/e2e/src/videos.e2e-spec.ts | |||
@@ -2,35 +2,56 @@ import { VideoWatchPage } from './po/video-watch.po' | |||
2 | import { VideoUploadPage } from './po/video-upload.po' | 2 | import { VideoUploadPage } from './po/video-upload.po' |
3 | import { LoginPage } from './po/login.po' | 3 | import { LoginPage } from './po/login.po' |
4 | import { browser } from 'protractor' | 4 | import { browser } from 'protractor' |
5 | import { VideoUpdatePage } from './po/video-update.po' | ||
6 | import { MyAccountPage } from './po/my-account' | ||
7 | |||
8 | async function skipIfUploadNotSupported () { | ||
9 | if (await isMobileDevice() || await isSafari()) { | ||
10 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | ||
11 | return true | ||
12 | } | ||
13 | |||
14 | return false | ||
15 | } | ||
16 | |||
17 | async function isMobileDevice () { | ||
18 | const caps = await browser.getCapabilities() | ||
19 | return caps.get('realMobile') === 'true' || caps.get('realMobile') === true | ||
20 | } | ||
21 | |||
22 | async function isSafari () { | ||
23 | const caps = await browser.getCapabilities() | ||
24 | return caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari' | ||
25 | } | ||
5 | 26 | ||
6 | describe('Videos workflow', () => { | 27 | describe('Videos workflow', () => { |
7 | let videoWatchPage: VideoWatchPage | 28 | let videoWatchPage: VideoWatchPage |
8 | let pageUploadPage: VideoUploadPage | 29 | let videoUploadPage: VideoUploadPage |
30 | let videoUpdatePage: VideoUpdatePage | ||
31 | let myAccountPage: MyAccountPage | ||
9 | let loginPage: LoginPage | 32 | let loginPage: LoginPage |
33 | |||
10 | const videoName = new Date().getTime() + ' video' | 34 | const videoName = new Date().getTime() + ' video' |
11 | let isMobileDevice = false | 35 | let videoWatchUrl: string |
12 | let isSafari = false | ||
13 | 36 | ||
14 | beforeEach(async () => { | 37 | beforeEach(async () => { |
15 | videoWatchPage = new VideoWatchPage() | 38 | videoWatchPage = new VideoWatchPage() |
16 | pageUploadPage = new VideoUploadPage() | 39 | videoUploadPage = new VideoUploadPage() |
40 | videoUpdatePage = new VideoUpdatePage() | ||
41 | myAccountPage = new MyAccountPage() | ||
17 | loginPage = new LoginPage() | 42 | loginPage = new LoginPage() |
18 | 43 | ||
19 | const caps = await browser.getCapabilities() | 44 | if (await isMobileDevice()) { |
20 | isMobileDevice = caps.get('realMobile') === 'true' || caps.get('realMobile') === true | ||
21 | isSafari = caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari' | ||
22 | |||
23 | if (isMobileDevice) { | ||
24 | console.log('Mobile device detected.') | 45 | console.log('Mobile device detected.') |
25 | } | 46 | } |
26 | 47 | ||
27 | if (isSafari) { | 48 | if (await isSafari()) { |
28 | console.log('Safari detected.') | 49 | console.log('Safari detected.') |
29 | } | 50 | } |
30 | }) | 51 | }) |
31 | 52 | ||
32 | it('Should log in', () => { | 53 | it('Should log in', async () => { |
33 | if (isMobileDevice || isSafari) { | 54 | if (await isMobileDevice() || await isSafari()) { |
34 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | 55 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') |
35 | return | 56 | return |
36 | } | 57 | } |
@@ -39,24 +60,18 @@ describe('Videos workflow', () => { | |||
39 | }) | 60 | }) |
40 | 61 | ||
41 | it('Should upload a video', async () => { | 62 | it('Should upload a video', async () => { |
42 | if (isMobileDevice || isSafari) { | 63 | if (await skipIfUploadNotSupported()) return |
43 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | ||
44 | return | ||
45 | } | ||
46 | 64 | ||
47 | await pageUploadPage.navigateTo() | 65 | await videoUploadPage.navigateTo() |
48 | 66 | ||
49 | await pageUploadPage.uploadVideo() | 67 | await videoUploadPage.uploadVideo() |
50 | return pageUploadPage.validSecondUploadStep(videoName) | 68 | return videoUploadPage.validSecondUploadStep(videoName) |
51 | }) | 69 | }) |
52 | 70 | ||
53 | it('Should list videos', async () => { | 71 | it('Should list videos', async () => { |
54 | await videoWatchPage.goOnVideosList(isMobileDevice, isSafari) | 72 | await videoWatchPage.goOnVideosList(await isMobileDevice(), await isSafari()) |
55 | 73 | ||
56 | if (isMobileDevice || isSafari) { | 74 | if (await skipIfUploadNotSupported()) return |
57 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | ||
58 | return | ||
59 | } | ||
60 | 75 | ||
61 | const videoNames = videoWatchPage.getVideosListName() | 76 | const videoNames = videoWatchPage.getVideosListName() |
62 | expect(videoNames).toContain(videoName) | 77 | expect(videoNames).toContain(videoName) |
@@ -65,14 +80,16 @@ describe('Videos workflow', () => { | |||
65 | it('Should go on video watch page', async () => { | 80 | it('Should go on video watch page', async () => { |
66 | let videoNameToExcept = videoName | 81 | let videoNameToExcept = videoName |
67 | 82 | ||
68 | if (isMobileDevice || isSafari) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() | 83 | if (await isMobileDevice() || await isSafari()) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() |
69 | else await videoWatchPage.clickOnVideo(videoName) | 84 | else await videoWatchPage.clickOnVideo(videoName) |
70 | 85 | ||
71 | return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice, isSafari) | 86 | return videoWatchPage.waitWatchVideoName(videoNameToExcept, await isMobileDevice(), await isSafari()) |
72 | }) | 87 | }) |
73 | 88 | ||
74 | it('Should play the video', async () => { | 89 | it('Should play the video', async () => { |
75 | await videoWatchPage.playAndPauseVideo(true, isMobileDevice) | 90 | videoWatchUrl = await browser.getCurrentUrl() |
91 | |||
92 | await videoWatchPage.playAndPauseVideo(true, await isMobileDevice()) | ||
76 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) | 93 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) |
77 | }) | 94 | }) |
78 | 95 | ||
@@ -81,7 +98,7 @@ describe('Videos workflow', () => { | |||
81 | 98 | ||
82 | await videoWatchPage.goOnAssociatedEmbed() | 99 | await videoWatchPage.goOnAssociatedEmbed() |
83 | 100 | ||
84 | await videoWatchPage.playAndPauseVideo(false, isMobileDevice) | 101 | await videoWatchPage.playAndPauseVideo(false, await isMobileDevice()) |
85 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) | 102 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) |
86 | 103 | ||
87 | await browser.waitForAngularEnabled(true) | 104 | await browser.waitForAngularEnabled(true) |
@@ -92,9 +109,93 @@ describe('Videos workflow', () => { | |||
92 | 109 | ||
93 | await videoWatchPage.goOnP2PMediaLoaderEmbed() | 110 | await videoWatchPage.goOnP2PMediaLoaderEmbed() |
94 | 111 | ||
95 | await videoWatchPage.playAndPauseVideo(false, isMobileDevice) | 112 | await videoWatchPage.playAndPauseVideo(false, await isMobileDevice()) |
96 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) | 113 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) |
97 | 114 | ||
98 | await browser.waitForAngularEnabled(true) | 115 | await browser.waitForAngularEnabled(true) |
99 | }) | 116 | }) |
117 | |||
118 | it('Should update the video', async () => { | ||
119 | if (await skipIfUploadNotSupported()) return | ||
120 | |||
121 | await browser.get(videoWatchUrl) | ||
122 | |||
123 | await videoWatchPage.clickOnUpdate() | ||
124 | |||
125 | await videoUpdatePage.updateName('my new name') | ||
126 | |||
127 | await videoUpdatePage.validUpdate() | ||
128 | |||
129 | const name = await videoWatchPage.getVideoName() | ||
130 | expect(name).toEqual('my new name') | ||
131 | }) | ||
132 | |||
133 | it('Should add the video in my playlist', async () => { | ||
134 | if (await skipIfUploadNotSupported()) return | ||
135 | |||
136 | await videoWatchPage.clickOnSave() | ||
137 | await videoWatchPage.saveToWatchLater() | ||
138 | |||
139 | await videoUploadPage.navigateTo() | ||
140 | |||
141 | await videoUploadPage.uploadVideo() | ||
142 | await videoUploadPage.validSecondUploadStep('second video') | ||
143 | |||
144 | await videoWatchPage.clickOnSave() | ||
145 | await videoWatchPage.saveToWatchLater() | ||
146 | }) | ||
147 | |||
148 | it('Should have the watch later playlist in my account', async () => { | ||
149 | if (await skipIfUploadNotSupported()) return | ||
150 | |||
151 | await myAccountPage.navigateToMyPlaylists() | ||
152 | |||
153 | const name = await myAccountPage.getLastUpdatedPlaylistName() | ||
154 | expect(name).toEqual('Watch later') | ||
155 | |||
156 | const videosNumberText = await myAccountPage.getLastUpdatedPlaylistVideosText() | ||
157 | expect(videosNumberText).toEqual('2 videos') | ||
158 | |||
159 | await myAccountPage.clickOnLastUpdatedPlaylist() | ||
160 | |||
161 | const count = await myAccountPage.countTotalPlaylistElements() | ||
162 | expect(count).toEqual(2) | ||
163 | }) | ||
164 | |||
165 | it('Should watch the playlist', async () => { | ||
166 | if (await skipIfUploadNotSupported()) return | ||
167 | |||
168 | await myAccountPage.playPlaylist() | ||
169 | |||
170 | await videoWatchPage.waitUntilVideoName('second video', 20000 * 1000) | ||
171 | }) | ||
172 | |||
173 | it('Should have the video in my account', async () => { | ||
174 | if (await skipIfUploadNotSupported()) return | ||
175 | |||
176 | await myAccountPage.navigateToMyVideos() | ||
177 | |||
178 | const lastVideoName = await myAccountPage.getLastVideoName() | ||
179 | expect(lastVideoName).toEqual('second video') | ||
180 | }) | ||
181 | |||
182 | it('Should delete the last video', async () => { | ||
183 | if (await skipIfUploadNotSupported()) return | ||
184 | |||
185 | await myAccountPage.removeLastVideo() | ||
186 | await myAccountPage.validRemove() | ||
187 | |||
188 | const count = await myAccountPage.countVideos() | ||
189 | expect(count).toEqual(1) | ||
190 | }) | ||
191 | |||
192 | it('Should delete the first video', async () => { | ||
193 | if (await skipIfUploadNotSupported()) return | ||
194 | |||
195 | await myAccountPage.removeLastVideo() | ||
196 | await myAccountPage.validRemove() | ||
197 | |||
198 | const count = await myAccountPage.countVideos() | ||
199 | expect(count).toEqual(0) | ||
200 | }) | ||
100 | }) | 201 | }) |