From 44d4ee4fcb7cf8beebac73f85693c09919b91e66 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 23 Jan 2020 14:23:19 +0100 Subject: [PATCH] Fix e2e tests --- client/e2e/fixtures/video.mp4 | Bin 619469 -> 619477 bytes client/e2e/src/po/app.po.ts | 21 +++++++++ client/e2e/src/videos.e2e-spec.ts | 9 ++++ client/src/app/shared/rxjs/zone.ts | 40 ++++++++++++++++++ .../user-subscription.service.ts | 14 +++--- .../video-playlist/video-playlist.service.ts | 14 +++--- scripts/e2e/local.sh | 2 +- shared/extra-utils/videos/videos.ts | 14 +++--- 8 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 client/e2e/src/po/app.po.ts create mode 100644 client/src/app/shared/rxjs/zone.ts diff --git a/client/e2e/fixtures/video.mp4 b/client/e2e/fixtures/video.mp4 index f9c9e2dd6e80f3e4678c7f142a92cd63f236a58b..c9ba8fd04bd2c56cd726710859af83d84dc65fde 100644 GIT binary patch delta 3165 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 delta 3157 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 WAQ_~BbdU+MK`zK|N=S~@Kk+{-k|AgS 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 @@ +import { browser, by, element } from 'protractor' + +export class AppPage { + + async closeWelcomeModal () { + const firstHandle = await browser.getWindowHandle() + + if (await element(by.css('.configure-instance-button')).isPresent() === false) return + + await element(by.css('.configure-instance-button')).click() + + await browser.switchTo().window(firstHandle) + + await browser.refresh() + + await element(by.css('.form-group-checkbox')).click() + await element(by.css('.action-button-cancel')).click() + + await browser.switchTo().window(firstHandle) + } +} 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' import { browser } from 'protractor' import { VideoUpdatePage } from './po/video-update.po' import { MyAccountPage } from './po/my-account' +import { AppPage } from './po/app.po' async function skipIfUploadNotSupported () { if (await isMobileDevice() || await isSafari()) { @@ -30,6 +31,7 @@ describe('Videos workflow', () => { let videoUpdatePage: VideoUpdatePage let myAccountPage: MyAccountPage let loginPage: LoginPage + let appPage: AppPage let videoName = new Date().getTime() + ' video' const video2Name = new Date().getTime() + ' second video' @@ -42,6 +44,7 @@ describe('Videos workflow', () => { videoUpdatePage = new VideoUpdatePage() myAccountPage = new MyAccountPage() loginPage = new LoginPage() + appPage = new AppPage() if (await isMobileDevice()) { console.log('Mobile device detected.') @@ -61,6 +64,12 @@ describe('Videos workflow', () => { return loginPage.loginAsRootUser() }) + it('Should close the welcome modal', async () => { + if (await skipIfUploadNotSupported()) return + + await appPage.closeWelcomeModal() + }) + it('Should upload a video', async () => { if (await skipIfUploadNotSupported()) return 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 @@ +import { SchedulerLike, Subscription } from 'rxjs' +import { NgZone } from '@angular/core' + +class LeaveZoneScheduler implements SchedulerLike { + constructor (private zone: NgZone, private scheduler: SchedulerLike) { + } + + schedule (...args: any[]): Subscription { + return this.zone.runOutsideAngular(() => + this.scheduler.schedule.apply(this.scheduler, args) + ) + } + + now (): number { + return this.scheduler.now() + } +} + +class EnterZoneScheduler implements SchedulerLike { + constructor (private zone: NgZone, private scheduler: SchedulerLike) { + } + + schedule (...args: any[]): Subscription { + return this.zone.run(() => + this.scheduler.schedule.apply(this.scheduler, args) + ) + } + + now (): number { + return this.scheduler.now() + } +} + +export function leaveZone (zone: NgZone, scheduler: SchedulerLike): SchedulerLike { + return new LeaveZoneScheduler(zone, scheduler) +} + +export function enterZone (zone: NgZone, scheduler: SchedulerLike): SchedulerLike { + return new EnterZoneScheduler(zone, scheduler) +} 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 @@ -import { bufferTime, catchError, filter, map, tap, share, switchMap } from 'rxjs/operators' -import { Observable, ReplaySubject, Subject, of, merge } from 'rxjs' +import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators' +import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs' import { HttpClient, HttpParams } from '@angular/common/http' -import { Injectable } from '@angular/core' +import { Injectable, NgZone } from '@angular/core' import { ResultList } from '../../../../../shared' import { environment } from '../../../environments/environment' import { RestExtractor, RestService } from '../rest' @@ -11,6 +11,7 @@ import { VideoChannel as VideoChannelServer } from '../../../../../shared/models import { ComponentPaginationLight } from '@app/shared/rest/component-pagination.model' import { uniq } from 'lodash-es' import * as debug from 'debug' +import { enterZone, leaveZone } from '@app/shared/rxjs/zone' const logger = debug('peertube:subscriptions:UserSubscriptionService') @@ -32,13 +33,16 @@ export class UserSubscriptionService { constructor ( private authHttp: HttpClient, private restExtractor: RestExtractor, - private restService: RestService + private restService: RestService, + private ngZone: NgZone ) { this.existsObservable = merge( this.existsSubject.pipe( - bufferTime(500), + // We leave Angular zone so Protractor does not get stuck + bufferTime(500, leaveZone(this.ngZone, asyncScheduler)), filter(uris => uris.length !== 0), map(uris => uniq(uris)), + observeOn(enterZone(this.ngZone, asyncScheduler)), switchMap(uris => this.doSubscriptionsExist(uris)), share() ), 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 @@ -import { bufferTime, catchError, filter, map, share, switchMap, tap } from 'rxjs/operators' -import { Injectable } from '@angular/core' -import { merge, Observable, of, ReplaySubject, Subject } from 'rxjs' +import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators' +import { Injectable, NgZone } from '@angular/core' +import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs' import { RestExtractor } from '../rest/rest-extractor.service' import { HttpClient, HttpParams } from '@angular/common/http' import { ResultList, VideoPlaylistElementCreate, VideoPlaylistElementUpdate } from '../../../../../shared' @@ -23,6 +23,7 @@ import { VideoPlaylistElement as ServerVideoPlaylistElement } from '@shared/mode import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' import { uniq } from 'lodash-es' import * as debug from 'debug' +import { enterZone, leaveZone } from '@app/shared/rxjs/zone' const logger = debug('peertube:playlists:VideoPlaylistService') @@ -49,13 +50,16 @@ export class VideoPlaylistService { private authHttp: HttpClient, private serverService: ServerService, private restExtractor: RestExtractor, - private restService: RestService + private restService: RestService, + private ngZone: NgZone ) { this.videoExistsInPlaylistObservable = merge( this.videoExistsInPlaylistNotifier.pipe( - bufferTime(500), + // We leave Angular zone so Protractor does not get stuck + bufferTime(500, leaveZone(this.ngZone, asyncScheduler)), filter(videoIds => videoIds.length !== 0), map(videoIds => uniq(videoIds)), + observeOn(enterZone(this.ngZone, asyncScheduler)), switchMap(videoIds => this.doVideosExistInPlaylist(videoIds)), share() ), 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 npm run concurrently -- -k -s first \ "cd client && npm run ng -- e2e --port 3333 -c local" \ - "NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"log\": { \"level\": \"warning\" } }' npm start" + "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 ( 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') .to.be.above(minSize).and.below(maxSize) - { - await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) - } - - if (attributes.previewfile) { - await testImage(url, attributes.previewfile, videoDetails.previewPath) - } - const torrent = await webtorrentAdd(file.magnetUri, true) expect(torrent.files).to.be.an('array') expect(torrent.files.length).to.equal(1) expect(torrent.files[0].path).to.exist.and.to.not.equal('') } + + await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) + + if (attributes.previewfile) { + await testImage(url, attributes.previewfile, videoDetails.previewPath) + } } async function videoUUIDToId (url: string, id: number | string) {