Added response mocking service

This commit is contained in:
lotte
2019-06-25 13:25:26 +02:00
parent 395509a19a
commit deef684d70
6 changed files with 216 additions and 2 deletions

View File

@@ -54,7 +54,7 @@ import { UUIDService } from './shared/uuid.service';
import { AuthenticatedGuard } from './auth/authenticated.guard'; import { AuthenticatedGuard } from './auth/authenticated.guard';
import { AuthRequestService } from './auth/auth-request.service'; import { AuthRequestService } from './auth/auth-request.service';
import { AuthResponseParsingService } from './auth/auth-response-parsing.service'; import { AuthResponseParsingService } from './auth/auth-response-parsing.service';
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { AuthInterceptor } from './auth/auth.interceptor'; import { AuthInterceptor } from './auth/auth.interceptor';
import { HALEndpointService } from './shared/hal-endpoint.service'; import { HALEndpointService } from './shared/hal-endpoint.service';
import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service'; import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service';
@@ -87,6 +87,21 @@ import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing
import { ClaimedTaskDataService } from './tasks/claimed-task-data.service'; import { ClaimedTaskDataService } from './tasks/claimed-task-data.service';
import { PoolTaskDataService } from './tasks/pool-task-data.service'; import { PoolTaskDataService } from './tasks/pool-task-data.service';
import { TaskResponseParsingService } from './tasks/task-response-parsing.service'; import { TaskResponseParsingService } from './tasks/task-response-parsing.service';
import {
MOCK_RESPONSE_MAP,
MockResponseMap,
mockResponseMap
} from './dspace-rest-v2/mocks/mock-response-map';
import { EndpointMockingRestService } from './dspace-rest-v2/endpoint-mocking-rest.service';
import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../../config';
export const restServiceFactory = (cfg: GlobalConfig, mocks: MockResponseMap, http: HttpClient) => {
if (ENV_CONFIG.production) {
return new DSpaceRESTv2Service(http);
} else {
return new EndpointMockingRestService(cfg, mocks, http);
}
};
const IMPORTS = [ const IMPORTS = [
CommonModule, CommonModule,
@@ -110,6 +125,8 @@ const PROVIDERS = [
CommunityDataService, CommunityDataService,
CollectionDataService, CollectionDataService,
DSOResponseParsingService, DSOResponseParsingService,
{ provide: MOCK_RESPONSE_MAP, useValue: mockResponseMap },
{ provide: DSpaceRESTv2Service, useFactory: restServiceFactory, deps: [GLOBAL_CONFIG, MOCK_RESPONSE_MAP, HttpClient]},
DSpaceRESTv2Service, DSpaceRESTv2Service,
DynamicFormLayoutService, DynamicFormLayoutService,
DynamicFormService, DynamicFormService,

View File

@@ -26,7 +26,7 @@ export interface HttpOptions {
@Injectable() @Injectable()
export class DSpaceRESTv2Service { export class DSpaceRESTv2Service {
constructor(private http: HttpClient) { constructor(protected http: HttpClient) {
} }

View File

@@ -0,0 +1,75 @@
import { HttpHeaders, HttpResponse } from '@angular/common/http';
import { of as observableOf } from 'rxjs';
import { GlobalConfig } from '../../../config/global-config.interface';
import { RestRequestMethod } from '../data/rest-request-method';
import { EndpointMockingRestService } from './endpoint-mocking-rest.service';
import { MockResponseMap } from './mocks/mock-response-map';
describe('EndpointMockingRestService', () => {
let service: EndpointMockingRestService;
const serverHttpResponse: HttpResponse<any> = {
body: { bar: false },
headers: new HttpHeaders(),
statusText: '200'
} as HttpResponse<any>;
const mockResponseMap: MockResponseMap = new Map([
[ '/foo', { bar: true } ]
]);
beforeEach(() => {
const EnvConfig = {
rest: {
nameSpace: '/api'
}
} as GlobalConfig;
const httpStub = jasmine.createSpyObj('http', {
get: observableOf(serverHttpResponse),
request: observableOf(serverHttpResponse)
});
service = new EndpointMockingRestService(EnvConfig, mockResponseMap, httpStub);
});
describe('get', () => {
describe('when the URL is mocked', () => {
it('should return the mock data', (done) => {
service.get('https://rest.com/api/foo').subscribe((response) => {
expect(response.payload).toEqual({ bar: true });
done();
});
});
});
describe('when the URL isn\'t mocked', () => {
it('should return the server data', (done) => {
service.get('https://rest.com/api').subscribe((response) => {
expect(response.payload).toEqual({ bar: false });
done();
});
});
});
});
describe('request', () => {
describe('when the URL is mocked', () => {
it('should return the mock data', (done) => {
service.request(RestRequestMethod.GET, 'https://rest.com/api/foo').subscribe((response) => {
expect(response.payload).toEqual({ bar: true });
done();
});
});
});
describe('when the URL isn\'t mocked', () => {
it('should return the server data', (done) => {
service.request(RestRequestMethod.GET, 'https://rest.com/api').subscribe((response) => {
expect(response.payload).toEqual({ bar: false });
done();
});
});
});
});
});

View File

@@ -0,0 +1,108 @@
import { HttpClient, HttpHeaders } from '@angular/common/http'
import { Inject, Injectable } from '@angular/core';
import { Observable, of as observableOf } from 'rxjs';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { isEmpty } from '../../shared/empty.util';
import { RestRequestMethod } from '../data/rest-request-method';
import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model';
import { DSpaceRESTv2Service, HttpOptions } from './dspace-rest-v2.service';
import { MOCK_RESPONSE_MAP, MockResponseMap } from './mocks/mock-response-map';
/**
* Service to access DSpace's REST API.
*
* If a URL is found in this.mockResponseMap, it returns the mock response instead
*/
@Injectable()
export class EndpointMockingRestService extends DSpaceRESTv2Service {
constructor(
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
@Inject(MOCK_RESPONSE_MAP) protected mockResponseMap: MockResponseMap,
protected http: HttpClient
) {
super(http);
}
/**
* Performs a request to the REST API with the `get` http method.
*
* If the URL is found in this.mockResponseMap,
* it returns the mock response instead
*
* @param absoluteURL
* A URL
* @return Observable<DSpaceRESTV2Response>
* An Observable<DSpaceRESTV2Response> containing the response
*/
get(absoluteURL: string): Observable<DSpaceRESTV2Response> {
const mockData = this.getMockData(absoluteURL);
if (isEmpty(mockData)) {
return super.get(absoluteURL);
} else {
return this.toMockResponse$(mockData);
}
}
/**
* Performs a request to the REST API.
*
* If the URL is found in this.mockResponseMap,
* it returns the mock response instead
*
* @param method
* the HTTP method for the request
* @param url
* the URL for the request
* @param body
* an optional body for the request
* @return Observable<DSpaceRESTV2Response>
* An Observable<DSpaceRESTV2Response> containing the response from the server
*/
request(method: RestRequestMethod, url: string, body?: any, options?: HttpOptions): Observable<DSpaceRESTV2Response> {
const mockData = this.getMockData(url);
if (isEmpty(mockData)) {
return super.request(method, url, body, options);
} else {
return this.toMockResponse$(mockData);
}
}
/**
* Turn the mock object in to an Observable<DSpaceRESTV2Response>
*
* @param mockData
* the mock response
* @return
* an Observable<DSpaceRESTV2Response> containing the mock response
*/
private toMockResponse$(mockData: any): Observable<DSpaceRESTV2Response> {
return observableOf({
payload: mockData,
headers: new HttpHeaders(),
statusCode: 200,
statusText: 'OK'
});
}
/**
* Get the mock response associated with this URL from this.mockResponseMap
*
* @param urlStr
* the URL to fetch a mock reponse for
* @return any
* the mock response if there is one, undefined otherwise
*/
private getMockData(urlStr: string): any {
const url = new URL(urlStr);
const key = url.pathname.slice(this.EnvConfig.rest.nameSpace.length);
if (this.mockResponseMap.has(key)) {
// parse and stringify to clone the object to ensure that any changes made
// to it afterwards don't affect future calls
return JSON.parse(JSON.stringify(this.mockResponseMap.get(key)));
} else {
return undefined;
}
}
}

View File

@@ -0,0 +1,10 @@
import { InjectionToken } from '@angular/core';
import mockSuggestResponse from './mock-suggest-response.json';
export class MockResponseMap extends Map<string, any> {};
export const MOCK_RESPONSE_MAP: InjectionToken<MockResponseMap> = new InjectionToken<MockResponseMap>('mockResponseMap');
export const mockResponseMap: MockResponseMap = new Map([
[ '/discover/suggestions', mockSuggestResponse ]
]);

View File

@@ -91,6 +91,10 @@ module.exports = {
{ {
test: /\.html$/, test: /\.html$/,
loader: 'raw-loader' loader: 'raw-loader'
},
{
test: /\.json$/,
loader: 'json-loader'
} }
] ]
}, },