|
|
@ -1,9 +1,13 @@ |
|
|
import { LocalizationPipe } from '@abp/ng.core'; |
|
|
import { LocalizationPipe } from '@abp/ng.core'; |
|
|
|
|
|
import { RouterTestingModule } from '@angular/router/testing'; |
|
|
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; |
|
|
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; |
|
|
import { Store } from '@ngxs/store'; |
|
|
import { Store } from '@ngxs/store'; |
|
|
import { timer } from 'rxjs'; |
|
|
import { fromEvent, Subject, timer } from 'rxjs'; |
|
|
|
|
|
import { delay, reduce, take } from 'rxjs/operators'; |
|
|
import { ButtonComponent, ConfirmationComponent, ModalComponent } from '../components'; |
|
|
import { ButtonComponent, ConfirmationComponent, ModalComponent } from '../components'; |
|
|
import { RouterTestingModule } from '@angular/router/testing'; |
|
|
import { ModalContainerComponent } from '../components/modal/modal-container.component'; |
|
|
|
|
|
import { Confirmation } from '../models'; |
|
|
|
|
|
import { ConfirmationService, ModalService } from '../services'; |
|
|
|
|
|
|
|
|
describe('ModalComponent', () => { |
|
|
describe('ModalComponent', () => { |
|
|
let spectator: SpectatorHost< |
|
|
let spectator: SpectatorHost< |
|
|
@ -12,16 +16,34 @@ describe('ModalComponent', () => { |
|
|
>; |
|
|
>; |
|
|
let appearFn; |
|
|
let appearFn; |
|
|
let disappearFn; |
|
|
let disappearFn; |
|
|
|
|
|
let mockConfirmation$: Subject<Confirmation.Status>; |
|
|
const createHost = createHostFactory({ |
|
|
const createHost = createHostFactory({ |
|
|
component: ModalComponent, |
|
|
component: ModalComponent, |
|
|
imports: [RouterTestingModule], |
|
|
imports: [RouterTestingModule], |
|
|
declarations: [ConfirmationComponent, LocalizationPipe, ButtonComponent], |
|
|
declarations: [ |
|
|
|
|
|
ConfirmationComponent, |
|
|
|
|
|
LocalizationPipe, |
|
|
|
|
|
ButtonComponent, |
|
|
|
|
|
ModalContainerComponent, |
|
|
|
|
|
], |
|
|
|
|
|
entryComponents: [ModalContainerComponent], |
|
|
|
|
|
providers: [ |
|
|
|
|
|
{ |
|
|
|
|
|
provide: ConfirmationService, |
|
|
|
|
|
useValue: { |
|
|
|
|
|
warn() { |
|
|
|
|
|
mockConfirmation$ = new Subject(); |
|
|
|
|
|
return mockConfirmation$; |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
], |
|
|
mocks: [Store], |
|
|
mocks: [Store], |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
beforeEach(async () => { |
|
|
appearFn = jest.fn(() => null); |
|
|
appearFn = jest.fn(); |
|
|
disappearFn = jest.fn(() => null); |
|
|
disappearFn = jest.fn(); |
|
|
|
|
|
|
|
|
spectator = createHost( |
|
|
spectator = createHost( |
|
|
`<abp-modal [(visible)]="visible" [busy]="busy" [centered]="true" (appear)="appearFn()" (disappear)="disappearFn()" size="sm" modalClass="test">
|
|
|
`<abp-modal [(visible)]="visible" [busy]="busy" [centered]="true" (appear)="appearFn()" (disappear)="disappearFn()" size="sm" modalClass="test">
|
|
|
@ -30,102 +52,170 @@ describe('ModalComponent', () => { |
|
|
</ng-template> |
|
|
</ng-template> |
|
|
|
|
|
|
|
|
<ng-template #abpBody> |
|
|
<ng-template #abpBody> |
|
|
<div class="body"> |
|
|
<div class="body"><input [class.ng-dirty]="ngDirty"></div> |
|
|
<input [class.ng-dirty]="ngDirty"> |
|
|
|
|
|
</div> |
|
|
|
|
|
</ng-template> |
|
|
</ng-template> |
|
|
|
|
|
|
|
|
<ng-template #abpFooter> |
|
|
<ng-template #abpFooter> |
|
|
<div class="footer"> |
|
|
<div class="footer"> |
|
|
<button id="abp-close" #abpClose></button> |
|
|
<button id="abp-close" #abpClose></button> |
|
|
|
|
|
<abp-button>Submit</abp-button> |
|
|
</div> |
|
|
</div> |
|
|
</ng-template> |
|
|
</ng-template> |
|
|
<abp-button>Submit</abp-button> |
|
|
|
|
|
<abp-confirmation></abp-confirmation> |
|
|
|
|
|
</abp-modal> |
|
|
</abp-modal> |
|
|
`,
|
|
|
`,
|
|
|
{ |
|
|
{ |
|
|
hostProps: { |
|
|
hostProps: { |
|
|
visible: true, |
|
|
visible: true, |
|
|
busy: false, |
|
|
busy: false, |
|
|
ngDirty: true, |
|
|
ngDirty: false, |
|
|
appearFn, |
|
|
appearFn, |
|
|
disappearFn, |
|
|
disappearFn, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
|
|
const modalService = spectator.get(ModalService); |
|
|
|
|
|
modalService.clearModal(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should be created', () => { |
|
|
it('should project its template to abp-modal-container', () => { |
|
|
expect(spectator.query('div.modal')).toBeTruthy(); |
|
|
const modal = selectModal(); |
|
|
expect(spectator.query('div.modal-backdrop')).toBeTruthy(); |
|
|
expect(modal).toBeTruthy(); |
|
|
expect(spectator.query('div#abp-modal-dialog')).toBeTruthy(); |
|
|
expect(modal.querySelector('div.modal-backdrop')).toBeTruthy(); |
|
|
|
|
|
expect(modal.querySelector('div#abp-modal-dialog')).toBeTruthy(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should works right the inputs', () => { |
|
|
it('should reflect its input properties to the template', () => { |
|
|
expect(spectator.query('div.test')).toBeTruthy(); |
|
|
const modal = selectModal('.test'); |
|
|
expect(spectator.query('div.modal-sm')).toBeTruthy(); |
|
|
expect(modal).toBeTruthy(); |
|
|
expect(spectator.query('div.modal-dialog-centered')).toBeTruthy(); |
|
|
expect(modal.querySelector('div.modal-sm')).toBeTruthy(); |
|
|
|
|
|
expect(modal.querySelector('div.modal-dialog-centered')).toBeTruthy(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should emit the appear output', () => { |
|
|
it('should emit the appear output when made visible', () => { |
|
|
expect(appearFn).toHaveBeenCalled(); |
|
|
expect(appearFn).toHaveBeenCalled(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should emit the disappear output', () => { |
|
|
it('should emit the disappear output when made invisible', async () => { |
|
|
spectator.hostComponent.visible = false; |
|
|
spectator.hostComponent.visible = false; |
|
|
spectator.detectChanges(); |
|
|
spectator.detectChanges(); |
|
|
expect(disappearFn).toHaveBeenCalled(); |
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
expect(disappearFn).toHaveBeenCalledTimes(1); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should open the confirmation popup and works correct', done => { |
|
|
xit('should close with the abpClose', async () => { |
|
|
setTimeout(() => { |
|
|
await wait0ms(); |
|
|
spectator.click('#abp-modal-close-button'); |
|
|
|
|
|
expect(disappearFn).not.toHaveBeenCalled(); |
|
|
spectator.dispatchMouseEvent(spectator.component.abpClose, 'click'); |
|
|
|
|
|
|
|
|
expect(spectator.query('div.confirmation')).toBeTruthy(); |
|
|
await wait0ms(); |
|
|
spectator.click('button#cancel'); |
|
|
|
|
|
expect(spectator.query('div.modal')).toBeTruthy(); |
|
|
expect(disappearFn).toHaveBeenCalledTimes(1); |
|
|
|
|
|
|
|
|
spectator.click('#abp-modal-close-button'); |
|
|
|
|
|
spectator.click('button#confirm'); |
|
|
|
|
|
expect(spectator.query('div.modal')).toBeFalsy(); |
|
|
|
|
|
expect(disappearFn).toHaveBeenCalled(); |
|
|
|
|
|
done(); |
|
|
|
|
|
}, 100); |
|
|
|
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should close with the abpClose', done => { |
|
|
it('should open the confirmation popup and works correct', async () => { |
|
|
spectator.hostComponent.ngDirty = false; |
|
|
const confirmationService = spectator.get(ConfirmationService); |
|
|
|
|
|
const warnSpy = jest.spyOn(confirmationService, 'warn'); |
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
spectator.hostComponent.ngDirty = true; |
|
|
spectator.detectChanges(); |
|
|
spectator.detectChanges(); |
|
|
setTimeout(() => { |
|
|
|
|
|
spectator.click('#abp-close'); |
|
|
expect(selectModal()).toBeTruthy(); |
|
|
expect(disappearFn).toHaveBeenCalled(); |
|
|
spectator.component.close(); // 1st try
|
|
|
done(); |
|
|
|
|
|
}, 10); |
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
spectator.component.close(); // 2nd try
|
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
expect(selectModal()).toBeTruthy(); |
|
|
|
|
|
expect(warnSpy).toHaveBeenCalledTimes(1); |
|
|
|
|
|
warnSpy.mockClear(); |
|
|
|
|
|
|
|
|
|
|
|
mockConfirmation$.next(Confirmation.Status.reject); |
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
expect(selectModal()).toBeTruthy(); |
|
|
|
|
|
spectator.component.close(); |
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
expect(selectModal()).toBeTruthy(); |
|
|
|
|
|
expect(warnSpy).toHaveBeenCalledTimes(1); |
|
|
|
|
|
warnSpy.mockClear(); |
|
|
|
|
|
|
|
|
|
|
|
mockConfirmation$.next(Confirmation.Status.confirm); |
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
expect(selectModal()).toBeNull(); |
|
|
|
|
|
expect(disappearFn).toHaveBeenCalledTimes(1); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should close with esc key', done => { |
|
|
it('should close with esc key', async () => { |
|
|
spectator.hostComponent.ngDirty = false; |
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
spectator.dispatchKeyboardEvent(document.body, 'keyup', 'Escape'); |
|
|
|
|
|
|
|
|
|
|
|
await wait300ms(); |
|
|
|
|
|
|
|
|
|
|
|
expect(spectator.component.visible).toBe(false); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should not close when busy is true', async () => { |
|
|
|
|
|
spectator.hostComponent.busy = true; |
|
|
spectator.detectChanges(); |
|
|
spectator.detectChanges(); |
|
|
timer(0).subscribe(() => { |
|
|
|
|
|
spectator.dispatchKeyboardEvent(document.body, 'keyup', 'Escape'); |
|
|
spectator.component.close(); |
|
|
}); |
|
|
|
|
|
timer(300).subscribe(() => { |
|
|
await wait0ms(); |
|
|
expect(spectator.component.visible).toBe(false); |
|
|
|
|
|
done(); |
|
|
expect(disappearFn).not.toHaveBeenCalled(); |
|
|
}); |
|
|
|
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should not close when busy is true', done => { |
|
|
it('should not let window unload when form is dirty', async done => { |
|
|
setTimeout(() => { |
|
|
fromEvent(window, 'beforeunload') |
|
|
spectator.hostComponent.busy = true; |
|
|
.pipe( |
|
|
spectator.hostComponent.ngDirty = false; |
|
|
take(2), |
|
|
spectator.detectChanges(); |
|
|
delay(0), |
|
|
spectator.click('#abp-modal-close-button'); |
|
|
reduce<Event[]>((acc, v) => acc.concat(v), []), |
|
|
expect(disappearFn).not.toHaveBeenCalled(); |
|
|
) |
|
|
expect(spectator.component.abpSubmit.loading).toBe(true); |
|
|
.subscribe(([event1, event2]) => { |
|
|
done(); |
|
|
expect(event1.returnValue).toBe(true); |
|
|
}, 0); |
|
|
expect(event2.returnValue).toBe(false); |
|
|
|
|
|
done(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
spectator.hostComponent.ngDirty = true; |
|
|
|
|
|
spectator.detectChanges(); |
|
|
|
|
|
spectator.dispatchFakeEvent(window, 'beforeunload'); |
|
|
|
|
|
|
|
|
|
|
|
await wait0ms(); |
|
|
|
|
|
|
|
|
|
|
|
spectator.hostComponent.ngDirty = false; |
|
|
|
|
|
spectator.detectChanges(); |
|
|
|
|
|
spectator.dispatchFakeEvent(window, 'beforeunload'); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
function selectModal(modalSelector = ''): Element { |
|
|
|
|
|
return document.querySelector(`abp-modal-container div.modal${modalSelector}`); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function wait0ms() { |
|
|
|
|
|
await timer(0).toPromise(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function wait300ms() { |
|
|
|
|
|
await timer(300).toPromise(); |
|
|
|
|
|
} |
|
|
|