mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-5378] ADF Previewer: Image Rotate + Save (#6958)
* updates including cropperJS * update on rotation + unit tests * small fix * hide toolbar on save * remove unused & duplicate method * added readonly & prettier code * include readOnly mode to hide/show media management actions * updated dependencies * fix emit spy * ADF-5378: Fix failing e2es * Fix comments for unit tests * ADF-5378: Removed obsolete buttons from e2e Co-authored-by: kristian <kristian.dimitrov@alfresco.com> Co-authored-by: adomi <ardit.domi@alfresco.com>
This commit is contained in:
@@ -16,14 +16,13 @@
|
||||
*/
|
||||
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { ContentService } from '../../services/content.service';
|
||||
|
||||
import { ImgViewerComponent } from './img-viewer.component';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import { setupTestBed, CoreTestingModule } from '../../testing';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
describe('Test Img viewer component ', () => {
|
||||
|
||||
@@ -52,218 +51,24 @@ describe('Test Img viewer component ', () => {
|
||||
|
||||
element = fixture.nativeElement;
|
||||
component = fixture.componentInstance;
|
||||
component.urlFile = 'fake-url-file.png';
|
||||
component.urlFile = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.ngAfterViewInit();
|
||||
component.ngAfterViewInit();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display current scale as percent string', () => {
|
||||
component.scaleX = 0.5;
|
||||
component.scale = 0.5;
|
||||
expect(component.currentScaleText).toBe('50%');
|
||||
|
||||
component.scaleX = 1.0;
|
||||
component.scale = 1.0;
|
||||
expect(component.currentScaleText).toBe('100%');
|
||||
});
|
||||
|
||||
it('should generate transform settings', () => {
|
||||
component.scaleX = 1.0;
|
||||
component.scaleY = 2.0;
|
||||
component.rotate = 10;
|
||||
component.offsetX = 20;
|
||||
component.offsetY = 30;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const elementCss: any = element.querySelector('#adf-image-container');
|
||||
|
||||
expect(elementCss.style.transform).toBe('scale(1, 2) rotate(10deg) translate(20px, 30px)');
|
||||
});
|
||||
|
||||
it('should start drag on mouse down', () => {
|
||||
expect(component.isDragged).toBeFalsy();
|
||||
|
||||
component.onMouseDown(<any> new CustomEvent('mousedown'));
|
||||
|
||||
expect(component.isDragged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should prevent default behaviour on mouse down', () => {
|
||||
const event = jasmine.createSpyObj('mousedown', ['preventDefault']);
|
||||
|
||||
component.onMouseDown(event);
|
||||
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prevent default mouse move during drag', () => {
|
||||
const event = jasmine.createSpyObj('mousemove', ['preventDefault']);
|
||||
|
||||
component.onMouseDown(<any> new CustomEvent('mousedown'));
|
||||
component.onMouseMove(event);
|
||||
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not prevent default mouse move if not dragged', () => {
|
||||
const event = jasmine.createSpyObj('mousemove', ['preventDefault']);
|
||||
|
||||
component.onMouseMove(event);
|
||||
|
||||
expect(component.isDragged).toBeFalsy();
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prevent default mouse up during drag end', () => {
|
||||
const event = jasmine.createSpyObj('mouseup', ['preventDefault']);
|
||||
|
||||
component.onMouseDown(<any> new CustomEvent('mousedown'));
|
||||
expect(component.isDragged).toBeTruthy();
|
||||
|
||||
component.onMouseUp(event);
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop drag on mouse up', () => {
|
||||
component.onMouseDown(<any> new CustomEvent('mousedown'));
|
||||
expect(component.isDragged).toBeTruthy();
|
||||
|
||||
component.onMouseUp(<any> new CustomEvent('mouseup'));
|
||||
expect(component.isDragged).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should stop drag on mouse leave', () => {
|
||||
component.onMouseDown(<any> new CustomEvent('mousedown'));
|
||||
expect(component.isDragged).toBeTruthy();
|
||||
|
||||
component.onMouseLeave(<any> new CustomEvent('mouseleave'));
|
||||
expect(component.isDragged).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should stop drag on mouse out', () => {
|
||||
component.onMouseDown(<any> new CustomEvent('mousedown'));
|
||||
expect(component.isDragged).toBeTruthy();
|
||||
|
||||
component.onMouseOut(<any> new CustomEvent('mouseout'));
|
||||
expect(component.isDragged).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update offset on keydown ArrowDown event', () => {
|
||||
const arrowDownEvent = new KeyboardEvent('keydown', { key : 'ArrowDown' });
|
||||
component.onKeyDown(arrowDownEvent);
|
||||
expect(component.offsetY).toBe(4);
|
||||
|
||||
component.onKeyDown(arrowDownEvent);
|
||||
expect(component.offsetY).toBe(8);
|
||||
});
|
||||
|
||||
it('should update offset on keydown ArrowUp event', () => {
|
||||
const arrowUpEvent = new KeyboardEvent('keydown', { key : 'ArrowUp' });
|
||||
component.onKeyDown(arrowUpEvent);
|
||||
expect(component.offsetY).toBe(-4);
|
||||
|
||||
component.onKeyDown(arrowUpEvent);
|
||||
expect(component.offsetY).toBe(-8);
|
||||
});
|
||||
|
||||
it('should update offset on keydown ArrowLeft event', () => {
|
||||
const arrowLeftEvent = new KeyboardEvent('keydown', { key : 'ArrowLeft' });
|
||||
component.onKeyDown(arrowLeftEvent);
|
||||
expect(component.offsetX).toBe(-4);
|
||||
|
||||
component.onKeyDown(arrowLeftEvent);
|
||||
expect(component.offsetX).toBe(-8);
|
||||
});
|
||||
|
||||
it('should update offset on keydown ArrowRight event', () => {
|
||||
const arrowRightEvent = new KeyboardEvent('keydown', { key : 'ArrowRight' });
|
||||
component.onKeyDown(arrowRightEvent);
|
||||
expect(component.offsetX).toBe(4);
|
||||
|
||||
component.onKeyDown(arrowRightEvent);
|
||||
expect(component.offsetX).toBe(8);
|
||||
});
|
||||
|
||||
it('should update scales on zoom in', () => {
|
||||
component.scaleX = 1.0;
|
||||
|
||||
component.zoomIn();
|
||||
expect(component.scaleX).toBe(1.2);
|
||||
expect(component.scaleY).toBe(1.2);
|
||||
|
||||
component.zoomIn();
|
||||
expect(component.scaleX).toBe(1.4);
|
||||
expect(component.scaleY).toBe(1.4);
|
||||
});
|
||||
|
||||
it('should update scales on zoom out', () => {
|
||||
component.scaleX = 1.0;
|
||||
|
||||
component.zoomOut();
|
||||
expect(component.scaleX).toBe(0.8);
|
||||
expect(component.scaleY).toBe(0.8);
|
||||
|
||||
component.zoomOut();
|
||||
expect(component.scaleX).toBe(0.6);
|
||||
expect(component.scaleY).toBe(0.6);
|
||||
});
|
||||
|
||||
it('should not zoom out past 20%', () => {
|
||||
component.scaleX = 0.4;
|
||||
|
||||
component.zoomOut();
|
||||
component.zoomOut();
|
||||
component.zoomOut();
|
||||
|
||||
expect(component.scaleX).toBe(0.2);
|
||||
});
|
||||
|
||||
it('should update angle by 90 degrees on rotate left', () => {
|
||||
component.rotate = 0;
|
||||
|
||||
component.rotateLeft();
|
||||
expect(component.rotate).toBe(-90);
|
||||
|
||||
component.rotateLeft();
|
||||
expect(component.rotate).toBe(-180);
|
||||
});
|
||||
|
||||
it('should reset to 0 degrees for full rotate left round', () => {
|
||||
component.rotate = -270;
|
||||
|
||||
component.rotateLeft();
|
||||
expect(component.rotate).toBe(0);
|
||||
});
|
||||
|
||||
it('should update angle by 90 degrees on rotate right', () => {
|
||||
component.rotate = 0;
|
||||
|
||||
component.rotateRight();
|
||||
expect(component.rotate).toBe(90);
|
||||
|
||||
component.rotateRight();
|
||||
expect(component.rotate).toBe(180);
|
||||
});
|
||||
|
||||
it('should reset to 0 degrees for full rotate right round', () => {
|
||||
component.rotate = 270;
|
||||
|
||||
component.rotateRight();
|
||||
expect(component.rotate).toBe(0);
|
||||
});
|
||||
|
||||
it('should reset all image modifications', () => {
|
||||
component.rotate = 10;
|
||||
component.scaleX = 20;
|
||||
component.scaleY = 30;
|
||||
component.offsetX = 40;
|
||||
component.offsetY = 50;
|
||||
|
||||
component.reset();
|
||||
|
||||
expect(component.rotate).toBe(0);
|
||||
expect(component.scaleX).toBe(1.0);
|
||||
expect(component.scaleY).toBe(1.0);
|
||||
expect(component.offsetX).toBe(0);
|
||||
expect(component.offsetY).toBe(0);
|
||||
it('should define cropper after init', () => {
|
||||
fixture.componentInstance.ngAfterViewInit();
|
||||
expect(component.cropper).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -326,8 +131,7 @@ describe('Test Img viewer component ', () => {
|
||||
|
||||
it('should use default zoom if is not present a custom zoom in the app.config', () => {
|
||||
fixture.detectChanges();
|
||||
expect(component.scaleX).toBe(1.0);
|
||||
expect(component.scaleY).toBe(1.0);
|
||||
expect(component.scale).toBe(1.0);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -344,11 +148,178 @@ describe('Test Img viewer component ', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
expect(component.scaleX).toBe(0.70);
|
||||
expect(component.scaleY).toBe(0.70);
|
||||
expect(component.scale).toBe(0.70);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toolbar actions', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ImgViewerComponent);
|
||||
element = fixture.nativeElement;
|
||||
component = fixture.componentInstance;
|
||||
component.blobFile = createFakeBlob();
|
||||
const change = new SimpleChange(null, component.blobFile, true);
|
||||
component.ngOnChanges({ 'blobFile': change });
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should update scales on zoom in', fakeAsync(() => {
|
||||
spyOn(component, 'zoomIn').and.callThrough();
|
||||
spyOn(component.cropper, 'zoom');
|
||||
component.scale = 1.0;
|
||||
tick();
|
||||
|
||||
component.zoomIn();
|
||||
expect(component.scale).toBe(1.2);
|
||||
expect(component.cropper.zoom).toHaveBeenCalledWith(0.2);
|
||||
|
||||
component.zoomIn();
|
||||
expect(component.scale).toBe(1.4);
|
||||
expect(component.cropper.zoom).toHaveBeenCalledWith(0.2);
|
||||
}));
|
||||
|
||||
it('should update scales on zoom out', fakeAsync(() => {
|
||||
spyOn(component, 'zoomOut').and.callThrough();
|
||||
spyOn(component.cropper, 'zoom');
|
||||
component.scale = 1.0;
|
||||
tick();
|
||||
|
||||
component.zoomOut();
|
||||
expect(component.scale).toBe(0.8);
|
||||
expect(component.cropper.zoom).toHaveBeenCalledWith(-0.2);
|
||||
|
||||
component.zoomOut();
|
||||
expect(component.scale).toBe(0.6);
|
||||
expect(component.cropper.zoom).toHaveBeenCalledWith(-0.2);
|
||||
}));
|
||||
|
||||
it('should not zoom out past 20%', fakeAsync(() => {
|
||||
component.scale = 0.2;
|
||||
tick();
|
||||
|
||||
component.zoomOut();
|
||||
component.zoomOut();
|
||||
component.zoomOut();
|
||||
|
||||
expect(component.scale).toBe(0.2);
|
||||
}));
|
||||
|
||||
it('should show rotate button if not in read only mode', () => {
|
||||
component.readOnly = false;
|
||||
fixture.detectChanges();
|
||||
const rotateButtonElement = element.querySelector('#viewer-rotate-button');
|
||||
|
||||
expect(rotateButtonElement).not.toEqual(null);
|
||||
});
|
||||
|
||||
it('should not show rotate button by default', () => {
|
||||
const rotateButtonElement = element.querySelector('#viewer-rotate-button');
|
||||
expect(rotateButtonElement).toEqual(null);
|
||||
});
|
||||
|
||||
it('should rotate image by -90 degrees on button click', fakeAsync(() => {
|
||||
component.readOnly = false;
|
||||
spyOn(component, 'rotateImage').and.callThrough();
|
||||
spyOn(component.cropper, 'rotate');
|
||||
fixture.detectChanges();
|
||||
const rotateButtonElement = fixture.debugElement.query(By.css('#viewer-rotate-button'));
|
||||
rotateButtonElement.triggerEventHandler('click', null);
|
||||
tick();
|
||||
|
||||
expect(component.rotateImage).toHaveBeenCalled();
|
||||
expect(component.cropper.rotate).toHaveBeenCalledWith(-90);
|
||||
}));
|
||||
|
||||
it('should display the second toolbar when in editing and not in read only mode', fakeAsync(() => {
|
||||
component.readOnly = false;
|
||||
component.isEditing = true;
|
||||
fixture.detectChanges();
|
||||
const secondaryToolbar = document.querySelector('.adf-secondary-toolbar');
|
||||
|
||||
expect(secondaryToolbar).not.toEqual(null);
|
||||
}));
|
||||
|
||||
it('should not display the second toolbar when in read only mode', () => {
|
||||
component.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
const secondaryToolbar = document.querySelector('.adf-secondary-toolbar');
|
||||
|
||||
expect(secondaryToolbar).toEqual(null);
|
||||
});
|
||||
|
||||
it('should not display the second toolbar when not in editing', () => {
|
||||
component.readOnly = true;
|
||||
component.isEditing = false;
|
||||
fixture.detectChanges();
|
||||
const secondaryToolbar = document.querySelector('.adf-secondary-toolbar');
|
||||
|
||||
expect(secondaryToolbar).toEqual(null);
|
||||
});
|
||||
|
||||
it('should display second toolbar in rotate mode', fakeAsync(() => {
|
||||
component.readOnly = false;
|
||||
component.isEditing = true;
|
||||
|
||||
fixture.detectChanges();
|
||||
const secondaryToolbar = document.querySelector('.adf-secondary-toolbar');
|
||||
const resetButton = document.querySelector('#viewer-cancel-button');
|
||||
const saveButton = document.querySelector('#viewer-save-button');
|
||||
|
||||
expect(secondaryToolbar).not.toEqual(null);
|
||||
expect(resetButton).not.toEqual(null);
|
||||
expect(saveButton).not.toEqual(null);
|
||||
}));
|
||||
|
||||
it('should not be in editing mode by default', () => {
|
||||
component.readOnly = false;
|
||||
|
||||
expect(component.isEditing).toEqual(false);
|
||||
});
|
||||
|
||||
it('should get in editing mode when the image gets rotated', () => {
|
||||
component.readOnly = false;
|
||||
component.rotateImage();
|
||||
|
||||
expect(component.isEditing).toEqual(true);
|
||||
});
|
||||
|
||||
it('should reset the scale and hide second toolbar', fakeAsync(() => {
|
||||
component.readOnly = false;
|
||||
component.isEditing = true;
|
||||
|
||||
spyOn(component, 'reset').and.callThrough();
|
||||
spyOn(component.cropper, 'reset');
|
||||
spyOn(component.cropper, 'zoomTo');
|
||||
|
||||
fixture.detectChanges();
|
||||
const cancelButtonElement = fixture.debugElement.query(By.css('#viewer-cancel-button'));
|
||||
cancelButtonElement.triggerEventHandler('click', null);
|
||||
tick();
|
||||
|
||||
expect(component.reset).toHaveBeenCalled();
|
||||
expect(component.scale).toEqual(1.0);
|
||||
expect(component.isEditing).toEqual(false);
|
||||
expect(component.cropper.reset).toHaveBeenCalled();
|
||||
expect(component.cropper.zoomTo).toHaveBeenCalledWith(component.scale);
|
||||
}));
|
||||
|
||||
it('should save when clicked on toolbar button', fakeAsync(() => {
|
||||
component.readOnly = false;
|
||||
component.isEditing = true;
|
||||
|
||||
spyOn(component, 'save');
|
||||
fixture.detectChanges();
|
||||
const saveButtonElement = fixture.debugElement.query(By.css('#viewer-save-button'));
|
||||
saveButtonElement.triggerEventHandler('click', null);
|
||||
tick();
|
||||
|
||||
expect(component.save).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
Reference in New Issue
Block a user