forked from AmadeusITGroup/otter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ama-sdk): create Mock Intercept angular plugin (AmadeusITGroup#2079
- Loading branch information
Showing
7 changed files
with
170 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import type { Observable } from 'rxjs'; | ||
import type { HttpResponse } from '@angular/common/http'; | ||
import type { ApiClient } from '../../fwk/core/api-client'; | ||
import type { PluginContext } from './plugin'; | ||
import type { RequestOptions } from './request-plugin'; | ||
|
||
/** | ||
* Interface of an async runnable plugin | ||
*/ | ||
export interface PluginObservableRunner<T, V> { | ||
/** Transformation function */ | ||
transform(data: V): Observable<T>; | ||
} | ||
|
||
/** Angular HTTP Call Response type */ | ||
export type AngularCall = Observable<HttpResponse<any>>; | ||
|
||
/** | ||
* Interface of an SDK reply plugin. | ||
* The plugin will be run on the reply of a call | ||
*/ | ||
export interface AngularPluginContext extends PluginContext { | ||
/** URL targeted */ | ||
url: string; | ||
|
||
/** List of loaded plugins apply to the Angular HTTP call */ | ||
angularPlugins: PluginObservableRunner<HttpResponse<any>, AngularCall>[]; | ||
|
||
/** Api Client processing the call the the API */ | ||
apiClient: ApiClient; | ||
|
||
/** Angular call options */ | ||
requestOptions: RequestOptions; | ||
} | ||
|
||
/** | ||
* Interface of a Angular plugin. | ||
* The plugin will be run around the Angular Http call | ||
*/ | ||
export interface AngularPlugin { | ||
/** | ||
* Load the plugin with the context | ||
* @param context Context of Angular plugin | ||
*/ | ||
load(context: AngularPluginContext): PluginObservableRunner<HttpResponse<any>, AngularCall>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './mock-intercept.request'; | ||
export * from './mock-intercept.fetch'; | ||
export * from './mock-intercept.interface'; |
76 changes: 76 additions & 0 deletions
76
packages/@ama-sdk/core/src/plugins/mock-intercept/mock-intercept.angular.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { delay, from, mergeMap } from 'rxjs'; | ||
import type { AngularCall, AngularPlugin, AngularPluginContext, PluginObservableRunner } from '../core/angular-plugin'; | ||
import { CUSTOM_MOCK_OPERATION_ID_HEADER, MockInterceptFetchParameters } from './mock-intercept.interface'; | ||
import { MockInterceptRequest } from './mock-intercept.request'; | ||
import { HttpResponse } from '@angular/common/http'; | ||
|
||
/** | ||
* Plugin to mock and intercept the call of SDK | ||
* | ||
* This plugin should be used only with the MockInterceptRequest Plugin. | ||
* It will allow the user to delay the response or to handle the getResponse function provided with the mock (if present). | ||
*/ | ||
export class MockInterceptAngular implements AngularPlugin { | ||
|
||
constructor(protected options: MockInterceptFetchParameters) {} | ||
|
||
public load(context: AngularPluginContext): PluginObservableRunner<HttpResponse<any>, AngularCall> { | ||
|
||
if (!context.apiClient.options.requestPlugins.some((plugin) => plugin instanceof MockInterceptRequest)) { | ||
throw new Error('MockInterceptAngular plugin should be used only with the MockInterceptRequest plugin'); | ||
} | ||
|
||
return { | ||
transform: (call: AngularCall) => { | ||
return from(( | ||
async () => { | ||
await this.options.adapter.initialize(); | ||
|
||
let originalCall = call; | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion | ||
if (!context.options.headers || !(context.options.headers instanceof Headers) || !(context.options.headers as Headers).has(CUSTOM_MOCK_OPERATION_ID_HEADER)) { | ||
return originalCall; | ||
} | ||
|
||
if (typeof this.options.delayTiming !== 'undefined') { | ||
const delayTime = typeof this.options.delayTiming === 'number' ? this.options.delayTiming : await this.options.delayTiming({ | ||
...context, | ||
fetchPlugins: [], | ||
options: context.requestOptions | ||
}); | ||
originalCall = originalCall.pipe(delay(delayTime)); | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion | ||
const operationId = (context.options.headers as Headers).get(CUSTOM_MOCK_OPERATION_ID_HEADER)!; | ||
try { | ||
const mock = this.options.adapter.getLatestMock(operationId); | ||
|
||
if (!mock.getResponse) { | ||
return originalCall; | ||
} | ||
|
||
const response = mock.getResponse(); | ||
return originalCall.pipe( | ||
mergeMap(async (res) => { | ||
const body = await response.json(); | ||
const responseCloned = res.clone(); | ||
return new HttpResponse<any>({ | ||
...responseCloned, | ||
body, | ||
url: responseCloned.url || undefined | ||
}); | ||
}) | ||
); | ||
|
||
} catch { | ||
(context.logger || console).error(`Failed to retrieve the latest mock for Operation ID ${operationId}, fallback to default mock`); | ||
return originalCall; | ||
} | ||
})() | ||
).pipe(mergeMap((res) => res)); | ||
} | ||
}; | ||
} | ||
|
||
} |