|
1 | 1 | import { provideZonelessChangeDetection } from '@angular/core'; |
2 | 2 | import { TestBed } from '@angular/core/testing'; |
3 | | -import { HttpErrorResponse, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http'; |
| 3 | +import { HttpContext, HttpErrorResponse, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http'; |
4 | 4 | import { Observable } from 'rxjs'; |
5 | 5 | import { of, throwError } from 'rxjs'; |
6 | 6 | import { firstValueFrom } from 'rxjs'; |
7 | 7 |
|
8 | | -import { kitAuthInterceptor, provideKitHttp, type KitHttpConfig } from './kit-http.interceptor'; |
| 8 | +import { KIT_AUTH_BOOTSTRAP_REQUEST, kitAuthInterceptor, provideKitHttp, type KitHttpConfig } from './kit-http.interceptor'; |
9 | 9 | import { KitAuthAccessService } from '../auth/auth-access.service'; |
10 | 10 |
|
11 | 11 | // --------------------------------------------------------------------------- |
@@ -175,6 +175,52 @@ describe('kitAuthInterceptor', () => { |
175 | 175 | expect(next).toHaveBeenCalledOnce(); |
176 | 176 | }); |
177 | 177 |
|
| 178 | + it.each(['none', 'local'] as const)( |
| 179 | + 'allows an explicitly marked auth bootstrap request from %s mode through the authenticated pipeline', |
| 180 | + async (mode) => { |
| 181 | + const config = makeConfig({ enforceAuthAccessMode: true }); |
| 182 | + setupInterceptor(config); |
| 183 | + const access = TestBed.inject(KitAuthAccessService); |
| 184 | + if (mode === 'local') access.grantLocal(); |
| 185 | + const request = baseReq.clone({ |
| 186 | + context: new HttpContext().set(KIT_AUTH_BOOTSTRAP_REQUEST, true), |
| 187 | + }); |
| 188 | + const response = new HttpResponse({ status: 200 }); |
| 189 | + const next = vi.fn().mockReturnValue(of(response)); |
| 190 | + |
| 191 | + await expect(firstValueFrom(runInterceptor(request, next))).resolves.toBe(response); |
| 192 | + |
| 193 | + expect(access.mode).toBe(mode); |
| 194 | + expect(config.getAuthHeaders).toHaveBeenCalledWith(request); |
| 195 | + expect(next).toHaveBeenCalledOnce(); |
| 196 | + }, |
| 197 | + ); |
| 198 | + |
| 199 | + it.each(['none', 'local'] as const)( |
| 200 | + 'never turns a failed auth bootstrap request from %s mode into an offline success', |
| 201 | + async (mode) => { |
| 202 | + const fallbackResponse = new HttpResponse({ status: 200, body: 'local' }); |
| 203 | + const config = makeConfig({ |
| 204 | + enforceAuthAccessMode: true, |
| 205 | + offlineFallback: vi.fn().mockReturnValue(of(fallbackResponse)), |
| 206 | + }); |
| 207 | + setupInterceptor(config); |
| 208 | + const access = TestBed.inject(KitAuthAccessService); |
| 209 | + if (mode === 'local') access.grantLocal(); |
| 210 | + const request = new HttpRequest('POST', '/login', null, { |
| 211 | + context: new HttpContext().set(KIT_AUTH_BOOTSTRAP_REQUEST, true), |
| 212 | + }); |
| 213 | + const error = new HttpErrorResponse({ status: 0 }); |
| 214 | + const next = vi.fn().mockReturnValue(throwError(() => error)); |
| 215 | + |
| 216 | + await expect(firstValueFrom(runInterceptor(request, next))).rejects.toBe(error); |
| 217 | + |
| 218 | + expect(access.mode).toBe(mode); |
| 219 | + expect(config.offlineFallback).not.toHaveBeenCalled(); |
| 220 | + expect(config.onNetworkError).toHaveBeenCalledOnce(); |
| 221 | + }, |
| 222 | + ); |
| 223 | + |
178 | 224 | it.each([ |
179 | 225 | [401, 'onUnauthorized'], |
180 | 226 | [403, 'onForbidden'], |
|
0 commit comments