diff options
-rw-r--r-- | client/e2e/fixtures/video.mp4 | bin | 619469 -> 619477 bytes | |||
-rw-r--r-- | client/e2e/src/po/app.po.ts | 21 | ||||
-rw-r--r-- | client/e2e/src/videos.e2e-spec.ts | 9 | ||||
-rw-r--r-- | client/src/app/shared/rxjs/zone.ts | 40 | ||||
-rw-r--r-- | client/src/app/shared/user-subscription/user-subscription.service.ts | 14 | ||||
-rw-r--r-- | client/src/app/shared/video-playlist/video-playlist.service.ts | 14 | ||||
-rwxr-xr-x | scripts/e2e/local.sh | 2 | ||||
-rw-r--r-- | shared/extra-utils/videos/videos.ts | 14 |
8 files changed, 95 insertions, 19 deletions
diff --git a/client/e2e/fixtures/video.mp4 b/client/e2e/fixtures/video.mp4 index f9c9e2dd6..c9ba8fd04 100644 --- a/client/e2e/fixtures/video.mp4 +++ b/client/e2e/fixtures/video.mp4 | |||
Binary files differ | |||
diff --git a/client/e2e/src/po/app.po.ts b/client/e2e/src/po/app.po.ts new file mode 100644 index 000000000..a636e825f --- /dev/null +++ b/client/e2e/src/po/app.po.ts | |||
@@ -0,0 +1,21 @@ | |||
1 | import { browser, by, element } from 'protractor' | ||
2 | |||
3 | export class AppPage { | ||
4 | |||
5 | async closeWelcomeModal () { | ||
6 | const firstHandle = await browser.getWindowHandle() | ||
7 | |||
8 | if (await element(by.css('.configure-instance-button')).isPresent() === false) return | ||
9 | |||
10 | await element(by.css('.configure-instance-button')).click() | ||
11 | |||
12 | await browser.switchTo().window(firstHandle) | ||
13 | |||
14 | await browser.refresh() | ||
15 | |||
16 | await element(by.css('.form-group-checkbox')).click() | ||
17 | await element(by.css('.action-button-cancel')).click() | ||
18 | |||
19 | await browser.switchTo().window(firstHandle) | ||
20 | } | ||
21 | } | ||
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts index 27706a506..075add531 100644 --- a/client/e2e/src/videos.e2e-spec.ts +++ b/client/e2e/src/videos.e2e-spec.ts | |||
@@ -4,6 +4,7 @@ import { LoginPage } from './po/login.po' | |||
4 | import { browser } from 'protractor' | 4 | import { browser } from 'protractor' |
5 | import { VideoUpdatePage } from './po/video-update.po' | 5 | import { VideoUpdatePage } from './po/video-update.po' |
6 | import { MyAccountPage } from './po/my-account' | 6 | import { MyAccountPage } from './po/my-account' |
7 | import { AppPage } from './po/app.po' | ||
7 | 8 | ||
8 | async function skipIfUploadNotSupported () { | 9 | async function skipIfUploadNotSupported () { |
9 | if (await isMobileDevice() || await isSafari()) { | 10 | if (await isMobileDevice() || await isSafari()) { |
@@ -30,6 +31,7 @@ describe('Videos workflow', () => { | |||
30 | let videoUpdatePage: VideoUpdatePage | 31 | let videoUpdatePage: VideoUpdatePage |
31 | let myAccountPage: MyAccountPage | 32 | let myAccountPage: MyAccountPage |
32 | let loginPage: LoginPage | 33 | let loginPage: LoginPage |
34 | let appPage: AppPage | ||
33 | 35 | ||
34 | let videoName = new Date().getTime() + ' video' | 36 | let videoName = new Date().getTime() + ' video' |
35 | const video2Name = new Date().getTime() + ' second video' | 37 | const video2Name = new Date().getTime() + ' second video' |
@@ -42,6 +44,7 @@ describe('Videos workflow', () => { | |||
42 | videoUpdatePage = new VideoUpdatePage() | 44 | videoUpdatePage = new VideoUpdatePage() |
43 | myAccountPage = new MyAccountPage() | 45 | myAccountPage = new MyAccountPage() |
44 | loginPage = new LoginPage() | 46 | loginPage = new LoginPage() |
47 | appPage = new AppPage() | ||
45 | 48 | ||
46 | if (await isMobileDevice()) { | 49 | if (await isMobileDevice()) { |
47 | console.log('Mobile device detected.') | 50 | console.log('Mobile device detected.') |
@@ -61,6 +64,12 @@ describe('Videos workflow', () => { | |||
61 | return loginPage.loginAsRootUser() | 64 | return loginPage.loginAsRootUser() |
62 | }) | 65 | }) |
63 | 66 | ||
67 | it('Should close the welcome modal', async () => { | ||
68 | if (await skipIfUploadNotSupported()) return | ||
69 | |||
70 | await appPage.closeWelcomeModal() | ||
71 | }) | ||
72 | |||
64 | it('Should upload a video', async () => { | 73 | it('Should upload a video', async () => { |
65 | if (await skipIfUploadNotSupported()) return | 74 | if (await skipIfUploadNotSupported()) return |
66 | 75 | ||
diff --git a/client/src/app/shared/rxjs/zone.ts b/client/src/app/shared/rxjs/zone.ts new file mode 100644 index 000000000..74eed7032 --- /dev/null +++ b/client/src/app/shared/rxjs/zone.ts | |||
@@ -0,0 +1,40 @@ | |||
1 | import { SchedulerLike, Subscription } from 'rxjs' | ||
2 | import { NgZone } from '@angular/core' | ||
3 | |||
4 | class LeaveZoneScheduler implements SchedulerLike { | ||
5 | constructor (private zone: NgZone, private scheduler: SchedulerLike) { | ||
6 | } | ||
7 | |||
8 | schedule (...args: any[]): Subscription { | ||
9 | return this.zone.runOutsideAngular(() => | ||
10 | this.scheduler.schedule.apply(this.scheduler, args) | ||
11 | ) | ||
12 | } | ||
13 | |||
14 | now (): number { | ||
15 | return this.scheduler.now() | ||
16 | } | ||
17 | } | ||
18 | |||
19 | class EnterZoneScheduler implements SchedulerLike { | ||
20 | constructor (private zone: NgZone, private scheduler: SchedulerLike) { | ||
21 | } | ||
22 | |||
23 | schedule (...args: any[]): Subscription { | ||
24 | return this.zone.run(() => | ||
25 | this.scheduler.schedule.apply(this.scheduler, args) | ||
26 | ) | ||
27 | } | ||
28 | |||
29 | now (): number { | ||
30 | return this.scheduler.now() | ||
31 | } | ||
32 | } | ||
33 | |||
34 | export function leaveZone (zone: NgZone, scheduler: SchedulerLike): SchedulerLike { | ||
35 | return new LeaveZoneScheduler(zone, scheduler) | ||
36 | } | ||
37 | |||
38 | export function enterZone (zone: NgZone, scheduler: SchedulerLike): SchedulerLike { | ||
39 | return new EnterZoneScheduler(zone, scheduler) | ||
40 | } | ||
diff --git a/client/src/app/shared/user-subscription/user-subscription.service.ts b/client/src/app/shared/user-subscription/user-subscription.service.ts index bfb5848bc..9af9ba23e 100644 --- a/client/src/app/shared/user-subscription/user-subscription.service.ts +++ b/client/src/app/shared/user-subscription/user-subscription.service.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { bufferTime, catchError, filter, map, tap, share, switchMap } from 'rxjs/operators' | 1 | import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators' |
2 | import { Observable, ReplaySubject, Subject, of, merge } from 'rxjs' | 2 | import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs' |
3 | import { HttpClient, HttpParams } from '@angular/common/http' | 3 | import { HttpClient, HttpParams } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 4 | import { Injectable, NgZone } from '@angular/core' |
5 | import { ResultList } from '../../../../../shared' | 5 | import { ResultList } from '../../../../../shared' |
6 | import { environment } from '../../../environments/environment' | 6 | import { environment } from '../../../environments/environment' |
7 | import { RestExtractor, RestService } from '../rest' | 7 | import { RestExtractor, RestService } from '../rest' |
@@ -11,6 +11,7 @@ import { VideoChannel as VideoChannelServer } from '../../../../../shared/models | |||
11 | import { ComponentPaginationLight } from '@app/shared/rest/component-pagination.model' | 11 | import { ComponentPaginationLight } from '@app/shared/rest/component-pagination.model' |
12 | import { uniq } from 'lodash-es' | 12 | import { uniq } from 'lodash-es' |
13 | import * as debug from 'debug' | 13 | import * as debug from 'debug' |
14 | import { enterZone, leaveZone } from '@app/shared/rxjs/zone' | ||
14 | 15 | ||
15 | const logger = debug('peertube:subscriptions:UserSubscriptionService') | 16 | const logger = debug('peertube:subscriptions:UserSubscriptionService') |
16 | 17 | ||
@@ -32,13 +33,16 @@ export class UserSubscriptionService { | |||
32 | constructor ( | 33 | constructor ( |
33 | private authHttp: HttpClient, | 34 | private authHttp: HttpClient, |
34 | private restExtractor: RestExtractor, | 35 | private restExtractor: RestExtractor, |
35 | private restService: RestService | 36 | private restService: RestService, |
37 | private ngZone: NgZone | ||
36 | ) { | 38 | ) { |
37 | this.existsObservable = merge( | 39 | this.existsObservable = merge( |
38 | this.existsSubject.pipe( | 40 | this.existsSubject.pipe( |
39 | bufferTime(500), | 41 | // We leave Angular zone so Protractor does not get stuck |
42 | bufferTime(500, leaveZone(this.ngZone, asyncScheduler)), | ||
40 | filter(uris => uris.length !== 0), | 43 | filter(uris => uris.length !== 0), |
41 | map(uris => uniq(uris)), | 44 | map(uris => uniq(uris)), |
45 | observeOn(enterZone(this.ngZone, asyncScheduler)), | ||
42 | switchMap(uris => this.doSubscriptionsExist(uris)), | 46 | switchMap(uris => this.doSubscriptionsExist(uris)), |
43 | share() | 47 | share() |
44 | ), | 48 | ), |
diff --git a/client/src/app/shared/video-playlist/video-playlist.service.ts b/client/src/app/shared/video-playlist/video-playlist.service.ts index fc5eb5337..bae6f9e04 100644 --- a/client/src/app/shared/video-playlist/video-playlist.service.ts +++ b/client/src/app/shared/video-playlist/video-playlist.service.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { bufferTime, catchError, filter, map, share, switchMap, tap } from 'rxjs/operators' | 1 | import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators' |
2 | import { Injectable } from '@angular/core' | 2 | import { Injectable, NgZone } from '@angular/core' |
3 | import { merge, Observable, of, ReplaySubject, Subject } from 'rxjs' | 3 | import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs' |
4 | import { RestExtractor } from '../rest/rest-extractor.service' | 4 | import { RestExtractor } from '../rest/rest-extractor.service' |
5 | import { HttpClient, HttpParams } from '@angular/common/http' | 5 | import { HttpClient, HttpParams } from '@angular/common/http' |
6 | import { ResultList, VideoPlaylistElementCreate, VideoPlaylistElementUpdate } from '../../../../../shared' | 6 | import { ResultList, VideoPlaylistElementCreate, VideoPlaylistElementUpdate } from '../../../../../shared' |
@@ -23,6 +23,7 @@ import { VideoPlaylistElement as ServerVideoPlaylistElement } from '@shared/mode | |||
23 | import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' | 23 | import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' |
24 | import { uniq } from 'lodash-es' | 24 | import { uniq } from 'lodash-es' |
25 | import * as debug from 'debug' | 25 | import * as debug from 'debug' |
26 | import { enterZone, leaveZone } from '@app/shared/rxjs/zone' | ||
26 | 27 | ||
27 | const logger = debug('peertube:playlists:VideoPlaylistService') | 28 | const logger = debug('peertube:playlists:VideoPlaylistService') |
28 | 29 | ||
@@ -49,13 +50,16 @@ export class VideoPlaylistService { | |||
49 | private authHttp: HttpClient, | 50 | private authHttp: HttpClient, |
50 | private serverService: ServerService, | 51 | private serverService: ServerService, |
51 | private restExtractor: RestExtractor, | 52 | private restExtractor: RestExtractor, |
52 | private restService: RestService | 53 | private restService: RestService, |
54 | private ngZone: NgZone | ||
53 | ) { | 55 | ) { |
54 | this.videoExistsInPlaylistObservable = merge( | 56 | this.videoExistsInPlaylistObservable = merge( |
55 | this.videoExistsInPlaylistNotifier.pipe( | 57 | this.videoExistsInPlaylistNotifier.pipe( |
56 | bufferTime(500), | 58 | // We leave Angular zone so Protractor does not get stuck |
59 | bufferTime(500, leaveZone(this.ngZone, asyncScheduler)), | ||
57 | filter(videoIds => videoIds.length !== 0), | 60 | filter(videoIds => videoIds.length !== 0), |
58 | map(videoIds => uniq(videoIds)), | 61 | map(videoIds => uniq(videoIds)), |
62 | observeOn(enterZone(this.ngZone, asyncScheduler)), | ||
59 | switchMap(videoIds => this.doVideosExistInPlaylist(videoIds)), | 63 | switchMap(videoIds => this.doVideosExistInPlaylist(videoIds)), |
60 | share() | 64 | share() |
61 | ), | 65 | ), |
diff --git a/scripts/e2e/local.sh b/scripts/e2e/local.sh index b883ccaa3..e8db2e808 100755 --- a/scripts/e2e/local.sh +++ b/scripts/e2e/local.sh | |||
@@ -11,4 +11,4 @@ npm run clean:server:test | |||
11 | 11 | ||
12 | npm run concurrently -- -k -s first \ | 12 | npm run concurrently -- -k -s first \ |
13 | "cd client && npm run ng -- e2e --port 3333 -c local" \ | 13 | "cd client && npm run ng -- e2e --port 3333 -c local" \ |
14 | "NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"log\": { \"level\": \"warning\" } }' npm start" | 14 | "NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"log\": { \"level\": \"warning\" } }' node dist/server" |
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 9dec12703..d1ac48292 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts | |||
@@ -587,19 +587,17 @@ async function completeVideoCheck ( | |||
587 | 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') | 587 | 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') |
588 | .to.be.above(minSize).and.below(maxSize) | 588 | .to.be.above(minSize).and.below(maxSize) |
589 | 589 | ||
590 | { | ||
591 | await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) | ||
592 | } | ||
593 | |||
594 | if (attributes.previewfile) { | ||
595 | await testImage(url, attributes.previewfile, videoDetails.previewPath) | ||
596 | } | ||
597 | |||
598 | const torrent = await webtorrentAdd(file.magnetUri, true) | 590 | const torrent = await webtorrentAdd(file.magnetUri, true) |
599 | expect(torrent.files).to.be.an('array') | 591 | expect(torrent.files).to.be.an('array') |
600 | expect(torrent.files.length).to.equal(1) | 592 | expect(torrent.files.length).to.equal(1) |
601 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | 593 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') |
602 | } | 594 | } |
595 | |||
596 | await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) | ||
597 | |||
598 | if (attributes.previewfile) { | ||
599 | await testImage(url, attributes.previewfile, videoDetails.previewPath) | ||
600 | } | ||
603 | } | 601 | } |
604 | 602 | ||
605 | async function videoUUIDToId (url: string, id: number | string) { | 603 | async function videoUUIDToId (url: string, id: number | string) { |