more automation

pull/4104/head
tidusjar 4 years ago
parent 77ac5e77cc
commit 3c37a21ab3

@ -42,31 +42,31 @@
<div class="details-button-container"> <div class="details-button-container">
<div class="col-12 media-row"> <div class="col-12 media-row">
<span *ngIf="movie.available"> <span *ngIf="movie.available">
<a *ngIf="movie.plexUrl" href="{{movie.plexUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn plex"> <a id="viewOnPlexButton" *ngIf="movie.plexUrl" href="{{movie.plexUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn plex">
{{'Search.ViewOnPlex' | translate}} {{'Search.ViewOnPlex' | translate}}
<i class="far fa-play-circle fa-2x"></i> <i class="far fa-play-circle fa-2x"></i>
</a> </a>
<a *ngIf="movie.embyUrl" href="{{movie.embyUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn emby"> <a id="viewOnEmbyButton" *ngIf="movie.embyUrl" href="{{movie.embyUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn emby">
{{'Search.ViewOnEmby' | translate}} {{'Search.ViewOnEmby' | translate}}
<i class="far fa-play-circle fa-2x"></i> <i class="far fa-play-circle fa-2x"></i>
</a> </a>
<a *ngIf="movie.jellyfinUrl" href="{{movie.jellyfinUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn jellyfinUrl"> <a id="viewOnJellyfinButton" *ngIf="movie.jellyfinUrl" href="{{movie.jellyfinUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn jellyfinUrl">
{{'Search.ViewOnJellyfin' | translate}} {{'Search.ViewOnJellyfin' | translate}}
<i class="far fa-play-circle fa-2x"></i> <i class="far fa-play-circle fa-2x"></i>
</a> </a>
</span> </span>
<button mat-raised-button class="btn-green btn-spacing" *ngIf="movie.available && !movie.plexUrl && !movie.embyUrl && !movie.jellyfinUrl"> {{ <button mat-raised-button class="btn-green btn-spacing" id="availableBtn" *ngIf="movie.available && !movie.plexUrl && !movie.embyUrl && !movie.jellyfinUrl"> {{
'Common.Available' | translate }}</button> 'Common.Available' | translate }}</button>
<span *ngIf="!movie.available"> <span *ngIf="!movie.available">
<span *ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span> <span *ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span>
<ng-template #requestedBtn> <ng-template #requestedBtn>
<button mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied" class="btn-spacing" color="warn" [disabled]> <button id="requestedBtn" mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied" class="btn-spacing" color="warn" [disabled]>
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
{{ 'Common.Requested' | translate }} {{ 'Common.Requested' | translate }}
</button> </button>
</ng-template> </ng-template>
<ng-template #notRequestedBtn> <ng-template #notRequestedBtn>
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()"> <button id="requestBtn" mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i> <i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i> <i *ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i> <i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i>
@ -75,26 +75,26 @@
</ng-template> </ng-template>
</span> </span>
<span *ngIf="isAdmin && hasRequest"> <span *ngIf="isAdmin && hasRequest">
<button *ngIf="!movie.approved" (click)="approve()" mat-raised-button class="btn-spacing" color="accent"> <button id="approveBtn" *ngIf="!movie.approved" (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }} <i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button> </button>
<button *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing" <button id="markAvailableBtn" *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
color="accent"> color="accent">
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }} <i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button> </button>
<button *ngIf="movieRequest && !movieRequest.denied && !movie.available" mat-raised-button class="btn-spacing" color="warn" (click)="deny()"> <button id="denyBtn" *ngIf="movieRequest && !movieRequest.denied && !movie.available" mat-raised-button class="btn-spacing" color="warn" (click)="deny()">
<i class="fas fa-times"></i> {{'Requests.Deny' | translate }} <i class="fas fa-times"></i> {{'Requests.Deny' | translate }}
</button> </button>
<button *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason" mat-raised-button class="btn-spacing" color="warn"> <button id="deniedButton" *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason" mat-raised-button class="btn-spacing" color="warn">
<i class="fas fa-times"></i> {{'MediaDetails.Denied' | translate }} <i class="fas fa-times"></i> {{'MediaDetails.Denied' | translate }}
</button> </button>
</span> </span>
<button mat-raised-button class="btn-spacing" color="danger" (click)="issue()" *ngIf="issuesEnabled"> <button id="reportIssueBtn" mat-raised-button class="btn-spacing" color="danger" (click)="issue()" *ngIf="issuesEnabled">
<i class="fas fa-exclamation"></i> {{'Requests.ReportIssue' | translate }} <i class="fas fa-exclamation"></i> {{'Requests.ReportIssue' | translate }}
</button> </button>
<button *ngIf="movie.belongsToCollection" [routerLink]="'/discover/collection/' + movie.belongsToCollection.id" mat-raised-button class="btn-spacing"> <button id="viewCollectionBtn" *ngIf="movie.belongsToCollection" [routerLink]="'/discover/collection/' + movie.belongsToCollection.id" mat-raised-button class="btn-spacing">
<i class="fas fa-list"></i> {{'MediaDetails.ViewCollection' | translate}} <i class="fas fa-list"></i> {{'MediaDetails.ViewCollection' | translate}}
</button> </button>
</div> </div>

@ -107,10 +107,8 @@ export class MovieDetailsComponent {
}); });
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe(result => {
this.movieRequest.denied = result; this.movieRequest.denied = result.denied;
if (this.movieRequest.denied) { this.movieRequest.deniedReason = result.reason;
this.movie.approved = false;
}
}); });
} }

@ -53,6 +53,11 @@
{{request.requestedDate | date}} {{request.requestedDate | date}}
</div> </div>
<div *ngIf="request && request.denied">
<span class="label">{{'Requests.DeniedReason' | translate }}: </span>
<span id="deniedReasonInfo">{{request.deniedReason}}</span>
</div>
<div *ngIf="movie.quality"> <div *ngIf="movie.quality">
<span class="label">{{'MediaDetails.Quality' | translate }}:</span> <span class="label">{{'MediaDetails.Quality' | translate }}:</span>

@ -1,10 +1,10 @@
<h1 mat-dialog-title>{{ 'Requests.DenyReason' | translate}}</h1> <h1 mat-dialog-title>{{ 'Requests.DenyReason' | translate}}</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-form-field> <mat-form-field>
<input matInput [(ngModel)]="denyReason"> <input id="denyInput" matInput [(ngModel)]="denyReason">
</mat-form-field> </mat-form-field>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-raised-button (click)="onNoClick()" [mat-dialog-close]="data.denied">Cancel</button> <button mat-raised-button (click)="onNoClick()" [mat-dialog-close]="data.denied">{{ 'Common.Cancel' | translate }}</button>
<button mat-raised-button (click)="deny()" color="danger" [mat-dialog-close]="data.denied" cdkFocusInitial>Deny</button> <button mat-raised-button id="denyButton" (click)="deny()" color="danger" [mat-dialog-close]="data.denied" cdkFocusInitial>{{ 'Requests.Deny' | translate}}</button>
</div> </div>

@ -1,4 +1,4 @@
import { Component, Inject, Output, EventEmitter } from "@angular/core"; import { Component, Inject } from "@angular/core";
import { IDenyDialogData } from "../interfaces/interfaces"; import { IDenyDialogData } from "../interfaces/interfaces";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { RequestService, MessageService } from "../../../../services"; import { RequestService, MessageService } from "../../../../services";
@ -36,8 +36,8 @@ export class DenyDialogComponent {
this.messageService.send(result.errorMessage, "Ok"); this.messageService.send(result.errorMessage, "Ok");
this.data.denied = false; this.data.denied = false;
} }
this.dialogRef.close(); this.dialogRef.close({denied: this.data.denied, reason: this.denyReason});
} }
onNoClick(): void { onNoClick(): void {

@ -147,6 +147,7 @@
"Remove": "Remove", "Remove": "Remove",
"Deny": "Deny", "Deny": "Deny",
"DenyReason": "Deny Reason", "DenyReason": "Deny Reason",
"DeniedReason": "Denied Reason",
"Season": "Season", "Season": "Season",
"GridTitle": "Title", "GridTitle": "Title",
"AirDate": "AirDate", "AirDate": "AirDate",

@ -0,0 +1,91 @@
import { BasePage } from "../../base.page";
class MovieInformationPanel {
get denyReason(): Cypress.Chainable<any> {
return cy.get('#deniedReasonInfo');
}
}
class DenyModal {
get denyReason(): Cypress.Chainable<any> {
return cy.get('#denyInput');
}
get denyButton(): Cypress.Chainable<any> {
return cy.get('#denyButton');
}
}
class MovieDetailsPage extends BasePage {
get title(): Cypress.Chainable<any> {
return cy.get('#mediaTitle');
}
get availableButton(): Cypress.Chainable<any> {
return cy.get('#availableBtn');
}
get requestButton(): Cypress.Chainable<any> {
return cy.get('#requestBtn');
}
get requestedButton(): Cypress.Chainable<any> {
return cy.get('#requestedBtn');
}
get approveButton(): Cypress.Chainable<any> {
return cy.get('#approveBtn');
}
get markAvailableButton(): Cypress.Chainable<any> {
return cy.get('#markAvailableBtn');
}
get denyButton(): Cypress.Chainable<any> {
return cy.get('#denyBtn');
}
get deniedButton(): Cypress.Chainable<any> {
return cy.get('#deniedButton');
}
get reportIssueButton(): Cypress.Chainable<any> {
return cy.get('#reportIssueBtn');
}
get viewCollectionButton(): Cypress.Chainable<any> {
return cy.get('#viewCollectionBtn');
}
get viewOnPlexButton(): Cypress.Chainable<any> {
return cy.get('#viewOnPlexButton');
}
get viewOnEmbyButton(): Cypress.Chainable<any> {
return cy.get('#viewOnEmbyButton');
}
get viewOnJellyfinButton(): Cypress.Chainable<any> {
return cy.get('#viewOnJellyfinButton');
}
denyModal = new DenyModal();
informationPanel = new MovieInformationPanel();
constructor() {
super();
}
visit(options: Cypress.VisitOptions): Cypress.Chainable<Cypress.AUTWindow>;
visit(): Cypress.Chainable<Cypress.AUTWindow>;
visit(id: string): Cypress.Chainable<Cypress.AUTWindow>;
visit(id: string, options: Cypress.VisitOptions): Cypress.Chainable<Cypress.AUTWindow>;
visit(id?: any, options?: any) {
return cy.visit(`/details/movie/` + id, options);
}
}
export const movieDetailsPage = new MovieDetailsPage();

@ -1,10 +1,5 @@
import { BasePage } from "../../base.page"; import { BasePage } from "../../base.page";
class BaseMediaPage extends BasePage {
get title(): Cypress.Chainable<any> {
return cy.get('#mediaTitle');
}
}
class TvRequestPanel { class TvRequestPanel {
seasonTab(seasonNumber: number): Cypress.Chainable<any> { seasonTab(seasonNumber: number): Cypress.Chainable<any> {
@ -61,8 +56,11 @@ class TvDetailsInformationPanel {
} }
} }
class TvDetailsPage extends BaseMediaPage { class TvDetailsPage extends BasePage {
get title(): Cypress.Chainable<any> {
return cy.get('#mediaTitle');
}
get availableButton(): Cypress.Chainable<any> { get availableButton(): Cypress.Chainable<any> {
return cy.get('#availableBtn'); return cy.get('#availableBtn');

@ -5,3 +5,4 @@ export * from './details/tv/tvdetails.page';
export * from './search/search.page'; export * from './search/search.page';
export * from './user-preferences/user-preferences.page'; export * from './user-preferences/user-preferences.page';
export * from './requests/requests.page'; export * from './requests/requests.page';
export * from './details/movies/moviedetails.page';

@ -0,0 +1,149 @@
import { movieDetailsPage as Page } from "@/integration/page-objects";
describe("Movie Details Buttons", () => {
it("Movie Requested by Admin should be auto approved", () => {
cy.login();
Page.visit("587807");
Page.requestButton.click();
cy.verifyNotification("Tom & Jerry (2021) has been successfully added");
Page.requestedButton.should("be.visible");
});
it("Movie Requested by Regular user should be pending", () => {
cy.generateUniqueId().then((id) => {
cy.login();
const roles = [];
roles.push({ value: "RequestMovie", enabled: true });
cy.createUser(id, "a", roles).then(() => {
cy.loginWithCreds(id, "a");
Page.visit("651571");
Page.requestButton.click();
cy.verifyNotification("Breach (2020) has been successfully added");
Page.requestedButton.should("be.visible");
});
});
});
it("Movie Requested by Regular with no movie permission", () => {
cy.generateUniqueId().then((id) => {
cy.login();
const roles = [];
roles.push({ value: "RequestTv", enabled: true });
cy.createUser(id, "a", roles).then(() => {
cy.loginWithCreds(id, "a");
Page.visit("791373");
Page.requestButton.click();
cy.verifyNotification("You do not have permissions to Request a Movie");
Page.requestedButton.should("not.exist");
});
});
});
it("Movie Requested by Regular can be approved by admin", () => {
cy.generateUniqueId().then((id) => {
cy.login();
const roles = [];
roles.push({ value: "RequestMovie", enabled: true });
cy.createUser(id, "a", roles).then(() => {
cy.loginWithCreds(id, "a");
Page.visit("793723");
Page.requestButton.click();
cy.verifyNotification("Sentinelle (2021) has been successfully added");
Page.requestedButton.should("be.visible");
// Login as admin now
cy.removeLogin();
cy.login();
cy.reload();
Page.visit("793723");
Page.approveButton.should("exist");
Page.approveButton.click();
cy.verifyNotification("Successfully Approved");
});
});
});
it("Movie Requested, mark as available", () => {
cy.login();
Page.visit("399566");
Page.requestButton.click();
cy.verifyNotification(
"Godzilla vs. Kong (2021) has been successfully added"
);
cy.reload();
Page.markAvailableButton.should("exist");
Page.markAvailableButton.click();
cy.verifyNotification("Request is now available");
Page.availableButton.should("exist");
});
it("Movie Requested, Deny Movie", () => {
cy.login();
Page.visit("484718");
Page.requestButton.click();
cy.verifyNotification(
"Coming 2 America (2021) has been successfully added"
);
cy.reload();
Page.denyButton.should("exist");
Page.denyButton.click();
Page.denyModal.denyReason.type("Automation Tests");
Page.denyModal.denyButton.click();
Page.deniedButton.should('exist');
cy.verifyNotification("Denied Request");
Page.informationPanel.denyReason.should('have.text', "Automation Tests");
});
it("Movie View Collection should be available", () => {
cy.login();
Page.visit("671");
Page.viewCollectionButton.should('be.visible');
});
it.only("Non requested movie valid buttons", () => {
cy.login();
Page.visit("590706");
Page.viewCollectionButton.should('not.exist');
Page.approveButton.should('not.exist');
Page.denyButton.should('not.exist');
Page.deniedButton.should('not.exist');
Page.markAvailableButton.should('not.exist');
Page.viewOnEmbyButton.should('not.exist');
Page.viewOnJellyfinButton.should('not.exist');
Page.viewOnPlexButton.should('not.exist');
Page.requestedButton.should('not.exist');
Page.reportIssueButton.should('not.exist'); // Issuess not enabled
Page.requestButton.should('exist');
});
});
Loading…
Cancel
Save