]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/components/confirmation-modal/confirmation-modal.component.spec.ts
import 15.2.0 Octopus source
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / shared / components / confirmation-modal / confirmation-modal.component.spec.ts
CommitLineData
9f95a23c 1import { Component, NgModule, NO_ERRORS_SCHEMA, TemplateRef, ViewChild } from '@angular/core';
11fdf7f2
TL
2import { ComponentFixture, TestBed } from '@angular/core/testing';
3import { ReactiveFormsModule } from '@angular/forms';
4import { RouterTestingModule } from '@angular/router/testing';
5
9f95a23c 6import { BsModalRef, BsModalService, ModalModule } from 'ngx-bootstrap/modal';
11fdf7f2 7
9f95a23c
TL
8import { By } from '@angular/platform-browser';
9import {
10 configureTestBed,
11 FixtureHelper,
12 i18nProviders,
13 modalServiceShow
14} from '../../../../testing/unit-test-helper';
11fdf7f2
TL
15import { BackButtonComponent } from '../back-button/back-button.component';
16import { ModalComponent } from '../modal/modal.component';
17import { SubmitButtonComponent } from '../submit-button/submit-button.component';
18import { ConfirmationModalComponent } from './confirmation-modal.component';
19
9f95a23c
TL
20@NgModule({
21 entryComponents: [ConfirmationModalComponent]
22})
23export class MockModule {}
24
25@Component({
26 template: `
27 <ng-template #fillTpl>
28 Template based description.
29 </ng-template>
30 `
31})
32class MockComponent {
33 @ViewChild('fillTpl', { static: true })
34 fillTpl: TemplateRef<any>;
35 modalRef: BsModalRef;
36 returnValue: any;
37
38 // Normally private, but public is needed by tests
39 constructor(public modalService: BsModalService) {}
40
41 private openModal(extendBaseState = {}) {
42 this.modalRef = this.modalService.show(ConfirmationModalComponent, {
43 initialState: Object.assign(
44 {
45 titleText: 'Title is a must have',
46 buttonText: 'Action label',
47 bodyTpl: this.fillTpl,
48 description: 'String based description.',
49 onSubmit: () => {
50 this.returnValue = 'The submit action has to hide manually.';
51 this.modalRef.hide();
52 }
53 },
54 extendBaseState
55 )
56 });
57 }
58
59 basicModal() {
60 this.openModal();
61 }
62
63 customCancelModal() {
64 this.openModal({
65 onCancel: () => (this.returnValue = 'If you have todo something besides hiding the modal.')
66 });
67 }
68}
69
11fdf7f2
TL
70describe('ConfirmationModalComponent', () => {
71 let component: ConfirmationModalComponent;
72 let fixture: ComponentFixture<ConfirmationModalComponent>;
9f95a23c
TL
73 let mockComponent: MockComponent;
74 let mockFixture: ComponentFixture<MockComponent>;
75 let modalService: BsModalService;
76 let fh: FixtureHelper;
77
78 /**
79 * The hide method of `BsModalService` doesn't emit events during tests that's why it's mocked.
80 *
81 * The only events of hide are `null`, `'backdrop-click'` and `'esc'` as described here:
82 * https://ngx-universal.herokuapp.com/#/modals#service-events
83 */
84 const hide = (x: string) => modalService.onHide.emit(null || x);
85
86 const expectReturnValue = (v: string) => expect(mockComponent.returnValue).toBe(v);
11fdf7f2
TL
87
88 configureTestBed({
89 declarations: [
90 ConfirmationModalComponent,
91 BackButtonComponent,
9f95a23c
TL
92 MockComponent,
93 ModalComponent,
94 SubmitButtonComponent
11fdf7f2 95 ],
9f95a23c
TL
96 schemas: [NO_ERRORS_SCHEMA],
97 imports: [ModalModule.forRoot(), ReactiveFormsModule, MockModule, RouterTestingModule],
98 providers: [BsModalRef, i18nProviders, SubmitButtonComponent]
11fdf7f2
TL
99 });
100
101 beforeEach(() => {
9f95a23c
TL
102 fh = new FixtureHelper();
103 mockFixture = TestBed.createComponent(MockComponent);
104 mockComponent = mockFixture.componentInstance;
105 mockFixture.detectChanges();
106 modalService = TestBed.get(BsModalService);
107 spyOn(modalService, 'show').and.callFake((_modalComp, config) => {
108 const data = modalServiceShow(ConfirmationModalComponent, config);
109 fixture = data.fixture;
110 component = data.component;
111 spyOn(component.modalRef, 'hide').and.callFake(hide);
112 fh.updateFixture(fixture);
113 return data.ref;
114 });
11fdf7f2
TL
115 });
116
117 it('should create', () => {
9f95a23c 118 mockComponent.basicModal();
11fdf7f2
TL
119 expect(component).toBeTruthy();
120 });
9f95a23c
TL
121
122 describe('Throws errors', () => {
123 const expectError = (config: object, expected: string) => {
124 mockComponent.basicModal();
125 component = Object.assign(component, config);
126 expect(() => component.ngOnInit()).toThrowError(expected);
127 };
128
129 it('has no submit action defined', () => {
130 expectError(
131 {
132 onSubmit: undefined
133 },
134 'No submit action defined'
135 );
136 });
137
138 it('has no title defined', () => {
139 expectError(
140 {
141 titleText: undefined
142 },
143 'No title defined'
144 );
145 });
146
147 it('has no action name defined', () => {
148 expectError(
149 {
150 buttonText: undefined
151 },
152 'No action name defined'
153 );
154 });
155
156 it('has no description defined', () => {
157 expectError(
158 {
159 bodyTpl: undefined,
160 description: undefined
161 },
162 'No description defined'
163 );
164 });
165 });
166
167 describe('basics', () => {
168 beforeEach(() => {
169 mockComponent.basicModal();
170 spyOn(mockComponent.modalRef, 'hide').and.callFake(hide);
171 });
172
173 it('should show the correct title', () => {
174 expect(fh.getText('.modal-title')).toBe('Title is a must have');
175 });
176
177 it('should show the correct action name', () => {
178 expect(fh.getText('.tc_submitButton')).toBe('Action label');
179 });
180
181 it('should use the correct submit action', () => {
182 // In order to ignore the `ElementRef` usage of `SubmitButtonComponent`
183 spyOn(
184 fixture.debugElement.query(By.directive(SubmitButtonComponent)).componentInstance,
185 'focusButton'
186 );
187 fh.clickElement('.tc_submitButton');
188 expect(mockComponent.modalRef.hide).toHaveBeenCalledTimes(1);
189 expect(component.modalRef.hide).toHaveBeenCalledTimes(0);
190 expectReturnValue('The submit action has to hide manually.');
191 });
192
193 it('should use the default cancel action', () => {
194 fh.clickElement('.tc_backButton');
195 expect(mockComponent.modalRef.hide).toHaveBeenCalledTimes(0);
196 expect(component.modalRef.hide).toHaveBeenCalledTimes(1);
197 expectReturnValue(undefined);
198 });
199
200 it('should show the description', () => {
201 expect(fh.getText('.modal-body')).toBe(
202 'Template based description. String based description.'
203 );
204 });
205 });
206
207 describe('custom cancel action', () => {
208 const expectCancelValue = () =>
209 expectReturnValue('If you have todo something besides hiding the modal.');
210
211 beforeEach(() => {
212 mockComponent.customCancelModal();
213 });
214
215 it('should use custom cancel action', () => {
216 fh.clickElement('.tc_backButton');
217 expectCancelValue();
218 });
219
220 it('should use custom cancel action if escape was pressed', () => {
221 hide('esc');
222 expectCancelValue();
223 });
224
225 it('should use custom cancel action if clicked outside the modal', () => {
226 hide('backdrop-click');
227 expectCancelValue();
228 });
229
230 it('should unsubscribe on destroy', () => {
231 hide('backdrop-click');
232 expectCancelValue();
233 const s = 'This value will not be changed.';
234 mockComponent.returnValue = s;
235 component.ngOnDestroy();
236 hide('backdrop-click');
237 expectReturnValue(s);
238 });
239 });
11fdf7f2 240});