refactor: move angular source to /packages rather than modules/@angular
This commit is contained in:
148
packages/compiler/testing/src/directive_resolver_mock.ts
Normal file
148
packages/compiler/testing/src/directive_resolver_mock.ts
Normal file
@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @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 {DirectiveResolver} from '@angular/compiler';
|
||||
import {Compiler, Component, Directive, Injectable, Injector, Provider, Type, resolveForwardRef, ɵViewMetadata as ViewMetadata} from '@angular/core';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of {@link DirectiveResolver} that allows overriding
|
||||
* various properties of directives.
|
||||
*/
|
||||
@Injectable()
|
||||
export class MockDirectiveResolver extends DirectiveResolver {
|
||||
private _directives = new Map<Type<any>, Directive>();
|
||||
private _providerOverrides = new Map<Type<any>, any[]>();
|
||||
private _viewProviderOverrides = new Map<Type<any>, any[]>();
|
||||
private _views = new Map<Type<any>, ViewMetadata>();
|
||||
private _inlineTemplates = new Map<Type<any>, string>();
|
||||
|
||||
constructor(private _injector: Injector) { super(); }
|
||||
|
||||
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
||||
|
||||
private _clearCacheFor(component: Type<any>) { this._compiler.clearCacheFor(component); }
|
||||
|
||||
resolve(type: Type<any>, throwIfNotFound = true): Directive {
|
||||
let metadata = this._directives.get(type);
|
||||
if (!metadata) {
|
||||
metadata = super.resolve(type, throwIfNotFound);
|
||||
}
|
||||
if (!metadata) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const providerOverrides = this._providerOverrides.get(type);
|
||||
const viewProviderOverrides = this._viewProviderOverrides.get(type);
|
||||
|
||||
let providers = metadata.providers;
|
||||
if (providerOverrides != null) {
|
||||
const originalViewProviders: Provider[] = metadata.providers || [];
|
||||
providers = originalViewProviders.concat(providerOverrides);
|
||||
}
|
||||
|
||||
if (metadata instanceof Component) {
|
||||
let viewProviders = metadata.viewProviders;
|
||||
if (viewProviderOverrides != null) {
|
||||
const originalViewProviders: Provider[] = metadata.viewProviders || [];
|
||||
viewProviders = originalViewProviders.concat(viewProviderOverrides);
|
||||
}
|
||||
|
||||
let view = this._views.get(type);
|
||||
if (!view) {
|
||||
view = <any>metadata;
|
||||
}
|
||||
|
||||
let animations = view.animations;
|
||||
let templateUrl = view.templateUrl;
|
||||
|
||||
let inlineTemplate = this._inlineTemplates.get(type);
|
||||
if (inlineTemplate != null) {
|
||||
templateUrl = null;
|
||||
} else {
|
||||
inlineTemplate = view.template;
|
||||
}
|
||||
|
||||
return new Component({
|
||||
selector: metadata.selector,
|
||||
inputs: metadata.inputs,
|
||||
outputs: metadata.outputs,
|
||||
host: metadata.host,
|
||||
exportAs: metadata.exportAs,
|
||||
moduleId: metadata.moduleId,
|
||||
queries: metadata.queries,
|
||||
changeDetection: metadata.changeDetection,
|
||||
providers: providers,
|
||||
viewProviders: viewProviders,
|
||||
entryComponents: metadata.entryComponents,
|
||||
template: inlineTemplate,
|
||||
templateUrl: templateUrl,
|
||||
animations: animations,
|
||||
styles: view.styles,
|
||||
styleUrls: view.styleUrls,
|
||||
encapsulation: view.encapsulation,
|
||||
interpolation: view.interpolation
|
||||
});
|
||||
}
|
||||
|
||||
return new Directive({
|
||||
selector: metadata.selector,
|
||||
inputs: metadata.inputs,
|
||||
outputs: metadata.outputs,
|
||||
host: metadata.host,
|
||||
providers: providers,
|
||||
exportAs: metadata.exportAs,
|
||||
queries: metadata.queries
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the {@link Directive} for a directive.
|
||||
*/
|
||||
setDirective(type: Type<any>, metadata: Directive): void {
|
||||
this._directives.set(type, metadata);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
setProvidersOverride(type: Type<any>, providers: Provider[]): void {
|
||||
this._providerOverrides.set(type, providers);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
setViewProvidersOverride(type: Type<any>, viewProviders: Provider[]): void {
|
||||
this._viewProviderOverrides.set(type, viewProviders);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the {@link ViewMetadata} for a component.
|
||||
*/
|
||||
setView(component: Type<any>, view: ViewMetadata): void {
|
||||
this._views.set(component, view);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
/**
|
||||
* Overrides the inline template for a component - other configuration remains unchanged.
|
||||
*/
|
||||
setInlineTemplate(component: Type<any>, template: string): void {
|
||||
this._inlineTemplates.set(component, template);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenArray(tree: any[], out: Array<Type<any>|any[]>): void {
|
||||
if (tree == null) return;
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
const item = resolveForwardRef(tree[i]);
|
||||
if (Array.isArray(item)) {
|
||||
flattenArray(item, out);
|
||||
} else {
|
||||
out.push(item);
|
||||
}
|
||||
}
|
||||
}
|
121
packages/compiler/testing/src/index.ts
Normal file
121
packages/compiler/testing/src/index.ts
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Entry point for all APIs of the compiler package.
|
||||
*
|
||||
* <div class="callout is-critical">
|
||||
* <header>Unstable APIs</header>
|
||||
* <p>
|
||||
* All compiler apis are currently considered experimental and private!
|
||||
* </p>
|
||||
* <p>
|
||||
* We expect the APIs in this package to keep on changing. Do not rely on them.
|
||||
* </p>
|
||||
* </div>
|
||||
*/
|
||||
export * from './schema_registry_mock';
|
||||
export * from './directive_resolver_mock';
|
||||
export * from './ng_module_resolver_mock';
|
||||
export * from './pipe_resolver_mock';
|
||||
|
||||
import {createPlatformFactory, ModuleWithComponentFactories, Injectable, CompilerOptions, COMPILER_OPTIONS, CompilerFactory, NgModuleFactory, Injector, NgModule, Component, Directive, Pipe, Type, PlatformRef} from '@angular/core';
|
||||
import {MetadataOverride, ɵTestingCompilerFactory as TestingCompilerFactory, ɵTestingCompiler as TestingCompiler} from '@angular/core/testing';
|
||||
import {platformCoreDynamic, JitCompiler, DirectiveResolver, NgModuleResolver, PipeResolver} from '@angular/compiler';
|
||||
import {MockDirectiveResolver} from './directive_resolver_mock';
|
||||
import {MockNgModuleResolver} from './ng_module_resolver_mock';
|
||||
import {MockPipeResolver} from './pipe_resolver_mock';
|
||||
import {MetadataOverrider} from './metadata_overrider';
|
||||
|
||||
@Injectable()
|
||||
export class TestingCompilerFactoryImpl implements TestingCompilerFactory {
|
||||
constructor(private _compilerFactory: CompilerFactory) {}
|
||||
|
||||
createTestingCompiler(options: CompilerOptions[]): TestingCompiler {
|
||||
const compiler = <JitCompiler>this._compilerFactory.createCompiler(options);
|
||||
return new TestingCompilerImpl(
|
||||
compiler, compiler.injector.get(MockDirectiveResolver),
|
||||
compiler.injector.get(MockPipeResolver), compiler.injector.get(MockNgModuleResolver));
|
||||
}
|
||||
}
|
||||
|
||||
export class TestingCompilerImpl implements TestingCompiler {
|
||||
private _overrider = new MetadataOverrider();
|
||||
constructor(
|
||||
private _compiler: JitCompiler, private _directiveResolver: MockDirectiveResolver,
|
||||
private _pipeResolver: MockPipeResolver, private _moduleResolver: MockNgModuleResolver) {}
|
||||
get injector(): Injector { return this._compiler.injector; }
|
||||
|
||||
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> {
|
||||
return this._compiler.compileModuleSync(moduleType);
|
||||
}
|
||||
|
||||
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>> {
|
||||
return this._compiler.compileModuleAsync(moduleType);
|
||||
}
|
||||
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T> {
|
||||
return this._compiler.compileModuleAndAllComponentsSync(moduleType);
|
||||
}
|
||||
|
||||
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>):
|
||||
Promise<ModuleWithComponentFactories<T>> {
|
||||
return this._compiler.compileModuleAndAllComponentsAsync(moduleType);
|
||||
}
|
||||
|
||||
getNgContentSelectors(component: Type<any>): string[] {
|
||||
return this._compiler.getNgContentSelectors(component);
|
||||
}
|
||||
|
||||
overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): void {
|
||||
const oldMetadata = this._moduleResolver.resolve(ngModule, false);
|
||||
this._moduleResolver.setNgModule(
|
||||
ngModule, this._overrider.overrideMetadata(NgModule, oldMetadata, override));
|
||||
}
|
||||
overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): void {
|
||||
const oldMetadata = this._directiveResolver.resolve(directive, false);
|
||||
this._directiveResolver.setDirective(
|
||||
directive, this._overrider.overrideMetadata(Directive, oldMetadata, override));
|
||||
}
|
||||
overrideComponent(component: Type<any>, override: MetadataOverride<Component>): void {
|
||||
const oldMetadata = this._directiveResolver.resolve(component, false);
|
||||
this._directiveResolver.setDirective(
|
||||
component, this._overrider.overrideMetadata(Component, oldMetadata, override));
|
||||
}
|
||||
overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): void {
|
||||
const oldMetadata = this._pipeResolver.resolve(pipe, false);
|
||||
this._pipeResolver.setPipe(pipe, this._overrider.overrideMetadata(Pipe, oldMetadata, override));
|
||||
}
|
||||
clearCache(): void { this._compiler.clearCache(); }
|
||||
clearCacheFor(type: Type<any>) { this._compiler.clearCacheFor(type); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Platform for dynamic tests
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export const platformCoreDynamicTesting: (extraProviders?: any[]) => PlatformRef =
|
||||
createPlatformFactory(platformCoreDynamic, 'coreDynamicTesting', [
|
||||
{
|
||||
provide: COMPILER_OPTIONS,
|
||||
useValue: {
|
||||
providers: [
|
||||
MockPipeResolver,
|
||||
{provide: PipeResolver, useExisting: MockPipeResolver},
|
||||
MockDirectiveResolver,
|
||||
{provide: DirectiveResolver, useExisting: MockDirectiveResolver},
|
||||
MockNgModuleResolver,
|
||||
{provide: NgModuleResolver, useExisting: MockNgModuleResolver},
|
||||
]
|
||||
},
|
||||
multi: true
|
||||
},
|
||||
{provide: TestingCompilerFactory, useClass: TestingCompilerFactoryImpl}
|
||||
]);
|
131
packages/compiler/testing/src/metadata_overrider.ts
Normal file
131
packages/compiler/testing/src/metadata_overrider.ts
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @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 {ɵstringify as stringify} from '@angular/core';
|
||||
import {MetadataOverride} from '@angular/core/testing';
|
||||
|
||||
type StringMap = {
|
||||
[key: string]: any
|
||||
};
|
||||
|
||||
let _nextReferenceId = 0;
|
||||
|
||||
export class MetadataOverrider {
|
||||
private _references = new Map<any, string>();
|
||||
/**
|
||||
* Creates a new instance for the given metadata class
|
||||
* based on an old instance and overrides.
|
||||
*/
|
||||
overrideMetadata<C extends T, T>(
|
||||
metadataClass: {new (options: T): C;}, oldMetadata: C, override: MetadataOverride<T>): C {
|
||||
const props: StringMap = {};
|
||||
if (oldMetadata) {
|
||||
_valueProps(oldMetadata).forEach((prop) => props[prop] = (<any>oldMetadata)[prop]);
|
||||
}
|
||||
|
||||
if (override.set) {
|
||||
if (override.remove || override.add) {
|
||||
throw new Error(`Cannot set and add/remove ${stringify(metadataClass)} at the same time!`);
|
||||
}
|
||||
setMetadata(props, override.set);
|
||||
}
|
||||
if (override.remove) {
|
||||
removeMetadata(props, override.remove, this._references);
|
||||
}
|
||||
if (override.add) {
|
||||
addMetadata(props, override.add);
|
||||
}
|
||||
return new metadataClass(<any>props);
|
||||
}
|
||||
}
|
||||
|
||||
function removeMetadata(metadata: StringMap, remove: any, references: Map<any, string>) {
|
||||
const removeObjects = new Set<string>();
|
||||
for (const prop in remove) {
|
||||
const removeValue = remove[prop];
|
||||
if (removeValue instanceof Array) {
|
||||
removeValue.forEach(
|
||||
(value: any) => { removeObjects.add(_propHashKey(prop, value, references)); });
|
||||
} else {
|
||||
removeObjects.add(_propHashKey(prop, removeValue, references));
|
||||
}
|
||||
}
|
||||
|
||||
for (const prop in metadata) {
|
||||
const propValue = metadata[prop];
|
||||
if (propValue instanceof Array) {
|
||||
metadata[prop] = propValue.filter(
|
||||
(value: any) => !removeObjects.has(_propHashKey(prop, value, references)));
|
||||
} else {
|
||||
if (removeObjects.has(_propHashKey(prop, propValue, references))) {
|
||||
metadata[prop] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addMetadata(metadata: StringMap, add: any) {
|
||||
for (const prop in add) {
|
||||
const addValue = add[prop];
|
||||
const propValue = metadata[prop];
|
||||
if (propValue != null && propValue instanceof Array) {
|
||||
metadata[prop] = propValue.concat(addValue);
|
||||
} else {
|
||||
metadata[prop] = addValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setMetadata(metadata: StringMap, set: any) {
|
||||
for (const prop in set) {
|
||||
metadata[prop] = set[prop];
|
||||
}
|
||||
}
|
||||
|
||||
function _propHashKey(propName: any, propValue: any, references: Map<any, string>): string {
|
||||
const replacer = (key: any, value: any) => {
|
||||
if (typeof value === 'function') {
|
||||
value = _serializeReference(value, references);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
return `${propName}:${JSON.stringify(propValue, replacer)}`;
|
||||
}
|
||||
|
||||
function _serializeReference(ref: any, references: Map<any, string>): string {
|
||||
let id = references.get(ref);
|
||||
if (!id) {
|
||||
id = `${stringify(ref)}${_nextReferenceId++}`;
|
||||
references.set(ref, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
function _valueProps(obj: any): string[] {
|
||||
const props: string[] = [];
|
||||
// regular public props
|
||||
Object.keys(obj).forEach((prop) => {
|
||||
if (!prop.startsWith('_')) {
|
||||
props.push(prop);
|
||||
}
|
||||
});
|
||||
|
||||
// getters
|
||||
let proto = obj;
|
||||
while (proto = Object.getPrototypeOf(proto)) {
|
||||
Object.keys(proto).forEach((protoProp) => {
|
||||
const desc = Object.getOwnPropertyDescriptor(proto, protoProp);
|
||||
if (!protoProp.startsWith('_') && desc && 'get' in desc) {
|
||||
props.push(protoProp);
|
||||
}
|
||||
});
|
||||
}
|
||||
return props;
|
||||
}
|
39
packages/compiler/testing/src/ng_module_resolver_mock.ts
Normal file
39
packages/compiler/testing/src/ng_module_resolver_mock.ts
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @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 {NgModuleResolver} from '@angular/compiler';
|
||||
import {Compiler, Injectable, Injector, NgModule, Type} from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class MockNgModuleResolver extends NgModuleResolver {
|
||||
private _ngModules = new Map<Type<any>, NgModule>();
|
||||
|
||||
constructor(private _injector: Injector) { super(); }
|
||||
|
||||
/**
|
||||
* Overrides the {@link NgModule} for a module.
|
||||
*/
|
||||
setNgModule(type: Type<any>, metadata: NgModule): void {
|
||||
this._ngModules.set(type, metadata);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link NgModule} for a module:
|
||||
* - Set the {@link NgModule} to the overridden view when it exists or fallback to the
|
||||
* default
|
||||
* `NgModuleResolver`, see `setNgModule`.
|
||||
*/
|
||||
resolve(type: Type<any>, throwIfNotFound = true): NgModule {
|
||||
return this._ngModules.get(type) || super.resolve(type, throwIfNotFound);
|
||||
}
|
||||
|
||||
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
||||
|
||||
private _clearCacheFor(component: Type<any>) { this._compiler.clearCacheFor(component); }
|
||||
}
|
43
packages/compiler/testing/src/pipe_resolver_mock.ts
Normal file
43
packages/compiler/testing/src/pipe_resolver_mock.ts
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @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 {PipeResolver} from '@angular/compiler';
|
||||
import {Compiler, Injectable, Injector, Pipe, Type} from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class MockPipeResolver extends PipeResolver {
|
||||
private _pipes = new Map<Type<any>, Pipe>();
|
||||
|
||||
constructor(private _injector: Injector) { super(); }
|
||||
|
||||
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
||||
|
||||
private _clearCacheFor(pipe: Type<any>) { this._compiler.clearCacheFor(pipe); }
|
||||
|
||||
/**
|
||||
* Overrides the {@link Pipe} for a pipe.
|
||||
*/
|
||||
setPipe(type: Type<any>, metadata: Pipe): void {
|
||||
this._pipes.set(type, metadata);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Pipe} for a pipe:
|
||||
* - Set the {@link Pipe} to the overridden view when it exists or fallback to the
|
||||
* default
|
||||
* `PipeResolver`, see `setPipe`.
|
||||
*/
|
||||
resolve(type: Type<any>, throwIfNotFound = true): Pipe {
|
||||
let metadata = this._pipes.get(type);
|
||||
if (!metadata) {
|
||||
metadata = super.resolve(type, throwIfNotFound);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
}
|
136
packages/compiler/testing/src/resource_loader_mock.ts
Normal file
136
packages/compiler/testing/src/resource_loader_mock.ts
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @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 {ResourceLoader} from '@angular/compiler';
|
||||
|
||||
/**
|
||||
* A mock implementation of {@link ResourceLoader} that allows outgoing requests to be mocked
|
||||
* and responded to within a single test, without going to the network.
|
||||
*/
|
||||
export class MockResourceLoader extends ResourceLoader {
|
||||
private _expectations: _Expectation[] = [];
|
||||
private _definitions = new Map<string, string>();
|
||||
private _requests: _PendingRequest[] = [];
|
||||
|
||||
get(url: string): Promise<string> {
|
||||
const request = new _PendingRequest(url);
|
||||
this._requests.push(request);
|
||||
return request.getPromise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an expectation for the given URL. Incoming requests will be checked against
|
||||
* the next expectation (in FIFO order). The `verifyNoOutstandingExpectations` method
|
||||
* can be used to check if any expectations have not yet been met.
|
||||
*
|
||||
* The response given will be returned if the expectation matches.
|
||||
*/
|
||||
expect(url: string, response: string) {
|
||||
const expectation = new _Expectation(url, response);
|
||||
this._expectations.push(expectation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a definition for the given URL to return the given response. Unlike expectations,
|
||||
* definitions have no order and will satisfy any matching request at any time. Also
|
||||
* unlike expectations, unused definitions do not cause `verifyNoOutstandingExpectations`
|
||||
* to return an error.
|
||||
*/
|
||||
when(url: string, response: string) { this._definitions.set(url, response); }
|
||||
|
||||
/**
|
||||
* Process pending requests and verify there are no outstanding expectations. Also fails
|
||||
* if no requests are pending.
|
||||
*/
|
||||
flush() {
|
||||
if (this._requests.length === 0) {
|
||||
throw new Error('No pending requests to flush');
|
||||
}
|
||||
|
||||
do {
|
||||
this._processRequest(this._requests.shift());
|
||||
} while (this._requests.length > 0);
|
||||
|
||||
this.verifyNoOutstandingExpectations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if any expectations have not been satisfied.
|
||||
*/
|
||||
verifyNoOutstandingExpectations() {
|
||||
if (this._expectations.length === 0) return;
|
||||
|
||||
const urls: string[] = [];
|
||||
for (let i = 0; i < this._expectations.length; i++) {
|
||||
const expectation = this._expectations[i];
|
||||
urls.push(expectation.url);
|
||||
}
|
||||
|
||||
throw new Error(`Unsatisfied requests: ${urls.join(', ')}`);
|
||||
}
|
||||
|
||||
private _processRequest(request: _PendingRequest) {
|
||||
const url = request.url;
|
||||
|
||||
if (this._expectations.length > 0) {
|
||||
const expectation = this._expectations[0];
|
||||
if (expectation.url == url) {
|
||||
remove(this._expectations, expectation);
|
||||
request.complete(expectation.response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._definitions.has(url)) {
|
||||
const response = this._definitions.get(url);
|
||||
request.complete(response == null ? null : response);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected request ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
class _PendingRequest {
|
||||
resolve: (result: string) => void;
|
||||
reject: (error: any) => void;
|
||||
promise: Promise<string>;
|
||||
|
||||
constructor(public url: string) {
|
||||
this.promise = new Promise((res, rej) => {
|
||||
this.resolve = res;
|
||||
this.reject = rej;
|
||||
});
|
||||
}
|
||||
|
||||
complete(response: string) {
|
||||
if (response == null) {
|
||||
this.reject(`Failed to load ${this.url}`);
|
||||
} else {
|
||||
this.resolve(response);
|
||||
}
|
||||
}
|
||||
|
||||
getPromise(): Promise<string> { return this.promise; }
|
||||
}
|
||||
|
||||
class _Expectation {
|
||||
url: string;
|
||||
response: string;
|
||||
constructor(url: string, response: string) {
|
||||
this.url = url;
|
||||
this.response = response;
|
||||
}
|
||||
}
|
||||
|
||||
function remove<T>(list: T[], el: T): void {
|
||||
const index = list.indexOf(el);
|
||||
if (index > -1) {
|
||||
list.splice(index, 1);
|
||||
}
|
||||
}
|
63
packages/compiler/testing/src/schema_registry_mock.ts
Normal file
63
packages/compiler/testing/src/schema_registry_mock.ts
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @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 {ElementSchemaRegistry} from '@angular/compiler';
|
||||
import {SchemaMetadata, SecurityContext} from '@angular/core';
|
||||
|
||||
export class MockSchemaRegistry implements ElementSchemaRegistry {
|
||||
constructor(
|
||||
public existingProperties: {[key: string]: boolean},
|
||||
public attrPropMapping: {[key: string]: string},
|
||||
public existingElements: {[key: string]: boolean}, public invalidProperties: Array<string>,
|
||||
public invalidAttributes: Array<string>) {}
|
||||
|
||||
hasProperty(tagName: string, property: string, schemas: SchemaMetadata[]): boolean {
|
||||
const value = this.existingProperties[property];
|
||||
return value === void 0 ? true : value;
|
||||
}
|
||||
|
||||
hasElement(tagName: string, schemaMetas: SchemaMetadata[]): boolean {
|
||||
const value = this.existingElements[tagName.toLowerCase()];
|
||||
return value === void 0 ? true : value;
|
||||
}
|
||||
|
||||
allKnownElementNames(): string[] { return Object.keys(this.existingElements); }
|
||||
|
||||
securityContext(selector: string, property: string, isAttribute: boolean): SecurityContext {
|
||||
return SecurityContext.NONE;
|
||||
}
|
||||
|
||||
getMappedPropName(attrName: string): string { return this.attrPropMapping[attrName] || attrName; }
|
||||
|
||||
getDefaultComponentElementName(): string { return 'ng-component'; }
|
||||
|
||||
validateProperty(name: string): {error: boolean, msg?: string} {
|
||||
if (this.invalidProperties.indexOf(name) > -1) {
|
||||
return {error: true, msg: `Binding to property '${name}' is disallowed for security reasons`};
|
||||
} else {
|
||||
return {error: false};
|
||||
}
|
||||
}
|
||||
|
||||
validateAttribute(name: string): {error: boolean, msg?: string} {
|
||||
if (this.invalidAttributes.indexOf(name) > -1) {
|
||||
return {
|
||||
error: true,
|
||||
msg: `Binding to attribute '${name}' is disallowed for security reasons`
|
||||
};
|
||||
} else {
|
||||
return {error: false};
|
||||
}
|
||||
}
|
||||
|
||||
normalizeAnimationStyleProperty(propName: string): string { return propName; }
|
||||
normalizeAnimationStyleValue(camelCaseProp: string, userProvidedProp: string, val: string|number):
|
||||
{error: string, value: string} {
|
||||
return {error: null, value: val.toString()};
|
||||
}
|
||||
}
|
25
packages/compiler/testing/src/test_bindings.ts
Normal file
25
packages/compiler/testing/src/test_bindings.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @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 {ElementSchemaRegistry, ResourceLoader, UrlResolver} from '@angular/compiler';
|
||||
import {Provider} from '@angular/core';
|
||||
import {MockResourceLoader} from './resource_loader_mock';
|
||||
import {MockSchemaRegistry} from './schema_registry_mock';
|
||||
|
||||
export function createUrlResolverWithoutPackagePrefix(): UrlResolver {
|
||||
return new UrlResolver();
|
||||
}
|
||||
|
||||
// This provider is put here just so that we can access it from multiple
|
||||
// internal test packages.
|
||||
// TODO: get rid of it or move to a separate @angular/internal_testing package
|
||||
export const TEST_COMPILER_PROVIDERS: Provider[] = [
|
||||
{provide: ElementSchemaRegistry, useValue: new MockSchemaRegistry({}, {}, {}, [], [])},
|
||||
{provide: ResourceLoader, useClass: MockResourceLoader},
|
||||
{provide: UrlResolver, useFactory: createUrlResolverWithoutPackagePrefix}
|
||||
];
|
17
packages/compiler/testing/tsconfig-build.json
Normal file
17
packages/compiler/testing/tsconfig-build.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig-build",
|
||||
|
||||
"compilerOptions": {
|
||||
// Test that we rely on decorator downleveling
|
||||
"emitDecoratorMetadata": false,
|
||||
"paths": {
|
||||
"@angular/core": ["../../../dist/packages-dist/core"],
|
||||
"@angular/core/testing": ["../../../dist/packages-dist/core/testing"],
|
||||
"@angular/compiler": ["../../../dist/packages-dist/compiler"]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"testing/index.ts",
|
||||
"../../../node_modules/zone.js/dist/zone.js.d.ts"
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user