From 606b7fa01c681efbf48bebca5a72cac70a2286b9 Mon Sep 17 00:00:00 2001 From: PiotrP Date: Tue, 30 Oct 2018 07:36:16 -0700 Subject: [PATCH] Unit tests for confirmation dialog component added --- ...project-confirmation-dialog.component.html | 8 +- ...ject-confirmation-dialog.component.spec.ts | 131 ++++++++++++++++++ .../import-project-dialog.component.spec.ts | 43 +++++- .../import-project-dialog.component.ts | 69 +++++++-- 4 files changed, 231 insertions(+), 20 deletions(-) diff --git a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html b/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html index 74d874d7..10cac4c9 100644 --- a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html +++ b/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.html @@ -1,9 +1,7 @@ - - {{confirmationMessage}} - +{{confirmationMessage}}
- - + +
diff --git a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts b/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts index e69de29b..b51e949d 100644 --- a/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts +++ b/src/app/components/projects/import-project-dialog/import-project-confirmation-dialog/import-project-confirmation-dialog.component.spec.ts @@ -0,0 +1,131 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatDialogModule, MatDialog } from "@angular/material"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { Component, NgModule } from '@angular/core'; +import { Project } from '../../../../models/project'; +import { ImportProjectConfirmationDialogComponent } from './import-project-confirmation-dialog.component'; +import { OverlayContainer } from '@angular/cdk/overlay'; + +describe('ImportProjectConfirmationDialogComponent', () => { + let dialog: MatDialog; + let overlayContainerElement: HTMLElement; + + let noop: ComponentFixture; + let existingProject: Project = { + auto_close: false, + auto_open: false, + auto_start: false, + filename: "blank", + name: "blank", + path: "", + project_id: "", + scene_height: 100, + scene_width: 100, + status: "", + readonly: false, + show_interface_labels: false, + show_layers: false, + show_grid: false, + snap_to_grid: false, + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ DialogTestModule ], + providers: [ + { provide: OverlayContainer, useFactory: () => { + overlayContainerElement = document.createElement('div'); + return { getContainerElement: () => overlayContainerElement }; + }} + ] + }); + + dialog = TestBed.get(MatDialog); + + noop = TestBed.createComponent(NoopComponent); + }); + + it('should show correct message if project is open', () => { + existingProject.status = "opened"; + const config = { + data: { + 'existingProject' : existingProject + } + }; + + dialog.open(ImportProjectConfirmationDialogComponent, config); + noop.detectChanges(); + + const message = overlayContainerElement.querySelector('span'); + expect(message.textContent).toBe("Project blank is open. You can not overwrite it."); + }); + + it('should show correct message if project is closed', () => { + existingProject.status = "closed"; + const config = { + data: { + 'existingProject' : existingProject + } + }; + + dialog.open(ImportProjectConfirmationDialogComponent, config); + noop.detectChanges(); + + const message = overlayContainerElement.querySelector('span'); + expect(message.textContent).toBe("Project blank already exist, overwrite it?"); + }); + + it('should return false after closing when project is open', () => { + existingProject.status = "opened"; + const config = { + data: { + 'existingProject' : existingProject + } + }; + + let dialogRef = dialog.open(ImportProjectConfirmationDialogComponent, config); + noop.detectChanges(); + const button = overlayContainerElement.querySelector('button'); + spyOn(dialogRef.componentInstance.dialogRef, 'close'); + button.click(); + + expect(dialogRef.componentInstance.dialogRef.close).toHaveBeenCalledWith(false); + }); + + it('should return true after choosing overriding', () => { + existingProject.status = "closed"; + const config = { + data: { + 'existingProject' : existingProject + } + }; + + let dialogRef = dialog.open(ImportProjectConfirmationDialogComponent, config); + noop.detectChanges(); + const button: HTMLButtonElement = overlayContainerElement.querySelector('.confirmButton'); + spyOn(dialogRef.componentInstance.dialogRef, 'close'); + button.click(); + + expect(dialogRef.componentInstance.dialogRef.close).toHaveBeenCalledWith(true); + }); +}); + +@Component({ + template: '' +}) +class NoopComponent {} + +const TEST_DIRECTIVES = [ + ImportProjectConfirmationDialogComponent, + NoopComponent +]; + +@NgModule({ + imports: [MatDialogModule, NoopAnimationsModule], + exports: TEST_DIRECTIVES, + declarations: TEST_DIRECTIVES, + entryComponents: [ + ImportProjectConfirmationDialogComponent + ], +}) +class DialogTestModule { } diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts index 7aa20d6a..e89c30fd 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts @@ -4,10 +4,37 @@ import { Server } from "../../../models/server"; import { MatInputModule, MatIconModule, MatSortModule, MatTableModule, MatTooltipModule, MatDialogModule, MatStepperModule, MatFormFieldModule, MatDialogRef, MatDialog, MAT_DIALOG_DATA } from "@angular/material"; import { RouterTestingModule } from "@angular/router/testing"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { FileUploadModule, FileSelectDirective, FileItem, FileUploader } from "ng2-file-upload"; +import { FileUploadModule, FileSelectDirective, FileItem, FileUploader, ParsedResponseHeaders } from "ng2-file-upload"; import { FormsModule, ReactiveFormsModule, FormBuilder, FormControl, Validators } from '@angular/forms'; import { DebugElement } from '@angular/core'; import { By } from '@angular/platform-browser'; +import { ProjectService } from '../../../services/project.service'; +import { of } from 'rxjs/internal/observable/of'; +import { Project } from '../../../models/project'; + +export class MockedProjectService { + public projects: Project[] = [{ + auto_close: false, + auto_open: false, + auto_start: false, + filename: "blank", + name: "blank", + path: "", + project_id: "", + scene_height: 100, + scene_width: 100, + status: "opened", + readonly: false, + show_interface_labels: false, + show_layers: false, + show_grid: false, + snap_to_grid: false, + }]; + + list(server: Server) { + return of(this.projects); + } +} describe('ImportProjectDialogComponent', () => { let component: ImportProjectDialogComponent; @@ -36,7 +63,8 @@ describe('ImportProjectDialogComponent', () => { ], providers: [ { provide: MatDialogRef }, - { provide: MAT_DIALOG_DATA } + { provide: MAT_DIALOG_DATA }, + { provide: ProjectService, useClass: MockedProjectService} ], declarations : [ImportProjectDialogComponent] }) @@ -61,6 +89,7 @@ describe('ImportProjectDialogComponent', () => { debugElement = fixture.debugElement.query(By.directive(FileSelectDirective)); fileSelectDirective = debugElement.injector.get(FileSelectDirective) as FileSelectDirective; + component.uploader.onErrorItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => {}; }); it('should be created', () => { @@ -134,6 +163,7 @@ describe('ImportProjectDialogComponent', () => { it('should navigate to next step after clicking import', () => { let fileItem = new FileItem(fileSelectDirective.uploader, new File([],"fileName"),{}); fileSelectDirective.uploader.queue.push(fileItem); + spyOn(component.stepper, "next"); component.onImportClick(); @@ -166,4 +196,13 @@ describe('ImportProjectDialogComponent', () => { expect(fileSelectDirective.uploader.uploadItem).not.toHaveBeenCalled(); expect(component.projectNameForm.valid).toBeFalsy(); }); + + it('should open confirmation dialog if project with the same exists', () => { + component.projectNameForm.controls['projectName'].setValue("blank"); + spyOn(component, "openConfirmationDialog"); + + component.onImportClick(); + + expect(component.openConfirmationDialog).toHaveBeenCalled(); + }); }); diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts index c8f23d58..e2ff62f1 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts @@ -1,9 +1,13 @@ import { Component, OnInit, Inject, ViewChild } from '@angular/core'; -import { MatStepper, MatDialogRef, MAT_DIALOG_DATA } from "@angular/material"; +import { MatStepper, MatDialogRef, MAT_DIALOG_DATA, MatDialog } from "@angular/material"; import { FileUploader, ParsedResponseHeaders, FileItem } from 'ng2-file-upload'; import { Server } from '../../../models/server'; import { v4 as uuid } from 'uuid'; import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; +import { ProjectService } from '../../../services/project.service'; +import { Project } from '../../../models/project'; +import { ImportProjectConfirmationDialogComponent } from './import-project-confirmation-dialog/import-project-confirmation-dialog.component'; +import { ServerResponse } from '../../../models/serverResponse'; export class Validator { static projectNameValidator(projectName) { @@ -34,9 +38,11 @@ export class ImportProjectDialogComponent implements OnInit { @ViewChild('stepper') stepper: MatStepper; constructor( + private dialog: MatDialog, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, - private formBuilder: FormBuilder){ + private formBuilder: FormBuilder, + private projectService: ProjectService){ this.projectNameForm = this.formBuilder.group({ projectName: new FormControl(null, [Validators.required, Validator.projectNameValidator]) }); @@ -45,6 +51,17 @@ export class ImportProjectDialogComponent implements OnInit { ngOnInit(){ this.uploader = new FileUploader({}); this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; }; + + this.uploader.onErrorItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => { + let serverResponse : ServerResponse = JSON.parse(response); + this.resultMessage = "An error occured: " + serverResponse.message; + this.isFinishEnabled = true; + }; + + this.uploader.onCompleteItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => { + this.resultMessage = "Project was imported succesfully!"; + this.isFinishEnabled = true; + }; } get form() { @@ -60,6 +77,22 @@ export class ImportProjectDialogComponent implements OnInit { if (this.projectNameForm.invalid){ this.submitted = true; } else { + this.projectService + .list(this.server) + .subscribe((projects: Project[]) => { + const projectName = this.projectNameForm.controls['projectName'].value; + let existingProject = projects.find(project => project.name === projectName); + + if (existingProject){ + this.openConfirmationDialog(existingProject); + } else { + this.importProject(); + } + }); + } + } + + importProject(){ const url = this.prepareUploadPath(); this.uploader.queue.forEach(elem => elem.url = url); @@ -67,18 +100,27 @@ export class ImportProjectDialogComponent implements OnInit { this.stepper.next(); const itemToUpload = this.uploader.queue[0]; - this.uploader.uploadItem(itemToUpload); + this.uploader.uploadItem(itemToUpload); + } - this.uploader.onErrorItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => { - this.resultMessage = response; - this.isFinishEnabled = true; - }; - - this.uploader.onSuccessItem = (item: FileItem, response: string, status: number, headers: ParsedResponseHeaders) => { - this.resultMessage = "Project was imported succesfully!"; - this.isFinishEnabled = true; - }; - } + openConfirmationDialog(existingProject: Project) { + const dialogRef = this.dialog.open(ImportProjectConfirmationDialogComponent, { + width: '300px', + height: '150px', + data: { + 'existingProject': existingProject + } + }); + + dialogRef.afterClosed().subscribe((answer: boolean) => { + if (answer) { + this.projectService.close(this.server, existingProject.project_id).subscribe(() => { + this.projectService.delete(this.server, existingProject.project_id).subscribe(() => { + this.importProject(); + }); + }); + } + }); } onNoClick() : void{ @@ -101,3 +143,4 @@ export class ImportProjectDialogComponent implements OnInit { return `http://${this.server.ip}:${this.server.port}/v2/projects/${uuid()}/import?name=${projectName}`; } } + \ No newline at end of file