File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ export class HttpHeaders {
|
||||
* Internal map of lowercase header names to values.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private headers !: Map<string, string[]>;
|
||||
private headers!: Map<string, string[]>;
|
||||
|
||||
|
||||
/**
|
||||
@ -36,7 +36,7 @@ export class HttpHeaders {
|
||||
/**
|
||||
* Complete the lazy initialization of this object (needed before reading).
|
||||
*/
|
||||
private lazyInit !: HttpHeaders | Function | null;
|
||||
private lazyInit!: HttpHeaders|Function|null;
|
||||
|
||||
/**
|
||||
* Queued updates to be materialized the next initialization.
|
||||
@ -59,7 +59,7 @@ export class HttpHeaders {
|
||||
const value = line.slice(index + 1).trim();
|
||||
this.maybeSetNormalizedName(name, key);
|
||||
if (this.headers.has(key)) {
|
||||
this.headers.get(key) !.push(value);
|
||||
this.headers.get(key)!.push(value);
|
||||
} else {
|
||||
this.headers.set(key, [value]);
|
||||
}
|
||||
@ -169,7 +169,7 @@ export class HttpHeaders {
|
||||
*
|
||||
* @returns A clone of the HTTP headers object with the given value deleted.
|
||||
*/
|
||||
delete (name: string, value?: string|string[]): HttpHeaders {
|
||||
delete(name: string, value?: string|string[]): HttpHeaders {
|
||||
return this.clone({name, value, op: 'd'});
|
||||
}
|
||||
|
||||
@ -197,8 +197,8 @@ export class HttpHeaders {
|
||||
private copyFrom(other: HttpHeaders) {
|
||||
other.init();
|
||||
Array.from(other.headers.keys()).forEach(key => {
|
||||
this.headers.set(key, other.headers.get(key) !);
|
||||
this.normalizedNames.set(key, other.normalizedNames.get(key) !);
|
||||
this.headers.set(key, other.headers.get(key)!);
|
||||
this.normalizedNames.set(key, other.normalizedNames.get(key)!);
|
||||
});
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ export class HttpHeaders {
|
||||
switch (update.op) {
|
||||
case 'a':
|
||||
case 's':
|
||||
let value = update.value !;
|
||||
let value = update.value!;
|
||||
if (typeof value === 'string') {
|
||||
value = [value];
|
||||
}
|
||||
@ -255,6 +255,6 @@ export class HttpHeaders {
|
||||
forEach(fn: (name: string, values: string[]) => void) {
|
||||
this.init();
|
||||
Array.from(this.normalizedNames.keys())
|
||||
.forEach(key => fn(this.normalizedNames.get(key) !, this.headers.get(key) !));
|
||||
.forEach(key => fn(this.normalizedNames.get(key)!, this.headers.get(key)!));
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ import {HttpEvent} from './response';
|
||||
* To use the same instance of `HttpInterceptors` for the entire app, import the `HttpClientModule`
|
||||
* only in your `AppModule`, and add the interceptors to the root application injector .
|
||||
* If you import `HttpClientModule` multiple times across different modules (for example, in lazy
|
||||
* loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the interceptors
|
||||
* provided in the root module.
|
||||
* loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the
|
||||
* interceptors provided in the root module.
|
||||
*
|
||||
*/
|
||||
export interface HttpInterceptor {
|
||||
|
@ -36,7 +36,9 @@ export const JSONP_ERR_WRONG_RESPONSE_TYPE = 'JSONP requests must use Json respo
|
||||
*
|
||||
*
|
||||
*/
|
||||
export abstract class JsonpCallbackContext { [key: string]: (data: any) => void; }
|
||||
export abstract class JsonpCallbackContext {
|
||||
[key: string]: (data: any) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an `HttpRequest` with the JSONP method,
|
||||
@ -53,7 +55,9 @@ export class JsonpClientBackend implements HttpBackend {
|
||||
/**
|
||||
* Get the name of the next callback method, by incrementing the global `nextRequestId`.
|
||||
*/
|
||||
private nextCallback(): string { return `ng_jsonp_callback_${nextRequestId++}`; }
|
||||
private nextCallback(): string {
|
||||
return `ng_jsonp_callback_${nextRequestId++}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a JSONP request and returns an event stream of the results.
|
||||
@ -157,7 +161,8 @@ export class JsonpClientBackend implements HttpBackend {
|
||||
observer.next(new HttpResponse({
|
||||
body,
|
||||
status: 200,
|
||||
statusText: 'OK', url,
|
||||
statusText: 'OK',
|
||||
url,
|
||||
}));
|
||||
|
||||
// Complete the stream, the response is over.
|
||||
@ -178,7 +183,8 @@ export class JsonpClientBackend implements HttpBackend {
|
||||
observer.error(new HttpErrorResponse({
|
||||
error,
|
||||
status: 0,
|
||||
statusText: 'JSONP Error', url,
|
||||
statusText: 'JSONP Error',
|
||||
url,
|
||||
}));
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ export class HttpInterceptingHandler implements HttpHandler {
|
||||
*
|
||||
*/
|
||||
export function interceptingHandler(
|
||||
backend: HttpBackend, interceptors: HttpInterceptor[] | null = []): HttpHandler {
|
||||
backend: HttpBackend, interceptors: HttpInterceptor[]|null = []): HttpHandler {
|
||||
if (!interceptors) {
|
||||
return backend;
|
||||
}
|
||||
|
@ -37,28 +37,36 @@ export class HttpUrlEncodingCodec implements HttpParameterCodec {
|
||||
* @param key The key name.
|
||||
* @returns The encoded key name.
|
||||
*/
|
||||
encodeKey(key: string): string { return standardEncoding(key); }
|
||||
encodeKey(key: string): string {
|
||||
return standardEncoding(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the value of a URL parameter or query-string.
|
||||
* @param value The value.
|
||||
* @returns The encoded value.
|
||||
*/
|
||||
encodeValue(value: string): string { return standardEncoding(value); }
|
||||
encodeValue(value: string): string {
|
||||
return standardEncoding(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an encoded URL parameter or query-string key.
|
||||
* @param key The encoded key name.
|
||||
* @returns The decoded key name.
|
||||
*/
|
||||
decodeKey(key: string): string { return decodeURIComponent(key); }
|
||||
decodeKey(key: string): string {
|
||||
return decodeURIComponent(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an encoded URL parameter or query-string value.
|
||||
* @param value The encoded value.
|
||||
* @returns The decoded value.
|
||||
*/
|
||||
decodeValue(value: string) { return decodeURIComponent(value); }
|
||||
decodeValue(value: string) {
|
||||
return decodeURIComponent(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -97,7 +105,8 @@ interface Update {
|
||||
op: 'a'|'d'|'s';
|
||||
}
|
||||
|
||||
/** Options used to construct an `HttpParams` instance.
|
||||
/**
|
||||
* Options used to construct an `HttpParams` instance.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
@ -109,7 +118,7 @@ export interface HttpParamsOptions {
|
||||
fromString?: string;
|
||||
|
||||
/** Object map of the HTTP parameters. Mutually exclusive with `fromString`. */
|
||||
fromObject?: {[param: string]: string | ReadonlyArray<string>};
|
||||
fromObject?: {[param: string]: string|ReadonlyArray<string>};
|
||||
|
||||
/** Encoding codec used to parse and serialize the parameters. */
|
||||
encoder?: HttpParameterCodec;
|
||||
@ -140,7 +149,7 @@ export class HttpParams {
|
||||
this.map = new Map<string, string[]>();
|
||||
Object.keys(options.fromObject).forEach(key => {
|
||||
const value = (options.fromObject as any)[key];
|
||||
this.map !.set(key, Array.isArray(value) ? value : [value]);
|
||||
this.map!.set(key, Array.isArray(value) ? value : [value]);
|
||||
});
|
||||
} else {
|
||||
this.map = null;
|
||||
@ -155,7 +164,7 @@ export class HttpParams {
|
||||
*/
|
||||
has(param: string): boolean {
|
||||
this.init();
|
||||
return this.map !.has(param);
|
||||
return this.map!.has(param);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,7 +175,7 @@ export class HttpParams {
|
||||
*/
|
||||
get(param: string): string|null {
|
||||
this.init();
|
||||
const res = this.map !.get(param);
|
||||
const res = this.map!.get(param);
|
||||
return !!res ? res[0] : null;
|
||||
}
|
||||
|
||||
@ -178,7 +187,7 @@ export class HttpParams {
|
||||
*/
|
||||
getAll(param: string): string[]|null {
|
||||
this.init();
|
||||
return this.map !.get(param) || null;
|
||||
return this.map!.get(param) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,7 +196,7 @@ export class HttpParams {
|
||||
*/
|
||||
keys(): string[] {
|
||||
this.init();
|
||||
return Array.from(this.map !.keys());
|
||||
return Array.from(this.map!.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,7 +205,9 @@ export class HttpParams {
|
||||
* @param value The new value to add.
|
||||
* @return A new body with the appended value.
|
||||
*/
|
||||
append(param: string, value: string): HttpParams { return this.clone({param, value, op: 'a'}); }
|
||||
append(param: string, value: string): HttpParams {
|
||||
return this.clone({param, value, op: 'a'});
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the value for a parameter.
|
||||
@ -204,7 +215,9 @@ export class HttpParams {
|
||||
* @param value The new value.
|
||||
* @return A new body with the new value.
|
||||
*/
|
||||
set(param: string, value: string): HttpParams { return this.clone({param, value, op: 's'}); }
|
||||
set(param: string, value: string): HttpParams {
|
||||
return this.clone({param, value, op: 's'});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given value or all values from a parameter.
|
||||
@ -213,7 +226,9 @@ export class HttpParams {
|
||||
* @return A new body with the given value removed, or with all values
|
||||
* removed if no value is specified.
|
||||
*/
|
||||
delete (param: string, value?: string): HttpParams { return this.clone({param, value, op: 'd'}); }
|
||||
delete(param: string, value?: string): HttpParams {
|
||||
return this.clone({param, value, op: 'd'});
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the body to an encoded string, where key-value pairs (separated by `=`) are
|
||||
@ -227,7 +242,7 @@ export class HttpParams {
|
||||
// `a: ['1']` produces `'a=1'`
|
||||
// `b: []` produces `''`
|
||||
// `c: ['1', '2']` produces `'c=1&c=2'`
|
||||
return this.map !.get(key) !.map(value => eKey + '=' + this.encoder.encodeValue(value))
|
||||
return this.map!.get(key)!.map(value => eKey + '=' + this.encoder.encodeValue(value))
|
||||
.join('&');
|
||||
})
|
||||
// filter out empty values because `b: []` produces `''`
|
||||
@ -237,7 +252,7 @@ export class HttpParams {
|
||||
}
|
||||
|
||||
private clone(update: Update): HttpParams {
|
||||
const clone = new HttpParams({ encoder: this.encoder } as HttpParamsOptions);
|
||||
const clone = new HttpParams({encoder: this.encoder} as HttpParamsOptions);
|
||||
clone.cloneFrom = this.cloneFrom || this;
|
||||
clone.updates = (this.updates || []).concat([update]);
|
||||
return clone;
|
||||
@ -249,29 +264,29 @@ export class HttpParams {
|
||||
}
|
||||
if (this.cloneFrom !== null) {
|
||||
this.cloneFrom.init();
|
||||
this.cloneFrom.keys().forEach(key => this.map !.set(key, this.cloneFrom !.map !.get(key) !));
|
||||
this.updates !.forEach(update => {
|
||||
this.cloneFrom.keys().forEach(key => this.map!.set(key, this.cloneFrom!.map!.get(key)!));
|
||||
this.updates!.forEach(update => {
|
||||
switch (update.op) {
|
||||
case 'a':
|
||||
case 's':
|
||||
const base = (update.op === 'a' ? this.map !.get(update.param) : undefined) || [];
|
||||
base.push(update.value !);
|
||||
this.map !.set(update.param, base);
|
||||
const base = (update.op === 'a' ? this.map!.get(update.param) : undefined) || [];
|
||||
base.push(update.value!);
|
||||
this.map!.set(update.param, base);
|
||||
break;
|
||||
case 'd':
|
||||
if (update.value !== undefined) {
|
||||
let base = this.map !.get(update.param) || [];
|
||||
let base = this.map!.get(update.param) || [];
|
||||
const idx = base.indexOf(update.value);
|
||||
if (idx !== -1) {
|
||||
base.splice(idx, 1);
|
||||
}
|
||||
if (base.length > 0) {
|
||||
this.map !.set(update.param, base);
|
||||
this.map!.set(update.param, base);
|
||||
} else {
|
||||
this.map !.delete(update.param);
|
||||
this.map!.delete(update.param);
|
||||
}
|
||||
} else {
|
||||
this.map !.delete(update.param);
|
||||
this.map!.delete(update.param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export class HttpRequest<T> {
|
||||
* Outgoing headers for this request.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
readonly headers !: HttpHeaders;
|
||||
readonly headers!: HttpHeaders;
|
||||
|
||||
/**
|
||||
* Whether this request should be made in a way that exposes progress events.
|
||||
@ -121,7 +121,7 @@ export class HttpRequest<T> {
|
||||
* Outgoing URL parameters.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
readonly params !: HttpParams;
|
||||
readonly params!: HttpParams;
|
||||
|
||||
/**
|
||||
* The outgoing URL with all URL parameters set.
|
||||
@ -312,7 +312,7 @@ export class HttpRequest<T> {
|
||||
body?: T|null,
|
||||
method?: string,
|
||||
url?: string,
|
||||
setHeaders?: {[name: string]: string | string[]},
|
||||
setHeaders?: {[name: string]: string|string[]},
|
||||
setParams?: {[param: string]: string},
|
||||
}): HttpRequest<T>;
|
||||
clone<V>(update: {
|
||||
@ -324,7 +324,7 @@ export class HttpRequest<T> {
|
||||
body?: V|null,
|
||||
method?: string,
|
||||
url?: string,
|
||||
setHeaders?: {[name: string]: string | string[]},
|
||||
setHeaders?: {[name: string]: string|string[]},
|
||||
setParams?: {[param: string]: string},
|
||||
}): HttpRequest<V>;
|
||||
clone(update: {
|
||||
@ -336,7 +336,7 @@ export class HttpRequest<T> {
|
||||
body?: any|null,
|
||||
method?: string,
|
||||
url?: string,
|
||||
setHeaders?: {[name: string]: string | string[]},
|
||||
setHeaders?: {[name: string]: string|string[]},
|
||||
setParams?: {[param: string]: string};
|
||||
} = {}): HttpRequest<any> {
|
||||
// For method, url, and responseType, take the current value unless
|
||||
@ -368,20 +368,23 @@ export class HttpRequest<T> {
|
||||
// Set every requested header.
|
||||
headers =
|
||||
Object.keys(update.setHeaders)
|
||||
.reduce((headers, name) => headers.set(name, update.setHeaders ![name]), headers);
|
||||
.reduce((headers, name) => headers.set(name, update.setHeaders![name]), headers);
|
||||
}
|
||||
|
||||
// Check whether the caller has asked to set params.
|
||||
if (update.setParams) {
|
||||
// Set every requested param.
|
||||
params = Object.keys(update.setParams)
|
||||
.reduce((params, param) => params.set(param, update.setParams ![param]), params);
|
||||
.reduce((params, param) => params.set(param, update.setParams![param]), params);
|
||||
}
|
||||
|
||||
// Finally, construct the new HttpRequest using the pieces from above.
|
||||
return new HttpRequest(
|
||||
method, url, body, {
|
||||
params, headers, reportProgress, responseType, withCredentials,
|
||||
});
|
||||
return new HttpRequest(method, url, body, {
|
||||
params,
|
||||
headers,
|
||||
reportProgress,
|
||||
responseType,
|
||||
withCredentials,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,9 @@ export interface HttpUploadProgressEvent extends HttpProgressEvent {
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export interface HttpSentEvent { type: HttpEventType.Sent; }
|
||||
export interface HttpSentEvent {
|
||||
type: HttpEventType.Sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined event.
|
||||
@ -110,7 +112,9 @@ export interface HttpSentEvent { type: HttpEventType.Sent; }
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export interface HttpUserEvent<T> { type: HttpEventType.User; }
|
||||
export interface HttpUserEvent<T> {
|
||||
type: HttpEventType.User;
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that represents a failed attempt to JSON.parse text coming back
|
||||
@ -133,7 +137,7 @@ export interface HttpJsonParseError {
|
||||
* @publicApi
|
||||
*/
|
||||
export type HttpEvent<T> =
|
||||
HttpSentEvent | HttpHeaderResponse | HttpResponse<T>| HttpProgressEvent | HttpUserEvent<T>;
|
||||
HttpSentEvent|HttpHeaderResponse|HttpResponse<T>|HttpProgressEvent|HttpUserEvent<T>;
|
||||
|
||||
/**
|
||||
* Base class for both `HttpResponse` and `HttpHeaderResponse`.
|
||||
@ -172,7 +176,7 @@ export abstract class HttpResponseBase {
|
||||
* Type of the response, narrowed to either the full response or the header.
|
||||
*/
|
||||
// TODO(issue/24571): remove '!'.
|
||||
readonly type !: HttpEventType.Response | HttpEventType.ResponseHeader;
|
||||
readonly type!: HttpEventType.Response|HttpEventType.ResponseHeader;
|
||||
|
||||
/**
|
||||
* Super-constructor for all responses.
|
||||
@ -260,7 +264,11 @@ export class HttpResponse<T> extends HttpResponseBase {
|
||||
* Construct a new `HttpResponse`.
|
||||
*/
|
||||
constructor(init: {
|
||||
body?: T | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
|
||||
body?: T|null,
|
||||
headers?: HttpHeaders;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
url?: string;
|
||||
} = {}) {
|
||||
super(init);
|
||||
this.body = init.body !== undefined ? init.body : null;
|
||||
@ -272,10 +280,18 @@ export class HttpResponse<T> extends HttpResponseBase {
|
||||
clone(update: {headers?: HttpHeaders; status?: number; statusText?: string; url?: string;}):
|
||||
HttpResponse<T>;
|
||||
clone<V>(update: {
|
||||
body?: V | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
|
||||
body?: V|null,
|
||||
headers?: HttpHeaders;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
url?: string;
|
||||
}): HttpResponse<V>;
|
||||
clone(update: {
|
||||
body?: any | null; headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
|
||||
body?: any|null;
|
||||
headers?: HttpHeaders;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
url?: string;
|
||||
} = {}): HttpResponse<any> {
|
||||
return new HttpResponse<any>({
|
||||
body: (update.body !== undefined) ? update.body : this.body,
|
||||
@ -311,7 +327,11 @@ export class HttpErrorResponse extends HttpResponseBase implements Error {
|
||||
readonly ok = false;
|
||||
|
||||
constructor(init: {
|
||||
error?: any; headers?: HttpHeaders; status?: number; statusText?: string; url?: string;
|
||||
error?: any;
|
||||
headers?: HttpHeaders;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
url?: string;
|
||||
}) {
|
||||
// Initialize with a default status of 0 / Unknown Error.
|
||||
super(init, 0, 'Unknown Error');
|
||||
@ -322,8 +342,8 @@ export class HttpErrorResponse extends HttpResponseBase implements Error {
|
||||
if (this.status >= 200 && this.status < 300) {
|
||||
this.message = `Http failure during parsing for ${init.url || '(unknown url)'}`;
|
||||
} else {
|
||||
this.message =
|
||||
`Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${init.statusText}`;
|
||||
this.message = `Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${
|
||||
init.statusText}`;
|
||||
}
|
||||
this.error = init.error || null;
|
||||
}
|
||||
|
@ -35,7 +35,9 @@ function getResponseUrl(xhr: any): string|null {
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export abstract class XhrFactory { abstract build(): XMLHttpRequest; }
|
||||
export abstract class XhrFactory {
|
||||
abstract build(): XMLHttpRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory for `HttpXhrBackend` that uses the `XMLHttpRequest` browser API.
|
||||
@ -44,7 +46,9 @@ export abstract class XhrFactory { abstract build(): XMLHttpRequest; }
|
||||
@Injectable()
|
||||
export class BrowserXhr implements XhrFactory {
|
||||
constructor() {}
|
||||
build(): any { return <any>(new XMLHttpRequest()); }
|
||||
build(): any {
|
||||
return <any>(new XMLHttpRequest());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,7 +204,7 @@ export class HttpXhrBackend implements HttpBackend {
|
||||
// Even though the response status was 2xx, this is still an error.
|
||||
ok = false;
|
||||
// The parse error contains the text of the body that failed to parse.
|
||||
body = { error, text: body } as HttpJsonParseError;
|
||||
body = {error, text: body} as HttpJsonParseError;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -318,7 +322,7 @@ export class HttpXhrBackend implements HttpBackend {
|
||||
}
|
||||
|
||||
// Fire the request, and notify the event stream that it was fired.
|
||||
xhr.send(reqBody !);
|
||||
xhr.send(reqBody!);
|
||||
observer.next({type: HttpEventType.Sent});
|
||||
|
||||
// This is the return from the Observable function, which is the
|
||||
|
@ -14,13 +14,15 @@ import {toArray} from 'rxjs/operators';
|
||||
|
||||
{
|
||||
describe('HttpClient', () => {
|
||||
let client: HttpClient = null !;
|
||||
let backend: HttpClientTestingBackend = null !;
|
||||
let client: HttpClient = null!;
|
||||
let backend: HttpClientTestingBackend = null!;
|
||||
beforeEach(() => {
|
||||
backend = new HttpClientTestingBackend();
|
||||
client = new HttpClient(backend);
|
||||
});
|
||||
afterEach(() => { backend.verify(); });
|
||||
afterEach(() => {
|
||||
backend.verify();
|
||||
});
|
||||
describe('makes a basic request', () => {
|
||||
it('for JSON data', done => {
|
||||
client.get('/test').subscribe(res => {
|
||||
|
@ -10,7 +10,6 @@ import {HttpHeaders} from '@angular/common/http/src/headers';
|
||||
|
||||
{
|
||||
describe('HttpHeaders', () => {
|
||||
|
||||
describe('initialization', () => {
|
||||
it('should conform to spec', () => {
|
||||
const httpHeaders = {
|
||||
|
@ -18,19 +18,23 @@ export class MockScriptElement {
|
||||
this.listeners[event] = handler as any;
|
||||
}
|
||||
|
||||
removeEventListener(event: 'load'|'error'): void { delete this.listeners[event]; }
|
||||
removeEventListener(event: 'load'|'error'): void {
|
||||
delete this.listeners[event];
|
||||
}
|
||||
}
|
||||
|
||||
export class MockDocument {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
mock !: MockScriptElement | null;
|
||||
mock!: MockScriptElement|null;
|
||||
readonly body: any = this;
|
||||
|
||||
createElement(tag: 'script'): HTMLScriptElement {
|
||||
return new MockScriptElement() as any as HTMLScriptElement;
|
||||
}
|
||||
|
||||
appendChild(node: any): void { this.mock = node; }
|
||||
appendChild(node: any): void {
|
||||
this.mock = node;
|
||||
}
|
||||
|
||||
removeNode(node: any): void {
|
||||
if (this.mock === node) {
|
||||
@ -38,7 +42,11 @@ export class MockDocument {
|
||||
}
|
||||
}
|
||||
|
||||
mockLoad(): void { this.mock !.listeners.load !(null as any); }
|
||||
mockLoad(): void {
|
||||
this.mock!.listeners.load!(null as any);
|
||||
}
|
||||
|
||||
mockError(err: Error) { this.mock !.listeners.error !(err); }
|
||||
mockError(err: Error) {
|
||||
this.mock!.listeners.error!(err);
|
||||
}
|
||||
}
|
||||
|
@ -38,11 +38,15 @@ class TestInterceptor implements HttpInterceptor {
|
||||
}
|
||||
|
||||
class InterceptorA extends TestInterceptor {
|
||||
constructor() { super('A'); }
|
||||
constructor() {
|
||||
super('A');
|
||||
}
|
||||
}
|
||||
|
||||
class InterceptorB extends TestInterceptor {
|
||||
constructor() { super('B'); }
|
||||
constructor() {
|
||||
super('B');
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -98,7 +102,9 @@ class ReentrantInterceptor implements HttpInterceptor {
|
||||
{provide: HTTP_INTERCEPTORS, useClass: ReentrantInterceptor, multi: true},
|
||||
],
|
||||
});
|
||||
injector.get(HttpClient).get('/test').subscribe(() => { done(); });
|
||||
injector.get(HttpClient).get('/test').subscribe(() => {
|
||||
done();
|
||||
});
|
||||
injector.get(HttpTestingController).expectOne('/test').flush('ok!');
|
||||
});
|
||||
});
|
||||
|
@ -80,16 +80,21 @@ const TEST_STRING = `I'm a body!`;
|
||||
expect(clone.headers).toBe(headers);
|
||||
expect(clone.headers.get('Test')).toBe('Test header');
|
||||
});
|
||||
it('and updates the url',
|
||||
() => { expect(req.clone({url: '/changed'}).url).toBe('/changed'); });
|
||||
it('and updates the method',
|
||||
() => { expect(req.clone({method: 'PUT'}).method).toBe('PUT'); });
|
||||
it('and updates the body',
|
||||
() => { expect(req.clone({body: 'changed body'}).body).toBe('changed body'); });
|
||||
it('and updates the url', () => {
|
||||
expect(req.clone({url: '/changed'}).url).toBe('/changed');
|
||||
});
|
||||
it('and updates the method', () => {
|
||||
expect(req.clone({method: 'PUT'}).method).toBe('PUT');
|
||||
});
|
||||
it('and updates the body', () => {
|
||||
expect(req.clone({body: 'changed body'}).body).toBe('changed body');
|
||||
});
|
||||
});
|
||||
describe('content type detection', () => {
|
||||
const baseReq = new HttpRequest('POST', '/test', null);
|
||||
it('handles a null body', () => { expect(baseReq.detectContentTypeHeader()).toBeNull(); });
|
||||
it('handles a null body', () => {
|
||||
expect(baseReq.detectContentTypeHeader()).toBeNull();
|
||||
});
|
||||
it('doesn\'t associate a content type with ArrayBuffers', () => {
|
||||
const req = baseReq.clone({body: new ArrayBuffer(4)});
|
||||
expect(req.detectContentTypeHeader()).toBeNull();
|
||||
@ -113,7 +118,9 @@ const TEST_STRING = `I'm a body!`;
|
||||
});
|
||||
describe('body serialization', () => {
|
||||
const baseReq = new HttpRequest('POST', '/test', null);
|
||||
it('handles a null body', () => { expect(baseReq.serializeBody()).toBeNull(); });
|
||||
it('handles a null body', () => {
|
||||
expect(baseReq.serializeBody()).toBeNull();
|
||||
});
|
||||
it('passes ArrayBuffers through', () => {
|
||||
const body = new ArrayBuffer(4);
|
||||
expect(baseReq.clone({body}).serializeBody()).toBe(body);
|
||||
@ -125,8 +132,9 @@ const TEST_STRING = `I'm a body!`;
|
||||
it('serializes arrays as json', () => {
|
||||
expect(baseReq.clone({body: ['a', 'b']}).serializeBody()).toBe('["a","b"]');
|
||||
});
|
||||
it('handles numbers as json',
|
||||
() => { expect(baseReq.clone({body: 314159}).serializeBody()).toBe('314159'); });
|
||||
it('handles numbers as json', () => {
|
||||
expect(baseReq.clone({body: 314159}).serializeBody()).toBe('314159');
|
||||
});
|
||||
it('handles objects as json', () => {
|
||||
const req = baseReq.clone({body: {data: 'test data'}});
|
||||
expect(req.serializeBody()).toBe('{"data":"test data"}');
|
||||
|
@ -11,9 +11,11 @@ import {XhrFactory} from '@angular/common/http/src/xhr';
|
||||
|
||||
export class MockXhrFactory implements XhrFactory {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
mock !: MockXMLHttpRequest;
|
||||
mock!: MockXMLHttpRequest;
|
||||
|
||||
build(): XMLHttpRequest { return (this.mock = new MockXMLHttpRequest()) as any; }
|
||||
build(): XMLHttpRequest {
|
||||
return (this.mock = new MockXMLHttpRequest()) as any;
|
||||
}
|
||||
}
|
||||
|
||||
export class MockXMLHttpRequestUpload {
|
||||
@ -32,9 +34,9 @@ export class MockXMLHttpRequest {
|
||||
// Set by method calls.
|
||||
body: any;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
method !: string;
|
||||
method!: string;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
url !: string;
|
||||
url!: string;
|
||||
mockHeaders: {[key: string]: string} = {};
|
||||
mockAborted: boolean = false;
|
||||
|
||||
@ -64,7 +66,9 @@ export class MockXMLHttpRequest {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
send(body: any): void { this.body = body; }
|
||||
send(body: any): void {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
addEventListener(event: 'error'|'load'|'progress'|'uploadProgress', handler: Function): void {
|
||||
this.listeners[event] = handler as any;
|
||||
@ -74,9 +78,13 @@ export class MockXMLHttpRequest {
|
||||
delete this.listeners[event];
|
||||
}
|
||||
|
||||
setRequestHeader(name: string, value: string): void { this.mockHeaders[name] = value; }
|
||||
setRequestHeader(name: string, value: string): void {
|
||||
this.mockHeaders[name] = value;
|
||||
}
|
||||
|
||||
getAllResponseHeaders(): string { return this.mockResponseHeaders; }
|
||||
getAllResponseHeaders(): string {
|
||||
return this.mockResponseHeaders;
|
||||
}
|
||||
|
||||
getResponseHeader(header: string): string|null {
|
||||
return new HttpHeaders(this.mockResponseHeaders).get(header);
|
||||
@ -95,14 +103,17 @@ export class MockXMLHttpRequest {
|
||||
|
||||
mockDownloadProgressEvent(loaded: number, total?: number): void {
|
||||
if (this.listeners.progress) {
|
||||
this.listeners.progress({ lengthComputable: total !== undefined, loaded, total } as any);
|
||||
this.listeners.progress({lengthComputable: total !== undefined, loaded, total} as any);
|
||||
}
|
||||
}
|
||||
|
||||
mockUploadProgressEvent(loaded: number, total?: number) {
|
||||
if (this.listeners.uploadProgress) {
|
||||
this.listeners.uploadProgress(
|
||||
{ lengthComputable: total !== undefined, loaded, total, } as any);
|
||||
this.listeners.uploadProgress({
|
||||
lengthComputable: total !== undefined,
|
||||
loaded,
|
||||
total,
|
||||
} as any);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,5 +129,7 @@ export class MockXMLHttpRequest {
|
||||
}
|
||||
}
|
||||
|
||||
abort() { this.mockAborted = true; }
|
||||
abort() {
|
||||
this.mockAborted = true;
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,22 @@ import {HttpXsrfCookieExtractor, HttpXsrfInterceptor, HttpXsrfTokenExtractor} fr
|
||||
import {HttpClientTestingBackend} from '@angular/common/http/testing/src/backend';
|
||||
|
||||
class SampleTokenExtractor extends HttpXsrfTokenExtractor {
|
||||
constructor(private token: string|null) { super(); }
|
||||
constructor(private token: string|null) {
|
||||
super();
|
||||
}
|
||||
|
||||
getToken(): string|null { return this.token; }
|
||||
getToken(): string|null {
|
||||
return this.token;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
describe('HttpXsrfInterceptor', () => {
|
||||
let backend: HttpClientTestingBackend;
|
||||
const interceptor = new HttpXsrfInterceptor(new SampleTokenExtractor('test'), 'X-XSRF-TOKEN');
|
||||
beforeEach(() => { backend = new HttpClientTestingBackend(); });
|
||||
beforeEach(() => {
|
||||
backend = new HttpClientTestingBackend();
|
||||
});
|
||||
it('applies XSRF protection to outgoing requests', () => {
|
||||
interceptor.intercept(new HttpRequest('POST', '/test', {}), backend).subscribe();
|
||||
const req = backend.expectOne('/test');
|
||||
@ -59,7 +65,9 @@ class SampleTokenExtractor extends HttpXsrfTokenExtractor {
|
||||
expect(req.request.headers.has('X-XSRF-TOKEN')).toEqual(false);
|
||||
req.flush({});
|
||||
});
|
||||
afterEach(() => { backend.verify(); });
|
||||
afterEach(() => {
|
||||
backend.verify();
|
||||
});
|
||||
});
|
||||
describe('HttpXsrfCookieExtractor', () => {
|
||||
let document: {[key: string]: string};
|
||||
@ -70,8 +78,9 @@ class SampleTokenExtractor extends HttpXsrfTokenExtractor {
|
||||
};
|
||||
extractor = new HttpXsrfCookieExtractor(document, 'browser', 'XSRF-TOKEN');
|
||||
});
|
||||
it('parses the cookie from document.cookie',
|
||||
() => { expect(extractor.getToken()).toEqual('test'); });
|
||||
it('parses the cookie from document.cookie', () => {
|
||||
expect(extractor.getToken()).toEqual('test');
|
||||
});
|
||||
it('does not re-parse if document.cookie has not changed', () => {
|
||||
expect(extractor.getToken()).toEqual('test');
|
||||
expect(extractor.getToken()).toEqual('test');
|
||||
|
@ -39,8 +39,10 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl
|
||||
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; };
|
||||
observer.next({type: HttpEventType.Sent} as HttpEvent<any>);
|
||||
return () => {
|
||||
testReq._cancelled = true;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -86,8 +88,8 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl
|
||||
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.`);
|
||||
throw new Error(`Expected one matching request for criteria "${description}", found ${
|
||||
matches.length} requests.`);
|
||||
}
|
||||
if (matches.length === 0) {
|
||||
let message = `Expected one matching request for criteria "${description}", found none.`;
|
||||
@ -116,8 +118,8 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl
|
||||
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}.`);
|
||||
throw new Error(`Expected zero matching requests for criteria "${description}", found ${
|
||||
matches.length}.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,9 @@ export class TestRequest {
|
||||
/**
|
||||
* Whether the request was cancelled after it was sent.
|
||||
*/
|
||||
get cancelled(): boolean { return this._cancelled; }
|
||||
get cancelled(): boolean {
|
||||
return this._cancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal set by `HttpClientTestingBackend`
|
||||
@ -39,7 +41,7 @@ export class TestRequest {
|
||||
* Both successful and unsuccessful responses can be delivered via `flush()`.
|
||||
*/
|
||||
flush(body: ArrayBuffer|Blob|string|number|Object|(string|number|Object|null)[]|null, opts: {
|
||||
headers?: HttpHeaders | {[name: string]: string | string[]},
|
||||
headers?: HttpHeaders|{[name: string]: string | string[]},
|
||||
status?: number,
|
||||
statusText?: string,
|
||||
} = {}): void {
|
||||
@ -75,7 +77,7 @@ export class TestRequest {
|
||||
* Resolve the request by returning an `ErrorEvent` (e.g. simulating a network failure).
|
||||
*/
|
||||
error(error: ErrorEvent, opts: {
|
||||
headers?: HttpHeaders | {[name: string]: string | string[]},
|
||||
headers?: HttpHeaders|{[name: string]: string | string[]},
|
||||
status?: number,
|
||||
statusText?: string,
|
||||
} = {}): void {
|
||||
@ -112,9 +114,8 @@ export class TestRequest {
|
||||
/**
|
||||
* Helper function to convert a response body to an ArrayBuffer.
|
||||
*/
|
||||
function _toArrayBufferBody(
|
||||
body: ArrayBuffer | Blob | string | number | Object |
|
||||
(string | number | Object | null)[]): ArrayBuffer {
|
||||
function _toArrayBufferBody(body: ArrayBuffer|Blob|string|number|Object|
|
||||
(string | number | Object | null)[]): ArrayBuffer {
|
||||
if (typeof ArrayBuffer === 'undefined') {
|
||||
throw new Error('ArrayBuffer responses are not supported on this platform.');
|
||||
}
|
||||
@ -127,9 +128,8 @@ function _toArrayBufferBody(
|
||||
/**
|
||||
* Helper function to convert a response body to a Blob.
|
||||
*/
|
||||
function _toBlob(
|
||||
body: ArrayBuffer | Blob | string | number | Object |
|
||||
(string | number | Object | null)[]): Blob {
|
||||
function _toBlob(body: ArrayBuffer|Blob|string|number|Object|
|
||||
(string | number | Object | null)[]): Blob {
|
||||
if (typeof Blob === 'undefined') {
|
||||
throw new Error('Blob responses are not supported on this platform.');
|
||||
}
|
||||
@ -146,7 +146,7 @@ function _toBlob(
|
||||
* Helper function to convert a response body to JSON data.
|
||||
*/
|
||||
function _toJsonBody(
|
||||
body: ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[],
|
||||
body: ArrayBuffer|Blob|string|number|Object|(string | number | Object | null)[],
|
||||
format: string = 'JSON'): Object|string|number|(Object | string | number)[] {
|
||||
if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) {
|
||||
throw new Error(`Automatic conversion to ${format} is not supported for ArrayBuffers.`);
|
||||
@ -164,9 +164,8 @@ function _toJsonBody(
|
||||
/**
|
||||
* Helper function to convert a response body to a string.
|
||||
*/
|
||||
function _toTextBody(
|
||||
body: ArrayBuffer | Blob | string | number | Object |
|
||||
(string | number | Object | null)[]): string {
|
||||
function _toTextBody(body: ArrayBuffer|Blob|string|number|Object|
|
||||
(string | number | Object | null)[]): string {
|
||||
if (typeof body === 'string') {
|
||||
return body;
|
||||
}
|
||||
@ -183,9 +182,9 @@ function _toTextBody(
|
||||
* Convert a response body to the requested type.
|
||||
*/
|
||||
function _maybeConvertBody(
|
||||
responseType: string, body: ArrayBuffer | Blob | string | number | Object |
|
||||
(string | number | Object | null)[] | null): ArrayBuffer|Blob|string|number|Object|
|
||||
(string | number | Object | null)[]|null {
|
||||
responseType: string,
|
||||
body: ArrayBuffer|Blob|string|number|Object|(string | number | Object | null)[]|
|
||||
null): ArrayBuffer|Blob|string|number|Object|(string | number | Object | null)[]|null {
|
||||
if (body === null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ describe('HttpClient TestRequest', () => {
|
||||
const client = new HttpClient(mock);
|
||||
|
||||
let resp: any;
|
||||
client.post('/some-url', {test: 'test'}).subscribe(body => { resp = body; });
|
||||
client.post('/some-url', {test: 'test'}).subscribe(body => {
|
||||
resp = body;
|
||||
});
|
||||
|
||||
const req = mock.expectOne('/some-url');
|
||||
req.flush(null);
|
||||
@ -28,7 +30,9 @@ describe('HttpClient TestRequest', () => {
|
||||
const client = new HttpClient(mock);
|
||||
|
||||
let resp: any;
|
||||
client.get('/some-other-url').subscribe(body => { resp = body; });
|
||||
client.get('/some-other-url').subscribe(body => {
|
||||
resp = body;
|
||||
});
|
||||
|
||||
try {
|
||||
// expect different URL
|
||||
@ -48,7 +52,9 @@ describe('HttpClient TestRequest', () => {
|
||||
|
||||
let resp: any;
|
||||
const params = {query: 'hello'};
|
||||
client.get('/some-url', {params}).subscribe(body => { resp = body; });
|
||||
client.get('/some-url', {params}).subscribe(body => {
|
||||
resp = body;
|
||||
});
|
||||
|
||||
try {
|
||||
// expect different query parameters
|
||||
@ -67,8 +73,12 @@ describe('HttpClient TestRequest', () => {
|
||||
const client = new HttpClient(mock);
|
||||
|
||||
let resp: any;
|
||||
client.get('/some-other-url?query=world').subscribe(body => { resp = body; });
|
||||
client.post('/and-another-url', {}).subscribe(body => { resp = body; });
|
||||
client.get('/some-other-url?query=world').subscribe(body => {
|
||||
resp = body;
|
||||
});
|
||||
client.post('/and-another-url', {}).subscribe(body => {
|
||||
resp = body;
|
||||
});
|
||||
|
||||
try {
|
||||
// expect different URL
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
import {Directive, DoCheck, ElementRef, Input, IterableChanges, IterableDiffer, IterableDiffers, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer2, ɵisListLikeIterable as isListLikeIterable, ɵstringify as stringify} from '@angular/core';
|
||||
|
||||
type NgClassSupportedTypes = string[] | Set<string>| {[klass: string]: any} | null | undefined;
|
||||
type NgClassSupportedTypes = string[]|Set<string>|{[klass: string]: any}|null|undefined;
|
||||
|
||||
/**
|
||||
* @ngModule CommonModule
|
||||
@ -83,7 +83,7 @@ export class NgClass implements DoCheck {
|
||||
this._applyIterableChanges(iterableChanges);
|
||||
}
|
||||
} else if (this._keyValueDiffer) {
|
||||
const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as{[k: string]: any});
|
||||
const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as {[k: string]: any});
|
||||
if (keyValueChanges) {
|
||||
this._applyKeyValueChanges(keyValueChanges);
|
||||
}
|
||||
@ -105,8 +105,8 @@ export class NgClass implements DoCheck {
|
||||
if (typeof record.item === 'string') {
|
||||
this._toggleClass(record.item, true);
|
||||
} else {
|
||||
throw new Error(
|
||||
`NgClass can only toggle CSS classes expressed as strings, got ${stringify(record.item)}`);
|
||||
throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${
|
||||
stringify(record.item)}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -67,13 +67,13 @@ import {ComponentFactoryResolver, ComponentRef, Directive, Injector, Input, NgMo
|
||||
@Directive({selector: '[ngComponentOutlet]'})
|
||||
export class NgComponentOutlet implements OnChanges, OnDestroy {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() ngComponentOutlet !: Type<any>;
|
||||
@Input() ngComponentOutlet!: Type<any>;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() ngComponentOutletInjector !: Injector;
|
||||
@Input() ngComponentOutletInjector!: Injector;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() ngComponentOutletContent !: any[][];
|
||||
@Input() ngComponentOutletContent!: any[][];
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input() ngComponentOutletNgModuleFactory !: NgModuleFactory<any>;
|
||||
@Input() ngComponentOutletNgModuleFactory!: NgModuleFactory<any>;
|
||||
|
||||
private _componentRef: ComponentRef<any>|null = null;
|
||||
private _moduleRef: NgModuleRef<any>|null = null;
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef, isDevMode} from '@angular/core';
|
||||
import {Directive, DoCheck, EmbeddedViewRef, Input, isDevMode, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef} from '@angular/core';
|
||||
|
||||
/**
|
||||
* @publicApi
|
||||
@ -14,13 +14,21 @@ import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, Iterab
|
||||
export class NgForOfContext<T, U extends NgIterable<T> = NgIterable<T>> {
|
||||
constructor(public $implicit: T, public ngForOf: U, public index: number, public count: number) {}
|
||||
|
||||
get first(): boolean { return this.index === 0; }
|
||||
get first(): boolean {
|
||||
return this.index === 0;
|
||||
}
|
||||
|
||||
get last(): boolean { return this.index === this.count - 1; }
|
||||
get last(): boolean {
|
||||
return this.index === this.count - 1;
|
||||
}
|
||||
|
||||
get even(): boolean { return this.index % 2 === 0; }
|
||||
get even(): boolean {
|
||||
return this.index % 2 === 0;
|
||||
}
|
||||
|
||||
get odd(): boolean { return !this.even; }
|
||||
get odd(): boolean {
|
||||
return !this.even;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,13 +170,15 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
|
||||
this._trackByFn = fn;
|
||||
}
|
||||
|
||||
get ngForTrackBy(): TrackByFunction<T> { return this._trackByFn; }
|
||||
get ngForTrackBy(): TrackByFunction<T> {
|
||||
return this._trackByFn;
|
||||
}
|
||||
|
||||
private _ngForOf: U|undefined|null = null;
|
||||
private _ngForOfDirty: boolean = true;
|
||||
private _differ: IterableDiffer<T>|null = null;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _trackByFn !: TrackByFunction<T>;
|
||||
private _trackByFn!: TrackByFunction<T>;
|
||||
|
||||
constructor(
|
||||
private _viewContainer: ViewContainerRef,
|
||||
@ -200,8 +210,8 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
|
||||
try {
|
||||
this._differ = this._differs.find(value).create(this.ngForTrackBy);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Cannot find a differ supporting object '${value}' of type '${getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
|
||||
throw new Error(`Cannot find a differ supporting object '${value}' of type '${
|
||||
getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,14 +224,14 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
|
||||
private _applyChanges(changes: IterableChanges<T>) {
|
||||
const insertTuples: RecordViewTuple<T, U>[] = [];
|
||||
changes.forEachOperation(
|
||||
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number | null,
|
||||
currentIndex: number | null) => {
|
||||
(item: IterableChangeRecord<any>, adjustedPreviousIndex: number|null,
|
||||
currentIndex: number|null) => {
|
||||
if (item.previousIndex == null) {
|
||||
// NgForOf is never "null" or "undefined" here because the differ detected
|
||||
// that a new item needs to be inserted from the iterable. This implies that
|
||||
// there is an iterable value for "_ngForOf".
|
||||
const view = this._viewContainer.createEmbeddedView(
|
||||
this._template, new NgForOfContext<T, U>(null !, this._ngForOf !, -1, -1),
|
||||
this._template, new NgForOfContext<T, U>(null!, this._ngForOf!, -1, -1),
|
||||
currentIndex === null ? undefined : currentIndex);
|
||||
const tuple = new RecordViewTuple<T, U>(item, view);
|
||||
insertTuples.push(tuple);
|
||||
@ -229,7 +239,7 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
|
||||
this._viewContainer.remove(
|
||||
adjustedPreviousIndex === null ? undefined : adjustedPreviousIndex);
|
||||
} else if (adjustedPreviousIndex !== null) {
|
||||
const view = this._viewContainer.get(adjustedPreviousIndex) !;
|
||||
const view = this._viewContainer.get(adjustedPreviousIndex)!;
|
||||
this._viewContainer.move(view, currentIndex);
|
||||
const tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForOfContext<T, U>>>view);
|
||||
insertTuples.push(tuple);
|
||||
@ -244,7 +254,7 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh
|
||||
const viewRef = <EmbeddedViewRef<NgForOfContext<T, U>>>this._viewContainer.get(i);
|
||||
viewRef.context.index = i;
|
||||
viewRef.context.count = ilen;
|
||||
viewRef.context.ngForOf = this._ngForOf !;
|
||||
viewRef.context.ngForOf = this._ngForOf!;
|
||||
}
|
||||
|
||||
changes.forEachIdentityChange((record: any) => {
|
||||
|
@ -241,11 +241,11 @@ export class NgIf<T = unknown> {
|
||||
* @publicApi
|
||||
*/
|
||||
export class NgIfContext<T = unknown> {
|
||||
public $implicit: T = null !;
|
||||
public ngIf: T = null !;
|
||||
public $implicit: T = null!;
|
||||
public ngIf: T = null!;
|
||||
}
|
||||
|
||||
function assertTemplate(property: string, templateRef: TemplateRef<any>| null): void {
|
||||
function assertTemplate(property: string, templateRef: TemplateRef<any>|null): void {
|
||||
const isTemplateRefOrNull = !!(!templateRef || templateRef.createEmbeddedView);
|
||||
if (!isTemplateRefOrNull) {
|
||||
throw new Error(`${property} must be a TemplateRef, but received '${stringify(templateRef)}'.`);
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {Attribute, Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
|
||||
import {NgLocalization, getPluralCategory} from '../i18n/localization';
|
||||
import {getPluralCategory, NgLocalization} from '../i18n/localization';
|
||||
|
||||
import {SwitchView} from './ng_switch';
|
||||
|
||||
@ -47,9 +47,9 @@ import {SwitchView} from './ng_switch';
|
||||
@Directive({selector: '[ngPlural]'})
|
||||
export class NgPlural {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _switchValue !: number;
|
||||
private _switchValue!: number;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _activeView !: SwitchView;
|
||||
private _activeView!: SwitchView;
|
||||
private _caseViews: {[k: string]: SwitchView} = {};
|
||||
|
||||
constructor(private _localization: NgLocalization) {}
|
||||
@ -60,7 +60,9 @@ export class NgPlural {
|
||||
this._updateView();
|
||||
}
|
||||
|
||||
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
|
||||
addCase(value: string, switchView: SwitchView): void {
|
||||
this._caseViews[value] = switchView;
|
||||
}
|
||||
|
||||
private _updateView(): void {
|
||||
this._clearViews();
|
||||
|
@ -62,7 +62,7 @@ export class NgStyle implements DoCheck {
|
||||
|
||||
ngDoCheck() {
|
||||
if (this._differ) {
|
||||
const changes = this._differ.diff(this._ngStyle !);
|
||||
const changes = this._differ.diff(this._ngStyle!);
|
||||
if (changes) {
|
||||
this._applyChanges(changes);
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ export class SwitchView {
|
||||
@Directive({selector: '[ngSwitch]'})
|
||||
export class NgSwitch {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _defaultViews !: SwitchView[];
|
||||
private _defaultViews!: SwitchView[];
|
||||
private _defaultUsed = false;
|
||||
private _caseCount = 0;
|
||||
private _lastCaseCheckIndex = 0;
|
||||
@ -120,7 +120,9 @@ export class NgSwitch {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_addCase(): number { return this._caseCount++; }
|
||||
_addCase(): number {
|
||||
return this._caseCount++;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_addDefault(view: SwitchView) {
|
||||
@ -193,8 +195,7 @@ export class NgSwitchCase implements DoCheck {
|
||||
/**
|
||||
* Stores the HTML template to be selected on match.
|
||||
*/
|
||||
@Input()
|
||||
ngSwitchCase: any;
|
||||
@Input() ngSwitchCase: any;
|
||||
|
||||
constructor(
|
||||
viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
|
||||
@ -206,7 +207,9 @@ export class NgSwitchCase implements DoCheck {
|
||||
/**
|
||||
* Performs case matching. For internal use only.
|
||||
*/
|
||||
ngDoCheck() { this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); }
|
||||
ngDoCheck() {
|
||||
this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,7 +101,7 @@ export class NgTemplateOutlet implements OnChanges {
|
||||
|
||||
private _updateExistingContext(ctx: Object): void {
|
||||
for (let propName of Object.keys(ctx)) {
|
||||
(<any>this._viewRef !.context)[propName] = (<any>this.ngTemplateOutletContext)[propName];
|
||||
(<any>this._viewRef!.context)[propName] = (<any>this.ngTemplateOutletContext)[propName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
let _DOM: DomAdapter = null !;
|
||||
let _DOM: DomAdapter = null!;
|
||||
|
||||
export function getDOM(): DomAdapter {
|
||||
return _DOM;
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {FormStyle, FormatWidth, NumberSymbol, Time, TranslationWidth, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleId, getLocaleMonthNames, getLocaleNumberSymbol, getLocaleTimeFormat} from './locale_data_api';
|
||||
import {FormatWidth, FormStyle, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleId, getLocaleMonthNames, getLocaleNumberSymbol, getLocaleTimeFormat, NumberSymbol, Time, TranslationWidth} from './locale_data_api';
|
||||
|
||||
export const ISO8601_DATE_REGEX =
|
||||
/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
|
||||
@ -62,7 +62,7 @@ enum TranslationType {
|
||||
* @publicApi
|
||||
*/
|
||||
export function formatDate(
|
||||
value: string | number | Date, format: string, locale: string, timezone?: string): string {
|
||||
value: string|number|Date, format: string, locale: string, timezone?: string): string {
|
||||
let date = toDate(value);
|
||||
const namedFormat = getNamedFormat(locale, format);
|
||||
format = namedFormat || format;
|
||||
@ -278,7 +278,7 @@ function getDateTranslation(
|
||||
const rules = getLocaleExtraDayPeriodRules(locale);
|
||||
const dayPeriods = getLocaleExtraDayPeriods(locale, form, width);
|
||||
let result;
|
||||
rules.forEach((rule: Time | [Time, Time], index: number) => {
|
||||
rules.forEach((rule: Time|[Time, Time], index: number) => {
|
||||
if (Array.isArray(rule)) {
|
||||
// morning, afternoon, evening, night
|
||||
const {hours: hoursFrom, minutes: minutesFrom} = rule[0];
|
||||
@ -652,7 +652,7 @@ function convertTimezoneToLocal(date: Date, timezone: string, reverse: boolean):
|
||||
*
|
||||
* Throws if unable to convert to a date.
|
||||
*/
|
||||
export function toDate(value: string | number | Date): Date {
|
||||
export function toDate(value: string|number|Date): Date {
|
||||
if (isDate(value)) {
|
||||
return value;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NumberFormatStyle, NumberSymbol, getLocaleNumberFormat, getLocaleNumberSymbol, getNumberOfCurrencyDigits} from './locale_data_api';
|
||||
import {getLocaleNumberFormat, getLocaleNumberSymbol, getNumberOfCurrencyDigits, NumberFormatStyle, NumberSymbol} from './locale_data_api';
|
||||
|
||||
export const NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
|
||||
const MAX_DIGITS = 22;
|
||||
@ -153,7 +153,7 @@ export function formatCurrency(
|
||||
const format = getLocaleNumberFormat(locale, NumberFormatStyle.Currency);
|
||||
const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
|
||||
|
||||
pattern.minFrac = getNumberOfCurrencyDigits(currencyCode !);
|
||||
pattern.minFrac = getNumberOfCurrencyDigits(currencyCode!);
|
||||
pattern.maxFrac = pattern.minFrac;
|
||||
|
||||
const res = formatNumberToLocaleString(
|
||||
@ -392,8 +392,8 @@ function parseNumber(num: number): ParsedNumber {
|
||||
*/
|
||||
function roundNumber(parsedNumber: ParsedNumber, minFrac: number, maxFrac: number) {
|
||||
if (minFrac > maxFrac) {
|
||||
throw new Error(
|
||||
`The minimum number of digits after fraction (${minFrac}) is higher than the maximum (${maxFrac}).`);
|
||||
throw new Error(`The minimum number of digits after fraction (${
|
||||
minFrac}) is higher than the maximum (${maxFrac}).`);
|
||||
}
|
||||
|
||||
let digits = parsedNumber.digits;
|
||||
|
@ -16,6 +16,6 @@ import {ɵregisterLocaleData} from '@angular/core';
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void {
|
||||
export function registerLocaleData(data: any, localeId?: string|any, extraData?: any): void {
|
||||
return ɵregisterLocaleData(data, localeId, extraData);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ɵCurrencyIndex, ɵExtraLocaleDataIndex, ɵLocaleDataIndex, ɵfindLocaleData, ɵgetLocaleCurrencyCode, ɵgetLocalePluralCase} from '@angular/core';
|
||||
import {ɵCurrencyIndex, ɵExtraLocaleDataIndex, ɵfindLocaleData, ɵgetLocaleCurrencyCode, ɵgetLocalePluralCase, ɵLocaleDataIndex} from '@angular/core';
|
||||
|
||||
import {CURRENCIES_EN, CurrenciesSymbols} from './currencies';
|
||||
|
||||
@ -235,9 +235,9 @@ export function getLocaleId(locale: string): string {
|
||||
export function getLocaleDayPeriods(
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): [string, string] {
|
||||
const data = ɵfindLocaleData(locale);
|
||||
const amPmData = <[
|
||||
string, string
|
||||
][][]>[data[ɵLocaleDataIndex.DayPeriodsFormat], data[ɵLocaleDataIndex.DayPeriodsStandalone]];
|
||||
const amPmData = <[string, string][][]>[
|
||||
data[ɵLocaleDataIndex.DayPeriodsFormat], data[ɵLocaleDataIndex.DayPeriodsStandalone]
|
||||
];
|
||||
const amPm = getLastDefinedValue(amPmData, formStyle);
|
||||
return getLastDefinedValue(amPm, width);
|
||||
}
|
||||
@ -509,8 +509,9 @@ export const getLocalePluralCase: (locale: string) => ((value: number) => Plural
|
||||
|
||||
function checkFullData(data: any) {
|
||||
if (!data[ɵLocaleDataIndex.ExtraData]) {
|
||||
throw new Error(
|
||||
`Missing extra locale data for the locale "${data[ɵLocaleDataIndex.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`);
|
||||
throw new Error(`Missing extra locale data for the locale "${
|
||||
data[ɵLocaleDataIndex
|
||||
.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -536,11 +537,11 @@ function checkFullData(data: any) {
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function getLocaleExtraDayPeriodRules(locale: string): (Time | [Time, Time])[] {
|
||||
export function getLocaleExtraDayPeriodRules(locale: string): (Time|[Time, Time])[] {
|
||||
const data = ɵfindLocaleData(locale);
|
||||
checkFullData(data);
|
||||
const rules = data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodsRules] || [];
|
||||
return rules.map((rule: string | [string, string]) => {
|
||||
return rules.map((rule: string|[string, string]) => {
|
||||
if (typeof rule === 'string') {
|
||||
return extractTime(rule);
|
||||
}
|
||||
@ -570,8 +571,8 @@ export function getLocaleExtraDayPeriods(
|
||||
const data = ɵfindLocaleData(locale);
|
||||
checkFullData(data);
|
||||
const dayPeriodsData = <string[][][]>[
|
||||
data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodFormats],
|
||||
data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone]
|
||||
data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodFormats],
|
||||
data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone]
|
||||
];
|
||||
const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || [];
|
||||
return getLastDefinedValue(dayPeriods, width) || [];
|
||||
@ -646,7 +647,7 @@ function extractTime(time: string): Time {
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function getCurrencySymbol(code: string, format: 'wide' | 'narrow', locale = 'en'): string {
|
||||
export function getCurrencySymbol(code: string, format: 'wide'|'narrow', locale = 'en'): string {
|
||||
const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || [];
|
||||
const symbolNarrow = currency[ɵCurrencyIndex.SymbolNarrow];
|
||||
|
||||
|
@ -7,7 +7,8 @@
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
||||
import {Plural, getLocalePluralCase} from './locale_data_api';
|
||||
|
||||
import {getLocalePluralCase, Plural} from './locale_data_api';
|
||||
|
||||
|
||||
/**
|
||||
@ -51,7 +52,9 @@ export function getPluralCategory(
|
||||
*/
|
||||
@Injectable()
|
||||
export class NgLocaleLocalization extends NgLocalization {
|
||||
constructor(@Inject(LOCALE_ID) protected locale: string) { super(); }
|
||||
constructor(@Inject(LOCALE_ID) protected locale: string) {
|
||||
super();
|
||||
}
|
||||
|
||||
getPluralCategory(value: any, locale?: string): string {
|
||||
const plural = getLocalePluralCase(locale || this.locale)(value);
|
||||
|
@ -48,7 +48,9 @@ export class HashLocationStrategy extends LocationStrategy {
|
||||
this._platformLocation.onHashChange(fn);
|
||||
}
|
||||
|
||||
getBaseHref(): string { return this._baseHref; }
|
||||
getBaseHref(): string {
|
||||
return this._baseHref;
|
||||
}
|
||||
|
||||
path(includeHash: boolean = false): string {
|
||||
// the hash value is always prefixed with a `#`
|
||||
@ -80,7 +82,11 @@ export class HashLocationStrategy extends LocationStrategy {
|
||||
this._platformLocation.replaceState(state, title, url);
|
||||
}
|
||||
|
||||
forward(): void { this._platformLocation.forward(); }
|
||||
forward(): void {
|
||||
this._platformLocation.forward();
|
||||
}
|
||||
|
||||
back(): void { this._platformLocation.back(); }
|
||||
back(): void {
|
||||
this._platformLocation.back();
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,9 @@ export class Location {
|
||||
* Reports the current state of the location history.
|
||||
* @returns The current value of the `history.state` object.
|
||||
*/
|
||||
getState(): unknown { return this._platformLocation.getState(); }
|
||||
getState(): unknown {
|
||||
return this._platformLocation.getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the given path and compares to the current normalized path.
|
||||
@ -173,12 +175,16 @@ export class Location {
|
||||
/**
|
||||
* Navigates forward in the platform's history.
|
||||
*/
|
||||
forward(): void { this._platformStrategy.forward(); }
|
||||
forward(): void {
|
||||
this._platformStrategy.forward();
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates back in the platform's history.
|
||||
*/
|
||||
back(): void { this._platformStrategy.back(); }
|
||||
back(): void {
|
||||
this._platformStrategy.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a URL change listener. Use to catch updates performed by the Angular
|
||||
@ -188,7 +194,9 @@ export class Location {
|
||||
*/
|
||||
onUrlChange(fn: (url: string, state: unknown) => void) {
|
||||
this._urlChangeListeners.push(fn);
|
||||
this.subscribe(v => { this._notifyUrlChangeListeners(v.url, v.state); });
|
||||
this.subscribe(v => {
|
||||
this._notifyUrlChangeListeners(v.url, v.state);
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -126,9 +126,13 @@ export class PathLocationStrategy extends LocationStrategy {
|
||||
this._platformLocation.onHashChange(fn);
|
||||
}
|
||||
|
||||
getBaseHref(): string { return this._baseHref; }
|
||||
getBaseHref(): string {
|
||||
return this._baseHref;
|
||||
}
|
||||
|
||||
prepareExternalUrl(internal: string): string { return joinWithSlash(this._baseHref, internal); }
|
||||
prepareExternalUrl(internal: string): string {
|
||||
return joinWithSlash(this._baseHref, internal);
|
||||
}
|
||||
|
||||
path(includeHash: boolean = false): string {
|
||||
const pathname =
|
||||
@ -147,7 +151,11 @@ export class PathLocationStrategy extends LocationStrategy {
|
||||
this._platformLocation.replaceState(state, title, externalUrl);
|
||||
}
|
||||
|
||||
forward(): void { this._platformLocation.forward(); }
|
||||
forward(): void {
|
||||
this._platformLocation.forward();
|
||||
}
|
||||
|
||||
back(): void { this._platformLocation.back(); }
|
||||
back(): void {
|
||||
this._platformLocation.back();
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,9 @@ export interface LocationChangeEvent {
|
||||
/**
|
||||
* @publicApi
|
||||
*/
|
||||
export interface LocationChangeListener { (event: LocationChangeEvent): any; }
|
||||
export interface LocationChangeListener {
|
||||
(event: LocationChangeEvent): any;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -101,8 +103,8 @@ export interface LocationChangeListener { (event: LocationChangeEvent): any; }
|
||||
useFactory: createBrowserPlatformLocation,
|
||||
})
|
||||
export class BrowserPlatformLocation extends PlatformLocation {
|
||||
public readonly location !: Location;
|
||||
private _history !: History;
|
||||
public readonly location!: Location;
|
||||
private _history!: History;
|
||||
|
||||
constructor(@Inject(DOCUMENT) private _doc: any) {
|
||||
super();
|
||||
@ -112,11 +114,13 @@ export class BrowserPlatformLocation extends PlatformLocation {
|
||||
// This is moved to its own method so that `MockPlatformLocationStrategy` can overwrite it
|
||||
/** @internal */
|
||||
_init() {
|
||||
(this as{location: Location}).location = getDOM().getLocation();
|
||||
(this as {location: Location}).location = getDOM().getLocation();
|
||||
this._history = getDOM().getHistory();
|
||||
}
|
||||
|
||||
getBaseHrefFromDOM(): string { return getDOM().getBaseHref(this._doc) !; }
|
||||
getBaseHrefFromDOM(): string {
|
||||
return getDOM().getBaseHref(this._doc)!;
|
||||
}
|
||||
|
||||
onPopState(fn: LocationChangeListener): void {
|
||||
getDOM().getGlobalEventTarget(this._doc, 'window').addEventListener('popstate', fn, false);
|
||||
@ -126,14 +130,30 @@ export class BrowserPlatformLocation extends PlatformLocation {
|
||||
getDOM().getGlobalEventTarget(this._doc, 'window').addEventListener('hashchange', fn, false);
|
||||
}
|
||||
|
||||
get href(): string { return this.location.href; }
|
||||
get protocol(): string { return this.location.protocol; }
|
||||
get hostname(): string { return this.location.hostname; }
|
||||
get port(): string { return this.location.port; }
|
||||
get pathname(): string { return this.location.pathname; }
|
||||
get search(): string { return this.location.search; }
|
||||
get hash(): string { return this.location.hash; }
|
||||
set pathname(newPath: string) { this.location.pathname = newPath; }
|
||||
get href(): string {
|
||||
return this.location.href;
|
||||
}
|
||||
get protocol(): string {
|
||||
return this.location.protocol;
|
||||
}
|
||||
get hostname(): string {
|
||||
return this.location.hostname;
|
||||
}
|
||||
get port(): string {
|
||||
return this.location.port;
|
||||
}
|
||||
get pathname(): string {
|
||||
return this.location.pathname;
|
||||
}
|
||||
get search(): string {
|
||||
return this.location.search;
|
||||
}
|
||||
get hash(): string {
|
||||
return this.location.hash;
|
||||
}
|
||||
set pathname(newPath: string) {
|
||||
this.location.pathname = newPath;
|
||||
}
|
||||
|
||||
pushState(state: any, title: string, url: string): void {
|
||||
if (supportsState()) {
|
||||
@ -151,11 +171,17 @@ export class BrowserPlatformLocation extends PlatformLocation {
|
||||
}
|
||||
}
|
||||
|
||||
forward(): void { this._history.forward(); }
|
||||
forward(): void {
|
||||
this._history.forward();
|
||||
}
|
||||
|
||||
back(): void { this._history.back(); }
|
||||
back(): void {
|
||||
this._history.back();
|
||||
}
|
||||
|
||||
getState(): unknown { return this._history.state; }
|
||||
getState(): unknown {
|
||||
return this._history.state;
|
||||
}
|
||||
}
|
||||
|
||||
export function supportsState(): boolean {
|
||||
|
@ -19,17 +19,28 @@ interface SubscriptionStrategy {
|
||||
|
||||
class ObservableStrategy implements SubscriptionStrategy {
|
||||
createSubscription(async: Observable<any>, updateLatestValue: any): SubscriptionLike {
|
||||
return async.subscribe({next: updateLatestValue, error: (e: any) => { throw e; }});
|
||||
return async.subscribe({
|
||||
next: updateLatestValue,
|
||||
error: (e: any) => {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dispose(subscription: SubscriptionLike): void { subscription.unsubscribe(); }
|
||||
dispose(subscription: SubscriptionLike): void {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
|
||||
onDestroy(subscription: SubscriptionLike): void { subscription.unsubscribe(); }
|
||||
onDestroy(subscription: SubscriptionLike): void {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
class PromiseStrategy implements SubscriptionStrategy {
|
||||
createSubscription(async: Promise<any>, updateLatestValue: (v: any) => any): Promise<any> {
|
||||
return async.then(updateLatestValue, e => { throw e; });
|
||||
return async.then(updateLatestValue, e => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
dispose(subscription: Promise<any>): void {}
|
||||
@ -74,7 +85,7 @@ export class AsyncPipe implements OnDestroy, PipeTransform {
|
||||
|
||||
private _subscription: SubscriptionLike|Promise<any>|null = null;
|
||||
private _obj: Observable<any>|Promise<any>|EventEmitter<any>|null = null;
|
||||
private _strategy: SubscriptionStrategy = null !;
|
||||
private _strategy: SubscriptionStrategy = null!;
|
||||
|
||||
constructor(private _ref: ChangeDetectorRef) {}
|
||||
|
||||
@ -130,7 +141,7 @@ export class AsyncPipe implements OnDestroy, PipeTransform {
|
||||
}
|
||||
|
||||
private _dispose(): void {
|
||||
this._strategy.dispose(this._subscription !);
|
||||
this._strategy.dispose(this._subscription!);
|
||||
this._latestValue = null;
|
||||
this._latestReturnedValue = null;
|
||||
this._subscription = null;
|
||||
|
@ -7,7 +7,9 @@
|
||||
*/
|
||||
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
import {NgLocalization, getPluralCategory} from '../i18n/localization';
|
||||
|
||||
import {getPluralCategory, NgLocalization} from '../i18n/localization';
|
||||
|
||||
import {invalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||
|
||||
const _INTERPOLATION_REGEXP: RegExp = /#/g;
|
||||
|
@ -26,11 +26,11 @@ export {
|
||||
CurrencyPipe,
|
||||
DatePipe,
|
||||
DecimalPipe,
|
||||
KeyValue,
|
||||
KeyValuePipe,
|
||||
I18nPluralPipe,
|
||||
I18nSelectPipe,
|
||||
JsonPipe,
|
||||
KeyValue,
|
||||
KeyValuePipe,
|
||||
LowerCasePipe,
|
||||
PercentPipe,
|
||||
SlicePipe,
|
||||
|
@ -28,5 +28,7 @@ export class JsonPipe implements PipeTransform {
|
||||
/**
|
||||
* @param value A value of any type to convert into a JSON-format string.
|
||||
*/
|
||||
transform(value: any): string { return JSON.stringify(value, null, 2); }
|
||||
transform(value: any): string {
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export interface KeyValue<K, V> {
|
||||
export class KeyValuePipe implements PipeTransform {
|
||||
constructor(private readonly differs: KeyValueDiffers) {}
|
||||
|
||||
private differ !: KeyValueDiffer<any, any>;
|
||||
private differ!: KeyValueDiffer<any, any>;
|
||||
private keyValues: Array<KeyValue<any, any>> = [];
|
||||
|
||||
transform<K, V>(input: null, compareFn?: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number): null;
|
||||
@ -90,7 +90,7 @@ export class KeyValuePipe implements PipeTransform {
|
||||
if (differChanges) {
|
||||
this.keyValues = [];
|
||||
differChanges.forEachItem((r: KeyValueChangeRecord<K, V>) => {
|
||||
this.keyValues.push(makeKeyValuePair(r.key, r.currentValue !));
|
||||
this.keyValues.push(makeKeyValuePair(r.key, r.currentValue!));
|
||||
});
|
||||
this.keyValues.sort(compareFn);
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ function isEmpty(value: any): boolean {
|
||||
/**
|
||||
* Transforms a string into a number (if needed).
|
||||
*/
|
||||
function strToNumber(value: number | string): number {
|
||||
function strToNumber(value: number|string): number {
|
||||
// Convert strings to numbers
|
||||
if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) {
|
||||
return Number(value);
|
||||
|
@ -75,5 +75,7 @@ export class SlicePipe implements PipeTransform {
|
||||
return value.slice(start, end);
|
||||
}
|
||||
|
||||
private supports(obj: any): boolean { return typeof obj === 'string' || Array.isArray(obj); }
|
||||
private supports(obj: any): boolean {
|
||||
return typeof obj === 'string' || Array.isArray(obj);
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +186,9 @@ export class NullViewportScroller implements ViewportScroller {
|
||||
/**
|
||||
* Empty implementation
|
||||
*/
|
||||
getScrollPosition(): [number, number] { return [0, 0]; }
|
||||
getScrollPosition(): [number, number] {
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty implementation
|
||||
|
@ -9,12 +9,12 @@
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
* @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 {parseCookieValue} from '@angular/common/src/cookie';
|
||||
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
{
|
||||
describe('binding to CSS class list', () => {
|
||||
@ -18,14 +18,18 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
}
|
||||
|
||||
function detectChangesAndExpectClassName(classes: string): void {
|
||||
fixture !.detectChanges();
|
||||
let nonNormalizedClassName = fixture !.debugElement.children[0].nativeElement.className;
|
||||
fixture!.detectChanges();
|
||||
let nonNormalizedClassName = fixture!.debugElement.children[0].nativeElement.className;
|
||||
expect(normalizeClassNames(nonNormalizedClassName)).toEqual(normalizeClassNames(classes));
|
||||
}
|
||||
|
||||
function getComponent(): TestComponent { return fixture !.debugElement.componentInstance; }
|
||||
function getComponent(): TestComponent {
|
||||
return fixture!.debugElement.componentInstance;
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null; });
|
||||
afterEach(() => {
|
||||
fixture = null;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@ -43,7 +47,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
}));
|
||||
|
||||
describe('expressions evaluating to objects', () => {
|
||||
|
||||
it('should add classes specified in an object literal', async(() => {
|
||||
fixture = createTestComponent('<div [ngClass]="{foo: true, bar: false}"></div>');
|
||||
|
||||
@ -74,13 +77,13 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
|
||||
detectChangesAndExpectClassName('foo');
|
||||
|
||||
objExpr !['bar'] = true;
|
||||
objExpr!['bar'] = true;
|
||||
detectChangesAndExpectClassName('foo bar');
|
||||
|
||||
objExpr !['baz'] = true;
|
||||
objExpr!['baz'] = true;
|
||||
detectChangesAndExpectClassName('foo bar baz');
|
||||
|
||||
delete (objExpr !['bar']);
|
||||
delete (objExpr!['bar']);
|
||||
detectChangesAndExpectClassName('foo baz');
|
||||
}));
|
||||
|
||||
@ -129,7 +132,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
});
|
||||
|
||||
describe('expressions evaluating to lists', () => {
|
||||
|
||||
it('should add classes specified in a list literal', async(() => {
|
||||
fixture =
|
||||
createTestComponent(`<div [ngClass]="['foo', 'bar', 'foo-bar', 'fooBar']"></div>`);
|
||||
@ -194,14 +196,13 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
|
||||
it('should throw with descriptive error message when CSS class is not a string', () => {
|
||||
fixture = createTestComponent(`<div [ngClass]="['foo', {}]"></div>`);
|
||||
expect(() => fixture !.detectChanges())
|
||||
expect(() => fixture!.detectChanges())
|
||||
.toThrowError(
|
||||
/NgClass can only toggle CSS classes expressed as strings, got \[object Object\]/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('expressions evaluating to sets', () => {
|
||||
|
||||
it('should add and remove classes if the set instance changed', async(() => {
|
||||
fixture = createTestComponent('<div [ngClass]="setExpr"></div>');
|
||||
let setExpr = new Set<string>();
|
||||
@ -217,7 +218,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
});
|
||||
|
||||
describe('expressions evaluating to string', () => {
|
||||
|
||||
it('should add classes specified in a string literal', async(() => {
|
||||
fixture = createTestComponent(`<div [ngClass]="'foo bar foo-bar fooBar'"></div>`);
|
||||
detectChangesAndExpectClassName('foo bar foo-bar fooBar');
|
||||
@ -257,19 +257,17 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
getComponent().strExpr = '';
|
||||
detectChangesAndExpectClassName('foo');
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('cooperation with other class-changing constructs', () => {
|
||||
|
||||
it('should co-operate with the class attribute', async(() => {
|
||||
fixture = createTestComponent('<div [ngClass]="objExpr" class="init foo"></div>');
|
||||
const objExpr = getComponent().objExpr;
|
||||
|
||||
objExpr !['bar'] = true;
|
||||
objExpr!['bar'] = true;
|
||||
detectChangesAndExpectClassName('init foo bar');
|
||||
|
||||
objExpr !['foo'] = false;
|
||||
objExpr!['foo'] = false;
|
||||
detectChangesAndExpectClassName('init bar');
|
||||
|
||||
getComponent().objExpr = null;
|
||||
@ -280,10 +278,10 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
fixture = createTestComponent(`<div [ngClass]="objExpr" class="{{'init foo'}}"></div>`);
|
||||
const objExpr = getComponent().objExpr;
|
||||
|
||||
objExpr !['bar'] = true;
|
||||
objExpr!['bar'] = true;
|
||||
detectChangesAndExpectClassName(`init foo bar`);
|
||||
|
||||
objExpr !['foo'] = false;
|
||||
objExpr!['foo'] = false;
|
||||
detectChangesAndExpectClassName(`init bar`);
|
||||
|
||||
getComponent().objExpr = null;
|
||||
@ -306,10 +304,10 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
createTestComponent(`<div [ngClass]="objExpr" class="init" [class]="'foo'"></div>`);
|
||||
const objExpr = getComponent().objExpr;
|
||||
|
||||
objExpr !['bar'] = true;
|
||||
objExpr!['bar'] = true;
|
||||
detectChangesAndExpectClassName(`init foo bar`);
|
||||
|
||||
objExpr !['foo'] = false;
|
||||
objExpr!['foo'] = false;
|
||||
detectChangesAndExpectClassName(`init bar`);
|
||||
|
||||
getComponent().objExpr = null;
|
||||
@ -324,10 +322,10 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
|
||||
detectChangesAndExpectClassName('init foo baz');
|
||||
|
||||
objExpr !['bar'] = true;
|
||||
objExpr!['bar'] = true;
|
||||
detectChangesAndExpectClassName('init foo baz bar');
|
||||
|
||||
objExpr !['foo'] = false;
|
||||
objExpr!['foo'] = false;
|
||||
detectChangesAndExpectClassName('init baz bar');
|
||||
|
||||
getComponent().condition = false;
|
||||
@ -342,7 +340,7 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
|
||||
detectChangesAndExpectClassName('init foo');
|
||||
|
||||
cmp.objExpr !['bar'] = true;
|
||||
cmp.objExpr!['bar'] = true;
|
||||
detectChangesAndExpectClassName('init foo bar');
|
||||
|
||||
cmp.strExpr = 'baz';
|
||||
@ -354,7 +352,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
});
|
||||
|
||||
describe('prevent regressions', () => {
|
||||
|
||||
// https://github.com/angular/angular/issues/34336
|
||||
it('should not write to the native node unless the bound expression has changed', () => {
|
||||
fixture = createTestComponent(`<div [ngClass]="{'color-red': condition}"></div>`);
|
||||
@ -392,7 +389,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
expect(leading.className).toBe('foo');
|
||||
expect(trailing.className).toBe('foo');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -406,7 +402,9 @@ class TestComponent {
|
||||
objExpr: {[klass: string]: any}|null = {'foo': true, 'bar': false};
|
||||
strExpr: string|null = 'foo';
|
||||
|
||||
constructor() { this.setExpr.add('foo'); }
|
||||
constructor() {
|
||||
this.setExpr.add('foo');
|
||||
}
|
||||
}
|
||||
|
||||
function createTestComponent(template: string): ComponentFixture<TestComponent> {
|
||||
|
@ -8,13 +8,14 @@
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {NgComponentOutlet} from '@angular/common/src/directives/ng_component_outlet';
|
||||
import {Compiler, Component, ComponentRef, Inject, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory, Optional, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
|
||||
import {TestBed, async} from '@angular/core/testing';
|
||||
import {Compiler, Component, ComponentRef, Inject, InjectionToken, Injector, NgModule, NgModuleFactory, NO_ERRORS_SCHEMA, Optional, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
|
||||
import {async, TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
describe('insert/remove', () => {
|
||||
|
||||
beforeEach(() => { TestBed.configureTestingModule({imports: [TestModule]}); });
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({imports: [TestModule]});
|
||||
});
|
||||
|
||||
it('should do nothing if component is null', async(() => {
|
||||
const template = `<ng-template *ngComponentOutlet="currentComponent"></ng-template>`;
|
||||
@ -51,7 +52,7 @@ describe('insert/remove', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('foo');
|
||||
expect(fixture.componentInstance.cmpRef).toBeAnInstanceOf(ComponentRef);
|
||||
expect(fixture.componentInstance.cmpRef !.instance).toBeAnInstanceOf(InjectedComponent);
|
||||
expect(fixture.componentInstance.cmpRef!.instance).toBeAnInstanceOf(InjectedComponent);
|
||||
}));
|
||||
|
||||
|
||||
@ -99,11 +100,10 @@ describe('insert/remove', () => {
|
||||
[{provide: TEST_TOKEN, useValue: uniqueValue}], fixture.componentRef.injector);
|
||||
|
||||
fixture.detectChanges();
|
||||
let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef !;
|
||||
let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef!;
|
||||
expect(cmpRef).toBeAnInstanceOf(ComponentRef);
|
||||
expect(cmpRef.instance).toBeAnInstanceOf(InjectedComponent);
|
||||
expect(cmpRef.instance.testToken).toBe(uniqueValue);
|
||||
|
||||
}));
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ describe('insert/remove', () => {
|
||||
fixture.componentInstance.cmpRef = null;
|
||||
fixture.componentInstance.currentComponent = InjectedComponent;
|
||||
fixture.detectChanges();
|
||||
let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef !;
|
||||
let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef!;
|
||||
expect(cmpRef).toBeAnInstanceOf(ComponentRef);
|
||||
expect(cmpRef.instance).toBeAnInstanceOf(InjectedComponent);
|
||||
expect(cmpRef.instance.testToken).toBeNull();
|
||||
@ -166,7 +166,7 @@ describe('insert/remove', () => {
|
||||
fixture.componentInstance.currentComponent = Module2InjectedComponent;
|
||||
fixture.detectChanges();
|
||||
|
||||
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef'] !;
|
||||
const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef']!;
|
||||
spyOn(moduleRef, 'destroy').and.callThrough();
|
||||
|
||||
expect(moduleRef.destroy).not.toHaveBeenCalled();
|
||||
@ -224,21 +224,25 @@ const TEST_CMP_TEMPLATE =
|
||||
@Component({selector: 'test-cmp', template: TEST_CMP_TEMPLATE})
|
||||
class TestComponent {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
currentComponent !: Type<any>| null;
|
||||
currentComponent!: Type<any>|null;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
injector !: Injector;
|
||||
injector!: Injector;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
projectables !: any[][];
|
||||
projectables!: any[][];
|
||||
// TODO(issue/24571): remove '!'.
|
||||
module !: NgModuleFactory<any>;
|
||||
module!: NgModuleFactory<any>;
|
||||
|
||||
get cmpRef(): ComponentRef<any>|null { return this.ngComponentOutlet['_componentRef']; }
|
||||
set cmpRef(value: ComponentRef<any>|null) { this.ngComponentOutlet['_componentRef'] = value; }
|
||||
get cmpRef(): ComponentRef<any>|null {
|
||||
return this.ngComponentOutlet['_componentRef'];
|
||||
}
|
||||
set cmpRef(value: ComponentRef<any>|null) {
|
||||
this.ngComponentOutlet['_componentRef'] = value;
|
||||
}
|
||||
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@ViewChildren(TemplateRef) tplRefs !: QueryList<TemplateRef<any>>;
|
||||
@ViewChildren(TemplateRef) tplRefs!: QueryList<TemplateRef<any>>;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@ViewChild(NgComponentOutlet, {static: true}) ngComponentOutlet !: NgComponentOutlet;
|
||||
@ViewChild(NgComponentOutlet, {static: true}) ngComponentOutlet!: NgComponentOutlet;
|
||||
|
||||
constructor(public vcRef: ViewContainerRef) {}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
@ -18,14 +18,18 @@ let thisArg: any;
|
||||
describe('ngFor', () => {
|
||||
let fixture: ComponentFixture<any>;
|
||||
|
||||
function getComponent(): TestComponent { return fixture.componentInstance; }
|
||||
function getComponent(): TestComponent {
|
||||
return fixture.componentInstance;
|
||||
}
|
||||
|
||||
function detectChangesAndExpectText(text: string): void {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText(text);
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null as any; });
|
||||
afterEach(() => {
|
||||
fixture = null as any;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@ -103,7 +107,7 @@ let thisArg: any;
|
||||
|
||||
detectChangesAndExpectText('1;2;');
|
||||
|
||||
getComponent().items = null !;
|
||||
getComponent().items = null!;
|
||||
detectChangesAndExpectText('');
|
||||
|
||||
getComponent().items = [1, 2, 3];
|
||||
@ -377,16 +381,24 @@ let thisArg: any;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
toString() { return 'foo'; }
|
||||
toString() {
|
||||
return 'foo';
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'test-cmp', template: ''})
|
||||
class TestComponent {
|
||||
value: any;
|
||||
items: any[] = [1, 2];
|
||||
trackById(index: number, item: any): string { return item['id']; }
|
||||
trackByIndex(index: number, item: any): number { return index; }
|
||||
trackByContext(): void { thisArg = this; }
|
||||
trackById(index: number, item: any): string {
|
||||
return item['id'];
|
||||
}
|
||||
trackByIndex(index: number, item: any): number {
|
||||
return index;
|
||||
}
|
||||
trackByContext(): void {
|
||||
thisArg = this;
|
||||
}
|
||||
}
|
||||
|
||||
const TEMPLATE = '<div><span *ngFor="let item of items">{{item.toString()}};</span></div>';
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {CommonModule, ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
@ -16,9 +16,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
describe('ngIf directive', () => {
|
||||
let fixture: ComponentFixture<any>;
|
||||
|
||||
function getComponent(): TestComponent { return fixture.componentInstance; }
|
||||
function getComponent(): TestComponent {
|
||||
return fixture.componentInstance;
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null !; });
|
||||
afterEach(() => {
|
||||
fixture = null!;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
|
@ -8,21 +8,25 @@
|
||||
|
||||
import {CommonModule, NgLocalization} from '@angular/common';
|
||||
import {Component, Injectable} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
{
|
||||
describe('ngPlural', () => {
|
||||
let fixture: ComponentFixture<any>;
|
||||
|
||||
function getComponent(): TestComponent { return fixture.componentInstance; }
|
||||
function getComponent(): TestComponent {
|
||||
return fixture.componentInstance;
|
||||
}
|
||||
|
||||
function detectChangesAndExpectText<T>(text: string): void {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText(text);
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null !; });
|
||||
afterEach(() => {
|
||||
fixture = null!;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
|
@ -8,19 +8,23 @@
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
{
|
||||
describe('NgStyle', () => {
|
||||
let fixture: ComponentFixture<TestComponent>;
|
||||
|
||||
function getComponent(): TestComponent { return fixture.componentInstance; }
|
||||
function getComponent(): TestComponent {
|
||||
return fixture.componentInstance;
|
||||
}
|
||||
|
||||
function expectNativeEl(fixture: ComponentFixture<any>): any {
|
||||
return expect(fixture.debugElement.children[0].nativeElement);
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null !; });
|
||||
afterEach(() => {
|
||||
fixture = null!;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({declarations: [TestComponent], imports: [CommonModule]});
|
||||
@ -159,7 +163,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
}));
|
||||
|
||||
it('should not write to the native node unless the bound expression has changed', () => {
|
||||
|
||||
const template = `<div [ngStyle]="{'color': expr}"></div>`;
|
||||
|
||||
fixture = createTestComponent(template);
|
||||
@ -189,7 +192,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
fixture.detectChanges();
|
||||
expectNativeEl(fixture).toHaveCssStyle({'width': '400px'});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,18 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
describe('NgSwitch', () => {
|
||||
let fixture: ComponentFixture<any>;
|
||||
|
||||
function getComponent(): TestComponent { return fixture.componentInstance; }
|
||||
function getComponent(): TestComponent {
|
||||
return fixture.componentInstance;
|
||||
}
|
||||
|
||||
function detectChangesAndExpectText(text: string): void {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText(text);
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null !; });
|
||||
afterEach(() => {
|
||||
fixture = null!;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@ -118,13 +122,14 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
|
||||
describe('corner cases', () => {
|
||||
|
||||
it('should not create the default case if another case matches', () => {
|
||||
const log: string[] = [];
|
||||
|
||||
@Directive({selector: '[test]'})
|
||||
class TestDirective {
|
||||
constructor(@Attribute('test') test: string) { log.push(test); }
|
||||
constructor(@Attribute('test') test: string) {
|
||||
log.push(test);
|
||||
}
|
||||
}
|
||||
|
||||
const template = '<div [ngSwitch]="switchValue">' +
|
||||
@ -149,7 +154,6 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
fixture = createTestComponent(template);
|
||||
detectChangesAndExpectText('when default1;when default2;');
|
||||
|
||||
});
|
||||
|
||||
it('should allow defaults before cases', () => {
|
||||
@ -223,8 +227,8 @@ class TestComponent {
|
||||
`
|
||||
})
|
||||
class ComplexComponent {
|
||||
@ViewChild('foo', {static: true}) foo !: TemplateRef<any>;
|
||||
@ViewChild('bar', {static: true}) bar !: TemplateRef<any>;
|
||||
@ViewChild('foo', {static: true}) foo!: TemplateRef<any>;
|
||||
@ViewChild('bar', {static: true}) bar!: TemplateRef<any>;
|
||||
state: string = 'case1';
|
||||
}
|
||||
|
||||
|
@ -8,20 +8,24 @@
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component, ContentChildren, Directive, Injectable, NO_ERRORS_SCHEMA, OnDestroy, QueryList, TemplateRef} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
describe('NgTemplateOutlet', () => {
|
||||
let fixture: ComponentFixture<any>;
|
||||
|
||||
function setTplRef(value: any): void { fixture.componentInstance.currentTplRef = value; }
|
||||
function setTplRef(value: any): void {
|
||||
fixture.componentInstance.currentTplRef = value;
|
||||
}
|
||||
|
||||
function detectChangesAndExpectText(text: string): void {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement).toHaveText(text);
|
||||
}
|
||||
|
||||
afterEach(() => { fixture = null as any; });
|
||||
afterEach(() => {
|
||||
fixture = null as any;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@ -58,7 +62,7 @@ describe('NgTemplateOutlet', () => {
|
||||
`<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`;
|
||||
fixture = createTestComponent(template);
|
||||
fixture.detectChanges();
|
||||
const refs = fixture.debugElement.children[0].references !['refs'];
|
||||
const refs = fixture.debugElement.children[0].references!['refs'];
|
||||
|
||||
setTplRef(refs.tplRefs.first);
|
||||
detectChangesAndExpectText('foo');
|
||||
@ -74,7 +78,7 @@ describe('NgTemplateOutlet', () => {
|
||||
fixture = createTestComponent(template);
|
||||
|
||||
fixture.detectChanges();
|
||||
const refs = fixture.debugElement.children[0].references !['refs'];
|
||||
const refs = fixture.debugElement.children[0].references!['refs'];
|
||||
|
||||
setTplRef(refs.tplRefs.first);
|
||||
detectChangesAndExpectText('foo');
|
||||
@ -223,7 +227,7 @@ describe('NgTemplateOutlet', () => {
|
||||
`<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`;
|
||||
fixture = createTestComponent(template);
|
||||
fixture.detectChanges();
|
||||
const refs = fixture.debugElement.children[0].references !['refs'];
|
||||
const refs = fixture.debugElement.children[0].references!['refs'];
|
||||
|
||||
setTplRef(refs.tplRefs.first);
|
||||
detectChangesAndExpectText('foo');
|
||||
@ -236,7 +240,6 @@ describe('NgTemplateOutlet', () => {
|
||||
detectChangesAndExpectText('foo');
|
||||
}).not.toThrow();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
@Injectable()
|
||||
@ -248,19 +251,21 @@ class DestroyedSpyService {
|
||||
class DestroyableCmpt implements OnDestroy {
|
||||
constructor(private _spyService: DestroyedSpyService) {}
|
||||
|
||||
ngOnDestroy(): void { this._spyService.destroyed = true; }
|
||||
ngOnDestroy(): void {
|
||||
this._spyService.destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
|
||||
class CaptureTplRefs {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@ContentChildren(TemplateRef) tplRefs !: QueryList<TemplateRef<any>>;
|
||||
@ContentChildren(TemplateRef) tplRefs!: QueryList<TemplateRef<any>>;
|
||||
}
|
||||
|
||||
@Component({selector: 'test-cmp', template: ''})
|
||||
class TestComponent {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
currentTplRef !: TemplateRef<any>;
|
||||
currentTplRef!: TemplateRef<any>;
|
||||
context: any = {foo: 'bar'};
|
||||
value = 'bar';
|
||||
}
|
||||
|
@ -9,13 +9,12 @@
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {Component, Directive} from '@angular/core';
|
||||
import {ElementRef} from '@angular/core/src/linker/element_ref';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {hasClass} from '@angular/platform-browser/testing/src/browser_util';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
{
|
||||
describe('non-bindable', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TestComponent, TestDirective],
|
||||
@ -53,13 +52,17 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
@Directive({selector: '[test-dec]'})
|
||||
class TestDirective {
|
||||
constructor(el: ElementRef) { el.nativeElement.classList.add('compiled'); }
|
||||
constructor(el: ElementRef) {
|
||||
el.nativeElement.classList.add('compiled');
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'test-cmp', template: ''})
|
||||
class TestComponent {
|
||||
text: string;
|
||||
constructor() { this.text = 'foo'; }
|
||||
constructor() {
|
||||
this.text = 'foo';
|
||||
}
|
||||
}
|
||||
|
||||
function createTestComponent(template: string): ComponentFixture<TestComponent> {
|
||||
|
@ -12,35 +12,50 @@ import localeEnExtra from '@angular/common/locales/extra/en';
|
||||
import localeHu from '@angular/common/locales/hu';
|
||||
import localeSr from '@angular/common/locales/sr';
|
||||
import localeTh from '@angular/common/locales/th';
|
||||
import {isDate, toDate, formatDate} from '@angular/common/src/i18n/format_date';
|
||||
import {ɵDEFAULT_LOCALE_ID, ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core';
|
||||
import {formatDate, isDate, toDate} from '@angular/common/src/i18n/format_date';
|
||||
import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
|
||||
describe('Format date', () => {
|
||||
describe('toDate', () => {
|
||||
it('should support date', () => { expect(isDate(toDate(new Date()))).toBeTruthy(); });
|
||||
it('should support date', () => {
|
||||
expect(isDate(toDate(new Date()))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should support int', () => { expect(isDate(toDate(123456789))).toBeTruthy(); });
|
||||
it('should support int', () => {
|
||||
expect(isDate(toDate(123456789))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should support numeric strings',
|
||||
() => { expect(isDate(toDate('123456789'))).toBeTruthy(); });
|
||||
it('should support numeric strings', () => {
|
||||
expect(isDate(toDate('123456789'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should support decimal strings',
|
||||
() => { expect(isDate(toDate('123456789.11'))).toBeTruthy(); });
|
||||
it('should support decimal strings', () => {
|
||||
expect(isDate(toDate('123456789.11'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should support ISO string',
|
||||
() => { expect(isDate(toDate('2015-06-15T21:43:11Z'))).toBeTruthy(); });
|
||||
it('should support ISO string', () => {
|
||||
expect(isDate(toDate('2015-06-15T21:43:11Z'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw for empty string', () => { expect(() => toDate('')).toThrow(); });
|
||||
it('should throw for empty string', () => {
|
||||
expect(() => toDate('')).toThrow();
|
||||
});
|
||||
|
||||
it('should throw for alpha numeric strings',
|
||||
() => { expect(() => toDate('123456789 hello')).toThrow(); });
|
||||
it('should throw for alpha numeric strings', () => {
|
||||
expect(() => toDate('123456789 hello')).toThrow();
|
||||
});
|
||||
|
||||
it('should throw for NaN', () => { expect(() => toDate(Number.NaN)).toThrow(); });
|
||||
it('should throw for NaN', () => {
|
||||
expect(() => toDate(Number.NaN)).toThrow();
|
||||
});
|
||||
|
||||
it('should support ISO string without time',
|
||||
() => { expect(isDate(toDate('2015-01-01'))).toBeTruthy(); });
|
||||
it('should support ISO string without time', () => {
|
||||
expect(isDate(toDate('2015-01-01'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw for objects', () => { expect(() => toDate({} as any)).toThrow(); });
|
||||
it('should throw for objects', () => {
|
||||
expect(() => toDate({} as any)).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatDate', () => {
|
||||
@ -49,7 +64,7 @@ describe('Format date', () => {
|
||||
let date: Date;
|
||||
|
||||
// Check the transformation of a date into a pattern
|
||||
function expectDateFormatAs(date: Date | string, pattern: any, output: string): void {
|
||||
function expectDateFormatAs(date: Date|string, pattern: any, output: string): void {
|
||||
expect(formatDate(date, pattern, ɵDEFAULT_LOCALE_ID))
|
||||
.toEqual(output, `pattern: "${pattern}"`);
|
||||
}
|
||||
@ -65,7 +80,9 @@ describe('Format date', () => {
|
||||
|
||||
afterAll(() => ɵunregisterLocaleData());
|
||||
|
||||
beforeEach(() => { date = new Date(2015, 5, 15, 9, 3, 1, 550); });
|
||||
beforeEach(() => {
|
||||
date = new Date(2015, 5, 15, 9, 3, 1, 550);
|
||||
});
|
||||
|
||||
it('should format each component correctly', () => {
|
||||
const dateFixtures: any = {
|
||||
@ -293,7 +310,7 @@ describe('Format date', () => {
|
||||
});
|
||||
|
||||
it('should remove bidi control characters',
|
||||
() => expect(formatDate(date, 'MM/dd/yyyy', ɵDEFAULT_LOCALE_ID) !.length).toEqual(10));
|
||||
() => expect(formatDate(date, 'MM/dd/yyyy', ɵDEFAULT_LOCALE_ID)!.length).toEqual(10));
|
||||
|
||||
it(`should format the date correctly in various locales`, () => {
|
||||
expect(formatDate(date, 'short', 'de')).toEqual('15.06.15, 09:03');
|
||||
|
@ -6,13 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {formatCurrency, formatNumber, formatPercent} from '@angular/common';
|
||||
import localeAr from '@angular/common/locales/ar';
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeEsUS from '@angular/common/locales/es-US';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeAr from '@angular/common/locales/ar';
|
||||
import {formatCurrency, formatNumber, formatPercent} from '@angular/common';
|
||||
import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
import {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {ɵDEFAULT_LOCALE_ID, ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core';
|
||||
|
||||
describe('Format number', () => {
|
||||
beforeAll(() => {
|
||||
@ -44,8 +44,9 @@ describe('Format number', () => {
|
||||
});
|
||||
|
||||
describe('transform with custom locales', () => {
|
||||
it('should return the correct format for es-US',
|
||||
() => { expect(formatNumber(9999999.99, 'es-US', '1.2-2')).toEqual('9,999,999.99'); });
|
||||
it('should return the correct format for es-US', () => {
|
||||
expect(formatNumber(9999999.99, 'es-US', '1.2-2')).toEqual('9,999,999.99');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -6,14 +6,14 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeEnAU from '@angular/common/locales/en-AU';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeHe from '@angular/common/locales/he';
|
||||
import localeZh from '@angular/common/locales/zh';
|
||||
import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeZh from '@angular/common/locales/zh';
|
||||
import localeEnAU from '@angular/common/locales/en-AU';
|
||||
import localeHe from '@angular/common/locales/he';
|
||||
import {getCurrencySymbol, getLocaleDateFormat, FormatWidth, getNumberOfCurrencyDigits, getLocaleDirection} from '../../src/i18n/locale_data_api';
|
||||
import {FormatWidth, getCurrencySymbol, getLocaleDateFormat, getLocaleDirection, getNumberOfCurrencyDigits} from '../../src/i18n/locale_data_api';
|
||||
|
||||
{
|
||||
describe('locale data api', () => {
|
||||
@ -25,7 +25,9 @@ import {getCurrencySymbol, getLocaleDateFormat, FormatWidth, getNumberOfCurrency
|
||||
ɵregisterLocaleData(localeHe);
|
||||
});
|
||||
|
||||
afterAll(() => { ɵunregisterLocaleData(); });
|
||||
afterAll(() => {
|
||||
ɵunregisterLocaleData();
|
||||
});
|
||||
|
||||
describe('getting currency symbol', () => {
|
||||
it('should return the correct symbol', () => {
|
||||
@ -55,16 +57,19 @@ import {getCurrencySymbol, getLocaleDateFormat, FormatWidth, getNumberOfCurrency
|
||||
});
|
||||
|
||||
describe('getLastDefinedValue', () => {
|
||||
it('should find the last defined date format when format not defined',
|
||||
() => { expect(getLocaleDateFormat('zh', FormatWidth.Long)).toEqual('y年M月d日'); });
|
||||
it('should find the last defined date format when format not defined', () => {
|
||||
expect(getLocaleDateFormat('zh', FormatWidth.Long)).toEqual('y年M月d日');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDirectionality', () => {
|
||||
it('should have correct direction for rtl languages',
|
||||
() => { expect(getLocaleDirection('he')).toEqual('rtl'); });
|
||||
it('should have correct direction for rtl languages', () => {
|
||||
expect(getLocaleDirection('he')).toEqual('rtl');
|
||||
});
|
||||
|
||||
it('should have correct direction for ltr languages',
|
||||
() => { expect(getLocaleDirection('en')).toEqual('ltr'); });
|
||||
it('should have correct direction for ltr languages', () => {
|
||||
expect(getLocaleDirection('en')).toEqual('ltr');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeRo from '@angular/common/locales/ro';
|
||||
import localeSr from '@angular/common/locales/sr';
|
||||
import localeZgh from '@angular/common/locales/zgh';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import {LOCALE_ID, ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core';
|
||||
import {TestBed, inject} from '@angular/core/testing';
|
||||
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '@angular/common/src/i18n/localization';
|
||||
import {getPluralCategory, NgLocaleLocalization, NgLocalization} from '@angular/common/src/i18n/localization';
|
||||
import {LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
|
||||
{
|
||||
describe('l10n', () => {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {CommonModule, Location, LocationStrategy, PathLocationStrategy, PlatformLocation} from '@angular/common';
|
||||
import {MockPlatformLocation} from '@angular/common/testing';
|
||||
import {TestBed, inject} from '@angular/core/testing';
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
|
||||
const baseUrl = '/base';
|
||||
|
||||
@ -46,14 +46,18 @@ describe('Location Class', () => {
|
||||
imports: [CommonModule],
|
||||
providers: [
|
||||
{provide: LocationStrategy, useClass: PathLocationStrategy},
|
||||
{provide: PlatformLocation, useFactory: () => { return new MockPlatformLocation(); }},
|
||||
{
|
||||
provide: PlatformLocation,
|
||||
useFactory: () => {
|
||||
return new MockPlatformLocation();
|
||||
}
|
||||
},
|
||||
{provide: Location, useClass: Location, deps: [LocationStrategy, PlatformLocation]},
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should get the state object', inject([Location], (location: Location) => {
|
||||
|
||||
expect(location.getState()).toBe(null);
|
||||
|
||||
location.go('/test', '', {foo: 'bar'});
|
||||
@ -62,7 +66,6 @@ describe('Location Class', () => {
|
||||
}));
|
||||
|
||||
it('should work after using back button', inject([Location], (location: Location) => {
|
||||
|
||||
expect(location.getState()).toBe(null);
|
||||
|
||||
location.go('/test1', '', {url: 'test1'});
|
||||
@ -74,7 +77,6 @@ describe('Location Class', () => {
|
||||
|
||||
expect(location.getState()).toEqual({url: 'test1'});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('location.onUrlChange()', () => {
|
||||
@ -83,7 +85,12 @@ describe('Location Class', () => {
|
||||
imports: [CommonModule],
|
||||
providers: [
|
||||
{provide: LocationStrategy, useClass: PathLocationStrategy},
|
||||
{provide: PlatformLocation, useFactory: () => { return new MockPlatformLocation(); }},
|
||||
{
|
||||
provide: PlatformLocation,
|
||||
useFactory: () => {
|
||||
return new MockPlatformLocation();
|
||||
}
|
||||
},
|
||||
{provide: Location, useClass: Location, deps: [LocationStrategy, PlatformLocation]},
|
||||
]
|
||||
});
|
||||
@ -95,8 +102,9 @@ describe('Location Class', () => {
|
||||
|
||||
it('should add registered functions to urlChangeListeners',
|
||||
inject([Location], (location: Location) => {
|
||||
|
||||
function changeListener(url: string, state: unknown) { return undefined; }
|
||||
function changeListener(url: string, state: unknown) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
expect((location as any)._urlChangeListeners.length).toBe(0);
|
||||
|
||||
@ -104,8 +112,6 @@ describe('Location Class', () => {
|
||||
|
||||
expect((location as any)._urlChangeListeners.length).toBe(1);
|
||||
expect((location as any)._urlChangeListeners[0]).toEqual(changeListener);
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
});
|
@ -15,7 +15,6 @@ import {SpyChangeDetectorRef} from '../spies';
|
||||
|
||||
{
|
||||
describe('AsyncPipe', () => {
|
||||
|
||||
describe('Observable', () => {
|
||||
let emitter: EventEmitter<any>;
|
||||
let pipe: AsyncPipe;
|
||||
@ -29,8 +28,9 @@ import {SpyChangeDetectorRef} from '../spies';
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return null when subscribing to an observable',
|
||||
() => { expect(pipe.transform(emitter)).toBe(null); });
|
||||
it('should return null when subscribing to an observable', () => {
|
||||
expect(pipe.transform(emitter)).toBe(null);
|
||||
});
|
||||
|
||||
it('should return the latest available value wrapped',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
@ -96,8 +96,9 @@ import {SpyChangeDetectorRef} from '../spies';
|
||||
});
|
||||
|
||||
describe('ngOnDestroy', () => {
|
||||
it('should do nothing when no subscription',
|
||||
() => { expect(() => pipe.ngOnDestroy()).not.toThrow(); });
|
||||
it('should do nothing when no subscription', () => {
|
||||
expect(() => pipe.ngOnDestroy()).not.toThrow();
|
||||
});
|
||||
|
||||
it('should dispose of the existing subscription',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
@ -133,8 +134,9 @@ import {SpyChangeDetectorRef} from '../spies';
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return null when subscribing to a promise',
|
||||
() => { expect(pipe.transform(promise)).toBe(null); });
|
||||
it('should return null when subscribing to a promise', () => {
|
||||
expect(pipe.transform(promise)).toBe(null);
|
||||
});
|
||||
|
||||
it('should return the latest available value',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
@ -189,8 +191,9 @@ import {SpyChangeDetectorRef} from '../spies';
|
||||
}));
|
||||
|
||||
describe('ngOnDestroy', () => {
|
||||
it('should do nothing when no source',
|
||||
() => { expect(() => pipe.ngOnDestroy()).not.toThrow(); });
|
||||
it('should do nothing when no source', () => {
|
||||
expect(() => pipe.ngOnDestroy()).not.toThrow();
|
||||
});
|
||||
|
||||
it('should dispose of the existing source',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
|
@ -12,41 +12,55 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common';
|
||||
describe('LowerCasePipe', () => {
|
||||
let pipe: LowerCasePipe;
|
||||
|
||||
beforeEach(() => { pipe = new LowerCasePipe(); });
|
||||
beforeEach(() => {
|
||||
pipe = new LowerCasePipe();
|
||||
});
|
||||
|
||||
it('should return lowercase', () => { expect(pipe.transform('FOO')).toEqual('foo'); });
|
||||
it('should return lowercase', () => {
|
||||
expect(pipe.transform('FOO')).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should lowercase when there is a new value', () => {
|
||||
expect(pipe.transform('FOO')).toEqual('foo');
|
||||
expect(pipe.transform('BAr')).toEqual('bar');
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
() => { expect(() => pipe.transform(<any>{})).toThrowError(); });
|
||||
it('should not support other objects', () => {
|
||||
expect(() => pipe.transform(<any>{})).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('TitleCasePipe', () => {
|
||||
let pipe: TitleCasePipe;
|
||||
|
||||
beforeEach(() => { pipe = new TitleCasePipe(); });
|
||||
beforeEach(() => {
|
||||
pipe = new TitleCasePipe();
|
||||
});
|
||||
|
||||
it('should return titlecase', () => { expect(pipe.transform('foo')).toEqual('Foo'); });
|
||||
it('should return titlecase', () => {
|
||||
expect(pipe.transform('foo')).toEqual('Foo');
|
||||
});
|
||||
|
||||
it('should return titlecase for subsequent words',
|
||||
() => { expect(pipe.transform('one TWO Three fouR')).toEqual('One Two Three Four'); });
|
||||
it('should return titlecase for subsequent words', () => {
|
||||
expect(pipe.transform('one TWO Three fouR')).toEqual('One Two Three Four');
|
||||
});
|
||||
|
||||
it('should support empty strings', () => { expect(pipe.transform('')).toEqual(''); });
|
||||
it('should support empty strings', () => {
|
||||
expect(pipe.transform('')).toEqual('');
|
||||
});
|
||||
|
||||
it('should persist whitespace',
|
||||
() => { expect(pipe.transform('one two')).toEqual('One Two'); });
|
||||
it('should persist whitespace', () => {
|
||||
expect(pipe.transform('one two')).toEqual('One Two');
|
||||
});
|
||||
|
||||
it('should titlecase when there is a new value', () => {
|
||||
expect(pipe.transform('bar')).toEqual('Bar');
|
||||
expect(pipe.transform('foo')).toEqual('Foo');
|
||||
});
|
||||
|
||||
it('should not capitalize letter after the quotes',
|
||||
() => { expect(pipe.transform('it\'s complicated')).toEqual('It\'s Complicated'); });
|
||||
it('should not capitalize letter after the quotes', () => {
|
||||
expect(pipe.transform('it\'s complicated')).toEqual('It\'s Complicated');
|
||||
});
|
||||
|
||||
it('should not treat non-space character as a separator', () => {
|
||||
expect(pipe.transform('one,two,three')).toEqual('One,two,three');
|
||||
@ -66,23 +80,29 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common';
|
||||
expect(pipe.transform('éric')).toEqual('Éric');
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
() => { expect(() => pipe.transform(<any>{})).toThrowError(); });
|
||||
it('should not support other objects', () => {
|
||||
expect(() => pipe.transform(<any>{})).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpperCasePipe', () => {
|
||||
let pipe: UpperCasePipe;
|
||||
|
||||
beforeEach(() => { pipe = new UpperCasePipe(); });
|
||||
beforeEach(() => {
|
||||
pipe = new UpperCasePipe();
|
||||
});
|
||||
|
||||
it('should return uppercase', () => { expect(pipe.transform('foo')).toEqual('FOO'); });
|
||||
it('should return uppercase', () => {
|
||||
expect(pipe.transform('foo')).toEqual('FOO');
|
||||
});
|
||||
|
||||
it('should uppercase when there is a new value', () => {
|
||||
expect(pipe.transform('foo')).toEqual('FOO');
|
||||
expect(pipe.transform('bar')).toEqual('BAR');
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
() => { expect(() => pipe.transform(<any>{})).toThrowError(); });
|
||||
it('should not support other objects', () => {
|
||||
expect(() => pipe.transform(<any>{})).toThrowError();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ import {DatePipe} from '@angular/common';
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeEnExtra from '@angular/common/locales/extra/en';
|
||||
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
|
||||
import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector';
|
||||
import {ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core';
|
||||
|
||||
{
|
||||
let date: Date;
|
||||
@ -28,33 +28,44 @@ import {ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core';
|
||||
});
|
||||
|
||||
it('should be marked as pure', () => {
|
||||
expect(new PipeResolver(new JitReflector()).resolve(DatePipe) !.pure).toEqual(true);
|
||||
expect(new PipeResolver(new JitReflector()).resolve(DatePipe)!.pure).toEqual(true);
|
||||
});
|
||||
|
||||
describe('supports', () => {
|
||||
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
|
||||
it('should support date', () => {
|
||||
expect(() => pipe.transform(date)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
|
||||
it('should support int', () => {
|
||||
expect(() => pipe.transform(123456789)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should support numeric strings',
|
||||
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
|
||||
it('should support numeric strings', () => {
|
||||
expect(() => pipe.transform('123456789')).not.toThrow();
|
||||
});
|
||||
|
||||
it('should support decimal strings',
|
||||
() => { expect(() => pipe.transform('123456789.11')).not.toThrow(); });
|
||||
it('should support decimal strings', () => {
|
||||
expect(() => pipe.transform('123456789.11')).not.toThrow();
|
||||
});
|
||||
|
||||
it('should support ISO string',
|
||||
() => expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow());
|
||||
|
||||
it('should return null for empty string',
|
||||
() => { expect(pipe.transform('')).toEqual(null); });
|
||||
it('should return null for empty string', () => {
|
||||
expect(pipe.transform('')).toEqual(null);
|
||||
});
|
||||
|
||||
it('should return null for NaN', () => { expect(pipe.transform(Number.NaN)).toEqual(null); });
|
||||
it('should return null for NaN', () => {
|
||||
expect(pipe.transform(Number.NaN)).toEqual(null);
|
||||
});
|
||||
|
||||
it('should support ISO string without time',
|
||||
() => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); });
|
||||
it('should support ISO string without time', () => {
|
||||
expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
() => { expect(() => pipe.transform({})).toThrowError(/InvalidPipeArgument/); });
|
||||
it('should not support other objects', () => {
|
||||
expect(() => pipe.transform({})).toThrowError(/InvalidPipeArgument/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
|
@ -29,7 +29,7 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle
|
||||
});
|
||||
|
||||
it('should be marked as pure', () => {
|
||||
expect(new PipeResolver(new JitReflector()).resolve(I18nPluralPipe) !.pure).toEqual(true);
|
||||
expect(new PipeResolver(new JitReflector()).resolve(I18nPluralPipe)!.pure).toEqual(true);
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
@ -54,17 +54,19 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle
|
||||
});
|
||||
|
||||
it('should use "" if value is undefined', () => {
|
||||
const val = pipe.transform(void(0) as any, mapping);
|
||||
const val = pipe.transform(void (0) as any, mapping);
|
||||
expect(val).toEqual('');
|
||||
});
|
||||
|
||||
it('should not support bad arguments',
|
||||
() => { expect(() => pipe.transform(0, <any>'hey')).toThrowError(); });
|
||||
it('should not support bad arguments', () => {
|
||||
expect(() => pipe.transform(0, <any>'hey')).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class TestLocalization extends NgLocalization {
|
||||
getPluralCategory(value: number): string { return value > 1 && value < 6 ? 'many' : 'other'; }
|
||||
getPluralCategory(value: number): string {
|
||||
return value > 1 && value < 6 ? 'many' : 'other';
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle
|
||||
const mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
|
||||
|
||||
it('should be marked as pure', () => {
|
||||
expect(new PipeResolver(new JitReflector()).resolve(I18nSelectPipe) !.pure).toEqual(true);
|
||||
expect(new PipeResolver(new JitReflector()).resolve(I18nSelectPipe)!.pure).toEqual(true);
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
@ -30,17 +30,18 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle
|
||||
expect(val).toEqual('Invite her.');
|
||||
});
|
||||
|
||||
it('should return the "other" text if value is neither "male" nor "female"',
|
||||
() => { expect(pipe.transform('Anything else', mapping)).toEqual('Invite them.'); });
|
||||
it('should return the "other" text if value is neither "male" nor "female"', () => {
|
||||
expect(pipe.transform('Anything else', mapping)).toEqual('Invite them.');
|
||||
});
|
||||
|
||||
it('should return an empty text if value is null or undefined', () => {
|
||||
expect(pipe.transform(null, mapping)).toEqual('');
|
||||
expect(pipe.transform(void 0, mapping)).toEqual('');
|
||||
});
|
||||
|
||||
it('should throw on bad arguments',
|
||||
() => { expect(() => pipe.transform('male', <any>'hey')).toThrowError(); });
|
||||
it('should throw on bad arguments', () => {
|
||||
expect(() => pipe.transform('male', <any>'hey')).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {CommonModule, JsonPipe} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {TestBed, async} from '@angular/core/testing';
|
||||
import {async, TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
{
|
||||
@ -18,7 +18,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
let inceptionObjString: string;
|
||||
let pipe: JsonPipe;
|
||||
|
||||
function normalize(obj: string): string { return obj.replace(regNewLine, ''); }
|
||||
function normalize(obj: string): string {
|
||||
return obj.replace(regNewLine, '');
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
inceptionObj = {dream: {dream: {dream: 'Limbo'}}};
|
||||
@ -35,8 +37,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return JSON-formatted string',
|
||||
() => { expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); });
|
||||
it('should return JSON-formatted string', () => {
|
||||
expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString);
|
||||
});
|
||||
|
||||
it('should return JSON-formatted string even when normalized', () => {
|
||||
const dream1 = normalize(pipe.transform(inceptionObj));
|
||||
@ -52,7 +55,6 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
|
||||
describe('integration', () => {
|
||||
|
||||
@Component({selector: 'test-comp', template: '{{data | json}}'})
|
||||
class TestComp {
|
||||
data: any;
|
||||
|
@ -64,12 +64,12 @@ describe('KeyValuePipe', () => {
|
||||
expect(transform1 !== transform2).toEqual(true);
|
||||
});
|
||||
it('should accept a type union of an object with string keys and null', () => {
|
||||
let value !: {[key: string]: string} | null;
|
||||
let value!: {[key: string]: string}|null;
|
||||
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
|
||||
expect(pipe.transform(value)).toEqual(null);
|
||||
});
|
||||
it('should accept a type union of an object with number keys and null', () => {
|
||||
let value !: {[key: number]: string} | null;
|
||||
let value!: {[key: number]: string}|null;
|
||||
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
|
||||
expect(pipe.transform(value)).toEqual(null);
|
||||
});
|
||||
@ -126,7 +126,7 @@ describe('KeyValuePipe', () => {
|
||||
expect(transform1 !== transform2).toEqual(true);
|
||||
});
|
||||
it('should accept a type union of a Map and null', () => {
|
||||
let value !: Map<number, number>| null;
|
||||
let value!: Map<number, number>|null;
|
||||
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
|
||||
expect(pipe.transform(value)).toEqual(null);
|
||||
});
|
||||
|
@ -6,14 +6,14 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common';
|
||||
import localeAr from '@angular/common/locales/ar';
|
||||
import localeDa from '@angular/common/locales/da';
|
||||
import localeDeAt from '@angular/common/locales/de-AT';
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeEsUS from '@angular/common/locales/es-US';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeAr from '@angular/common/locales/ar';
|
||||
import localeDeAt from '@angular/common/locales/de-AT';
|
||||
import localeDa from '@angular/common/locales/da';
|
||||
import {ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core';
|
||||
import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common';
|
||||
import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
||||
|
||||
{
|
||||
@ -32,7 +32,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
|
||||
describe('DecimalPipe', () => {
|
||||
describe('transform', () => {
|
||||
let pipe: DecimalPipe;
|
||||
beforeEach(() => { pipe = new DecimalPipe('en-US'); });
|
||||
beforeEach(() => {
|
||||
pipe = new DecimalPipe('en-US');
|
||||
});
|
||||
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(12345)).toEqual('12,345');
|
||||
@ -68,7 +70,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
|
||||
describe('PercentPipe', () => {
|
||||
let pipe: PercentPipe;
|
||||
|
||||
beforeEach(() => { pipe = new PercentPipe('en-US'); });
|
||||
beforeEach(() => {
|
||||
pipe = new PercentPipe('en-US');
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
@ -89,7 +93,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin
|
||||
describe('CurrencyPipe', () => {
|
||||
let pipe: CurrencyPipe;
|
||||
|
||||
beforeEach(() => { pipe = new CurrencyPipe('en-US', 'USD'); });
|
||||
beforeEach(() => {
|
||||
pipe = new CurrencyPipe('en-US', 'USD');
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {CommonModule, SlicePipe} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {TestBed, async} from '@angular/core/testing';
|
||||
import {async, TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
{
|
||||
@ -24,24 +24,32 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
|
||||
describe('supports', () => {
|
||||
it('should support strings', () => { expect(() => pipe.transform(str, 0)).not.toThrow(); });
|
||||
it('should support lists', () => { expect(() => pipe.transform(list, 0)).not.toThrow(); });
|
||||
it('should support readonly lists',
|
||||
() => { expect(() => pipe.transform(list as ReadonlyArray<number>, 0)).not.toThrow(); });
|
||||
it('should support strings', () => {
|
||||
expect(() => pipe.transform(str, 0)).not.toThrow();
|
||||
});
|
||||
it('should support lists', () => {
|
||||
expect(() => pipe.transform(list, 0)).not.toThrow();
|
||||
});
|
||||
it('should support readonly lists', () => {
|
||||
expect(() => pipe.transform(list as ReadonlyArray<number>, 0)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not support other objects',
|
||||
// this would not compile
|
||||
// so we cast as `any` to check that it throws for unsupported objects
|
||||
() => { expect(() => pipe.transform({} as any, 0)).toThrow(); });
|
||||
() => {
|
||||
expect(() => pipe.transform({} as any, 0)).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transform', () => {
|
||||
it('should return null if the value is null', () => {
|
||||
expect(pipe.transform(null, 1)).toBe(null);
|
||||
});
|
||||
|
||||
it('should return null if the value is null',
|
||||
() => { expect(pipe.transform(null, 1)).toBe(null); });
|
||||
|
||||
it('should return undefined if the value is undefined',
|
||||
() => { expect(pipe.transform(undefined, 1)).toBe(undefined); });
|
||||
it('should return undefined if the value is undefined', () => {
|
||||
expect(pipe.transform(undefined, 1)).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return all items after START index when START is positive and END is omitted',
|
||||
() => {
|
||||
@ -85,11 +93,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
expect(pipe.transform(list, 2)).toEqual([3, 4, 5]);
|
||||
expect(list).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('integration', () => {
|
||||
|
||||
@Component({selector: 'test-comp', template: '{{(data | slice:1).join(",") }}'})
|
||||
class TestComp {
|
||||
data: any;
|
||||
|
@ -18,4 +18,6 @@ export class SpyChangeDetectorRef extends SpyObject {
|
||||
|
||||
export class SpyNgControl extends SpyObject {}
|
||||
|
||||
export class SpyValueAccessor extends SpyObject { writeValue: any; }
|
||||
export class SpyValueAccessor extends SpyObject {
|
||||
writeValue: any;
|
||||
}
|
||||
|
@ -9,12 +9,12 @@
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
* @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 {describe, expect, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {BrowserViewportScroller, ViewportScroller} from '../src/viewport_scroller';
|
||||
@ -25,7 +25,7 @@ import {BrowserViewportScroller, ViewportScroller} from '../src/viewport_scrolle
|
||||
let documentSpy: any;
|
||||
beforeEach(() => {
|
||||
documentSpy = jasmine.createSpyObj('document', ['querySelector']);
|
||||
scroller = new BrowserViewportScroller(documentSpy, {scrollTo: 1}, null !);
|
||||
scroller = new BrowserViewportScroller(documentSpy, {scrollTo: 1}, null!);
|
||||
});
|
||||
it('escapes invalid characters selectors', () => {
|
||||
const invalidSelectorChars = `"' :.[],=`;
|
||||
|
@ -25,19 +25,27 @@ export class SpyLocation implements Location {
|
||||
/** @internal */
|
||||
_baseHref: string = '';
|
||||
/** @internal */
|
||||
_platformStrategy: LocationStrategy = null !;
|
||||
_platformStrategy: LocationStrategy = null!;
|
||||
/** @internal */
|
||||
_platformLocation: PlatformLocation = null !;
|
||||
_platformLocation: PlatformLocation = null!;
|
||||
/** @internal */
|
||||
_urlChangeListeners: ((url: string, state: unknown) => void)[] = [];
|
||||
|
||||
setInitialPath(url: string) { this._history[this._historyIndex].path = url; }
|
||||
setInitialPath(url: string) {
|
||||
this._history[this._historyIndex].path = url;
|
||||
}
|
||||
|
||||
setBaseHref(url: string) { this._baseHref = url; }
|
||||
setBaseHref(url: string) {
|
||||
this._baseHref = url;
|
||||
}
|
||||
|
||||
path(): string { return this._history[this._historyIndex].path; }
|
||||
path(): string {
|
||||
return this._history[this._historyIndex].path;
|
||||
}
|
||||
|
||||
getState(): unknown { return this._history[this._historyIndex].state; }
|
||||
getState(): unknown {
|
||||
return this._history[this._historyIndex].state;
|
||||
}
|
||||
|
||||
isCurrentPathEqualTo(path: string, query: string = ''): boolean {
|
||||
const givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
|
||||
@ -115,7 +123,9 @@ export class SpyLocation implements Location {
|
||||
}
|
||||
onUrlChange(fn: (url: string, state: unknown) => void) {
|
||||
this._urlChangeListeners.push(fn);
|
||||
this.subscribe(v => { this._notifyUrlChangeListeners(v.url, v.state); });
|
||||
this.subscribe(v => {
|
||||
this._notifyUrlChangeListeners(v.url, v.state);
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@ -129,7 +139,9 @@ export class SpyLocation implements Location {
|
||||
return this._subject.subscribe({next: onNext, error: onThrow, complete: onReturn});
|
||||
}
|
||||
|
||||
normalize(url: string): string { return null !; }
|
||||
normalize(url: string): string {
|
||||
return null!;
|
||||
}
|
||||
}
|
||||
|
||||
class LocationState {
|
||||
|
@ -26,14 +26,18 @@ export class MockLocationStrategy extends LocationStrategy {
|
||||
/** @internal */
|
||||
_subject: EventEmitter<any> = new EventEmitter();
|
||||
private stateChanges: any[] = [];
|
||||
constructor() { super(); }
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
simulatePopState(url: string): void {
|
||||
this.internalPath = url;
|
||||
this._subject.emit(new _MockPopStateEvent(this.path()));
|
||||
}
|
||||
|
||||
path(includeHash: boolean = false): string { return this.internalPath; }
|
||||
path(includeHash: boolean = false): string {
|
||||
return this.internalPath;
|
||||
}
|
||||
|
||||
prepareExternalUrl(internal: string): string {
|
||||
if (internal.startsWith('/') && this.internalBaseHref.endsWith('/')) {
|
||||
@ -68,9 +72,13 @@ export class MockLocationStrategy extends LocationStrategy {
|
||||
this.urlChanges.push('replace: ' + externalUrl);
|
||||
}
|
||||
|
||||
onPopState(fn: (value: any) => void): void { this._subject.subscribe({next: fn}); }
|
||||
onPopState(fn: (value: any) => void): void {
|
||||
this._subject.subscribe({next: fn});
|
||||
}
|
||||
|
||||
getBaseHref(): string { return this.internalBaseHref; }
|
||||
getBaseHref(): string {
|
||||
return this.internalBaseHref;
|
||||
}
|
||||
|
||||
back(): void {
|
||||
if (this.urlChanges.length > 0) {
|
||||
@ -81,9 +89,13 @@ export class MockLocationStrategy extends LocationStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
forward(): void { throw 'not implemented'; }
|
||||
forward(): void {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getState(): unknown { return this.stateChanges[(this.stateChanges.length || 1) - 1]; }
|
||||
getState(): unknown {
|
||||
return this.stateChanges[(this.stateChanges.length || 1) - 1];
|
||||
}
|
||||
}
|
||||
|
||||
class _MockPopStateEvent {
|
||||
|
@ -126,23 +126,41 @@ export class MockPlatformLocation implements PlatformLocation {
|
||||
}
|
||||
}
|
||||
|
||||
get hostname() { return this.urlChanges[0].hostname; }
|
||||
get protocol() { return this.urlChanges[0].protocol; }
|
||||
get port() { return this.urlChanges[0].port; }
|
||||
get pathname() { return this.urlChanges[0].pathname; }
|
||||
get search() { return this.urlChanges[0].search; }
|
||||
get hash() { return this.urlChanges[0].hash; }
|
||||
get state() { return this.urlChanges[0].state; }
|
||||
get hostname() {
|
||||
return this.urlChanges[0].hostname;
|
||||
}
|
||||
get protocol() {
|
||||
return this.urlChanges[0].protocol;
|
||||
}
|
||||
get port() {
|
||||
return this.urlChanges[0].port;
|
||||
}
|
||||
get pathname() {
|
||||
return this.urlChanges[0].pathname;
|
||||
}
|
||||
get search() {
|
||||
return this.urlChanges[0].search;
|
||||
}
|
||||
get hash() {
|
||||
return this.urlChanges[0].hash;
|
||||
}
|
||||
get state() {
|
||||
return this.urlChanges[0].state;
|
||||
}
|
||||
|
||||
|
||||
getBaseHrefFromDOM(): string { return this.baseHref; }
|
||||
getBaseHrefFromDOM(): string {
|
||||
return this.baseHref;
|
||||
}
|
||||
|
||||
onPopState(fn: LocationChangeListener): void {
|
||||
// No-op: a state stack is not implemented, so
|
||||
// no events will ever come.
|
||||
}
|
||||
|
||||
onHashChange(fn: LocationChangeListener): void { this.hashUpdate.subscribe(fn); }
|
||||
onHashChange(fn: LocationChangeListener): void {
|
||||
this.hashUpdate.subscribe(fn);
|
||||
}
|
||||
|
||||
get href(): string {
|
||||
let url = `${this.protocol}//${this.hostname}${this.port ? ':' + this.port : ''}`;
|
||||
@ -150,7 +168,9 @@ export class MockPlatformLocation implements PlatformLocation {
|
||||
return url;
|
||||
}
|
||||
|
||||
get url(): string { return `${this.pathname}${this.search}${this.hash}`; }
|
||||
get url(): string {
|
||||
return `${this.pathname}${this.search}${this.hash}`;
|
||||
}
|
||||
|
||||
private parseChanges(state: unknown, url: string, baseHref: string = '') {
|
||||
// When the `history.state` value is stored, it is always copied.
|
||||
@ -169,7 +189,9 @@ export class MockPlatformLocation implements PlatformLocation {
|
||||
this.urlChanges.unshift({...this.urlChanges[0], pathname, search, hash, state: parsedState});
|
||||
}
|
||||
|
||||
forward(): void { throw new Error('Not implemented'); }
|
||||
forward(): void {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
back(): void {
|
||||
const oldUrl = this.url;
|
||||
@ -178,13 +200,15 @@ export class MockPlatformLocation implements PlatformLocation {
|
||||
const newHash = this.hash;
|
||||
|
||||
if (oldHash !== newHash) {
|
||||
scheduleMicroTask(() => this.hashUpdate.next({
|
||||
type: 'hashchange', state: null, oldUrl, newUrl: this.url
|
||||
} as LocationChangeEvent));
|
||||
scheduleMicroTask(
|
||||
() => this.hashUpdate.next(
|
||||
{type: 'hashchange', state: null, oldUrl, newUrl: this.url} as LocationChangeEvent));
|
||||
}
|
||||
}
|
||||
|
||||
getState(): unknown { return this.state; }
|
||||
getState(): unknown {
|
||||
return this.state;
|
||||
}
|
||||
}
|
||||
|
||||
export function scheduleMicroTask(cb: () => any) {
|
||||
|
@ -55,7 +55,7 @@ const APP_BASE_HREF_RESOLVED = new InjectionToken<string>('APP_BASE_HREF_RESOLVE
|
||||
|
||||
/**
|
||||
* `NgModule` used for providing and configuring Angular's Unified Location Service for upgrading.
|
||||
*
|
||||
*
|
||||
* @see [Using the Unified Angular Location Service](guide/upgrade#using-the-unified-angular-location-service)
|
||||
*
|
||||
* @publicApi
|
||||
|
@ -152,7 +152,9 @@ export class AngularJSUrlCodec implements UrlCodec {
|
||||
}
|
||||
|
||||
// https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L72
|
||||
decodeSearch(search: string) { return parseKeyValue(search); }
|
||||
decodeSearch(search: string) {
|
||||
return parseKeyValue(search);
|
||||
}
|
||||
|
||||
// https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L73
|
||||
decodeHash(hash: string) {
|
||||
@ -193,7 +195,9 @@ export class AngularJSUrlCodec implements UrlCodec {
|
||||
}
|
||||
}
|
||||
|
||||
areEqual(valA: string, valB: string) { return this.normalize(valA) === this.normalize(valB); }
|
||||
areEqual(valA: string, valB: string) {
|
||||
return this.normalize(valA) === this.normalize(valB);
|
||||
}
|
||||
|
||||
// https://github.com/angular/angular.js/blob/864c7f0/src/ng/urlUtils.js#L60
|
||||
parse(url: string, base?: string) {
|
||||
|
@ -27,7 +27,7 @@ export function deepEqual(a: any, b: any): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export function isAnchor(el: (Node & ParentNode) | Element | null): el is HTMLAnchorElement {
|
||||
export function isAnchor(el: (Node&ParentNode)|Element|null): el is HTMLAnchorElement {
|
||||
return (<HTMLAnchorElement>el).href !== undefined;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {CommonModule, PathLocationStrategy} from '@angular/common';
|
||||
import {TestBed, inject} from '@angular/core/testing';
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import {UpgradeModule} from '@angular/upgrade/static';
|
||||
|
||||
import {$locationShim} from '../src/location_shim';
|
||||
@ -43,15 +43,26 @@ export function injectorFactory() {
|
||||
export class $rootScopeMock {
|
||||
private watchers: any[] = [];
|
||||
private events: {[k: string]: any[]} = {};
|
||||
runWatchers() { this.watchers.forEach(fn => fn()); }
|
||||
runWatchers() {
|
||||
this.watchers.forEach(fn => fn());
|
||||
}
|
||||
|
||||
$watch(fn: any) { this.watchers.push(fn); }
|
||||
$watch(fn: any) {
|
||||
this.watchers.push(fn);
|
||||
}
|
||||
|
||||
$broadcast(evt: string, ...args: any[]) {
|
||||
if (this.events[evt]) {
|
||||
this.events[evt].forEach(fn => { fn.apply(fn, args); });
|
||||
this.events[evt].forEach(fn => {
|
||||
fn.apply(fn, args);
|
||||
});
|
||||
}
|
||||
return {defaultPrevented: false, preventDefault() { this.defaultPrevented = true; }};
|
||||
return {
|
||||
defaultPrevented: false,
|
||||
preventDefault() {
|
||||
this.defaultPrevented = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$on(evt: string, fn: any) {
|
||||
@ -61,7 +72,9 @@ export class $rootScopeMock {
|
||||
this.events[evt].push(fn);
|
||||
}
|
||||
|
||||
$evalAsync(fn: any) { fn(); }
|
||||
$evalAsync(fn: any) {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
describe('LocationProvider', () => {
|
||||
@ -83,7 +96,6 @@ describe('LocationProvider', () => {
|
||||
expect($location).toBeDefined();
|
||||
expect($location instanceof $locationShim).toBe(true);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
@ -105,7 +117,9 @@ describe('LocationHtml5Url', function() {
|
||||
upgradeModule.$injector = {get: injectorFactory()};
|
||||
});
|
||||
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; }));
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => {
|
||||
$location = loc;
|
||||
}));
|
||||
|
||||
|
||||
it('should set the URL', () => {
|
||||
@ -158,8 +172,9 @@ describe('LocationHtml5Url', function() {
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should support state',
|
||||
function() { expect($location.state({a: 2}).state()).toEqual({a: 2}); });
|
||||
it('should support state', function() {
|
||||
expect($location.state({a: 2}).state()).toEqual({a: 2});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -180,10 +195,14 @@ describe('NewUrl', function() {
|
||||
upgradeModule.$injector = {get: injectorFactory()};
|
||||
});
|
||||
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; }));
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => {
|
||||
$location = loc;
|
||||
}));
|
||||
|
||||
// Sets the default most of these tests rely on
|
||||
function setupUrl(url = '/path/b?search=a&b=c&d#hash') { $location.url(url); }
|
||||
function setupUrl(url = '/path/b?search=a&b=c&d#hash') {
|
||||
$location.url(url);
|
||||
}
|
||||
|
||||
it('should provide common getters', function() {
|
||||
setupUrl();
|
||||
@ -409,7 +428,6 @@ describe('NewUrl', function() {
|
||||
});
|
||||
|
||||
describe('encoding', function() {
|
||||
|
||||
it('should encode special characters', function() {
|
||||
$location.path('/a <>#');
|
||||
$location.search({'i j': '<>#'});
|
||||
@ -455,7 +473,6 @@ describe('NewUrl', function() {
|
||||
$location.search({'a+b': 'c+d'});
|
||||
expect($location.search()).toEqual({'a+b': 'c+d'});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should not preserve old properties when parsing new url', function() {
|
||||
@ -486,7 +503,9 @@ describe('New URL Parsing', () => {
|
||||
upgradeModule.$injector = {get: injectorFactory()};
|
||||
});
|
||||
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; }));
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => {
|
||||
$location = loc;
|
||||
}));
|
||||
|
||||
it('should prepend path with basePath', function() {
|
||||
$location.$$parse('http://server/base/abc?a');
|
||||
@ -496,7 +515,6 @@ describe('New URL Parsing', () => {
|
||||
$location.path('/new/path');
|
||||
expect($location.absUrl()).toBe('http://server/base/new/path?a');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('New URL Parsing', () => {
|
||||
@ -516,7 +534,9 @@ describe('New URL Parsing', () => {
|
||||
upgradeModule.$injector = {get: injectorFactory()};
|
||||
});
|
||||
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; }));
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => {
|
||||
$location = loc;
|
||||
}));
|
||||
|
||||
it('should parse new url', function() {
|
||||
$location.$$parse('http://host.com/base');
|
||||
@ -549,8 +569,9 @@ describe('New URL Parsing', () => {
|
||||
});
|
||||
|
||||
it('should throw error when invalid server url given', function() {
|
||||
|
||||
expect(function() { $location.$$parse('http://other.server.org/path#/path'); })
|
||||
expect(function() {
|
||||
$location.$$parse('http://other.server.org/path#/path');
|
||||
})
|
||||
.toThrowError(
|
||||
'Invalid url "http://other.server.org/path#/path", missing path prefix "http://host.com/".');
|
||||
});
|
||||
@ -620,12 +641,10 @@ describe('New URL Parsing', () => {
|
||||
// After watchers have been run, location should be updated and `state` should change
|
||||
expect($location.state()).toBe(null);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('$location.onChange()', () => {
|
||||
|
||||
let $location: $locationShim;
|
||||
let upgradeModule: UpgradeModule;
|
||||
let mock$rootScope: $rootScopeMock;
|
||||
@ -644,13 +663,18 @@ describe('$location.onChange()', () => {
|
||||
mock$rootScope = upgradeModule.$injector.get('$rootScope');
|
||||
});
|
||||
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; }));
|
||||
beforeEach(inject([$locationShim], (loc: $locationShim) => {
|
||||
$location = loc;
|
||||
}));
|
||||
|
||||
it('should have onChange method', () => { expect(typeof $location.onChange).toBe('function'); });
|
||||
it('should have onChange method', () => {
|
||||
expect(typeof $location.onChange).toBe('function');
|
||||
});
|
||||
|
||||
it('should add registered functions to changeListeners', () => {
|
||||
|
||||
function changeListener(url: string, state: unknown) { return undefined; }
|
||||
function changeListener(url: string, state: unknown) {
|
||||
return undefined;
|
||||
}
|
||||
function errorHandler(e: Error) {}
|
||||
|
||||
expect(($location as any).$$changeListeners.length).toBe(0);
|
||||
@ -663,7 +687,6 @@ describe('$location.onChange()', () => {
|
||||
});
|
||||
|
||||
it('should call changeListeners when URL is updated', () => {
|
||||
|
||||
const onChangeVals =
|
||||
{url: 'url', state: 'state' as unknown, oldUrl: 'oldUrl', oldState: 'oldState' as unknown};
|
||||
|
||||
@ -688,7 +711,6 @@ describe('$location.onChange()', () => {
|
||||
});
|
||||
|
||||
it('should call changeListeners after $locationChangeSuccess', () => {
|
||||
|
||||
let changeListenerCalled = false;
|
||||
let locationChangeSuccessEmitted = false;
|
||||
|
||||
@ -715,13 +737,14 @@ describe('$location.onChange()', () => {
|
||||
});
|
||||
|
||||
it('should call forward errors to error handler', () => {
|
||||
|
||||
let error !: Error;
|
||||
let error!: Error;
|
||||
|
||||
function changeListener(url: string, state: unknown, oldUrl: string, oldState: unknown) {
|
||||
throw new Error('Handle error');
|
||||
}
|
||||
function errorHandler(e: Error) { error = e; }
|
||||
function errorHandler(e: Error) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
$location.onChange(changeListener, errorHandler);
|
||||
|
||||
@ -729,7 +752,6 @@ describe('$location.onChange()', () => {
|
||||
mock$rootScope.runWatchers();
|
||||
expect(error.message).toBe('Handle error');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function parseLinkAndReturn(location: $locationShim, toUrl: string, relHref?: string) {
|
||||
|
@ -72,7 +72,7 @@ export class LocationUpgradeTestModule {
|
||||
appBaseHref: config && config.appBaseHref,
|
||||
useHash: config && config.useHash || false
|
||||
})
|
||||
.providers !
|
||||
.providers!
|
||||
],
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user