Skip to content

Commit

Permalink
updated autoFocus and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pimenovoleg committed Aug 8, 2018
1 parent c4c16f6 commit e0fcadf
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 59 deletions.
5 changes: 3 additions & 2 deletions src/lib/modal/modal-control.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface IRegisteredMeta {

@Injectable()
export class McModalControlService {

// Track singleton afterAllClose through over the injection tree
get afterAllClose(): Subject<void> {
return this.parentService ? this.parentService.afterAllClose : this.rootAfterAllClose;
Expand All @@ -26,11 +27,11 @@ export class McModalControlService {
private rootOpenModals: McModalRef[] = this.parentService ? null : [];
// @ts-ignore
private rootAfterAllClose: Subject<void> = this.parentService ? null : new Subject<void>();

// @ts-ignore
private rootRegisteredMetaMap: Map<McModalRef, IRegisteredMeta> = this.parentService ? null : new Map();

private get registeredMetaMap(): Map<McModalRef, IRegisteredMeta> { // Registered modal for later usage
// Registered modal for later usage
private get registeredMetaMap(): Map<McModalRef, IRegisteredMeta> {
return this.parentService ? this.parentService.registeredMetaMap : this.rootRegisteredMetaMap;
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/modal/modal.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
</div> <!-- /.mc-confirm-body-wrapper -->
</div>
<div class="mc-confirm-btns">
<button mc-button [color]="mcOkType" *ngIf="mcOkText !== ''" (click)="onClickOkCancel('ok')">
<button mc-button [color]="mcOkType" #autoFocusButtonOk *ngIf="mcOkText !== ''" (click)="onClickOkCancel('ok')">
{{ okText }}
</button>
<button mc-button color="second" *ngIf="mcCancelText!==''" (click)="onClickOkCancel('cancel')">
Expand Down
24 changes: 18 additions & 6 deletions src/lib/modal/modal.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Observable } from 'rxjs';

import { DOCUMENT } from '@angular/common';
import {
AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef,
Expand All @@ -22,15 +20,17 @@ import {
ViewChild,
ViewContainerRef, ViewEncapsulation
} from '@angular/core';

import { ESCAPE } from '@ptsecurity/cdk/keycodes';
import { Overlay, OverlayRef } from '@ptsecurity/cdk/overlay';
import { McMeasureScrollbarService } from '@ptsecurity/mosaic/core';
import { Observable } from 'rxjs';

import { McModalControlService } from './modal-control.service';
import { McModalRef } from './modal-ref.class';
import { IModalButtonOptions, IModalOptions, ModalType, OnClickCallback } from './modal.type';
// tslint:disable-next-line
import ModalUtil from './modal-util';
import { IModalButtonOptions, IModalOptions, ModalType, OnClickCallback } from './modal.type';


// Duration when perform animations (ms)
export const MODAL_ANIMATE_DURATION = 200;
Expand All @@ -42,7 +42,10 @@ type AnimationState = 'enter' | 'leave' | null;
templateUrl: './modal.component.html',
styleUrls: ['./modal.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
encapsulation: ViewEncapsulation.None,
host: {
'(keydown)': 'onKeyDown($event)'
}
})
export class McModalComponent<T = any, R = any> extends McModalRef<T, R>
implements OnInit, OnChanges, AfterViewInit, OnDestroy, IModalOptions {
Expand All @@ -59,7 +62,7 @@ export class McModalComponent<T = any, R = any> extends McModalRef<T, R>
@Input()
get mcVisible() { return this._mcVisible; }
set mcVisible(value) { this._mcVisible = value; }
_mcVisible = false;
_mcVisible = false;

@Output() mcVisibleChange = new EventEmitter<boolean>();

Expand Down Expand Up @@ -273,6 +276,15 @@ export class McModalComponent<T = any, R = any> extends McModalRef<T, R>
return this.mcModalType === type;
}

onKeyDown(event: KeyboardEvent): void {

if (event.keyCode === ESCAPE && this.container && (this.container instanceof OverlayRef)) {

this.close();
event.preventDefault();
}
}

// AoT
onClickCloseBtn() {
if (this.mcVisible) {
Expand Down
149 changes: 99 additions & 50 deletions src/lib/modal/modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,62 +16,22 @@ import { McModalService } from './modal.service';
// tslint:disable:max-line-length
// tslint:disable:no-console
// tslint:disable:no-unnecessary-class
describe('McModal - css-unit.pipe', () => {
let testElement: HTMLDivElement;
let fixture: ComponentFixture<{}>;

beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
declarations: [
CssUnitPipe, TestCssUnitPipeComponent
]
});

TestBed.compileComponents();
}));

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ]
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TestCssUnitPipeComponent);
testElement = fixture.debugElement.query(By.css('div')).nativeElement;
fixture.detectChanges();
});

it('should "width" & "height" to be 100px', () => {
// fixture.detectChanges();
expect(testElement.style.width).toBe('100px');
expect(testElement.style.height).toBe('100px');
});

it('should "top" to be 100pt', () => {
// fixture.detectChanges();
expect(testElement.style.top).toBe('100pt');
});
});

describe('McModal', () => {
let modalService: McModalService;
let overlayContainer: OverlayContainer;
let overlayContainerElement: HTMLElement;

beforeEach(fakeAsync(() => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ McModalModule ],
providers : [ McMeasureScrollbarService ],
declarations: [
ModalByServiceComponent
]
imports: [ ModalTestModule ],
providers: [ McMeasureScrollbarService ]
});

TestBed.compileComponents();
}));

beforeEach(inject([ McModalService, OverlayContainer ], (ms: McModalService, oc: OverlayContainer) => {
beforeEach(inject([ McModalService, OverlayContainer ],
(ms: McModalService, oc: OverlayContainer) => {
modalService = ms;
overlayContainer = oc;
overlayContainerElement = oc.getContainerElement();
Expand All @@ -88,8 +48,7 @@ describe('McModal', () => {
fixture = TestBed.createComponent(ModalByServiceComponent);
});

// wait all openModals tobe closed to clean up the ModalManager as it is globally static
afterEach(fakeAsync(() => {
afterEach(fakeAsync(() => { // wait all openModals tobe closed to clean up the ModalManager as it is globally static
modalService.closeAll();
fixture.detectChanges();
tick(1000);
Expand All @@ -112,6 +71,80 @@ describe('McModal', () => {
expect(modalService.openModals.length).toBe(1);
}));

it('should trigger both afterClose/mcAfterClose and have the correct openModals length', fakeAsync(() => {
const spy = jasmine.createSpy('afterClose spy');
const mcAfterClose = new EventEmitter<void>();
const modalRef = modalService.create({ mcAfterClose });

modalRef.afterClose.subscribe(spy);
mcAfterClose.subscribe(spy);

fixture.detectChanges();
tick(600);
modalRef.close();
fixture.detectChanges();
expect(spy).not.toHaveBeenCalled();

tick(600);
expect(spy).toHaveBeenCalledTimes(2);
expect(modalService.openModals.indexOf(modalRef)).toBe(-1);
expect(modalService.openModals.length).toBe(0);
}));

it('should return/receive with/without result data', fakeAsync(() => {
const spy = jasmine.createSpy('afterClose without result spy');
const modalRef = modalService.success();

modalRef.afterClose.subscribe(spy);
fixture.detectChanges();
tick(600);
modalRef.destroy();
expect(spy).not.toHaveBeenCalled();
tick(600);
expect(spy).toHaveBeenCalledWith(undefined);
}));

it('should return/receive with result data', fakeAsync(() => {
const result = { data: 'Fake Error' };
const spy = jasmine.createSpy('afterClose with result spy');
const modalRef = modalService.delete();

fixture.detectChanges();
tick(600);
modalRef.destroy(result);
modalRef.afterClose.subscribe(spy);
expect(spy).not.toHaveBeenCalled();
tick(600);
expect(spy).toHaveBeenCalledWith(result);
}));

it('should close all opened modals (include non-service modals)', fakeAsync(() => {
const spy = jasmine.createSpy('afterAllClose spy');
const modalMethods = [ 'create', 'delete', 'success' ];
const uniqueId = (name: string) => `__${name}_ID_SUFFIX__`;
const queryOverlayElement = (name: string) => overlayContainerElement.querySelector(`.${uniqueId(name)}`) as HTMLElement;

modalService.afterAllClose.subscribe(spy);

fixture.componentInstance.nonServiceModalVisible = true; // Show non-service modal
modalMethods.forEach((method) => modalService[method]({ mcWrapClassName: uniqueId(method) })); // Service modals

fixture.detectChanges();
tick(600);
// Cover non-service modal for later checking
(modalMethods.concat('NON_SERVICE')).forEach((method) => {
expect(queryOverlayElement(method).style.display).not.toBe('none');
});
expect(modalService.openModals.length).toBe(4);

modalService.closeAll();
fixture.detectChanges();
expect(spy).not.toHaveBeenCalled();
tick(600);
expect(spy).toHaveBeenCalled();
expect(modalService.openModals.length).toBe(0);
}));

it('should modal not be registered twice', fakeAsync(() => {
const modalRef = modalService.create();

Expand All @@ -121,7 +154,7 @@ describe('McModal', () => {
expect(modalService.openModals.length).toBe(1);
}));

it('should trigger mcOnOk/mcOnCancel', () => {
it('should trigger nzOnOk/nzOnCancel', () => {
const spyOk = jasmine.createSpy('ok spy');
const spyCancel = jasmine.createSpy('cancel spy');
const modalRef: McModalRef = modalService.create({
Expand Down Expand Up @@ -154,13 +187,29 @@ class TestCssUnitPipeComponent { }
@Component({
selector: 'mc-modal-by-service',
template: `
<mc-modal [(mcVisible)]="nonServiceModalVisible"></mc-modal>
<mc-modal [(mcVisible)]="nonServiceModalVisible" mcWrapClassName="__NON_SERVICE_ID_SUFFIX__"></mc-modal>
`,
// Testing for service with parent service
providers: [ McModalControlService ]
})
export class ModalByServiceComponent {
class ModalByServiceComponent {
nonServiceModalVisible = false;

// @ts-ignore
constructor(modalControlService: McModalControlService) {}
}


const TEST_DIRECTIVES = [
ModalByServiceComponent
];

@NgModule({
imports: [ McModalModule ],
exports: TEST_DIRECTIVES,
declarations: TEST_DIRECTIVES,
entryComponents: [
ModalByServiceComponent
]
})
class ModalTestModule { }

0 comments on commit e0fcadf

Please sign in to comment.