]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | import { Component, NgModule, NO_ERRORS_SCHEMA, TemplateRef, ViewChild } from '@angular/core'; |
11fdf7f2 TL |
2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; |
3 | import { ReactiveFormsModule } from '@angular/forms'; | |
4 | import { RouterTestingModule } from '@angular/router/testing'; | |
5 | ||
9f95a23c | 6 | import { BsModalRef, BsModalService, ModalModule } from 'ngx-bootstrap/modal'; |
11fdf7f2 | 7 | |
9f95a23c TL |
8 | import { By } from '@angular/platform-browser'; |
9 | import { | |
10 | configureTestBed, | |
11 | FixtureHelper, | |
12 | i18nProviders, | |
13 | modalServiceShow | |
14 | } from '../../../../testing/unit-test-helper'; | |
11fdf7f2 TL |
15 | import { BackButtonComponent } from '../back-button/back-button.component'; |
16 | import { ModalComponent } from '../modal/modal.component'; | |
17 | import { SubmitButtonComponent } from '../submit-button/submit-button.component'; | |
18 | import { ConfirmationModalComponent } from './confirmation-modal.component'; | |
19 | ||
9f95a23c TL |
20 | @NgModule({ |
21 | entryComponents: [ConfirmationModalComponent] | |
22 | }) | |
23 | export class MockModule {} | |
24 | ||
25 | @Component({ | |
26 | template: ` | |
27 | <ng-template #fillTpl> | |
28 | Template based description. | |
29 | </ng-template> | |
30 | ` | |
31 | }) | |
32 | class 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 |
70 | describe('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 | }); |