]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | import { HttpClient, HttpErrorResponse } from '@angular/common/http'; |
2 | import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; | |
3 | import { fakeAsync, TestBed, tick } from '@angular/core/testing'; | |
4 | import { Router } from '@angular/router'; | |
5 | ||
494da23a | 6 | import { ToastrService } from 'ngx-toastr'; |
11fdf7f2 TL |
7 | |
8 | import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper'; | |
9 | import { AppModule } from '../../app.module'; | |
10 | import { CdNotification, CdNotificationConfig } from '../models/cd-notification'; | |
11 | import { ApiInterceptorService } from './api-interceptor.service'; | |
12 | import { NotificationService } from './notification.service'; | |
13 | ||
14 | describe('ApiInterceptorService', () => { | |
15 | let notificationService: NotificationService; | |
16 | let httpTesting: HttpTestingController; | |
17 | let httpClient: HttpClient; | |
18 | let router: Router; | |
19 | const url = 'api/xyz'; | |
20 | ||
21 | const httpError = (error, errorOpts, done = (_resp) => {}) => { | |
22 | httpClient.get(url).subscribe( | |
23 | () => {}, | |
24 | (resp) => { | |
25 | // Error must have been forwarded by the interceptor. | |
26 | expect(resp instanceof HttpErrorResponse).toBeTruthy(); | |
27 | done(resp); | |
28 | } | |
29 | ); | |
30 | httpTesting.expectOne(url).error(error, errorOpts); | |
31 | }; | |
32 | ||
33 | const runRouterTest = (errorOpts, expectedCallParams) => { | |
34 | httpError(new ErrorEvent('abc'), errorOpts); | |
35 | httpTesting.verify(); | |
36 | expect(router.navigate).toHaveBeenCalledWith(...expectedCallParams); | |
37 | }; | |
38 | ||
39 | const runNotificationTest = (error, errorOpts, expectedCallParams) => { | |
40 | httpError(error, errorOpts); | |
41 | httpTesting.verify(); | |
42 | expect(notificationService.show).toHaveBeenCalled(); | |
43 | expect(notificationService.save).toHaveBeenCalledWith(expectedCallParams); | |
44 | }; | |
45 | ||
46 | const createCdNotification = (type, title?, message?, options?, application?) => { | |
47 | return new CdNotification(new CdNotificationConfig(type, title, message, options, application)); | |
48 | }; | |
49 | ||
50 | configureTestBed({ | |
51 | imports: [AppModule, HttpClientTestingModule], | |
52 | providers: [ | |
53 | NotificationService, | |
54 | i18nProviders, | |
55 | { | |
494da23a | 56 | provide: ToastrService, |
11fdf7f2 TL |
57 | useValue: { |
58 | error: () => true | |
59 | } | |
60 | } | |
61 | ] | |
62 | }); | |
63 | ||
64 | beforeEach(() => { | |
65 | const baseTime = new Date('2022-02-22'); | |
66 | spyOn(global, 'Date').and.returnValue(baseTime); | |
67 | ||
68 | httpClient = TestBed.get(HttpClient); | |
69 | httpTesting = TestBed.get(HttpTestingController); | |
70 | ||
71 | notificationService = TestBed.get(NotificationService); | |
72 | spyOn(notificationService, 'show').and.callThrough(); | |
73 | spyOn(notificationService, 'save'); | |
74 | ||
75 | router = TestBed.get(Router); | |
76 | spyOn(router, 'navigate'); | |
77 | }); | |
78 | ||
79 | it('should be created', () => { | |
80 | const service = TestBed.get(ApiInterceptorService); | |
81 | expect(service).toBeTruthy(); | |
82 | }); | |
83 | ||
84 | describe('test different error behaviours', () => { | |
85 | beforeEach(() => { | |
86 | spyOn(window, 'setTimeout').and.callFake((fn) => fn()); | |
87 | }); | |
88 | ||
89 | it('should redirect 401', () => { | |
90 | runRouterTest( | |
91 | { | |
92 | status: 401 | |
93 | }, | |
94 | [['/login']] | |
95 | ); | |
96 | }); | |
97 | ||
98 | it('should redirect 403', () => { | |
99 | runRouterTest( | |
100 | { | |
101 | status: 403 | |
102 | }, | |
103 | [['/403']] | |
104 | ); | |
105 | }); | |
106 | ||
107 | it('should show notification (error string)', () => { | |
108 | runNotificationTest( | |
109 | 'foobar', | |
110 | { | |
111 | status: 500, | |
112 | statusText: 'Foo Bar' | |
113 | }, | |
114 | createCdNotification(0, '500 - Foo Bar', 'foobar') | |
115 | ); | |
116 | }); | |
117 | ||
118 | it('should show notification (error object, triggered from backend)', () => { | |
119 | runNotificationTest( | |
120 | { detail: 'abc' }, | |
121 | { | |
122 | status: 504, | |
123 | statusText: 'AAA bbb CCC' | |
124 | }, | |
125 | createCdNotification(0, '504 - AAA bbb CCC', 'abc') | |
126 | ); | |
127 | }); | |
128 | ||
129 | it('should show notification (error object with unknown keys)', () => { | |
130 | runNotificationTest( | |
131 | { type: 'error' }, | |
132 | { | |
133 | status: 0, | |
134 | statusText: 'Unknown Error', | |
135 | message: 'Http failure response for (unknown url): 0 Unknown Error', | |
136 | name: 'HttpErrorResponse', | |
137 | ok: false, | |
138 | url: null | |
139 | }, | |
140 | createCdNotification( | |
141 | 0, | |
142 | '0 - Unknown Error', | |
143 | 'Http failure response for api/xyz: 0 Unknown Error' | |
144 | ) | |
145 | ); | |
146 | }); | |
147 | ||
148 | it('should show notification (undefined error)', () => { | |
149 | runNotificationTest( | |
150 | undefined, | |
151 | { | |
152 | status: 502 | |
153 | }, | |
154 | createCdNotification(0, '502 - Unknown Error', 'Http failure response for api/xyz: 502 ') | |
155 | ); | |
156 | }); | |
157 | ||
158 | it('should show 400 notification', () => { | |
159 | spyOn(notificationService, 'notifyTask'); | |
160 | httpError({ task: { name: 'mytask', metadata: { component: 'foobar' } } }, { status: 400 }); | |
161 | httpTesting.verify(); | |
162 | expect(notificationService.show).toHaveBeenCalledTimes(0); | |
163 | expect(notificationService.notifyTask).toHaveBeenCalledWith({ | |
164 | exception: { task: { metadata: { component: 'foobar' }, name: 'mytask' } }, | |
165 | metadata: { component: 'foobar' }, | |
166 | name: 'mytask', | |
167 | success: false | |
168 | }); | |
169 | }); | |
170 | }); | |
171 | ||
172 | describe('interceptor error handling', () => { | |
81eedcae TL |
173 | const expectSaveToHaveBeenCalled = (called) => { |
174 | tick(510); | |
175 | if (called) { | |
176 | expect(notificationService.save).toHaveBeenCalled(); | |
177 | } else { | |
178 | expect(notificationService.save).not.toHaveBeenCalled(); | |
179 | } | |
180 | }; | |
181 | ||
11fdf7f2 TL |
182 | it('should show default behaviour', fakeAsync(() => { |
183 | httpError(undefined, { status: 500 }); | |
81eedcae | 184 | expectSaveToHaveBeenCalled(true); |
11fdf7f2 TL |
185 | })); |
186 | ||
187 | it('should prevent the default behaviour with preventDefault', fakeAsync(() => { | |
188 | httpError(undefined, { status: 500 }, (resp) => resp.preventDefault()); | |
81eedcae | 189 | expectSaveToHaveBeenCalled(false); |
11fdf7f2 TL |
190 | })); |
191 | ||
192 | it('should be able to use preventDefault with 400 errors', fakeAsync(() => { | |
193 | httpError( | |
194 | { task: { name: 'someName', metadata: { component: 'someComponent' } } }, | |
195 | { status: 400 }, | |
196 | (resp) => resp.preventDefault() | |
197 | ); | |
81eedcae | 198 | expectSaveToHaveBeenCalled(false); |
11fdf7f2 TL |
199 | })); |
200 | ||
201 | it('should prevent the default behaviour by status code', fakeAsync(() => { | |
202 | httpError(undefined, { status: 500 }, (resp) => resp.ignoreStatusCode(500)); | |
81eedcae | 203 | expectSaveToHaveBeenCalled(false); |
11fdf7f2 TL |
204 | })); |
205 | ||
206 | it('should use different application icon (default Ceph) in error message', fakeAsync(() => { | |
207 | const msg = 'Cannot connect to Alertmanager'; | |
208 | httpError(undefined, { status: 500 }, (resp) => { | |
209 | (resp.application = 'Prometheus'), (resp.message = msg); | |
210 | }); | |
81eedcae | 211 | expectSaveToHaveBeenCalled(true); |
11fdf7f2 TL |
212 | expect(notificationService.save).toHaveBeenCalledWith( |
213 | createCdNotification(0, '500 - Unknown Error', msg, undefined, 'Prometheus') | |
214 | ); | |
215 | })); | |
216 | }); | |
217 | }); |