Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { HttpBackend } from './src/common-http/src/backend';
import { Type } from 'injection-js/facade/type';
import { HTTP_INTERCEPTORS } from './src/common-http/src/interceptor';

require('zone.js');

export const HTTP_CLIENT_PROVIDERS: Provider[] = [
...SERVER_HTTP_PROVIDERS,
HttpClient,
Expand Down
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-angular-http-client",
"version": "1.1.7",
"version": "1.1.8",
"description": "The Angular 4.3 HttpClient for node.js",
"keywords": [
"Angular",
Expand All @@ -12,24 +12,27 @@
"HTTP",
"fetch"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"main": "index.js",
"types": "index.d.ts",
"author": "Ionut Costica <ionut.costica@gmail.com>",
"license": "MIT",
"repository": "https://github.com/souldreamer/http-client.git",
"dependencies": {
"injection-js": "^2.1.0",
"rxjs": "^5.5.2",
"xhr2-cookies": "^1.1.0",
"xhr2-cookies": "^1.1.0"
},
"peerDependencies": {
"zone.js": "^0.8.18"
},
"devDependencies": {
"@types/node": "^8.0.51",
"ts-loader": "^3.1.1",
"typescript": "^2.6.1",
"webpack": "^3.8.1"
"webpack": "^3.8.1",
"rimraf": "^2.6.0"
},
"scripts": {
"prepare": "tsc"
"prepare": "rimraf dist && tsc && cp package.json dist"
}
}
9 changes: 9 additions & 0 deletions src/common-http-testing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

export * from './public_api';
11 changes: 11 additions & 0 deletions src/common-http-testing/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

export {HttpTestingController, RequestMatch} from './src/api';
export {TESTING_HTTP_PROVIDERS} from './src/module';
export {TestRequest} from './src/request';
116 changes: 116 additions & 0 deletions src/common-http-testing/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {HttpRequest} from '../../common-http';
import {TestRequest} from './request';

/**
* Defines a matcher for requests based on URL, method, or both.
*
* @stable
*/
export interface RequestMatch {
method?: string;
url?: string;
}

/**
* Controller to be injected into tests, that allows for mocking and flushing
* of requests.
*
* @stable
*/
export abstract class HttpTestingController {
/**
* Search for requests that match the given parameter, without any expectations.
*/
abstract match(match: string|RequestMatch|((req: HttpRequest<any>) => boolean)): TestRequest[];

/**
* Expect that a single request has been made which matches the given URL, and return its
* mock.
*
* If no such request has been made, or more than one such request has been made, fail with an
* error message including the given request description, if any.
*/
abstract expectOne(url: string, description?: string): TestRequest;

/**
* Expect that a single request has been made which matches the given parameters, and return
* its mock.
*
* If no such request has been made, or more than one such request has been made, fail with an
* error message including the given request description, if any.
*/
abstract expectOne(params: RequestMatch, description?: string): TestRequest;

/**
* Expect that a single request has been made which matches the given predicate function, and
* return its mock.
*
* If no such request has been made, or more than one such request has been made, fail with an
* error message including the given request description, if any.
*/
abstract expectOne(matchFn: ((req: HttpRequest<any>) => boolean), description?: string):
TestRequest;

/**
* Expect that a single request has been made which matches the given condition, and return
* its mock.
*
* If no such request has been made, or more than one such request has been made, fail with an
* error message including the given request description, if any.
*/
abstract expectOne(
match: string|RequestMatch|((req: HttpRequest<any>) => boolean),
description?: string): TestRequest;

/**
* Expect that no requests have been made which match the given URL.
*
* If a matching request has been made, fail with an error message including the given request
* description, if any.
*/
abstract expectNone(url: string, description?: string): void;

/**
* Expect that no requests have been made which match the given parameters.
*
* If a matching request has been made, fail with an error message including the given request
* description, if any.
*/
abstract expectNone(params: RequestMatch, description?: string): void;

/**
* Expect that no requests have been made which match the given predicate function.
*
* If a matching request has been made, fail with an error message including the given request
* description, if any.
*/
abstract expectNone(matchFn: ((req: HttpRequest<any>) => boolean), description?: string): void;

/**
* Expect that no requests have been made which match the given condition.
*
* If a matching request has been made, fail with an error message including the given request
* description, if any.
*/
abstract expectNone(
match: string|RequestMatch|((req: HttpRequest<any>) => boolean), description?: string): void;

/**
* Verify that no unmatched requests are outstanding.
*
* If any requests are outstanding, fail with an error message indicating which requests were not
* handled.
*
* If `ignoreCancelled` is not set (the default), `verify()` will also fail if cancelled requests
* were not explicitly matched.
*/
abstract verify(opts?: {ignoreCancelled?: boolean}): void;
}
149 changes: 149 additions & 0 deletions src/common-http-testing/src/backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {HttpBackend, HttpEvent, HttpEventType, HttpRequest} from '../../common-http';
import {Injectable} from 'injection-js';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import {startWith} from 'rxjs/operator/startWith';

import {HttpTestingController, RequestMatch} from './api';
import {TestRequest} from './request';


/**
* A testing backend for `HttpClient` which both acts as an `HttpBackend`
* and as the `HttpTestingController`.
*
* `HttpClientTestingBackend` works by keeping a list of all open requests.
* As requests come in, they're added to the list. Users can assert that specific
* requests were made and then flush them. In the end, a verify() method asserts
* that no unexpected requests were made.
*
* @stable
*/
@Injectable()
export class HttpClientTestingBackend implements HttpBackend, HttpTestingController {
/**
* List of pending requests which have not yet been expected.
*/
private open: TestRequest[] = [];

/**
* Handle an incoming request by queueing it in the list of open requests.
*/
handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
console.log("HttpClient: ", req.url);
return new Observable((observer: Observer<any>) => {
const testReq = new TestRequest(req, observer);
this.open.push(testReq);
observer.next({ type: HttpEventType.Sent } as HttpEvent<any>);
return () => { testReq._cancelled = true; };
});
}

/**
* Helper function to search for requests in the list of open requests.
*/
private _match(match: string|RequestMatch|((req: HttpRequest<any>) => boolean)): TestRequest[] {
if (typeof match === 'string') {
return this.open.filter(testReq => testReq.request.urlWithParams === match);
} else if (typeof match === 'function') {
return this.open.filter(testReq => match(testReq.request));
} else {
return this.open.filter(
testReq => (!match.method || testReq.request.method === match.method.toUpperCase()) &&
(!match.url || testReq.request.urlWithParams === match.url));
}
}

/**
* Search for requests in the list of open requests, and return all that match
* without asserting anything about the number of matches.
*/
match(match: string|RequestMatch|((req: HttpRequest<any>) => boolean)): TestRequest[] {
const results = this._match(match);
results.forEach(result => {
const index = this.open.indexOf(result);
if (index !== -1) {
this.open.splice(index, 1);
}
});
return results;
}

/**
* Expect that a single outstanding request matches the given matcher, and return
* it.
*
* Requests returned through this API will no longer be in the list of open requests,
* and thus will not match twice.
*/
expectOne(match: string|RequestMatch|((req: HttpRequest<any>) => boolean), description?: string):
TestRequest {
description = description || this.descriptionFromMatcher(match);
const matches = this.match(match);
if (matches.length > 1) {
throw new Error(
`Expected one matching request for criteria "${description}", found ${matches.length} requests.`);
}
if (matches.length === 0) {
throw new Error(`Expected one matching request for criteria "${description}", found none.`);
}
return matches[0];
}

/**
* Expect that no outstanding requests match the given matcher, and throw an error
* if any do.
*/
expectNone(match: string|RequestMatch|((req: HttpRequest<any>) => boolean), description?: string):
void {
description = description || this.descriptionFromMatcher(match);
const matches = this.match(match);
if (matches.length > 0) {
throw new Error(
`Expected zero matching requests for criteria "${description}", found ${matches.length}.`);
}
}

/**
* Validate that there are no outstanding requests.
*/
verify(opts: {ignoreCancelled?: boolean} = {}): void {
let open = this.open;
// It's possible that some requests may be cancelled, and this is expected.
// The user can ask to ignore open requests which have been cancelled.
if (opts.ignoreCancelled) {
open = open.filter(testReq => !testReq.cancelled);
}
if (open.length > 0) {
// Show the methods and URLs of open requests in the error, for convenience.
const requests = open.map(testReq => {
const url = testReq.request.urlWithParams.split('?')[0];
const method = testReq.request.method;
return `${method} ${url}`;
})
.join(', ');
throw new Error(`Expected no open requests, found ${open.length}: ${requests}`);
}
}

private descriptionFromMatcher(matcher: string|RequestMatch|
((req: HttpRequest<any>) => boolean)): string {
if (typeof matcher === 'string') {
return `Match URL: ${matcher}`;
} else if (typeof matcher === 'object') {
const method = matcher.method || '(any)';
const url = matcher.url || '(any)';
return `Match method: ${method}, URL: ${url}`;
} else {
return `Match by function: ${matcher.name}`;
}
}
}
20 changes: 20 additions & 0 deletions src/common-http-testing/src/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { HTTP_CLIENT_PROVIDERS } from './../../../index';
import { ReflectiveInjector } from 'injection-js';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {HttpBackend} from '../../common-http';

import {HttpTestingController} from './api';
import {HttpClientTestingBackend} from './backend';

export const TESTING_HTTP_PROVIDERS = [
HttpClientTestingBackend,
{provide: HttpBackend, useExisting: HttpClientTestingBackend},
{provide: HttpTestingController, useExisting: HttpClientTestingBackend},
];
Loading