Removed SyncTasks from the project. Massively alterered tests to handle the new async behavior (#62)
* Removed SyncTasks from the project. Massively alterered tests to handle the new async behavior. * PR feedback
This commit is contained in:
Родитель
f0cd0355a3
Коммит
c97f650f49
10
README.md
10
README.md
|
@ -14,7 +14,8 @@ npm install --save simplerestclients
|
|||
|
||||
### `SimpleWebRequest`
|
||||
|
||||
Wraps a single web request. Has lots of overrides for priorization, delays, retry logic, error handling, etc.
|
||||
Wraps a single web request. Takes an options structure with overrides for priorization, delays, retry logic, error handling, etc. Has
|
||||
an `abort()` method to cancel the request early (will result in a rejected promise from the `start()` method).
|
||||
|
||||
### `GenericRestClient`
|
||||
|
||||
|
@ -25,7 +26,6 @@ etc.
|
|||
## GenericRestClient Sample Usage
|
||||
|
||||
```typescript
|
||||
import * as SyncTasks from 'synctasks';
|
||||
import { GenericRestClient, ApiCallOptions, Headers } from 'simplerestclients';
|
||||
|
||||
interface User {
|
||||
|
@ -45,15 +45,15 @@ class MyRestClient extends GenericRestClient {
|
|||
}
|
||||
|
||||
// Define public methods that expose the APIs provided through the REST service.
|
||||
getAllUsers(): SyncTasks.Promise<User[]> {
|
||||
getAllUsers(): Promise<User[]> {
|
||||
return this.performApiGet<User[]>('users');
|
||||
}
|
||||
|
||||
getUserById(id: string): SyncTasks.Promise<User> {
|
||||
getUserById(id: string): Promise<User> {
|
||||
return this.performApiGet<User>(`user/${ id }`);
|
||||
}
|
||||
|
||||
setUser(user: User): SyncTasks.Promise<void> {
|
||||
setUser(user: User): Promise<void> {
|
||||
return this.performApiPut<void>(`user/${ user.id }`, user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "simplerestclients",
|
||||
"version": "0.2.12",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -5134,11 +5134,6 @@
|
|||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"synctasks": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/synctasks/-/synctasks-0.3.3.tgz",
|
||||
"integrity": "sha512-8Gr8WHInZt5oU1q2N7ANqLSZ/TJn6bYlkqkwJJoGowFc5l81DRORgtHH9eJUpJGJsGJgYyWeVfKGVtUdTu4TEQ=="
|
||||
},
|
||||
"table": {
|
||||
"version": "5.4.6",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
|
||||
|
@ -5723,8 +5718,7 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -5745,14 +5739,12 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -5767,20 +5759,17 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -5897,8 +5886,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -5910,7 +5898,6 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -5925,7 +5912,6 @@
|
|||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -5933,14 +5919,12 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -5959,7 +5943,6 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -6040,8 +6023,7 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -6053,7 +6035,6 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -6139,8 +6120,7 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -6176,7 +6156,6 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -6196,7 +6175,6 @@
|
|||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -6240,14 +6218,12 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "simplerestclients",
|
||||
"version": "0.2.12",
|
||||
"version": "1.0.0",
|
||||
"description": "A library of components for accessing RESTful services with javascript/typescript.",
|
||||
"author": "David de Regt <David.de.Regt@microsoft.com>",
|
||||
"scripts": {
|
||||
|
@ -13,9 +13,7 @@
|
|||
"test:watch": "npm run clean && karma start",
|
||||
"test:browser": "npm run clean && karma start --browsers=Chrome --single-run=false --auto-watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"synctasks": "^0.3.3"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/faker": "4.1.8",
|
||||
"@types/jasmine": "3.5.0",
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
* Base client type for accessing RESTful services
|
||||
*/
|
||||
|
||||
import * as SyncTasks from 'synctasks';
|
||||
|
||||
import { isString } from './utils';
|
||||
import { WebRequestOptions, SimpleWebRequest, WebResponse, Headers } from './SimpleWebRequest';
|
||||
|
||||
|
@ -30,7 +28,12 @@ export interface ETagResponse<T> {
|
|||
eTag?: string;
|
||||
}
|
||||
|
||||
export class GenericRestClient {
|
||||
export interface ApiCallResponse<T, TCustomOptions extends {}> {
|
||||
req: SimpleWebRequest<T, ApiCallOptions & Partial<TCustomOptions>>;
|
||||
promise: Promise<WebResponse<T, ApiCallOptions & Partial<TCustomOptions>>>;
|
||||
}
|
||||
|
||||
export class GenericRestClient<TCustomOptions extends {} = {}> {
|
||||
|
||||
protected _endpointUrl: string;
|
||||
|
||||
|
@ -47,9 +50,9 @@ export class GenericRestClient {
|
|||
protected _performApiCall<T>(apiPath: string,
|
||||
action: HttpAction,
|
||||
objToPost: any,
|
||||
givenOptions: ApiCallOptions = {}): SyncTasks.Promise<WebResponse<T, ApiCallOptions>> {
|
||||
givenOptions: Partial<ApiCallOptions & TCustomOptions> = {}): ApiCallResponse<T, TCustomOptions> {
|
||||
|
||||
const options: ApiCallOptions = { ...this._defaultOptions, ...givenOptions };
|
||||
const options: ApiCallOptions & Partial<TCustomOptions> = { ...this._defaultOptions, ...givenOptions };
|
||||
if (objToPost) {
|
||||
options.sendData = objToPost;
|
||||
}
|
||||
|
@ -67,90 +70,94 @@ export class GenericRestClient {
|
|||
|
||||
const finalUrl = options.excludeEndpointUrl ? apiPath : this._endpointUrl + apiPath;
|
||||
|
||||
return new SimpleWebRequest<T, ApiCallOptions>(
|
||||
const req = new SimpleWebRequest<T, ApiCallOptions & Partial<TCustomOptions>>(
|
||||
action,
|
||||
finalUrl,
|
||||
options,
|
||||
() => this._getHeaders(options),
|
||||
() => this._blockRequestUntil(options),
|
||||
)
|
||||
.start()
|
||||
.then(response => {
|
||||
this._processSuccessResponse<T>(response);
|
||||
return response;
|
||||
});
|
||||
);
|
||||
|
||||
const promise = req.start().then(response => {
|
||||
this._processSuccessResponse<T>(response);
|
||||
return response;
|
||||
});
|
||||
|
||||
return {
|
||||
req,
|
||||
promise,
|
||||
};
|
||||
}
|
||||
|
||||
protected _getHeaders(options: ApiCallOptions): Headers {
|
||||
protected _getHeaders(options: ApiCallOptions & Partial<TCustomOptions>): Headers {
|
||||
// Virtual function -- No-op by default
|
||||
return {};
|
||||
}
|
||||
|
||||
// Override (but make sure to call super and chain appropriately) this function if you want to add more blocking criteria.
|
||||
// Also, this might be called multiple times to check if the conditions changed
|
||||
protected _blockRequestUntil(options: ApiCallOptions): SyncTasks.Promise<void> | undefined {
|
||||
protected _blockRequestUntil(options: ApiCallOptions & Partial<TCustomOptions>): Promise<void> | undefined {
|
||||
// No-op by default
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Override this function to process any generic headers that come down with a successful response
|
||||
protected _processSuccessResponse<T>(resp: WebResponse<T, ApiCallOptions>): void {
|
||||
protected _processSuccessResponse<T>(resp: WebResponse<T, ApiCallOptions & Partial<TCustomOptions>>): void {
|
||||
// No-op by default
|
||||
}
|
||||
|
||||
performApiGet<T>(apiPath: string, options?: ApiCallOptions): SyncTasks.Promise<T> {
|
||||
performApiGet<T>(apiPath: string, options?: ApiCallOptions & Partial<TCustomOptions>): Promise<T> {
|
||||
return this
|
||||
.performApiGetDetailed<T>(apiPath, options)
|
||||
.then(resp => resp.body);
|
||||
.promise.then(resp => resp.body);
|
||||
}
|
||||
|
||||
performApiGetDetailed<T>(apiPath: string, options?: ApiCallOptions): SyncTasks.Promise<WebResponse<T, ApiCallOptions>> {
|
||||
performApiGetDetailed<T>(apiPath: string, options?: ApiCallOptions & Partial<TCustomOptions>):
|
||||
ApiCallResponse<T, ApiCallOptions & Partial<TCustomOptions>> {
|
||||
return this._performApiCall<T>(apiPath, 'GET', undefined, options);
|
||||
}
|
||||
|
||||
performApiPost<T>(apiPath: string, objToPost: any, options?: ApiCallOptions): SyncTasks.Promise<T> {
|
||||
performApiPost<T>(apiPath: string, objToPost: any, options?: ApiCallOptions & Partial<TCustomOptions>): Promise<T> {
|
||||
return this
|
||||
.performApiPostDetailed<T>(apiPath, objToPost, options)
|
||||
.then(resp => resp.body);
|
||||
.promise.then(resp => resp.body);
|
||||
}
|
||||
|
||||
performApiPostDetailed<T>(apiPath: string,
|
||||
objToPost: any,
|
||||
options?: ApiCallOptions): SyncTasks.Promise<WebResponse<T, ApiCallOptions>> {
|
||||
performApiPostDetailed<T>(apiPath: string, objToPost: any, options?: ApiCallOptions & Partial<TCustomOptions>):
|
||||
ApiCallResponse<T, ApiCallOptions & Partial<TCustomOptions>> {
|
||||
return this._performApiCall<T>(apiPath, 'POST', objToPost, options);
|
||||
}
|
||||
|
||||
performApiPatch<T>(apiPath: string, objToPatch: any, options?: ApiCallOptions): SyncTasks.Promise<T> {
|
||||
performApiPatch<T>(apiPath: string, objToPatch: any, options?: ApiCallOptions & Partial<TCustomOptions>): Promise<T> {
|
||||
return this
|
||||
.performApiPatchDetailed<T>(apiPath, objToPatch, options)
|
||||
.then(resp => resp.body);
|
||||
.promise.then(resp => resp.body);
|
||||
}
|
||||
|
||||
performApiPatchDetailed<T>(apiPath: string,
|
||||
objToPatch: any,
|
||||
options?: ApiCallOptions): SyncTasks.Promise<WebResponse<T, ApiCallOptions>> {
|
||||
performApiPatchDetailed<T>(apiPath: string, objToPatch: any, options?: ApiCallOptions & Partial<TCustomOptions>):
|
||||
ApiCallResponse<T, ApiCallOptions & Partial<TCustomOptions>> {
|
||||
return this._performApiCall<T>(apiPath, 'PATCH', objToPatch, options);
|
||||
}
|
||||
|
||||
performApiPut<T>(apiPath: string, objToPut: any, options?: ApiCallOptions): SyncTasks.Promise<T> {
|
||||
performApiPut<T>(apiPath: string, objToPut: any, options?: ApiCallOptions & Partial<TCustomOptions>): Promise<T> {
|
||||
return this
|
||||
.performApiPutDetailed<T>(apiPath, objToPut, options)
|
||||
.then(resp => resp.body);
|
||||
.promise.then(resp => resp.body);
|
||||
}
|
||||
|
||||
performApiPutDetailed<T>(apiPath: string, objToPut: any, options?: ApiCallOptions): SyncTasks.Promise<WebResponse<T, ApiCallOptions>> {
|
||||
performApiPutDetailed<T>(apiPath: string, objToPut: any, options?: ApiCallOptions & Partial<TCustomOptions>):
|
||||
ApiCallResponse<T, ApiCallOptions & Partial<TCustomOptions>> {
|
||||
return this._performApiCall<T>(apiPath, 'PUT', objToPut, options);
|
||||
}
|
||||
|
||||
performApiDelete<T>(apiPath: string, objToDelete?: any, options?: ApiCallOptions): SyncTasks.Promise<T> {
|
||||
performApiDelete<T>(apiPath: string, objToDelete?: any, options?: ApiCallOptions & Partial<TCustomOptions>): Promise<T> {
|
||||
return this
|
||||
.performApiDeleteDetailed<T>(apiPath, objToDelete, options)
|
||||
.then(resp => resp.body);
|
||||
.promise.then(resp => resp.body);
|
||||
}
|
||||
|
||||
performApiDeleteDetailed<T>(apiPath: string,
|
||||
objToDelete: any,
|
||||
options?: ApiCallOptions): SyncTasks.Promise<WebResponse<T, ApiCallOptions>> {
|
||||
performApiDeleteDetailed<T>(apiPath: string, objToDelete: any, options?: ApiCallOptions & Partial<TCustomOptions>):
|
||||
ApiCallResponse<T, ApiCallOptions & Partial<TCustomOptions>> {
|
||||
return this._performApiCall<T>(apiPath, 'DELETE', objToDelete, options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
* Simple client for issuing web requests.
|
||||
*/
|
||||
|
||||
import * as SyncTasks from 'synctasks';
|
||||
|
||||
import { attempt, isObject, isString, remove, assert, clone } from './utils';
|
||||
import { ExponentialTime } from './ExponentialTime';
|
||||
|
||||
|
@ -218,7 +216,7 @@ export abstract class SimpleWebRequestBase<TOptions extends WebRequestOptions =
|
|||
protected _url: string,
|
||||
protected readonly options: TOptions,
|
||||
protected readonly _getHeaders?: () => Headers,
|
||||
protected readonly _blockRequestUntil?: () => SyncTasks.Promise<void> | undefined) {
|
||||
protected readonly _blockRequestUntil?: () => Promise<void> | undefined) {
|
||||
|
||||
this._options = { ...DefaultOptions, ...options };
|
||||
}
|
||||
|
@ -230,13 +228,17 @@ export abstract class SimpleWebRequestBase<TOptions extends WebRequestOptions =
|
|||
abstract abort(): void;
|
||||
|
||||
protected static checkQueueProcessing(): void {
|
||||
while (requestQueue.length > 0 && executingList.length < SimpleWebRequestOptions.MaxSimultaneousRequests) {
|
||||
const req = requestQueue.shift()!!!;
|
||||
while (executingList.length < SimpleWebRequestOptions.MaxSimultaneousRequests) {
|
||||
const req = requestQueue.shift();
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockedList.push(req);
|
||||
const blockPromise = (req._blockRequestUntil && req._blockRequestUntil()) || SyncTasks.Resolved();
|
||||
blockPromise.finally(() => {
|
||||
const blockPromise = (req._blockRequestUntil && req._blockRequestUntil()) || Promise.resolve();
|
||||
blockPromise.then(() => {
|
||||
remove(blockedList, req);
|
||||
}).then(() => {
|
||||
|
||||
if (executingList.length < SimpleWebRequestOptions.MaxSimultaneousRequests && !req._aborted) {
|
||||
executingList.push(req);
|
||||
SimpleWebRequest._scheduleHungRequestCleanupIfNeeded();
|
||||
|
@ -245,6 +247,8 @@ export abstract class SimpleWebRequestBase<TOptions extends WebRequestOptions =
|
|||
req._enqueue();
|
||||
}
|
||||
}, (err: any) => {
|
||||
remove(blockedList, req);
|
||||
|
||||
// fail the request if the block promise is rejected
|
||||
req._respond('_blockRequestUntil rejected: ' + err);
|
||||
});
|
||||
|
@ -664,14 +668,14 @@ export abstract class SimpleWebRequestBase<TOptions extends WebRequestOptions =
|
|||
}
|
||||
|
||||
export class SimpleWebRequest<TBody, TOptions extends WebRequestOptions = WebRequestOptions> extends SimpleWebRequestBase<TOptions> {
|
||||
|
||||
private _deferred: SyncTasks.Deferred<WebResponse<TBody, TOptions>>;
|
||||
private _resolve?: (resp: WebResponse<TBody, TOptions>) => void;
|
||||
private _reject?: (resp?: any) => void;
|
||||
|
||||
constructor(action: string,
|
||||
url: string,
|
||||
options: TOptions,
|
||||
getHeaders?: () => Headers,
|
||||
blockRequestUntil?: () => SyncTasks.Promise<void> | undefined) {
|
||||
blockRequestUntil?: () => Promise<void> | undefined) {
|
||||
super(action, url, options, getHeaders, blockRequestUntil);
|
||||
}
|
||||
|
||||
|
@ -693,7 +697,7 @@ export class SimpleWebRequest<TBody, TOptions extends WebRequestOptions = WebReq
|
|||
this._requestTimeoutTimer = undefined;
|
||||
}
|
||||
|
||||
if (!this._deferred) {
|
||||
if (!this._resolve) {
|
||||
assert(false, 'Haven\'t even fired start() yet -- can\'t abort');
|
||||
return;
|
||||
}
|
||||
|
@ -707,21 +711,20 @@ export class SimpleWebRequest<TBody, TOptions extends WebRequestOptions = WebReq
|
|||
}
|
||||
}
|
||||
|
||||
start(): SyncTasks.Promise<WebResponse<TBody, TOptions>> {
|
||||
if (this._deferred) {
|
||||
start(): Promise<WebResponse<TBody, TOptions>> {
|
||||
if (this._resolve) {
|
||||
assert(false, 'WebRequest already started');
|
||||
return SyncTasks.Rejected('WebRequest already started');
|
||||
return Promise.reject('WebRequest already started');
|
||||
}
|
||||
|
||||
this._deferred = SyncTasks.Defer<WebResponse<TBody, TOptions>>();
|
||||
this._deferred.onCancel(() => {
|
||||
// Abort the XHR -- this should chain through to the fail case on readystatechange
|
||||
this.abort();
|
||||
const promise = new Promise<WebResponse<TBody, TOptions>>((res, rej) => {
|
||||
this._resolve = res;
|
||||
this._reject = rej;
|
||||
});
|
||||
|
||||
this._enqueue();
|
||||
|
||||
return this._deferred.promise();
|
||||
return promise;
|
||||
}
|
||||
|
||||
protected _respond(errorStatusText?: string): void {
|
||||
|
@ -828,7 +831,7 @@ export class SimpleWebRequest<TBody, TOptions extends WebRequestOptions = WebReq
|
|||
responseParsingException: responseParsingException,
|
||||
};
|
||||
|
||||
this._deferred.resolve(resp);
|
||||
this._resolve!!!(resp);
|
||||
} else {
|
||||
let errResp: WebErrorResponse<TOptions> = {
|
||||
url: (this._xhr ? this._xhr.responseURL : undefined) || this._url,
|
||||
|
@ -898,7 +901,7 @@ export class SimpleWebRequest<TBody, TOptions extends WebRequestOptions = WebReq
|
|||
}
|
||||
} else {
|
||||
// No more retries -- fail.
|
||||
this._deferred.reject(errResp);
|
||||
this._reject!!!(errResp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import * as faker from 'faker';
|
||||
import * as SyncTasks from 'synctasks';
|
||||
|
||||
import { ErrorHandlingType, SimpleWebRequestBase, WebErrorResponse } from '../src/SimpleWebRequest';
|
||||
import { GenericRestClient, ApiCallOptions } from '../src/GenericRestClient';
|
||||
|
||||
import { DETAILED_RESPONSE, REQUEST_OPTIONS } from './helpers';
|
||||
import { DETAILED_RESPONSE, REQUEST_OPTIONS, asyncTick } from './helpers';
|
||||
|
||||
class RestClient extends GenericRestClient { }
|
||||
const BASE_URL = faker.internet.url();
|
||||
|
@ -13,6 +12,7 @@ const http = new RestClient(BASE_URL);
|
|||
describe('GenericRestClient', () => {
|
||||
beforeAll(() => {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.clock().install();
|
||||
// Run an initial request to finish feature detection - this is needed so we can directly call onLoad
|
||||
const statusCode = 200;
|
||||
const onSuccess = jasmine.createSpy('onSuccess');
|
||||
|
@ -21,16 +21,27 @@ describe('GenericRestClient', () => {
|
|||
http.performApiGet(path)
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: statusCode });
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
jasmine.Ajax.uninstall();
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: statusCode });
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
jasmine.Ajax.uninstall();
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => jasmine.Ajax.install());
|
||||
afterEach(() => jasmine.Ajax.uninstall());
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.clock().install();
|
||||
});
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('performs GET request with performApiGet', () => {
|
||||
it('performs GET request with performApiGet ', () => {
|
||||
const id = faker.random.uuid();
|
||||
const statusCode = 200;
|
||||
const onSuccess = jasmine.createSpy('onSuccess');
|
||||
|
@ -43,19 +54,22 @@ describe('GenericRestClient', () => {
|
|||
const path = `/get/${id}`;
|
||||
const url = BASE_URL + path;
|
||||
|
||||
http.performApiGet(path)
|
||||
const p1 = http.performApiGet(path)
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
|
||||
it('performs GET request with performApiGetDetailed', () => {
|
||||
|
@ -81,21 +95,25 @@ describe('GenericRestClient', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
http.performApiGetDetailed(path, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
const p1 = http.performApiGetDetailed(path, { contentType: 'json' })
|
||||
.promise.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
it('performs POST request with performApiPost', () => {
|
||||
it('performs POST request with performApiPost ', () => {
|
||||
const statusCode = 201;
|
||||
const onSuccess = jasmine.createSpy('onSuccess');
|
||||
const method = 'POST';
|
||||
|
@ -107,20 +125,24 @@ describe('GenericRestClient', () => {
|
|||
const path = '/post';
|
||||
const url = BASE_URL + path;
|
||||
|
||||
http.performApiPost(path, sendData, { contentType: 'json' })
|
||||
const p1 = http.performApiPost(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
});
|
||||
|
||||
it('performs POST request with performApiPostDetailed', () => {
|
||||
|
@ -145,19 +167,23 @@ describe('GenericRestClient', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
http.performApiPostDetailed(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
const p1 = http.performApiPostDetailed(path, sendData, { contentType: 'json' })
|
||||
.promise.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
it('performs PUT request with performApiPut', () => {
|
||||
|
@ -170,20 +196,24 @@ describe('GenericRestClient', () => {
|
|||
const path = '/put/' + id;
|
||||
const url = BASE_URL + path;
|
||||
|
||||
http.performApiPut(path, sendData, { contentType: 'json' })
|
||||
const p1 = http.performApiPut(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
});
|
||||
|
||||
it('performs PUT request with performApiPutDetailed', () => {
|
||||
|
@ -206,20 +236,24 @@ describe('GenericRestClient', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
http.performApiPutDetailed(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
const p1 = http.performApiPutDetailed(path, sendData, { contentType: 'json' })
|
||||
.promise.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
it('performs PATCH request with performApiPatch', () => {
|
||||
|
@ -235,20 +269,24 @@ describe('GenericRestClient', () => {
|
|||
const path = '/patch' + id;
|
||||
const url = BASE_URL + path;
|
||||
|
||||
http.performApiPatch(path, sendData, { contentType: 'json' })
|
||||
const p1 = http.performApiPatch(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
});
|
||||
|
||||
it('performs PATCH request with performApiPatchDetailed', () => {
|
||||
|
@ -274,20 +312,24 @@ describe('GenericRestClient', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
http.performApiPatchDetailed(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
const p1 = http.performApiPatchDetailed(path, sendData, { contentType: 'json' })
|
||||
.promise.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
it('performs DELETE request with performApiDelete', () => {
|
||||
|
@ -298,18 +340,21 @@ describe('GenericRestClient', () => {
|
|||
const path = `/delete/${faker.random.uuid()}`;
|
||||
const url = BASE_URL + path;
|
||||
|
||||
http.performApiDelete(path)
|
||||
const p1 = http.performApiDelete(path)
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(onSuccess).toHaveBeenCalledWith(body);
|
||||
});
|
||||
|
||||
it('performs DELETE request with performApiDeleteDetailed', () => {
|
||||
|
@ -332,19 +377,23 @@ describe('GenericRestClient', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
http.performApiDeleteDetailed(path, sendData, { contentType: 'json' })
|
||||
.then(onSuccess);
|
||||
const p1 = http.performApiDeleteDetailed(path, sendData, { contentType: 'json' })
|
||||
.promise.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.data() as any).toEqual(sendData);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
|
||||
it('performs request with custom headers', () => {
|
||||
|
@ -362,14 +411,17 @@ describe('GenericRestClient', () => {
|
|||
const http = new Http(BASE_URL);
|
||||
const path = '/auth';
|
||||
|
||||
http.performApiGet(path)
|
||||
const p1 = http.performApiGet(path)
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: statusCode });
|
||||
|
||||
expect(request.requestHeaders['Authorization']).toEqual(headers['Authorization']);
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.requestHeaders['Authorization']).toEqual(headers['Authorization']);
|
||||
request.respondWith({ status: statusCode });
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('overrides response', () => {
|
||||
|
@ -386,27 +438,33 @@ describe('GenericRestClient', () => {
|
|||
const body = [' x ', ' y ', ' z '];
|
||||
const url = BASE_URL + path;
|
||||
|
||||
http.performApiGet<string[]>(path)
|
||||
const p1 = http.performApiGet<string[]>(path)
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
return asyncTick().then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(body.map((str: string) => str.trim()));
|
||||
request.respondWith({
|
||||
responseText: JSON.stringify(body),
|
||||
status: statusCode,
|
||||
});
|
||||
expect(request.status).toEqual(statusCode);
|
||||
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(body.map((str: string) => str.trim()));
|
||||
});
|
||||
});
|
||||
|
||||
it('blocks the request with custom method', () => {
|
||||
const blockDefer = SyncTasks.Defer<void>();
|
||||
let blockResolver: () => void = () => undefined;
|
||||
const blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
|
||||
class Http extends GenericRestClient {
|
||||
protected _blockRequestUntil(): SyncTasks.Promise<void> {
|
||||
return blockDefer.promise();
|
||||
protected _blockRequestUntil(): Promise<void> {
|
||||
return blockPromise;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,21 +473,29 @@ describe('GenericRestClient', () => {
|
|||
const http = new Http(BASE_URL);
|
||||
const path = '/auth';
|
||||
|
||||
http.performApiGet(path)
|
||||
const p1 = http.performApiGet(path)
|
||||
.then(onSuccess);
|
||||
|
||||
let request = jasmine.Ajax.requests.mostRecent();
|
||||
let request: any;
|
||||
return asyncTick().then(() => {
|
||||
request = jasmine.Ajax.requests.mostRecent();
|
||||
|
||||
expect(request).toBeUndefined();
|
||||
blockDefer.resolve(void 0);
|
||||
expect(request).toBeUndefined();
|
||||
blockResolver();
|
||||
|
||||
request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: statusCode });
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: statusCode });
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('aborting request after failure w/retry', () => {
|
||||
let blockDefer = SyncTasks.Defer<void>();
|
||||
let blockResolver: () => void = () => undefined;
|
||||
let blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
|
||||
class Http extends GenericRestClient {
|
||||
constructor(endpointUrl: string) {
|
||||
|
@ -437,8 +503,8 @@ describe('GenericRestClient', () => {
|
|||
this._defaultOptions.customErrorHandler = this._customErrorHandler;
|
||||
this._defaultOptions.timeout = 1;
|
||||
}
|
||||
protected _blockRequestUntil(): SyncTasks.Promise<void> {
|
||||
return blockDefer.promise();
|
||||
protected _blockRequestUntil(): Promise<void> {
|
||||
return blockPromise;
|
||||
}
|
||||
|
||||
protected _customErrorHandler = (webRequest: SimpleWebRequestBase, errorResponse: WebErrorResponse): ErrorHandlingType => {
|
||||
|
@ -455,38 +521,38 @@ describe('GenericRestClient', () => {
|
|||
const http = new Http(BASE_URL);
|
||||
const path = '/auth';
|
||||
|
||||
const req = http.performApiGet(path)
|
||||
const resp = http.performApiGetDetailed(path);
|
||||
const p1 = resp.promise
|
||||
.then(onSuccess)
|
||||
.catch(onFailure);
|
||||
|
||||
blockDefer.resolve(void 0);
|
||||
const request1 = jasmine.Ajax.requests.mostRecent();
|
||||
return asyncTick().then(() => {
|
||||
blockResolver();
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
const request1 = jasmine.Ajax.requests.mostRecent();
|
||||
|
||||
// Reset blockuntil so retries may block
|
||||
blockDefer = SyncTasks.Defer<void>();
|
||||
// Reset blockuntil so retries may block
|
||||
blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
|
||||
request1.respondWith({ status: statusCode });
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
expect(onFailure).not.toHaveBeenCalled();
|
||||
request1.respondWith({ status: statusCode });
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
expect(onFailure).not.toHaveBeenCalled();
|
||||
|
||||
// Calls abort function
|
||||
req.cancel();
|
||||
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
expect(onFailure).toHaveBeenCalled();
|
||||
resp.req.abort();
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
expect(onFailure).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Timing related tests' , () => {
|
||||
beforeEach(() => {
|
||||
jasmine.clock().install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('failed request with retry handles multiple _respond calls', () => {
|
||||
let blockDefer = SyncTasks.Defer<void>();
|
||||
let blockResolver: () => void = () => undefined;
|
||||
let blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
|
||||
class Http extends GenericRestClient {
|
||||
constructor(endpointUrl: string) {
|
||||
|
@ -494,8 +560,8 @@ describe('GenericRestClient', () => {
|
|||
this._defaultOptions.customErrorHandler = this._customErrorHandler;
|
||||
this._defaultOptions.timeout = 1;
|
||||
}
|
||||
protected _blockRequestUntil(): SyncTasks.Promise<void> {
|
||||
return blockDefer.promise();
|
||||
protected _blockRequestUntil(): Promise<void> {
|
||||
return blockPromise;
|
||||
}
|
||||
|
||||
protected _customErrorHandler = (): ErrorHandlingType => {
|
||||
|
@ -508,27 +574,37 @@ describe('GenericRestClient', () => {
|
|||
const http = new Http(BASE_URL);
|
||||
const path = '/auth';
|
||||
|
||||
http.performApiGet(path)
|
||||
const p1 = http.performApiGet(path)
|
||||
.then(onSuccess);
|
||||
|
||||
blockDefer.resolve(void 0);
|
||||
const request1 = jasmine.Ajax.requests.mostRecent();
|
||||
return asyncTick().then(() => {
|
||||
blockResolver();
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
const request1 = jasmine.Ajax.requests.mostRecent();
|
||||
|
||||
// Reset blockuntil so retries may block
|
||||
blockDefer = SyncTasks.Defer<void>();
|
||||
// Reset blockuntil so retries may block
|
||||
blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
|
||||
// Store this so we're able to emulate double-request callbacks
|
||||
const onloadToCall = request1.onload as any;
|
||||
request1.respondWith({ status: statusCode });
|
||||
onloadToCall(undefined);
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
blockDefer.resolve(void 0);
|
||||
// Store this so we're able to emulate double-request callbacks
|
||||
const onloadToCall = request1.onload as any;
|
||||
request1.respondWith({ status: statusCode });
|
||||
onloadToCall(undefined);
|
||||
|
||||
jasmine.clock().tick(100);
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
blockResolver();
|
||||
|
||||
const request2 = jasmine.Ajax.requests.mostRecent();
|
||||
request2.respondWith({ status: 200 });
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
jasmine.clock().tick(100);
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
const request2 = jasmine.Ajax.requests.mostRecent();
|
||||
request2.respondWith({ status: 200 });
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccess).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as faker from 'faker';
|
||||
import * as SyncTasks from 'synctasks';
|
||||
|
||||
import {
|
||||
ErrorHandlingType,
|
||||
|
@ -9,19 +8,13 @@ import {
|
|||
WebRequestPriority,
|
||||
} from '../src/SimpleWebRequest';
|
||||
|
||||
import { DETAILED_RESPONSE } from './helpers';
|
||||
import { asyncTick, DETAILED_RESPONSE } from './helpers';
|
||||
|
||||
describe('SimpleWebRequest', () => {
|
||||
let catchExceptions = false;
|
||||
const status = 200;
|
||||
|
||||
beforeEach(() => {
|
||||
catchExceptions = SyncTasks.config.catchExceptions;
|
||||
SyncTasks.config.catchExceptions = false;
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
afterEach(() => {
|
||||
SyncTasks.config.catchExceptions = catchExceptions;
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
|
@ -42,17 +35,21 @@ describe('SimpleWebRequest', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
new SimpleWebRequest<string>(method, url, requestOptions)
|
||||
let request: any;
|
||||
setTimeout(() => {
|
||||
request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ responseText: JSON.stringify(''), status: statusCode });
|
||||
}, 0);
|
||||
|
||||
return new SimpleWebRequest<string>(method, url, requestOptions)
|
||||
.start()
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ responseText: JSON.stringify(''), status: statusCode });
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
.then(onSuccess)
|
||||
.then(() => {
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
});
|
||||
|
||||
it('sends json POST request', () => {
|
||||
|
@ -77,17 +74,21 @@ describe('SimpleWebRequest', () => {
|
|||
responseParsingException,
|
||||
};
|
||||
|
||||
new SimpleWebRequest<string>(method, url, requestOptions)
|
||||
let request: any;
|
||||
setTimeout(() => {
|
||||
request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ responseText: JSON.stringify(body), status: statusCode });
|
||||
}, 0);
|
||||
|
||||
return new SimpleWebRequest<string>(method, url, requestOptions)
|
||||
.start()
|
||||
.then(onSuccess);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ responseText: JSON.stringify(body), status: statusCode });
|
||||
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
.then(onSuccess)
|
||||
.then(() => {
|
||||
expect(request.url).toEqual(url);
|
||||
expect(request.method).toEqual(method);
|
||||
expect(request.status).toEqual(statusCode);
|
||||
expect(onSuccess).toHaveBeenCalledWith(response);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows to set request headers', () => {
|
||||
|
@ -98,14 +99,16 @@ describe('SimpleWebRequest', () => {
|
|||
const method = 'POST';
|
||||
const url = faker.internet.url();
|
||||
|
||||
new SimpleWebRequest<string>(url, method, {}, () => headers).start();
|
||||
let request: any;
|
||||
setTimeout(() => {
|
||||
request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: 200 });
|
||||
}, 0);
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
|
||||
expect(request.requestHeaders['X-Requested-With']).toEqual(headers['X-Requested-With']);
|
||||
expect(request.requestHeaders['Max-Forwards']).toEqual(headers['Max-Forwards']);
|
||||
|
||||
request.respondWith({ status });
|
||||
return new SimpleWebRequest<string>(method, url, {}, () => headers).start().then(() => {
|
||||
expect(request.requestHeaders['X-Requested-With']).toEqual(headers['X-Requested-With']);
|
||||
expect(request.requestHeaders['Max-Forwards']).toEqual(headers['Max-Forwards']);
|
||||
});
|
||||
});
|
||||
|
||||
it('forbids to set Accept header', () => {
|
||||
|
@ -117,9 +120,9 @@ describe('SimpleWebRequest', () => {
|
|||
const method = 'GET';
|
||||
const url = faker.internet.url();
|
||||
const error = `Don't set Accept with options.headers -- use it with the options.acceptType property`;
|
||||
const request = new SimpleWebRequest<string>(url, method, {}, () => headers);
|
||||
const request = new SimpleWebRequest<string>(method, url, {}, () => headers);
|
||||
|
||||
expect(() => request.start()).toThrowError(error);
|
||||
expect(() => (request as any)._fire()).toThrowError(error);
|
||||
expect(console.error).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
|
@ -132,9 +135,9 @@ describe('SimpleWebRequest', () => {
|
|||
const method = 'GET';
|
||||
const url = faker.internet.url();
|
||||
const error = `Don't set Content-Type with options.headers -- use it with the options.contentType property`;
|
||||
const request = new SimpleWebRequest<string>(url, method, {}, () => headers);
|
||||
const request = new SimpleWebRequest<string>(method, url, {}, () => headers);
|
||||
|
||||
expect(() => request.start()).toThrowError(error);
|
||||
expect(() => (request as any)._fire()).toThrowError(error);
|
||||
expect(console.error).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
|
@ -161,132 +164,186 @@ describe('SimpleWebRequest', () => {
|
|||
const onSuccessCritical2 = jasmine.createSpy('onSuccessCritical2');
|
||||
const status = 200;
|
||||
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Low }).start().then(onSuccessLow1);
|
||||
const p1 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Low })
|
||||
.start().then(onSuccessLow1);
|
||||
jasmine.clock().tick(10);
|
||||
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Critical }).start().then(onSuccessCritical1);
|
||||
const p2 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Critical })
|
||||
.start().then(onSuccessCritical1);
|
||||
jasmine.clock().tick(10);
|
||||
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Low }).start().then(onSuccessLow2);
|
||||
const p3 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Low })
|
||||
.start().then(onSuccessLow2);
|
||||
jasmine.clock().tick(10);
|
||||
|
||||
SimpleWebRequestOptions.MaxSimultaneousRequests = 1;
|
||||
// add a new request to kick the queue
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Critical }).start().then(onSuccessCritical2);
|
||||
const p4 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Critical })
|
||||
.start().then(onSuccessCritical2);
|
||||
|
||||
// only one is executed
|
||||
expect(jasmine.Ajax.requests.count()).toBe(1);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
// they're executed in correct order
|
||||
expect(onSuccessCritical1).toHaveBeenCalled();
|
||||
asyncTick().then(() => {
|
||||
// only one is executed
|
||||
expect(jasmine.Ajax.requests.count()).toBe(1);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
expect(onSuccessCritical2).toHaveBeenCalled();
|
||||
return p2.then(() => {
|
||||
// they're executed in correct order
|
||||
expect(onSuccessCritical1).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(2);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
expect(onSuccessLow1).toHaveBeenCalled();
|
||||
return p4;
|
||||
}).then(() => {
|
||||
expect(onSuccessCritical2).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(3);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
expect(onSuccessLow2).toHaveBeenCalled();
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccessLow1).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(4);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({status});
|
||||
|
||||
return p3;
|
||||
}).then(() => {
|
||||
expect(onSuccessLow2).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('blocks the request with custom promise', () => {
|
||||
SimpleWebRequestOptions.MaxSimultaneousRequests = 1;
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
const blockDefer = SyncTasks.Defer<void>();
|
||||
let blockResolver: () => void = () => undefined;
|
||||
const blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
const onSuccess1 = jasmine.createSpy('onSuccess1');
|
||||
new SimpleWebRequest<string>(url, method, {}, undefined, () => blockDefer.promise()).start().then(onSuccess1);
|
||||
const p1 = new SimpleWebRequest<string>(method, url, {}, undefined, () => blockPromise).start().then(onSuccess1);
|
||||
|
||||
expect(jasmine.Ajax.requests.count()).toBe(0);
|
||||
blockDefer.resolve(void 0);
|
||||
asyncTick().then(() => {
|
||||
expect(jasmine.Ajax.requests.count()).toBe(0);
|
||||
blockResolver();
|
||||
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: 200 });
|
||||
expect(onSuccess1).toHaveBeenCalled();
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
const request = jasmine.Ajax.requests.mostRecent();
|
||||
request.respondWith({ status: 200 });
|
||||
});
|
||||
|
||||
return p1.then(() => {
|
||||
expect(onSuccess1).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('after the request is unblocked, it\'s returned to the queue with correct priority', () => {
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
const blockDefer = SyncTasks.Defer<void>();
|
||||
let blockResolver: () => void = () => undefined;
|
||||
const blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
const onSuccessHigh = jasmine.createSpy('onSuccessHigh');
|
||||
const onSuccessLow = jasmine.createSpy('onSuccessLow');
|
||||
const onSuccessCritical = jasmine.createSpy('onSuccessCritical');
|
||||
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.High }, undefined, () => blockDefer.promise())
|
||||
const p1 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.High }, undefined, () => blockPromise)
|
||||
.start()
|
||||
.then(onSuccessHigh);
|
||||
jasmine.clock().tick(10);
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Low }).start().then(onSuccessLow);
|
||||
const p2 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Low }).start().then(onSuccessLow);
|
||||
jasmine.clock().tick(10);
|
||||
|
||||
SimpleWebRequestOptions.MaxSimultaneousRequests = 1;
|
||||
// add a new request to kick the queue
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Critical }).start().then(onSuccessCritical);
|
||||
const p3 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Critical }).start().then(onSuccessCritical);
|
||||
|
||||
// unblock the request
|
||||
blockDefer.resolve(void 0);
|
||||
blockResolver();
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
// first the critical one gets sent
|
||||
expect(onSuccessCritical).toHaveBeenCalled();
|
||||
// have to do an awkward async tick to get the blocking blocker to resolve before the request goes out
|
||||
asyncTick().then(() => {
|
||||
expect(jasmine.Ajax.requests.count()).toBe(1);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
});
|
||||
|
||||
// then the high, which was returned to the queue at after getting unblocked
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
expect(onSuccessHigh).toHaveBeenCalled();
|
||||
return p3.then(() => {
|
||||
// first the critical one gets sent
|
||||
expect(onSuccessCritical).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(2);
|
||||
|
||||
// and the low priority one gets sent last
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
expect(onSuccessLow).toHaveBeenCalled();
|
||||
// then the high, which was returned to the queue at after getting unblocked
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccessHigh).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(3);
|
||||
|
||||
// and the low priority one gets sent last
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
|
||||
return p2;
|
||||
}).then(() => {
|
||||
expect(onSuccessLow).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('checks the blocked function again, once the request is on top of the queue', () => {
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
const blockDefer = SyncTasks.Defer<void>();
|
||||
let blockResolver: () => void = () => undefined;
|
||||
const blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
const onSuccessCritical = jasmine.createSpy('onSuccessCritical');
|
||||
const onSuccessHigh = jasmine.createSpy('onSuccessHigh');
|
||||
const onSuccessHigh2 = jasmine.createSpy('onSuccessHigh2');
|
||||
const blockSpy = jasmine.createSpy('blockSpy').and.callFake(() => blockDefer.promise());
|
||||
const blockSpy = jasmine.createSpy('blockSpy').and.callFake(() => blockPromise);
|
||||
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Critical }, undefined, blockSpy)
|
||||
const p1 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Critical }, undefined, blockSpy)
|
||||
.start()
|
||||
.then(onSuccessCritical);
|
||||
jasmine.clock().tick(10);
|
||||
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.High }).start().then(onSuccessHigh);
|
||||
const p2 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.High }).start().then(onSuccessHigh);
|
||||
jasmine.clock().tick(10);
|
||||
|
||||
SimpleWebRequestOptions.MaxSimultaneousRequests = 1;
|
||||
// add a new request to kick the queue
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.High }).start().then(onSuccessHigh2);
|
||||
const p3 = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.High }).start().then(onSuccessHigh2);
|
||||
|
||||
expect(blockSpy).toHaveBeenCalled();
|
||||
asyncTick().then(() => {
|
||||
expect(blockSpy).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(1);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
expect(onSuccessHigh).toHaveBeenCalled();
|
||||
return p2.then(() => {
|
||||
expect(onSuccessHigh).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(2);
|
||||
|
||||
// unblock the request, it will go back to the queue after the currently executed request
|
||||
blockDefer.resolve(void 0);
|
||||
// unblock the request, it will go back to the queue after the currently executed request
|
||||
blockResolver();
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
expect(onSuccessHigh2).toHaveBeenCalled();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
|
||||
// check if the request at the top of the queue got called again
|
||||
expect(blockSpy).toHaveBeenCalledTimes(2);
|
||||
return p3;
|
||||
}).then(() => {
|
||||
expect(onSuccessHigh2).toHaveBeenCalled();
|
||||
expect(jasmine.Ajax.requests.count()).toBe(3);
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
expect(onSuccessCritical).toHaveBeenCalled();
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200 });
|
||||
|
||||
return p1;
|
||||
}).then(() => {
|
||||
expect(onSuccessCritical).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails the request, if the blocking promise rejects', done => {
|
||||
SimpleWebRequestOptions.MaxSimultaneousRequests = 1;
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
const blockDefer = SyncTasks.Defer<void>();
|
||||
let blockRejecter: (err: any) => void = () => undefined;
|
||||
const blockPromise = new Promise<void>((res, rej) => { blockRejecter = rej; });
|
||||
const errorString = 'Terrible error';
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Critical }, undefined, () => blockDefer.promise())
|
||||
new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Critical }, undefined, () => blockPromise)
|
||||
.start()
|
||||
.then(() => fail(), (err: WebErrorResponse) => {
|
||||
expect(err.statusCode).toBe(0);
|
||||
|
@ -294,21 +351,30 @@ describe('SimpleWebRequest', () => {
|
|||
done();
|
||||
});
|
||||
|
||||
blockDefer.reject(errorString);
|
||||
blockRejecter(errorString);
|
||||
});
|
||||
|
||||
it('does not attempt to fire aborted request, if it was aborted while blocked', () => {
|
||||
SimpleWebRequestOptions.MaxSimultaneousRequests = 1;
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
const blockDefer = SyncTasks.Defer<void>();
|
||||
new SimpleWebRequest<string>(url, method, { priority: WebRequestPriority.Critical }, undefined, () => blockDefer.promise())
|
||||
.start()
|
||||
.cancel();
|
||||
|
||||
blockDefer.resolve(void 0);
|
||||
expect(jasmine.Ajax.requests.count()).toBe(0);
|
||||
let blockResolver: () => void = () => undefined;
|
||||
const blockPromise = new Promise<void>((res, rej) => { blockResolver = res; });
|
||||
const req = new SimpleWebRequest<string>(method, url, { priority: WebRequestPriority.Critical }, undefined, () => blockPromise);
|
||||
const p1 = req.start();
|
||||
|
||||
return asyncTick().then(() => {
|
||||
expect(jasmine.Ajax.requests.count()).toBe(0);
|
||||
req.abort();
|
||||
return asyncTick();
|
||||
}).then(() => {
|
||||
blockResolver();
|
||||
return p1;
|
||||
}).then(() => {
|
||||
fail();
|
||||
}, () => {
|
||||
expect(jasmine.Ajax.requests.count()).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -324,7 +390,7 @@ describe('SimpleWebRequest', () => {
|
|||
it('fails the request with "timedOut: true" if it times out without retries', done => {
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
new SimpleWebRequest<string>(url, method, { timeout: 10, customErrorHandler: () => ErrorHandlingType.DoNotRetry })
|
||||
new SimpleWebRequest<string>(method, url, { timeout: 10, customErrorHandler: () => ErrorHandlingType.DoNotRetry })
|
||||
.start()
|
||||
.then(() => {
|
||||
expect(false).toBeTruthy();
|
||||
|
@ -335,17 +401,20 @@ describe('SimpleWebRequest', () => {
|
|||
done();
|
||||
});
|
||||
|
||||
jasmine.clock().tick(10);
|
||||
asyncTick().then(() => {
|
||||
jasmine.clock().tick(10);
|
||||
});
|
||||
});
|
||||
|
||||
it('timedOut flag is reset on retry', done => {
|
||||
const url = faker.internet.url();
|
||||
const method = 'GET';
|
||||
const requestPromise = new SimpleWebRequest<string>(url, method, {
|
||||
const req = new SimpleWebRequest<string>(method, url, {
|
||||
timeout: 10,
|
||||
retries: 1,
|
||||
customErrorHandler: () => ErrorHandlingType.RetryCountedWithBackoff,
|
||||
}).start();
|
||||
});
|
||||
const requestPromise = req.start();
|
||||
|
||||
requestPromise
|
||||
.then(() => {
|
||||
|
@ -359,8 +428,10 @@ describe('SimpleWebRequest', () => {
|
|||
});
|
||||
|
||||
// first try will time out, the second one will be aborted
|
||||
jasmine.clock().tick(10);
|
||||
requestPromise.cancel();
|
||||
asyncTick().then(() => {
|
||||
jasmine.clock().tick(10);
|
||||
req.abort();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -20,3 +20,10 @@ export const DETAILED_RESPONSE = {
|
|||
body: '',
|
||||
url: '',
|
||||
};
|
||||
|
||||
export function asyncTick(): Promise<void> {
|
||||
return new Promise((res, rej) => {
|
||||
setTimeout(res, 0);
|
||||
jasmine.clock().tick(10);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"noUnusedLocals": true,
|
||||
"declaration": true,
|
||||
"noResolve": false,
|
||||
"sourceMap": true,
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"outDir": "dist",
|
||||
|
|
Загрузка…
Ссылка в новой задаче