13
build.sh
13
build.sh
@ -8,8 +8,8 @@ source ${currentDir}/scripts/ci/_travis-fold.sh
|
|||||||
# TODO(i): wrap into subshell, so that we don't pollute CWD, but not yet to minimize diff collision with Jason
|
# TODO(i): wrap into subshell, so that we don't pollute CWD, but not yet to minimize diff collision with Jason
|
||||||
cd ${currentDir}
|
cd ${currentDir}
|
||||||
|
|
||||||
PACKAGES=(core
|
PACKAGES=(compiler
|
||||||
compiler
|
core
|
||||||
common
|
common
|
||||||
animations
|
animations
|
||||||
platform-browser
|
platform-browser
|
||||||
@ -27,7 +27,8 @@ PACKAGES=(core
|
|||||||
service-worker
|
service-worker
|
||||||
elements)
|
elements)
|
||||||
|
|
||||||
TSC_PACKAGES=(compiler-cli
|
TSC_PACKAGES=(compiler
|
||||||
|
compiler-cli
|
||||||
language-service
|
language-service
|
||||||
benchpress)
|
benchpress)
|
||||||
|
|
||||||
@ -239,7 +240,13 @@ compilePackage() {
|
|||||||
# For TSC_PACKAGES items
|
# For TSC_PACKAGES items
|
||||||
if containsElement "${3}" "${TSC_PACKAGES[@]}"; then
|
if containsElement "${3}" "${TSC_PACKAGES[@]}"; then
|
||||||
echo "====== [${3}]: COMPILING: ${TSC} -p ${1}/tsconfig-build.json"
|
echo "====== [${3}]: COMPILING: ${TSC} -p ${1}/tsconfig-build.json"
|
||||||
|
local package_name=$(basename "${2}")
|
||||||
$TSC -p ${1}/tsconfig-build.json
|
$TSC -p ${1}/tsconfig-build.json
|
||||||
|
if [[ "${3}" = "compiler" ]]; then
|
||||||
|
if [[ "${package_name}" = "testing" ]]; then
|
||||||
|
echo "$(cat ${LICENSE_BANNER}) ${N} export * from './${package_name}/${package_name}'" > ${2}/../${package_name}.d.ts
|
||||||
|
fi
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "====== [${3}]: COMPILING: ${NGC} -p ${1}/tsconfig-build.json"
|
echo "====== [${3}]: COMPILING: ${NGC} -p ${1}/tsconfig-build.json"
|
||||||
local package_name=$(basename "${2}")
|
local package_name=$(basename "${2}")
|
||||||
|
@ -24,9 +24,8 @@ filegroup(
|
|||||||
|
|
||||||
ANGULAR_TESTING = [
|
ANGULAR_TESTING = [
|
||||||
"node_modules/@angular/*/bundles/*-testing.umd.js",
|
"node_modules/@angular/*/bundles/*-testing.umd.js",
|
||||||
# We use AOT, so the compiler and the dynamic platform-browser should be
|
# We use AOT, so the dynamic platform-browser should be visible only in tests
|
||||||
# visible only in tests
|
# NOTE that we still need to include the compiler because the core depends on it
|
||||||
"node_modules/@angular/compiler/bundles/*.umd.js",
|
|
||||||
"node_modules/@angular/platform-browser-dynamic/bundles/*.umd.js",
|
"node_modules/@angular/platform-browser-dynamic/bundles/*.umd.js",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ node_modules/zone.js/dist/zone_externs.js
|
|||||||
--js node_modules/rxjs/operators/package.json
|
--js node_modules/rxjs/operators/package.json
|
||||||
--js node_modules/rxjs/_esm2015/operators/index.js
|
--js node_modules/rxjs/_esm2015/operators/index.js
|
||||||
|
|
||||||
|
--js node_modules/@angular/compiler/package.json
|
||||||
|
--js node_modules/@angular/compiler/fesm2015/compiler.js
|
||||||
|
|
||||||
--js node_modules/@angular/core/package.json
|
--js node_modules/@angular/core/package.json
|
||||||
--js node_modules/@angular/core/fesm2015/core.js
|
--js node_modules/@angular/core/fesm2015/core.js
|
||||||
--js node_modules/@angular/core/src/testability/testability.externs.js
|
--js node_modules/@angular/core/src/testability/testability.externs.js
|
||||||
|
@ -17,6 +17,9 @@ node_modules/zone.js/dist/zone_externs.js
|
|||||||
--module_resolution=node
|
--module_resolution=node
|
||||||
--package_json_entry_names es2015
|
--package_json_entry_names es2015
|
||||||
|
|
||||||
|
--js node_modules/@angular/compiler/package.json
|
||||||
|
--js node_modules/@angular/compiler/fesm2015/compiler.js
|
||||||
|
|
||||||
--js node_modules/@angular/core/package.json
|
--js node_modules/@angular/core/package.json
|
||||||
--js node_modules/@angular/core/fesm2015/core.js
|
--js node_modules/@angular/core/fesm2015/core.js
|
||||||
--js node_modules/@angular/core/src/testability/testability.externs.js
|
--js node_modules/@angular/core/src/testability/testability.externs.js
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||||
"@angular/core": "file:../../dist/packages-dist/core",
|
"@angular/core": "file:../../dist/packages-dist/core",
|
||||||
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
|
||||||
|
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
|
||||||
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
|
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
|
||||||
"google-closure-compiler": "git+https://github.com/alexeagle/closure-compiler.git#packagejson.dist",
|
"google-closure-compiler": "git+https://github.com/alexeagle/closure-compiler.git#packagejson.dist",
|
||||||
"rxjs": "file:../../node_modules/rxjs",
|
"rxjs": "file:../../node_modules/rxjs",
|
||||||
@ -30,4 +31,4 @@
|
|||||||
"preprotractor": "tsc -p e2e",
|
"preprotractor": "tsc -p e2e",
|
||||||
"protractor": "protractor e2e/protractor.config.js"
|
"protractor": "protractor e2e/protractor.config.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,40 +3,48 @@
|
|||||||
|
|
||||||
|
|
||||||
"@angular/animations@file:../../dist/packages-dist/animations":
|
"@angular/animations@file:../../dist/packages-dist/animations":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
"@angular/common@file:../../dist/packages-dist/common":
|
"@angular/common@file:../../dist/packages-dist/common":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli":
|
"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar "^1.4.2"
|
chokidar "^1.4.2"
|
||||||
|
convert-source-map "^1.5.1"
|
||||||
|
magic-string "^0.25.0"
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
reflect-metadata "^0.1.2"
|
reflect-metadata "^0.1.2"
|
||||||
tsickle "^0.27.2"
|
source-map "^0.6.1"
|
||||||
|
tsickle "^0.32.1"
|
||||||
|
|
||||||
"@angular/compiler@file:../../dist/packages-dist/compiler":
|
"@angular/compiler@file:../../dist/packages-dist/compiler":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
"@angular/core@file:../../dist/packages-dist/core":
|
"@angular/core@file:../../dist/packages-dist/core":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
|
dependencies:
|
||||||
|
tslib "^1.9.0"
|
||||||
|
|
||||||
|
"@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic":
|
||||||
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
"@angular/platform-browser@file:../../dist/packages-dist/platform-browser":
|
"@angular/platform-browser@file:../../dist/packages-dist/platform-browser":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
"@angular/platform-server@file:../../dist/packages-dist/platform-server":
|
"@angular/platform-server@file:../../dist/packages-dist/platform-server":
|
||||||
version "6.0.0-beta.7-8203e0365a"
|
version "7.0.0-beta.1-d2d510089c"
|
||||||
dependencies:
|
dependencies:
|
||||||
domino "^2.0.1"
|
domino "^2.0.1"
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
@ -510,6 +518,10 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
|
|||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||||
|
|
||||||
|
convert-source-map@^1.5.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
|
||||||
|
|
||||||
cookie@0.3.1:
|
cookie@0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||||
@ -612,6 +624,10 @@ dev-ip@^1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
|
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
|
||||||
|
|
||||||
|
diff@^3.2.0:
|
||||||
|
version "3.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
||||||
|
|
||||||
domino@^2.0.1:
|
domino@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/domino/-/domino-2.0.1.tgz#9e1d63215d0fe8dcb8202bff07effa1a216db504"
|
resolved "https://registry.yarnpkg.com/domino/-/domino-2.0.1.tgz#9e1d63215d0fe8dcb8202bff07effa1a216db504"
|
||||||
@ -1203,6 +1219,12 @@ jasmine-core@~2.8.0:
|
|||||||
version "2.8.0"
|
version "2.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e"
|
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e"
|
||||||
|
|
||||||
|
jasmine-diff@^0.1.3:
|
||||||
|
version "0.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/jasmine-diff/-/jasmine-diff-0.1.3.tgz#93ccc2dcc41028c5ddd4606558074839f2deeaa8"
|
||||||
|
dependencies:
|
||||||
|
diff "^3.2.0"
|
||||||
|
|
||||||
jasmine@^2.5.3:
|
jasmine@^2.5.3:
|
||||||
version "2.8.0"
|
version "2.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e"
|
resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e"
|
||||||
@ -1319,6 +1341,12 @@ lodash@^4.11.1, lodash@^4.5.1:
|
|||||||
version "4.17.4"
|
version "4.17.4"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||||
|
|
||||||
|
magic-string@^0.25.0:
|
||||||
|
version "0.25.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.0.tgz#1f3696f9931ff0a1ed4c132250529e19cad6759b"
|
||||||
|
dependencies:
|
||||||
|
sourcemap-codec "^1.4.1"
|
||||||
|
|
||||||
micromatch@2.3.11, micromatch@^2.1.5:
|
micromatch@2.3.11, micromatch@^2.1.5:
|
||||||
version "2.3.11"
|
version "2.3.11"
|
||||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
|
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
|
||||||
@ -1835,7 +1863,7 @@ rx@4.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
|
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
|
||||||
|
|
||||||
"rxjs@file:../../node_modules/rxjs":
|
"rxjs@file:../../node_modules/rxjs":
|
||||||
version "6.0.0-alpha.4"
|
version "6.0.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
@ -2016,10 +2044,14 @@ source-map@^0.5.1, source-map@^0.5.6:
|
|||||||
version "0.5.7"
|
version "0.5.7"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||||
|
|
||||||
source-map@^0.6.0:
|
source-map@^0.6.0, source-map@^0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||||
|
|
||||||
|
sourcemap-codec@^1.4.1:
|
||||||
|
version "1.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2"
|
||||||
|
|
||||||
spawn-command@^0.0.2-1:
|
spawn-command@^0.0.2-1:
|
||||||
version "0.0.2"
|
version "0.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
|
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
|
||||||
@ -2180,10 +2212,11 @@ tree-kill@^1.1.0:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36"
|
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36"
|
||||||
|
|
||||||
tsickle@^0.27.2:
|
tsickle@^0.32.1:
|
||||||
version "0.27.2"
|
version "0.32.1"
|
||||||
resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.27.2.tgz#f33d46d046f73dd5c155a37922e422816e878736"
|
resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.32.1.tgz#f16e94ba80b32fc9ebe320dc94fbc2ca7f3521a5"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
jasmine-diff "^0.1.3"
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
source-map "^0.6.0"
|
source-map "^0.6.0"
|
||||||
@ -2204,7 +2237,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
|||||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||||
|
|
||||||
"typescript@file:../../node_modules/typescript":
|
"typescript@file:../../node_modules/typescript":
|
||||||
version "2.7.2"
|
version "2.9.2"
|
||||||
|
|
||||||
ua-parser-js@0.7.12:
|
ua-parser-js@0.7.12:
|
||||||
version "0.7.12"
|
version "0.7.12"
|
||||||
@ -2424,4 +2457,4 @@ yeast@0.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
|
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
|
||||||
|
|
||||||
"zone.js@file:../../node_modules/zone.js":
|
"zone.js@file:../../node_modules/zone.js":
|
||||||
version "0.8.20"
|
version "0.8.26"
|
||||||
|
@ -52,5 +52,12 @@ function getHookName(hook: LifecycleHooks): string {
|
|||||||
return 'ngAfterViewInit';
|
return 'ngAfterViewInit';
|
||||||
case LifecycleHooks.AfterViewChecked:
|
case LifecycleHooks.AfterViewChecked:
|
||||||
return 'ngAfterViewChecked';
|
return 'ngAfterViewChecked';
|
||||||
|
default:
|
||||||
|
// This default case is not needed by TypeScript compiler, as the switch is exhaustive.
|
||||||
|
// However Closure Compiler does not understand that and reports an error in typed mode.
|
||||||
|
// The `throw new Error` below works around the problem, and the unexpected: never variable
|
||||||
|
// makes sure tsc still checks this code is unreachable.
|
||||||
|
const unexpected: never = hook;
|
||||||
|
throw new Error(`unexpected ${unexpected}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,16 +115,13 @@ export class CompileMetadataResolver {
|
|||||||
return this.getGeneratedClass(dirType, cpl.hostViewClassName(dirType));
|
return this.getGeneratedClass(dirType, cpl.hostViewClassName(dirType));
|
||||||
}
|
}
|
||||||
|
|
||||||
getHostComponentType(dirType: any): StaticSymbol|Type {
|
getHostComponentType(dirType: any): StaticSymbol|cpl.ProxyClass {
|
||||||
const name = `${cpl.identifierName({reference: dirType})}_Host`;
|
const name = `${cpl.identifierName({reference: dirType})}_Host`;
|
||||||
if (dirType instanceof StaticSymbol) {
|
if (dirType instanceof StaticSymbol) {
|
||||||
return this._staticSymbolCache.get(dirType.filePath, name);
|
return this._staticSymbolCache.get(dirType.filePath, name);
|
||||||
} else {
|
|
||||||
const HostClass = <any>function HostClass() {};
|
|
||||||
HostClass.overriddenName = name;
|
|
||||||
|
|
||||||
return HostClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this._createProxyClass(dirType, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRendererType(dirType: any): StaticSymbol|object {
|
private getRendererType(dirType: any): StaticSymbol|object {
|
||||||
|
@ -940,7 +940,8 @@ function needsAdditionalRootNode(astNodes: TemplateAst[]): boolean {
|
|||||||
|
|
||||||
|
|
||||||
function elementBindingDef(inputAst: BoundElementPropertyAst, dirAst: DirectiveAst): o.Expression {
|
function elementBindingDef(inputAst: BoundElementPropertyAst, dirAst: DirectiveAst): o.Expression {
|
||||||
switch (inputAst.type) {
|
const inputType = inputAst.type;
|
||||||
|
switch (inputType) {
|
||||||
case PropertyBindingType.Attribute:
|
case PropertyBindingType.Attribute:
|
||||||
return o.literalArr([
|
return o.literalArr([
|
||||||
o.literal(BindingFlags.TypeElementAttribute), o.literal(inputAst.name),
|
o.literal(BindingFlags.TypeElementAttribute), o.literal(inputAst.name),
|
||||||
@ -965,6 +966,13 @@ function elementBindingDef(inputAst: BoundElementPropertyAst, dirAst: DirectiveA
|
|||||||
return o.literalArr([
|
return o.literalArr([
|
||||||
o.literal(BindingFlags.TypeElementStyle), o.literal(inputAst.name), o.literal(inputAst.unit)
|
o.literal(BindingFlags.TypeElementStyle), o.literal(inputAst.name), o.literal(inputAst.unit)
|
||||||
]);
|
]);
|
||||||
|
default:
|
||||||
|
// This default case is not needed by TypeScript compiler, as the switch is exhaustive.
|
||||||
|
// However Closure Compiler does not understand that and reports an error in typed mode.
|
||||||
|
// The `throw new Error` below works around the problem, and the unexpected: never variable
|
||||||
|
// makes sure tsc still checks this code is unreachable.
|
||||||
|
const unexpected: never = inputType;
|
||||||
|
throw new Error(`unexpected ${unexpected}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ export {
|
|||||||
detectChanges as ɵdetectChanges,
|
detectChanges as ɵdetectChanges,
|
||||||
renderComponent as ɵrenderComponent,
|
renderComponent as ɵrenderComponent,
|
||||||
ComponentType as ɵComponentType,
|
ComponentType as ɵComponentType,
|
||||||
|
ComponentFactory as ɵRender3ComponentFactory,
|
||||||
|
ComponentRef as ɵRender3ComponentRef,
|
||||||
DirectiveType as ɵDirectiveType,
|
DirectiveType as ɵDirectiveType,
|
||||||
RenderFlags as ɵRenderFlags,
|
RenderFlags as ɵRenderFlags,
|
||||||
directiveInject as ɵdirectiveInject,
|
directiveInject as ɵdirectiveInject,
|
||||||
@ -29,6 +31,7 @@ export {
|
|||||||
InheritDefinitionFeature as ɵInheritDefinitionFeature,
|
InheritDefinitionFeature as ɵInheritDefinitionFeature,
|
||||||
NgOnChangesFeature as ɵNgOnChangesFeature,
|
NgOnChangesFeature as ɵNgOnChangesFeature,
|
||||||
NgModuleType as ɵNgModuleType,
|
NgModuleType as ɵNgModuleType,
|
||||||
|
NgModuleRef as ɵRender3NgModuleRef,
|
||||||
CssSelectorList as ɵCssSelectorList,
|
CssSelectorList as ɵCssSelectorList,
|
||||||
markDirty as ɵmarkDirty,
|
markDirty as ɵmarkDirty,
|
||||||
NgModuleFactory as ɵNgModuleFactory,
|
NgModuleFactory as ɵNgModuleFactory,
|
||||||
@ -95,6 +98,7 @@ export {
|
|||||||
ld as ɵld,
|
ld as ɵld,
|
||||||
Pp as ɵPp,
|
Pp as ɵPp,
|
||||||
ComponentDef as ɵComponentDef,
|
ComponentDef as ɵComponentDef,
|
||||||
|
ComponentDefInternal as ɵComponentDefInternal,
|
||||||
DirectiveDef as ɵDirectiveDef,
|
DirectiveDef as ɵDirectiveDef,
|
||||||
PipeDef as ɵPipeDef,
|
PipeDef as ɵPipeDef,
|
||||||
whenRendered as ɵwhenRendered,
|
whenRendered as ɵwhenRendered,
|
||||||
@ -112,14 +116,38 @@ export {
|
|||||||
iM as ɵiM,
|
iM as ɵiM,
|
||||||
I18nInstruction as ɵI18nInstruction,
|
I18nInstruction as ɵI18nInstruction,
|
||||||
I18nExpInstruction as ɵI18nExpInstruction,
|
I18nExpInstruction as ɵI18nExpInstruction,
|
||||||
|
WRAP_RENDERER_FACTORY2 as ɵWRAP_RENDERER_FACTORY2,
|
||||||
|
Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2,
|
||||||
} from './render3/index';
|
} from './render3/index';
|
||||||
export {NgModuleDef as ɵNgModuleDef} from './metadata/ng_module';
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
compileNgModuleDefs as ɵcompileNgModuleDefs,
|
||||||
|
patchComponentDefWithScope as ɵpatchComponentDefWithScope,
|
||||||
|
} from './render3/jit/module';
|
||||||
|
|
||||||
|
export {
|
||||||
|
compileComponent as ɵcompileComponent,
|
||||||
|
compileDirective as ɵcompileDirective,
|
||||||
|
} from './render3/jit/directive';
|
||||||
|
|
||||||
|
export {
|
||||||
|
compilePipe as ɵcompilePipe,
|
||||||
|
} from './render3/jit/pipe';
|
||||||
|
|
||||||
|
export {
|
||||||
|
NgModuleDef as ɵNgModuleDef,
|
||||||
|
NgModuleDefInternal as ɵNgModuleDefInternal,
|
||||||
|
NgModuleTransitiveScopes as ɵNgModuleTransitiveScopes,
|
||||||
|
} from './metadata/ng_module';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
sanitizeHtml as ɵsanitizeHtml,
|
sanitizeHtml as ɵsanitizeHtml,
|
||||||
sanitizeStyle as ɵsanitizeStyle,
|
sanitizeStyle as ɵsanitizeStyle,
|
||||||
sanitizeUrl as ɵsanitizeUrl,
|
sanitizeUrl as ɵsanitizeUrl,
|
||||||
sanitizeResourceUrl as ɵsanitizeResourceUrl,
|
sanitizeResourceUrl as ɵsanitizeResourceUrl,
|
||||||
} from './sanitization/sanitization';
|
} from './sanitization/sanitization';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml,
|
bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml,
|
||||||
bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle,
|
bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle,
|
||||||
@ -127,4 +155,4 @@ export {
|
|||||||
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
||||||
bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl,
|
bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl,
|
||||||
} from './sanitization/bypass';
|
} from './sanitization/bypass';
|
||||||
// clang-format on
|
// clang-format on
|
@ -6,12 +6,12 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||||
import {InjectionToken} from '../di/injection_token';
|
import {InjectionToken} from '../di/injection_token';
|
||||||
import {Injector, inject} from '../di/injector';
|
import {Injector, inject} from '../di/injector';
|
||||||
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
|
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
|
||||||
import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver';
|
import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver';
|
||||||
import {ElementRef} from '../linker/element_ref';
|
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
|
||||||
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
|
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
|
||||||
import {RendererFactory2} from '../render/api';
|
import {RendererFactory2} from '../render/api';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
@ -21,7 +21,7 @@ import {LifecycleHooksFeature, createRootContext} from './component';
|
|||||||
import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderEmbeddedTemplate} from './instructions';
|
import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderEmbeddedTemplate} from './instructions';
|
||||||
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
|
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
|
||||||
import {LElementNode, TNode, TNodeType} from './interfaces/node';
|
import {LElementNode, TNode, TNodeType} from './interfaces/node';
|
||||||
import {RElement, domRendererFactory3} from './interfaces/renderer';
|
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||||
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
||||||
import {RootViewRef, ViewRef} from './view_ref';
|
import {RootViewRef, ViewRef} from './view_ref';
|
||||||
|
|
||||||
@ -55,8 +55,20 @@ export const ROOT_CONTEXT = new InjectionToken<RootContext>(
|
|||||||
* A change detection scheduler token for {@link RootContext}. This token is the default value used
|
* A change detection scheduler token for {@link RootContext}. This token is the default value used
|
||||||
* for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
|
* for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
|
||||||
*/
|
*/
|
||||||
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>(
|
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDULER_TOKEN', {
|
||||||
'SCHEDULER_TOKEN', {providedIn: 'root', factory: () => requestAnimationFrame.bind(window)});
|
providedIn: 'root',
|
||||||
|
factory: () => {
|
||||||
|
const useRaf = typeof requestAnimationFrame !== 'undefined' && typeof window !== 'undefined';
|
||||||
|
return useRaf ? requestAnimationFrame.bind(window) : setTimeout;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function used to wrap the `RendererFactory2`.
|
||||||
|
* Used in tests to change the `RendererFactory2` into a `DebugRendererFactory2`.
|
||||||
|
*/
|
||||||
|
export const WRAP_RENDERER_FACTORY2 =
|
||||||
|
new InjectionToken<(rf: RendererFactory2) => RendererFactory2>('WRAP_RENDERER_FACTORY2');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render3 implementation of {@link viewEngine_ComponentFactory}.
|
* Render3 implementation of {@link viewEngine_ComponentFactory}.
|
||||||
@ -65,9 +77,11 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
selector: string;
|
selector: string;
|
||||||
componentType: Type<any>;
|
componentType: Type<any>;
|
||||||
ngContentSelectors: string[];
|
ngContentSelectors: string[];
|
||||||
|
|
||||||
get inputs(): {propName: string; templateName: string;}[] {
|
get inputs(): {propName: string; templateName: string;}[] {
|
||||||
return toRefArray(this.componentDef.inputs);
|
return toRefArray(this.componentDef.inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
get outputs(): {propName: string; templateName: string;}[] {
|
get outputs(): {propName: string; templateName: string;}[] {
|
||||||
return toRefArray(this.componentDef.outputs);
|
return toRefArray(this.componentDef.outputs);
|
||||||
}
|
}
|
||||||
@ -84,8 +98,15 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
ngModule?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<T> {
|
ngModule?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<T> {
|
||||||
const isInternalRootView = rootSelectorOrNode === undefined;
|
const isInternalRootView = rootSelectorOrNode === undefined;
|
||||||
|
|
||||||
const rendererFactory =
|
let rendererFactory: RendererFactory3;
|
||||||
ngModule ? ngModule.injector.get(RendererFactory2) : domRendererFactory3;
|
|
||||||
|
if (ngModule) {
|
||||||
|
const wrapper = ngModule.injector.get(WRAP_RENDERER_FACTORY2, (v: RendererFactory2) => v);
|
||||||
|
rendererFactory = wrapper(ngModule.injector.get(RendererFactory2)) as RendererFactory3;
|
||||||
|
} else {
|
||||||
|
rendererFactory = domRendererFactory3;
|
||||||
|
}
|
||||||
|
|
||||||
const hostNode = isInternalRootView ?
|
const hostNode = isInternalRootView ?
|
||||||
elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef)) :
|
elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef)) :
|
||||||
locateHostElement(rendererFactory, rootSelectorOrNode);
|
locateHostElement(rendererFactory, rootSelectorOrNode);
|
||||||
@ -116,11 +137,10 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
elementNode = hostElement(componentTag, hostNode, this.componentDef);
|
elementNode = hostElement(componentTag, hostNode, this.componentDef);
|
||||||
|
|
||||||
// Create directive instance with factory() and store at index 0 in directives array
|
// Create directive instance with factory() and store at index 0 in directives array
|
||||||
rootContext.components.push(
|
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef);
|
||||||
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef) as T);
|
rootContext.components.push(component);
|
||||||
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
|
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
|
||||||
(elementNode.data as LViewData)[CONTEXT] = component;
|
(elementNode.data as LViewData)[CONTEXT] = component;
|
||||||
|
|
||||||
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
||||||
// executed here?
|
// executed here?
|
||||||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
||||||
@ -177,11 +197,11 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
*/
|
*/
|
||||||
export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
||||||
destroyCbs: (() => void)[]|null = [];
|
destroyCbs: (() => void)[]|null = [];
|
||||||
location: ElementRef<any>;
|
location: viewEngine_ElementRef<any>;
|
||||||
injector: Injector;
|
injector: Injector;
|
||||||
instance: T;
|
instance: T;
|
||||||
hostView: ViewRef<T>;
|
hostView: ViewRef<T>;
|
||||||
changeDetectorRef: ChangeDetectorRef;
|
changeDetectorRef: ViewEngine_ChangeDetectorRef;
|
||||||
componentType: Type<T>;
|
componentType: Type<T>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -192,7 +212,7 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
|||||||
this.hostView = this.changeDetectorRef = new RootViewRef<T>(rootView);
|
this.hostView = this.changeDetectorRef = new RootViewRef<T>(rootView);
|
||||||
this.hostView._lViewNode = createLNode(-1, TNodeType.View, null, null, null, rootView);
|
this.hostView._lViewNode = createLNode(-1, TNodeType.View, null, null, null, rootView);
|
||||||
this.injector = injector;
|
this.injector = injector;
|
||||||
this.location = new ElementRef(hostNode);
|
this.location = new viewEngine_ElementRef(hostNode);
|
||||||
this.componentType = componentType;
|
this.componentType = componentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,4 +225,4 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
|
|||||||
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
|
ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed');
|
||||||
this.destroyCbs !.push(callback);
|
this.destroyCbs !.push(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
115
packages/core/src/render3/debug.ts
Normal file
115
packages/core/src/render3/debug.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* @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 {Injector} from '../di/injector';
|
||||||
|
import {Renderer2, RendererType2} from '../render/api';
|
||||||
|
import {DebugContext} from '../view';
|
||||||
|
import {DebugRenderer2, DebugRendererFactory2} from '../view/services';
|
||||||
|
|
||||||
|
import * as di from './di';
|
||||||
|
import {NG_HOST_SYMBOL, _getViewData} from './instructions';
|
||||||
|
import {LElementNode} from './interfaces/node';
|
||||||
|
import {CONTEXT, DIRECTIVES, LViewData, TVIEW} from './interfaces/view';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts the DebugRendererFactory2 to create a DebugRenderer2 specific for IVY.
|
||||||
|
*
|
||||||
|
* The created DebugRenderer know how to create a Debug Context specific to IVY.
|
||||||
|
*/
|
||||||
|
export class Render3DebugRendererFactory2 extends DebugRendererFactory2 {
|
||||||
|
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
|
||||||
|
const renderer = super.createRenderer(element, renderData) as DebugRenderer2;
|
||||||
|
renderer.debugContextFactory = () => new Render3DebugContext(_getViewData());
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores context information about view nodes.
|
||||||
|
*
|
||||||
|
* Used in tests to retrieve information those nodes.
|
||||||
|
*/
|
||||||
|
class Render3DebugContext implements DebugContext {
|
||||||
|
readonly nodeIndex: number|null;
|
||||||
|
|
||||||
|
constructor(private viewData: LViewData) {
|
||||||
|
// The LNode will be created next and appended to viewData
|
||||||
|
this.nodeIndex = viewData ? viewData.length : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get view(): any { return this.viewData; }
|
||||||
|
|
||||||
|
get injector(): Injector {
|
||||||
|
if (this.nodeIndex !== null) {
|
||||||
|
const lElementNode: LElementNode = this.view[this.nodeIndex];
|
||||||
|
const nodeInjector = lElementNode.nodeInjector;
|
||||||
|
|
||||||
|
if (nodeInjector) {
|
||||||
|
return new di.NodeInjector(nodeInjector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Injector.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
get component(): any {
|
||||||
|
// TODO(vicb): why/when
|
||||||
|
if (this.nodeIndex === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tView = this.view[TVIEW];
|
||||||
|
const components: number[]|null = tView.components;
|
||||||
|
|
||||||
|
return (components && components.indexOf(this.nodeIndex) == -1) ?
|
||||||
|
null :
|
||||||
|
this.view[this.nodeIndex].data[CONTEXT];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(vicb): add view providers when supported
|
||||||
|
get providerTokens(): any[] {
|
||||||
|
const matchedDirectives: any[] = [];
|
||||||
|
|
||||||
|
// TODO(vicb): why/when
|
||||||
|
if (this.nodeIndex === null) {
|
||||||
|
return matchedDirectives;
|
||||||
|
}
|
||||||
|
|
||||||
|
const directives = this.view[DIRECTIVES];
|
||||||
|
|
||||||
|
if (directives) {
|
||||||
|
const currentNode = this.view[this.nodeIndex];
|
||||||
|
for (let dirIndex = 0; dirIndex < directives.length; dirIndex++) {
|
||||||
|
const directive = directives[dirIndex];
|
||||||
|
if (directive[NG_HOST_SYMBOL] === currentNode) {
|
||||||
|
matchedDirectives.push(directive.constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matchedDirectives;
|
||||||
|
}
|
||||||
|
|
||||||
|
get references(): {[key: string]: any} {
|
||||||
|
// TODO(vicb): implement retrieving references
|
||||||
|
throw new Error('Not implemented yet in ivy');
|
||||||
|
}
|
||||||
|
|
||||||
|
get context(): any {
|
||||||
|
if (this.nodeIndex === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const lNode = this.view[this.nodeIndex];
|
||||||
|
return lNode.view[CONTEXT];
|
||||||
|
}
|
||||||
|
|
||||||
|
get componentRenderElement(): any { throw new Error('Not implemented in ivy'); }
|
||||||
|
|
||||||
|
get renderNode(): any { throw new Error('Not implemented in ivy'); }
|
||||||
|
|
||||||
|
// TODO(vicb): check previous implementation
|
||||||
|
logError(console: Console, ...values: any[]): void { console.error(...values); }
|
||||||
|
}
|
@ -605,7 +605,7 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine.ViewContainer
|
|||||||
return di.viewContainerRef;
|
return di.viewContainerRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NodeInjector implements Injector {
|
export class NodeInjector implements Injector {
|
||||||
constructor(private _lInjector: LInjector) {}
|
constructor(private _lInjector: LInjector) {}
|
||||||
|
|
||||||
get(token: any): any {
|
get(token: any): any {
|
||||||
|
@ -89,7 +89,9 @@ export function NgOnChangesFeature<T>(definition: DirectiveDefInternal<T>): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (setter) setter.call(this, value);
|
if (setter) setter.call(this, value);
|
||||||
}
|
},
|
||||||
|
// Make the property configurable in dev mode to allow overriding in tests
|
||||||
|
configurable: !!ngDevMode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,12 @@ import {NgOnChangesFeature} from './features/ng_onchanges_feature';
|
|||||||
import {PublicFeature} from './features/public_feature';
|
import {PublicFeature} from './features/public_feature';
|
||||||
import {ComponentDef, ComponentDefInternal, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefInternal, DirectiveType, PipeDef} from './interfaces/definition';
|
import {ComponentDef, ComponentDefInternal, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefInternal, DirectiveType, PipeDef} from './interfaces/definition';
|
||||||
|
|
||||||
export {ComponentFactory, ComponentFactoryResolver, ComponentRef} from './component_ref';
|
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2} from './component_ref';
|
||||||
|
export {Render3DebugRendererFactory2} from './debug';
|
||||||
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectChangeDetectorRef, injectComponentFactoryResolver, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
|
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectChangeDetectorRef, injectComponentFactoryResolver, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
|
||||||
export {RenderFlags} from './interfaces/definition';
|
export {RenderFlags} from './interfaces/definition';
|
||||||
export {CssSelectorList} from './interfaces/projection';
|
export {CssSelectorList} from './interfaces/projection';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Naming scheme:
|
// Naming scheme:
|
||||||
// - Capital letters are for creating things: T(Text), E(Element), D(Directive), V(View),
|
// - Capital letters are for creating things: T(Text), E(Element), D(Directive), V(View),
|
||||||
// C(Container), L(Listener)
|
// C(Container), L(Listener)
|
||||||
|
@ -30,8 +30,6 @@ import {StylingContext, allocStylingContext, createStylingContextTemplate, rende
|
|||||||
import {assertDataInRangeInternal, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
|
import {assertDataInRangeInternal, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directive (D) sets a property on all component instances using this constant as a key and the
|
* Directive (D) sets a property on all component instances using this constant as a key and the
|
||||||
* component's host node (LElement) as the value. This is used in methods like detectChanges to
|
* component's host node (LElement) as the value. This is used in methods like detectChanges to
|
||||||
@ -126,16 +124,6 @@ export function getCurrentView(): OpaqueViewState {
|
|||||||
return viewData as any as OpaqueViewState;
|
return viewData as any as OpaqueViewState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal function that returns the current LViewData instance.
|
|
||||||
*
|
|
||||||
* The getCurrentView() instruction should be used for anything public.
|
|
||||||
*/
|
|
||||||
export function _getViewData(): LViewData {
|
|
||||||
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
|
||||||
return viewData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores `contextViewData` to the given OpaqueViewState instance.
|
* Restores `contextViewData` to the given OpaqueViewState instance.
|
||||||
*
|
*
|
||||||
@ -207,6 +195,16 @@ export function getCreationMode(): boolean {
|
|||||||
*/
|
*/
|
||||||
let viewData: LViewData;
|
let viewData: LViewData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function that returns the current LViewData instance.
|
||||||
|
*
|
||||||
|
* The getCurrentView() instruction should be used for anything public.
|
||||||
|
*/
|
||||||
|
export function _getViewData(): LViewData {
|
||||||
|
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||||
|
return viewData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last viewData retrieved by nextContext().
|
* The last viewData retrieved by nextContext().
|
||||||
* Allows building nextContext() and reference() calls.
|
* Allows building nextContext() and reference() calls.
|
||||||
|
@ -10,13 +10,12 @@ import {ConstantPool, R3DirectiveMetadata, WrappedNodeExpr, compileComponentFrom
|
|||||||
|
|
||||||
import {Component, Directive, HostBinding, HostListener, Input, Output} from '../../metadata/directives';
|
import {Component, Directive, HostBinding, HostListener, Input, Output} from '../../metadata/directives';
|
||||||
import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading';
|
import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading';
|
||||||
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
|
|
||||||
import {Type} from '../../type';
|
import {Type} from '../../type';
|
||||||
import {stringify} from '../../util';
|
import {stringify} from '../../util';
|
||||||
|
|
||||||
import {angularCoreEnv} from './environment';
|
import {angularCoreEnv} from './environment';
|
||||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from './fields';
|
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from './fields';
|
||||||
import {patchComponentDefWithScope} from './module';
|
import {patchComponentDefWithScope, transitiveScopesFor} from './module';
|
||||||
import {getReflect, reflectDependencies} from './util';
|
import {getReflect, reflectDependencies} from './util';
|
||||||
|
|
||||||
type StringMap = {
|
type StringMap = {
|
||||||
@ -33,12 +32,12 @@ type StringMap = {
|
|||||||
* until the global queue has been resolved with a call to `resolveComponentResources`.
|
* until the global queue has been resolved with a call to `resolveComponentResources`.
|
||||||
*/
|
*/
|
||||||
export function compileComponent(type: Type<any>, metadata: Component): void {
|
export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||||
let def: any = null;
|
let ngComponentDef: any = null;
|
||||||
// Metadata may have resources which need to be resolved.
|
// Metadata may have resources which need to be resolved.
|
||||||
maybeQueueResolutionOfComponentResources(metadata);
|
maybeQueueResolutionOfComponentResources(metadata);
|
||||||
Object.defineProperty(type, NG_COMPONENT_DEF, {
|
Object.defineProperty(type, NG_COMPONENT_DEF, {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (def === null) {
|
if (ngComponentDef === null) {
|
||||||
if (componentNeedsResolution(metadata)) {
|
if (componentNeedsResolution(metadata)) {
|
||||||
const error = [`Component '${stringify(type)}' is not resolved:`];
|
const error = [`Component '${stringify(type)}' is not resolved:`];
|
||||||
if (metadata.templateUrl) {
|
if (metadata.templateUrl) {
|
||||||
@ -78,7 +77,7 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
|||||||
constantPool, makeBindingParser());
|
constantPool, makeBindingParser());
|
||||||
const preStatements = [...constantPool.statements, ...res.statements];
|
const preStatements = [...constantPool.statements, ...res.statements];
|
||||||
|
|
||||||
def = jitExpression(
|
ngComponentDef = jitExpression(
|
||||||
res.expression, angularCoreEnv, `ng://${type.name}/ngComponentDef.js`, preStatements);
|
res.expression, angularCoreEnv, `ng://${type.name}/ngComponentDef.js`, preStatements);
|
||||||
|
|
||||||
// If component compilation is async, then the @NgModule annotation which declares the
|
// If component compilation is async, then the @NgModule annotation which declares the
|
||||||
@ -86,11 +85,14 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
|||||||
// allows the component to patch itself with directiveDefs from the module after it finishes
|
// allows the component to patch itself with directiveDefs from the module after it finishes
|
||||||
// compiling.
|
// compiling.
|
||||||
if (hasSelectorScope(type)) {
|
if (hasSelectorScope(type)) {
|
||||||
patchComponentDefWithScope(def, type.ngSelectorScope);
|
const scopes = transitiveScopesFor(type.ngSelectorScope);
|
||||||
|
patchComponentDefWithScope(ngComponentDef, scopes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return def;
|
return ngComponentDef;
|
||||||
},
|
},
|
||||||
|
// Make the property configurable in dev mode to allow overriding in tests
|
||||||
|
configurable: !!ngDevMode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,23 +109,24 @@ function hasSelectorScope<T>(component: Type<T>): component is Type<T>&
|
|||||||
* will resolve when compilation completes and the directive becomes usable.
|
* will resolve when compilation completes and the directive becomes usable.
|
||||||
*/
|
*/
|
||||||
export function compileDirective(type: Type<any>, directive: Directive): void {
|
export function compileDirective(type: Type<any>, directive: Directive): void {
|
||||||
let def: any = null;
|
let ngDirectiveDef: any = null;
|
||||||
Object.defineProperty(type, NG_DIRECTIVE_DEF, {
|
Object.defineProperty(type, NG_DIRECTIVE_DEF, {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (def === null) {
|
if (ngDirectiveDef === null) {
|
||||||
const constantPool = new ConstantPool();
|
const constantPool = new ConstantPool();
|
||||||
const sourceMapUrl = `ng://${type && type.name}/ngDirectiveDef.js`;
|
const sourceMapUrl = `ng://${type && type.name}/ngDirectiveDef.js`;
|
||||||
const res = compileR3Directive(
|
const res = compileR3Directive(
|
||||||
directiveMetadata(type, directive), constantPool, makeBindingParser());
|
directiveMetadata(type, directive), constantPool, makeBindingParser());
|
||||||
const preStatements = [...constantPool.statements, ...res.statements];
|
const preStatements = [...constantPool.statements, ...res.statements];
|
||||||
def = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements);
|
ngDirectiveDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements);
|
||||||
}
|
}
|
||||||
return def;
|
return ngDirectiveDef;
|
||||||
},
|
},
|
||||||
|
// Make the property configurable in dev mode to allow overriding in tests
|
||||||
|
configurable: !!ngDevMode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function extendsDirectlyFromObject(type: Type<any>): boolean {
|
export function extendsDirectlyFromObject(type: Type<any>): boolean {
|
||||||
return Object.getPrototypeOf(type.prototype) === Object.prototype;
|
return Object.getPrototypeOf(type.prototype) === Object.prototype;
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,28 @@ import {reflectDependencies} from './util';
|
|||||||
|
|
||||||
const EMPTY_ARRAY: Type<any>[] = [];
|
const EMPTY_ARRAY: Type<any>[] = [];
|
||||||
|
|
||||||
export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
/**
|
||||||
|
* Compiles a module in JIT mode.
|
||||||
|
*
|
||||||
|
* This function automatically gets called when a class has a `@NgModule` decorator.
|
||||||
|
*/
|
||||||
|
export function compileNgModule(moduleType: Type<any>, ngModule: NgModule): void {
|
||||||
|
compileNgModuleDefs(moduleType, ngModule);
|
||||||
|
setScopeOnDeclaredComponents(moduleType, ngModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles and adds the `ngModuleDef` and `ngInjectorDef` properties to the module class.
|
||||||
|
*/
|
||||||
|
export function compileNgModuleDefs(moduleType: Type<any>, ngModule: NgModule): void {
|
||||||
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
||||||
|
|
||||||
let ngModuleDef: any = null;
|
let ngModuleDef: any = null;
|
||||||
Object.defineProperty(type, NG_MODULE_DEF, {
|
Object.defineProperty(moduleType, NG_MODULE_DEF, {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (ngModuleDef === null) {
|
if (ngModuleDef === null) {
|
||||||
const meta: R3NgModuleMetadata = {
|
const meta: R3NgModuleMetadata = {
|
||||||
type: wrap(type),
|
type: wrap(moduleType),
|
||||||
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrap),
|
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrap),
|
||||||
declarations: declarations.map(wrapReference),
|
declarations: declarations.map(wrapReference),
|
||||||
imports: flatten(ngModule.imports || EMPTY_ARRAY)
|
imports: flatten(ngModule.imports || EMPTY_ARRAY)
|
||||||
@ -38,21 +51,23 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
|||||||
emitInline: true,
|
emitInline: true,
|
||||||
};
|
};
|
||||||
const res = compileR3NgModule(meta);
|
const res = compileR3NgModule(meta);
|
||||||
ngModuleDef =
|
ngModuleDef = jitExpression(
|
||||||
jitExpression(res.expression, angularCoreEnv, `ng://${type.name}/ngModuleDef.js`, []);
|
res.expression, angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, []);
|
||||||
}
|
}
|
||||||
return ngModuleDef;
|
return ngModuleDef;
|
||||||
},
|
},
|
||||||
|
// Make the property configurable in dev mode to allow overriding in tests
|
||||||
|
configurable: !!ngDevMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
let ngInjectorDef: any = null;
|
let ngInjectorDef: any = null;
|
||||||
Object.defineProperty(type, NG_INJECTOR_DEF, {
|
Object.defineProperty(moduleType, NG_INJECTOR_DEF, {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (ngInjectorDef === null) {
|
if (ngInjectorDef === null) {
|
||||||
const meta: R3InjectorMetadata = {
|
const meta: R3InjectorMetadata = {
|
||||||
name: type.name,
|
name: moduleType.name,
|
||||||
type: wrap(type),
|
type: wrap(moduleType),
|
||||||
deps: reflectDependencies(type),
|
deps: reflectDependencies(moduleType),
|
||||||
providers: new WrappedNodeExpr(ngModule.providers || EMPTY_ARRAY),
|
providers: new WrappedNodeExpr(ngModule.providers || EMPTY_ARRAY),
|
||||||
imports: new WrappedNodeExpr([
|
imports: new WrappedNodeExpr([
|
||||||
ngModule.imports || EMPTY_ARRAY,
|
ngModule.imports || EMPTY_ARRAY,
|
||||||
@ -61,25 +76,36 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
|||||||
};
|
};
|
||||||
const res = compileInjector(meta);
|
const res = compileInjector(meta);
|
||||||
ngInjectorDef = jitExpression(
|
ngInjectorDef = jitExpression(
|
||||||
res.expression, angularCoreEnv, `ng://${type.name}/ngInjectorDef.js`, res.statements);
|
res.expression, angularCoreEnv, `ng://${moduleType.name}/ngInjectorDef.js`,
|
||||||
|
res.statements);
|
||||||
}
|
}
|
||||||
return ngInjectorDef;
|
return ngInjectorDef;
|
||||||
},
|
},
|
||||||
|
// Make the property configurable in dev mode to allow overriding in tests
|
||||||
|
configurable: !!ngDevMode,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some declared components may be compiled asynchronously, and thus may not have their
|
||||||
|
* ngComponentDef set yet. If this is the case, then a reference to the module is written into
|
||||||
|
* the `ngSelectorScope` property of the declared type.
|
||||||
|
*/
|
||||||
|
function setScopeOnDeclaredComponents(moduleType: Type<any>, ngModule: NgModule) {
|
||||||
|
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
||||||
|
|
||||||
|
const transitiveScopes = transitiveScopesFor(moduleType);
|
||||||
|
|
||||||
declarations.forEach(declaration => {
|
declarations.forEach(declaration => {
|
||||||
// Some declared components may be compiled asynchronously, and thus may not have their
|
|
||||||
// ngComponentDef set yet. If this is the case, then a reference to the module is written into
|
|
||||||
// the `ngSelectorScope` property of the declared type.
|
|
||||||
if (declaration.hasOwnProperty(NG_COMPONENT_DEF)) {
|
if (declaration.hasOwnProperty(NG_COMPONENT_DEF)) {
|
||||||
// An `ngComponentDef` field exists - go ahead and patch the component directly.
|
// An `ngComponentDef` field exists - go ahead and patch the component directly.
|
||||||
patchComponentDefWithScope(
|
const component = declaration as Type<any>& {ngComponentDef: ComponentDefInternal<any>};
|
||||||
(declaration as Type<any>& {ngComponentDef: ComponentDefInternal<any>}).ngComponentDef,
|
const componentDef = component.ngComponentDef;
|
||||||
type);
|
patchComponentDefWithScope(componentDef, transitiveScopes);
|
||||||
} else if (
|
} else if (
|
||||||
!declaration.hasOwnProperty(NG_DIRECTIVE_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
|
!declaration.hasOwnProperty(NG_DIRECTIVE_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
|
||||||
// Set `ngSelectorScope` for future reference when the component compilation finishes.
|
// Set `ngSelectorScope` for future reference when the component compilation finishes.
|
||||||
(declaration as Type<any>& {ngSelectorScope?: any}).ngSelectorScope = type;
|
(declaration as Type<any>& {ngSelectorScope?: any}).ngSelectorScope = moduleType;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -88,13 +114,13 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
|||||||
* Patch the definition of a component with directives and pipes from the compilation scope of
|
* Patch the definition of a component with directives and pipes from the compilation scope of
|
||||||
* a given module.
|
* a given module.
|
||||||
*/
|
*/
|
||||||
export function patchComponentDefWithScope<C, M>(
|
export function patchComponentDefWithScope<C>(
|
||||||
componentDef: ComponentDefInternal<C>, module: Type<M>) {
|
componentDef: ComponentDefInternal<C>, transitiveScopes: NgModuleTransitiveScopes) {
|
||||||
componentDef.directiveDefs = () => Array.from(transitiveScopesFor(module).compilation.directives)
|
componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives)
|
||||||
.map(dir => dir.ngDirectiveDef || dir.ngComponentDef)
|
.map(dir => dir.ngDirectiveDef || dir.ngComponentDef)
|
||||||
.filter(def => !!def);
|
.filter(def => !!def);
|
||||||
componentDef.pipeDefs = () =>
|
componentDef.pipeDefs = () =>
|
||||||
Array.from(transitiveScopesFor(module).compilation.pipes).map(pipe => pipe.ngPipeDef);
|
Array.from(transitiveScopes.compilation.pipes).map(pipe => pipe.ngPipeDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,7 +130,7 @@ export function patchComponentDefWithScope<C, M>(
|
|||||||
* on modules with components that have not fully compiled yet, but the result should not be used
|
* on modules with components that have not fully compiled yet, but the result should not be used
|
||||||
* until they have.
|
* until they have.
|
||||||
*/
|
*/
|
||||||
function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveScopes {
|
export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveScopes {
|
||||||
if (!isNgModule(moduleType)) {
|
if (!isNgModule(moduleType)) {
|
||||||
throw new Error(`${moduleType.name} does not have an ngModuleDef`);
|
throw new Error(`${moduleType.name} does not have an ngModuleDef`);
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@ import {NG_PIPE_DEF} from './fields';
|
|||||||
import {reflectDependencies} from './util';
|
import {reflectDependencies} from './util';
|
||||||
|
|
||||||
export function compilePipe(type: Type<any>, meta: Pipe): void {
|
export function compilePipe(type: Type<any>, meta: Pipe): void {
|
||||||
let def: any = null;
|
let ngPipeDef: any = null;
|
||||||
Object.defineProperty(type, NG_PIPE_DEF, {
|
Object.defineProperty(type, NG_PIPE_DEF, {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (def === null) {
|
if (ngPipeDef === null) {
|
||||||
const sourceMapUrl = `ng://${stringify(type)}/ngPipeDef.js`;
|
const sourceMapUrl = `ng://${stringify(type)}/ngPipeDef.js`;
|
||||||
|
|
||||||
const name = type.name;
|
const name = type.name;
|
||||||
@ -32,9 +32,11 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
|
|||||||
pure: meta.pure !== undefined ? meta.pure : true,
|
pure: meta.pure !== undefined ? meta.pure : true,
|
||||||
});
|
});
|
||||||
|
|
||||||
def = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
|
ngPipeDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
|
||||||
}
|
}
|
||||||
return def;
|
return ngPipeDef;
|
||||||
}
|
},
|
||||||
|
// Make the property configurable in dev mode to allow overriding in tests
|
||||||
|
configurable: !!ngDevMode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
const ngDevMode: null|NgDevModePerfCounters;
|
const ngDevMode: null|NgDevModePerfCounters;
|
||||||
interface NgDevModePerfCounters {
|
interface NgDevModePerfCounters {
|
||||||
@ -33,8 +32,6 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
declare let global: any;
|
declare let global: any;
|
||||||
|
|
||||||
// NOTE: The order here matters: Checking window, then global, then self is important.
|
// NOTE: The order here matters: Checking window, then global, then self is important.
|
||||||
|
@ -663,8 +663,7 @@ export function getCurrentDebugContext(): DebugContext|null {
|
|||||||
return _currentView ? new DebugContext_(_currentView, _currentNodeIndex) : null;
|
return _currentView ? new DebugContext_(_currentView, _currentNodeIndex) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DebugRendererFactory2 implements RendererFactory2 {
|
||||||
class DebugRendererFactory2 implements RendererFactory2 {
|
|
||||||
constructor(private delegate: RendererFactory2) {}
|
constructor(private delegate: RendererFactory2) {}
|
||||||
|
|
||||||
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
|
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
|
||||||
@ -690,9 +689,21 @@ class DebugRendererFactory2 implements RendererFactory2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DebugRenderer2 implements Renderer2 {
|
||||||
class DebugRenderer2 implements Renderer2 {
|
|
||||||
readonly data: {[key: string]: any};
|
readonly data: {[key: string]: any};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory function used to create a `DebugContext` when a node is created.
|
||||||
|
*
|
||||||
|
* The `DebugContext` allows to retrieve information about the nodes that are useful in tests.
|
||||||
|
*
|
||||||
|
* The factory is configurable so that the `DebugRenderer2` could instantiate either a View Engine
|
||||||
|
* or a Render context.
|
||||||
|
*/
|
||||||
|
debugContextFactory: () => DebugContext | null = getCurrentDebugContext;
|
||||||
|
|
||||||
|
private get debugContext() { return this.debugContextFactory(); }
|
||||||
|
|
||||||
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
|
constructor(private delegate: Renderer2) { this.data = this.delegate.data; }
|
||||||
|
|
||||||
destroyNode(node: any) {
|
destroyNode(node: any) {
|
||||||
@ -706,7 +717,7 @@ class DebugRenderer2 implements Renderer2 {
|
|||||||
|
|
||||||
createElement(name: string, namespace?: string): any {
|
createElement(name: string, namespace?: string): any {
|
||||||
const el = this.delegate.createElement(name, namespace);
|
const el = this.delegate.createElement(name, namespace);
|
||||||
const debugCtx = getCurrentDebugContext();
|
const debugCtx = this.debugContext;
|
||||||
if (debugCtx) {
|
if (debugCtx) {
|
||||||
const debugEl = new DebugElement(el, null, debugCtx);
|
const debugEl = new DebugElement(el, null, debugCtx);
|
||||||
debugEl.name = name;
|
debugEl.name = name;
|
||||||
@ -717,7 +728,7 @@ class DebugRenderer2 implements Renderer2 {
|
|||||||
|
|
||||||
createComment(value: string): any {
|
createComment(value: string): any {
|
||||||
const comment = this.delegate.createComment(value);
|
const comment = this.delegate.createComment(value);
|
||||||
const debugCtx = getCurrentDebugContext();
|
const debugCtx = this.debugContext;
|
||||||
if (debugCtx) {
|
if (debugCtx) {
|
||||||
indexDebugNode(new DebugNode(comment, null, debugCtx));
|
indexDebugNode(new DebugNode(comment, null, debugCtx));
|
||||||
}
|
}
|
||||||
@ -726,7 +737,7 @@ class DebugRenderer2 implements Renderer2 {
|
|||||||
|
|
||||||
createText(value: string): any {
|
createText(value: string): any {
|
||||||
const text = this.delegate.createText(value);
|
const text = this.delegate.createText(value);
|
||||||
const debugCtx = getCurrentDebugContext();
|
const debugCtx = this.debugContext;
|
||||||
if (debugCtx) {
|
if (debugCtx) {
|
||||||
indexDebugNode(new DebugNode(text, null, debugCtx));
|
indexDebugNode(new DebugNode(text, null, debugCtx));
|
||||||
}
|
}
|
||||||
@ -764,7 +775,7 @@ class DebugRenderer2 implements Renderer2 {
|
|||||||
|
|
||||||
selectRootElement(selectorOrNode: string|any): any {
|
selectRootElement(selectorOrNode: string|any): any {
|
||||||
const el = this.delegate.selectRootElement(selectorOrNode);
|
const el = this.delegate.selectRootElement(selectorOrNode);
|
||||||
const debugCtx = getCurrentDebugContext();
|
const debugCtx = this.debugContext;
|
||||||
if (debugCtx) {
|
if (debugCtx) {
|
||||||
indexDebugNode(new DebugElement(el, null, debugCtx));
|
indexDebugNode(new DebugElement(el, null, debugCtx));
|
||||||
}
|
}
|
||||||
|
@ -6,44 +6,33 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ApplicationModule, ApplicationRef, DoCheck, InjectFlags, InjectorType, Input, OnInit, PlatformRef, TestabilityRegistry, Type, defineInjector, inject, ɵE as elementStart, ɵNgModuleDef as NgModuleDef, ɵRenderFlags as RenderFlags, ɵT as text, ɵdefineComponent as defineComponent, ɵe as elementEnd, ɵi1 as interpolation1, ɵt as textBinding} from '@angular/core';
|
import {ApplicationRef, Component, DoCheck, NgModule, OnInit, TestabilityRegistry, ɵivyEnabled as ivyEnabled} from '@angular/core';
|
||||||
import {getTestBed} from '@angular/core/testing';
|
import {getTestBed} from '@angular/core/testing';
|
||||||
import {BrowserModule, EVENT_MANAGER_PLUGINS, platformBrowser} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {withBody} from '@angular/private/testing';
|
import {withBody} from '@angular/private/testing';
|
||||||
|
|
||||||
import {BROWSER_MODULE_PROVIDERS} from '../../platform-browser/src/browser';
|
|
||||||
import {APPLICATION_MODULE_PROVIDERS} from '../src/application_module';
|
|
||||||
import {NgModuleFactory} from '../src/render3/ng_module_ref';
|
import {NgModuleFactory} from '../src/render3/ng_module_ref';
|
||||||
|
|
||||||
describe('ApplicationRef bootstrap', () => {
|
ivyEnabled && describe('ApplicationRef bootstrap', () => {
|
||||||
class HelloWorldComponent implements OnInit, DoCheck {
|
@Component({
|
||||||
|
selector: 'hello-world',
|
||||||
|
template: '<div>Hello {{ name }}</div>',
|
||||||
|
})
|
||||||
|
class HelloWorldComponent implements OnInit,
|
||||||
|
DoCheck {
|
||||||
log: string[] = [];
|
log: string[] = [];
|
||||||
name = 'World';
|
name = 'World';
|
||||||
static ngComponentDef = defineComponent({
|
|
||||||
type: HelloWorldComponent,
|
|
||||||
selectors: [['hello-world']],
|
|
||||||
factory: () => new HelloWorldComponent(),
|
|
||||||
template: function(rf: RenderFlags, ctx: HelloWorldComponent): void {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
elementStart(0, 'div');
|
|
||||||
text(1);
|
|
||||||
elementEnd();
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
textBinding(1, interpolation1('Hello ', ctx.name, ''));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ngOnInit(): void { this.log.push('OnInit'); }
|
ngOnInit(): void { this.log.push('OnInit'); }
|
||||||
|
|
||||||
ngDoCheck(): void { this.log.push('DoCheck'); }
|
ngDoCheck(): void { this.log.push('DoCheck'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [HelloWorldComponent],
|
||||||
|
bootstrap: [HelloWorldComponent],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
})
|
||||||
class MyAppModule {
|
class MyAppModule {
|
||||||
static ngInjectorDef =
|
|
||||||
defineInjector({factory: () => new MyAppModule(), imports: [BrowserModule]});
|
|
||||||
static ngModuleDef = defineNgModule({bootstrap: [HelloWorldComponent]});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should bootstrap hello world', withBody('<hello-world></hello-world>', async() => {
|
it('should bootstrap hello world', withBody('<hello-world></hello-world>', async() => {
|
||||||
@ -66,29 +55,3 @@ describe('ApplicationRef bootstrap', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// These go away when Compiler is ready
|
|
||||||
|
|
||||||
(BrowserModule as any as InjectorType<BrowserModule>).ngInjectorDef = defineInjector({
|
|
||||||
factory: function BrowserModule_Factory() {
|
|
||||||
return new BrowserModule(inject(BrowserModule, InjectFlags.Optional | InjectFlags.SkipSelf));
|
|
||||||
},
|
|
||||||
imports: [ApplicationModule],
|
|
||||||
providers: BROWSER_MODULE_PROVIDERS
|
|
||||||
});
|
|
||||||
|
|
||||||
(ApplicationModule as any as InjectorType<ApplicationModule>).ngInjectorDef = defineInjector({
|
|
||||||
factory: function ApplicationModule_Factory() {
|
|
||||||
return new ApplicationModule(inject(ApplicationRef));
|
|
||||||
},
|
|
||||||
providers: APPLICATION_MODULE_PROVIDERS
|
|
||||||
});
|
|
||||||
|
|
||||||
export function defineNgModule({bootstrap}: {bootstrap?: Type<any>[]}):
|
|
||||||
NgModuleDef<any, any, any, any> {
|
|
||||||
return ({ bootstrap: bootstrap || [], } as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
|
||||||
|
149
packages/core/test/test_bed_spec.ts
Normal file
149
packages/core/test/test_bed_spec.ts
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component, Inject, InjectionToken, NgModule, Optional} from '@angular/core';
|
||||||
|
import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed';
|
||||||
|
import {By} from '@angular/platform-browser';
|
||||||
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
|
|
||||||
|
const NAME = new InjectionToken<string>('name');
|
||||||
|
|
||||||
|
// -- module: HWModule
|
||||||
|
@Component({
|
||||||
|
selector: 'hello-world',
|
||||||
|
template: '<greeting-cmp></greeting-cmp>',
|
||||||
|
})
|
||||||
|
export class HelloWorld {
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- module: Greeting
|
||||||
|
@Component({
|
||||||
|
selector: 'greeting-cmp',
|
||||||
|
template: 'Hello {{ name }}',
|
||||||
|
})
|
||||||
|
export class GreetingCmp {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(@Inject(NAME) @Optional() name: string) { this.name = name || 'nobody!'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [GreetingCmp],
|
||||||
|
exports: [GreetingCmp],
|
||||||
|
})
|
||||||
|
export class GreetingModule {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'simple-cmp', template: '<b>simple</b>'})
|
||||||
|
export class SimpleCmp {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [HelloWorld, SimpleCmp],
|
||||||
|
imports: [GreetingModule],
|
||||||
|
providers: [
|
||||||
|
{provide: NAME, useValue: 'World!'},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class HelloWorldModule {
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('TestBed', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
getTestBed().resetTestingModule();
|
||||||
|
TestBed.configureTestingModule({imports: [HelloWorldModule]});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compile and render a component', () => {
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
|
||||||
|
expect(hello.nativeElement).toHaveText('Hello World!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should give access to the component instance', () => {
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
|
||||||
|
expect(hello.componentInstance).toBeAnInstanceOf(HelloWorld);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should give the ability to query by css', () => {
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
|
||||||
|
const greetingByCss = hello.debugElement.query(By.css('greeting-cmp'));
|
||||||
|
expect(greetingByCss.nativeElement).toHaveText('Hello World!');
|
||||||
|
expect(greetingByCss.componentInstance).toBeAnInstanceOf(GreetingCmp);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should give the ability to trigger the change detection', () => {
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
|
||||||
|
hello.detectChanges();
|
||||||
|
const greetingByCss = hello.debugElement.query(By.css('greeting-cmp'));
|
||||||
|
expect(greetingByCss.nativeElement).toHaveText('Hello World!');
|
||||||
|
|
||||||
|
greetingByCss.componentInstance.name = 'TestBed!';
|
||||||
|
hello.detectChanges();
|
||||||
|
expect(greetingByCss.nativeElement).toHaveText('Hello TestBed!');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should give access to the node injector', () => {
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
const injector = hello.debugElement.query(By.css('greeting-cmp')).injector;
|
||||||
|
|
||||||
|
// from the node injector
|
||||||
|
const helloInjected = injector.get(HelloWorld);
|
||||||
|
expect(helloInjected).toBe(hello.componentInstance);
|
||||||
|
|
||||||
|
// from the module injector
|
||||||
|
const nameInjected = injector.get(NAME);
|
||||||
|
expect(nameInjected).toEqual('World!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should give the ability to query by directive', () => {
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
|
||||||
|
const greetingByDirective = hello.debugElement.query(By.directive(GreetingCmp));
|
||||||
|
expect(greetingByDirective.componentInstance).toBeAnInstanceOf(GreetingCmp);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('allow to override a template', () => {
|
||||||
|
// use original template when there is no override
|
||||||
|
let hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
expect(hello.nativeElement).toHaveText('Hello World!');
|
||||||
|
|
||||||
|
// override the template
|
||||||
|
getTestBed().resetTestingModule();
|
||||||
|
TestBed.configureTestingModule({imports: [HelloWorldModule]});
|
||||||
|
TestBed.overrideComponent(GreetingCmp, {set: {template: `Bonjour {{ name }}`}});
|
||||||
|
hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
expect(hello.nativeElement).toHaveText('Bonjour World!');
|
||||||
|
|
||||||
|
// restore the original template by calling `.resetTestingModule()`
|
||||||
|
getTestBed().resetTestingModule();
|
||||||
|
TestBed.configureTestingModule({imports: [HelloWorldModule]});
|
||||||
|
hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
expect(hello.nativeElement).toHaveText('Hello World!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allow to override a provider', () => {
|
||||||
|
TestBed.overrideProvider(NAME, {useValue: 'injected World !'});
|
||||||
|
const hello = TestBed.createComponent(HelloWorld);
|
||||||
|
hello.detectChanges();
|
||||||
|
expect(hello.nativeElement).toHaveText('Hello injected World !');
|
||||||
|
});
|
||||||
|
});
|
@ -11,6 +11,7 @@ const sourcemaps = require('rollup-plugin-sourcemaps');
|
|||||||
|
|
||||||
const globals = {
|
const globals = {
|
||||||
'@angular/core': 'ng.core',
|
'@angular/core': 'ng.core',
|
||||||
|
'@angular/compiler': 'ng.compiler',
|
||||||
'rxjs': 'rxjs',
|
'rxjs': 'rxjs',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
131
packages/core/testing/src/metadata_overrider.ts
Normal file
131
packages/core/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 './metadata_override';
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
604
packages/core/testing/src/r3_test_bed.ts
Normal file
604
packages/core/testing/src/r3_test_bed.ts
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
/**
|
||||||
|
* @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 {Component, Directive, Injector, NgModule, Pipe, PlatformRef, Provider, RendererFactory2, SchemaMetadata, Type, ɵNgModuleDefInternal as NgModuleDefInternal, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵRender3ComponentFactory as ComponentFactory, ɵRender3DebugRendererFactory2 as Render3DebugRendererFactory2, ɵRender3NgModuleRef as NgModuleRef, ɵWRAP_RENDERER_FACTORY2 as WRAP_RENDERER_FACTORY2, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵstringify as stringify} from '@angular/core';
|
||||||
|
|
||||||
|
import {ComponentFixture} from './component_fixture';
|
||||||
|
import {MetadataOverride} from './metadata_override';
|
||||||
|
import {ComponentResolver, DirectiveResolver, NgModuleResolver, PipeResolver, Resolver} from './resolvers';
|
||||||
|
import {ComponentFixtureAutoDetect, TestComponentRenderer, TestModuleMetadata} from './test_bed_common';
|
||||||
|
|
||||||
|
let _nextRootElementId = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description
|
||||||
|
* Configures and initializes environment for unit testing and provides methods for
|
||||||
|
* creating components and services in unit tests.
|
||||||
|
*
|
||||||
|
* TestBed is the primary api for writing unit tests for Angular applications and libraries.
|
||||||
|
*
|
||||||
|
* Note: Use `TestBed` in tests. It will be set to either `TestBedViewEngine` or `TestBedRender3`
|
||||||
|
* according to the compiler used.
|
||||||
|
*/
|
||||||
|
export class TestBedRender3 {
|
||||||
|
/**
|
||||||
|
* Initialize the environment for testing with a compiler factory, a PlatformRef, and an
|
||||||
|
* angular module. These are common to every test in the suite.
|
||||||
|
*
|
||||||
|
* This may only be called once, to set up the common providers for the current test
|
||||||
|
* suite on the current platform. If you absolutely need to change the providers,
|
||||||
|
* first use `resetTestEnvironment`.
|
||||||
|
*
|
||||||
|
* Test modules and platforms for individual platforms are available from
|
||||||
|
* '@angular/<platform_name>/testing'.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
static initTestEnvironment(
|
||||||
|
ngModule: Type<any>|Type<any>[], platform: PlatformRef,
|
||||||
|
aotSummaries?: () => any[]): TestBedRender3 {
|
||||||
|
const testBed = _getTestBedRender3();
|
||||||
|
testBed.initTestEnvironment(ngModule, platform, aotSummaries);
|
||||||
|
return testBed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the providers for the test injector.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
static resetTestEnvironment(): void { _getTestBedRender3().resetTestEnvironment(); }
|
||||||
|
|
||||||
|
static configureCompiler(config: {providers?: any[]; useJit?: boolean;}): typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().configureCompiler(config);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows overriding default providers, directives, pipes, modules of the test injector,
|
||||||
|
* which are defined in test_injector.js
|
||||||
|
*/
|
||||||
|
static configureTestingModule(moduleDef: TestModuleMetadata): typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().configureTestingModule(moduleDef);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile components with a `templateUrl` for the test's NgModule.
|
||||||
|
* It is necessary to call this function
|
||||||
|
* as fetching urls is asynchronous.
|
||||||
|
*/
|
||||||
|
static compileComponents(): Promise<any> { return _getTestBedRender3().compileComponents(); }
|
||||||
|
|
||||||
|
static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>):
|
||||||
|
typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overrideModule(ngModule, override);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static overrideComponent(component: Type<any>, override: MetadataOverride<Component>):
|
||||||
|
typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overrideComponent(component, override);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>):
|
||||||
|
typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overrideDirective(directive, override);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overridePipe(pipe, override);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static overrideTemplate(component: Type<any>, template: string): typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overrideComponent(component, {set: {template, templateUrl: null !}});
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the template of the given component, compiling the template
|
||||||
|
* in the context of the TestingModule.
|
||||||
|
*
|
||||||
|
* Note: This works for JIT and AOTed components as well.
|
||||||
|
*/
|
||||||
|
static overrideTemplateUsingTestingModule(component: Type<any>, template: string):
|
||||||
|
typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overrideTemplateUsingTestingModule(component, template);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideTemplateUsingTestingModule(component: Type<any>, template: string): void {
|
||||||
|
throw new Error('Render3TestBed.overrideTemplateUsingTestingModule is not implemented yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
static overrideProvider(token: any, provider: {
|
||||||
|
useFactory: Function,
|
||||||
|
deps: any[],
|
||||||
|
}): typeof TestBedRender3;
|
||||||
|
static overrideProvider(token: any, provider: {useValue: any;}): typeof TestBedRender3;
|
||||||
|
static overrideProvider(token: any, provider: {
|
||||||
|
useFactory?: Function,
|
||||||
|
useValue?: any,
|
||||||
|
deps?: any[],
|
||||||
|
}): typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().overrideProvider(token, provider);
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrites all providers for the given token with the given provider definition.
|
||||||
|
*
|
||||||
|
* @deprecated as it makes all NgModules lazy. Introduced only for migrating off of it.
|
||||||
|
*/
|
||||||
|
static deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useFactory: Function,
|
||||||
|
deps: any[],
|
||||||
|
}): void;
|
||||||
|
static deprecatedOverrideProvider(token: any, provider: {useValue: any;}): void;
|
||||||
|
static deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useFactory?: Function,
|
||||||
|
useValue?: any,
|
||||||
|
deps?: any[],
|
||||||
|
}): typeof TestBedRender3 {
|
||||||
|
throw new Error('Render3TestBed.deprecatedOverrideProvider is not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
static get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
|
||||||
|
return _getTestBedRender3().get(token, notFoundValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static createComponent<T>(component: Type<T>): ComponentFixture<T> {
|
||||||
|
return _getTestBedRender3().createComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static resetTestingModule(): typeof TestBedRender3 {
|
||||||
|
_getTestBedRender3().resetTestingModule();
|
||||||
|
return TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
|
||||||
|
platform: PlatformRef = null !;
|
||||||
|
ngModule: Type<any>|Type<any>[] = null !;
|
||||||
|
|
||||||
|
// metadata overrides
|
||||||
|
private _moduleOverrides: [Type<any>, MetadataOverride<NgModule>][] = [];
|
||||||
|
private _componentOverrides: [Type<any>, MetadataOverride<Component>][] = [];
|
||||||
|
private _directiveOverrides: [Type<any>, MetadataOverride<Directive>][] = [];
|
||||||
|
private _pipeOverrides: [Type<any>, MetadataOverride<Pipe>][] = [];
|
||||||
|
private _providerOverrides: Provider[] = [];
|
||||||
|
private _rootProviderOverrides: Provider[] = [];
|
||||||
|
|
||||||
|
// test module configuration
|
||||||
|
private _providers: Provider[] = [];
|
||||||
|
private _declarations: Array<Type<any>|any[]|any> = [];
|
||||||
|
private _imports: Array<Type<any>|any[]|any> = [];
|
||||||
|
private _schemas: Array<SchemaMetadata|any[]> = [];
|
||||||
|
|
||||||
|
private _activeFixtures: ComponentFixture<any>[] = [];
|
||||||
|
|
||||||
|
private _moduleRef: NgModuleRef<any> = null !;
|
||||||
|
|
||||||
|
private _instantiated: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the environment for testing with a compiler factory, a PlatformRef, and an
|
||||||
|
* angular module. These are common to every test in the suite.
|
||||||
|
*
|
||||||
|
* This may only be called once, to set up the common providers for the current test
|
||||||
|
* suite on the current platform. If you absolutely need to change the providers,
|
||||||
|
* first use `resetTestEnvironment`.
|
||||||
|
*
|
||||||
|
* Test modules and platforms for individual platforms are available from
|
||||||
|
* '@angular/<platform_name>/testing'.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
initTestEnvironment(
|
||||||
|
ngModule: Type<any>|Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): void {
|
||||||
|
if (this.platform || this.ngModule) {
|
||||||
|
throw new Error('Cannot set base providers because it has already been called');
|
||||||
|
}
|
||||||
|
this.platform = platform;
|
||||||
|
this.ngModule = ngModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the providers for the test injector.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
resetTestEnvironment(): void {
|
||||||
|
this.resetTestingModule();
|
||||||
|
this.platform = null !;
|
||||||
|
this.ngModule = null !;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTestingModule(): void {
|
||||||
|
// reset metadata overrides
|
||||||
|
this._moduleOverrides = [];
|
||||||
|
this._componentOverrides = [];
|
||||||
|
this._directiveOverrides = [];
|
||||||
|
this._pipeOverrides = [];
|
||||||
|
this._providerOverrides = [];
|
||||||
|
this._rootProviderOverrides = [];
|
||||||
|
|
||||||
|
// reset test module config
|
||||||
|
this._providers = [];
|
||||||
|
this._declarations = [];
|
||||||
|
this._imports = [];
|
||||||
|
this._schemas = [];
|
||||||
|
this._moduleRef = null !;
|
||||||
|
|
||||||
|
this._instantiated = false;
|
||||||
|
this._activeFixtures.forEach((fixture) => {
|
||||||
|
try {
|
||||||
|
fixture.destroy();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error during cleanup of component', {
|
||||||
|
component: fixture.componentInstance,
|
||||||
|
stacktrace: e,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._activeFixtures = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
configureCompiler(config: {providers?: any[]; useJit?: boolean;}): void {
|
||||||
|
throw new Error('the Render3 compiler is not configurable !');
|
||||||
|
}
|
||||||
|
|
||||||
|
configureTestingModule(moduleDef: TestModuleMetadata): void {
|
||||||
|
this._assertNotInstantiated('R3TestBed.configureTestingModule', 'configure the test module');
|
||||||
|
if (moduleDef.providers) {
|
||||||
|
this._providers.push(...moduleDef.providers);
|
||||||
|
}
|
||||||
|
if (moduleDef.declarations) {
|
||||||
|
this._declarations.push(...moduleDef.declarations);
|
||||||
|
}
|
||||||
|
if (moduleDef.imports) {
|
||||||
|
this._imports.push(...moduleDef.imports);
|
||||||
|
}
|
||||||
|
if (moduleDef.schemas) {
|
||||||
|
this._schemas.push(...moduleDef.schemas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(vicb): implement
|
||||||
|
compileComponents(): Promise<any> {
|
||||||
|
throw new Error('Render3TestBed.compileComponents is not implemented yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
|
||||||
|
this._initIfNeeded();
|
||||||
|
if (token === TestBedRender3) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return this._moduleRef.injector.get(token, notFoundValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(tokens: any[], fn: Function, context?: any): any {
|
||||||
|
this._initIfNeeded();
|
||||||
|
const params = tokens.map(t => this.get(t));
|
||||||
|
return fn.apply(context, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): void {
|
||||||
|
this._assertNotInstantiated('overrideModule', 'override module metadata');
|
||||||
|
this._moduleOverrides.push([ngModule, override]);
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideComponent(component: Type<any>, override: MetadataOverride<Component>): void {
|
||||||
|
this._assertNotInstantiated('overrideComponent', 'override component metadata');
|
||||||
|
this._componentOverrides.push([component, override]);
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): void {
|
||||||
|
this._assertNotInstantiated('overrideDirective', 'override directive metadata');
|
||||||
|
this._directiveOverrides.push([directive, override]);
|
||||||
|
}
|
||||||
|
|
||||||
|
overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): void {
|
||||||
|
this._assertNotInstantiated('overridePipe', 'override pipe metadata');
|
||||||
|
this._pipeOverrides.push([pipe, override]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrites all providers for the given token with the given provider definition.
|
||||||
|
*/
|
||||||
|
overrideProvider(token: any, provider: {useFactory?: Function, useValue?: any, deps?: any[]}):
|
||||||
|
void {
|
||||||
|
const isRoot =
|
||||||
|
(typeof token !== 'string' && token.ngInjectableDef &&
|
||||||
|
token.ngInjectableDef.providedIn === 'root');
|
||||||
|
const overrides = isRoot ? this._rootProviderOverrides : this._providerOverrides;
|
||||||
|
|
||||||
|
if (provider.useFactory) {
|
||||||
|
overrides.push({provide: token, useFactory: provider.useFactory, deps: provider.deps || []});
|
||||||
|
} else {
|
||||||
|
overrides.push({provide: token, useValue: provider.useValue});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrites all providers for the given token with the given provider definition.
|
||||||
|
*
|
||||||
|
* @deprecated as it makes all NgModules lazy. Introduced only for migrating off of it.
|
||||||
|
*/
|
||||||
|
deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useFactory: Function,
|
||||||
|
deps: any[],
|
||||||
|
}): void;
|
||||||
|
deprecatedOverrideProvider(token: any, provider: {useValue: any;}): void;
|
||||||
|
deprecatedOverrideProvider(
|
||||||
|
token: any, provider: {useFactory?: Function, useValue?: any, deps?: any[]}): void {
|
||||||
|
throw new Error('No implemented in IVY');
|
||||||
|
}
|
||||||
|
|
||||||
|
createComponent<T>(type: Type<T>): ComponentFixture<T> {
|
||||||
|
this._initIfNeeded();
|
||||||
|
|
||||||
|
const testComponentRenderer: TestComponentRenderer = this.get(TestComponentRenderer);
|
||||||
|
const rootElId = `root${_nextRootElementId++}`;
|
||||||
|
testComponentRenderer.insertRootElement(rootElId);
|
||||||
|
|
||||||
|
const componentDef = (type as any).ngComponentDef;
|
||||||
|
|
||||||
|
if (!componentDef) {
|
||||||
|
throw new Error(
|
||||||
|
`It looks like '${stringify(type)}' has not been IVY compiled - it has no 'ngComponentDef' field`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const componentFactory = new ComponentFactory(componentDef);
|
||||||
|
const componentRef =
|
||||||
|
componentFactory.create(Injector.NULL, [], `#${rootElId}`, this._moduleRef);
|
||||||
|
const autoDetect: boolean = this.get(ComponentFixtureAutoDetect, false);
|
||||||
|
const fixture = new ComponentFixture<any>(componentRef, null, autoDetect);
|
||||||
|
this._activeFixtures.push(fixture);
|
||||||
|
return fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal methods
|
||||||
|
|
||||||
|
private _initIfNeeded(): void {
|
||||||
|
if (this._instantiated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvers = this._getResolvers();
|
||||||
|
const testModuleType = this._createTestModule();
|
||||||
|
|
||||||
|
compileNgModule(testModuleType, resolvers);
|
||||||
|
|
||||||
|
const parentInjector = this.platform.injector;
|
||||||
|
this._moduleRef = new NgModuleRef(testModuleType, parentInjector);
|
||||||
|
|
||||||
|
this._instantiated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates resolvers taking overrides into account
|
||||||
|
private _getResolvers() {
|
||||||
|
const module = new NgModuleResolver();
|
||||||
|
module.setOverrides(this._moduleOverrides);
|
||||||
|
|
||||||
|
const component = new ComponentResolver();
|
||||||
|
component.setOverrides(this._componentOverrides);
|
||||||
|
|
||||||
|
const directive = new DirectiveResolver();
|
||||||
|
directive.setOverrides(this._directiveOverrides);
|
||||||
|
|
||||||
|
const pipe = new PipeResolver();
|
||||||
|
pipe.setOverrides(this._pipeOverrides);
|
||||||
|
|
||||||
|
return {module, component, directive, pipe};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _assertNotInstantiated(methodName: string, methodDescription: string) {
|
||||||
|
if (this._instantiated) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot ${methodDescription} when the test module has already been instantiated. ` +
|
||||||
|
`Make sure you are not using \`inject\` before \`${methodName}\`.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createTestModule(): Type<any> {
|
||||||
|
const rootProviderOverrides = this._rootProviderOverrides;
|
||||||
|
|
||||||
|
const rendererFactoryWrapper = {
|
||||||
|
provide: WRAP_RENDERER_FACTORY2,
|
||||||
|
useFactory: () => (rf: RendererFactory2) => new Render3DebugRendererFactory2(rf),
|
||||||
|
};
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
providers: [...rootProviderOverrides, rendererFactoryWrapper],
|
||||||
|
jit: true,
|
||||||
|
})
|
||||||
|
class RootScopeModule {
|
||||||
|
}
|
||||||
|
|
||||||
|
const providers = [...this._providers, ...this._providerOverrides];
|
||||||
|
|
||||||
|
const declarations = this._declarations;
|
||||||
|
const imports = [RootScopeModule, this.ngModule, this._imports];
|
||||||
|
const schemas = this._schemas;
|
||||||
|
|
||||||
|
@NgModule({providers, declarations, imports, schemas, jit: true})
|
||||||
|
class DynamicTestModule {
|
||||||
|
}
|
||||||
|
|
||||||
|
return DynamicTestModule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let testBed: TestBedRender3;
|
||||||
|
|
||||||
|
export function _getTestBedRender3(): TestBedRender3 {
|
||||||
|
return testBed = testBed || new TestBedRender3();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Module compiler
|
||||||
|
|
||||||
|
const EMPTY_ARRAY: Type<any>[] = [];
|
||||||
|
|
||||||
|
// Resolvers for Angular decorators
|
||||||
|
type Resolvers = {
|
||||||
|
module: Resolver<NgModule>,
|
||||||
|
component: Resolver<Directive>,
|
||||||
|
directive: Resolver<Component>,
|
||||||
|
pipe: Resolver<Pipe>,
|
||||||
|
};
|
||||||
|
|
||||||
|
function compileNgModule(moduleType: Type<any>, resolvers: Resolvers): void {
|
||||||
|
const ngModule = resolvers.module.resolve(moduleType);
|
||||||
|
|
||||||
|
if (ngModule === null) {
|
||||||
|
throw new Error(`${stringify(moduleType)} has not @NgModule annotation`);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileNgModuleDefs(moduleType, ngModule);
|
||||||
|
|
||||||
|
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
||||||
|
|
||||||
|
const compiledComponents: Type<any>[] = [];
|
||||||
|
|
||||||
|
// Compile the components, directives and pipes declared by this module
|
||||||
|
declarations.forEach(declaration => {
|
||||||
|
const component = resolvers.component.resolve(declaration);
|
||||||
|
if (component) {
|
||||||
|
compileComponent(declaration, component);
|
||||||
|
compiledComponents.push(declaration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const directive = resolvers.directive.resolve(declaration);
|
||||||
|
if (directive) {
|
||||||
|
compileDirective(declaration, directive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipe = resolvers.pipe.resolve(declaration);
|
||||||
|
if (pipe) {
|
||||||
|
compilePipe(declaration, pipe);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compile transitive modules, components, directives and pipes
|
||||||
|
const transitiveScope = transitiveScopesFor(moduleType, resolvers);
|
||||||
|
compiledComponents.forEach(
|
||||||
|
cmp => patchComponentDefWithScope((cmp as any).ngComponentDef, transitiveScope));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the pair of transitive scopes (compilation scope and exported scope) for a given module.
|
||||||
|
*
|
||||||
|
* This operation is memoized and the result is cached on the module's definition. It can be called
|
||||||
|
* on modules with components that have not fully compiled yet, but the result should not be used
|
||||||
|
* until they have.
|
||||||
|
*/
|
||||||
|
function transitiveScopesFor<T>(
|
||||||
|
moduleType: Type<T>, resolvers: Resolvers): NgModuleTransitiveScopes {
|
||||||
|
if (!isNgModule(moduleType)) {
|
||||||
|
throw new Error(`${moduleType.name} does not have an ngModuleDef`);
|
||||||
|
}
|
||||||
|
const def = moduleType.ngModuleDef;
|
||||||
|
|
||||||
|
if (def.transitiveCompileScopes !== null) {
|
||||||
|
return def.transitiveCompileScopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scopes: NgModuleTransitiveScopes = {
|
||||||
|
compilation: {
|
||||||
|
directives: new Set<any>(),
|
||||||
|
pipes: new Set<any>(),
|
||||||
|
},
|
||||||
|
exported: {
|
||||||
|
directives: new Set<any>(),
|
||||||
|
pipes: new Set<any>(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
def.declarations.forEach(declared => {
|
||||||
|
const declaredWithDefs = declared as Type<any>& { ngPipeDef?: any; };
|
||||||
|
|
||||||
|
if (declaredWithDefs.ngPipeDef !== undefined) {
|
||||||
|
scopes.compilation.pipes.add(declared);
|
||||||
|
} else {
|
||||||
|
scopes.compilation.directives.add(declared);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
def.imports.forEach(<I>(imported: Type<I>) => {
|
||||||
|
const ngModule = resolvers.module.resolve(imported);
|
||||||
|
|
||||||
|
if (ngModule === null) {
|
||||||
|
throw new Error(`Importing ${imported.name} which does not have an @ngModule`);
|
||||||
|
} else {
|
||||||
|
compileNgModule(imported, resolvers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When this module imports another, the imported module's exported directives and pipes are
|
||||||
|
// added to the compilation scope of this module.
|
||||||
|
const importedScope = transitiveScopesFor(imported, resolvers);
|
||||||
|
importedScope.exported.directives.forEach(entry => scopes.compilation.directives.add(entry));
|
||||||
|
importedScope.exported.pipes.forEach(entry => scopes.compilation.pipes.add(entry));
|
||||||
|
});
|
||||||
|
|
||||||
|
def.exports.forEach(<E>(exported: Type<E>) => {
|
||||||
|
const exportedTyped = exported as Type<E>& {
|
||||||
|
// Components, Directives, NgModules, and Pipes can all be exported.
|
||||||
|
ngComponentDef?: any;
|
||||||
|
ngDirectiveDef?: any;
|
||||||
|
ngModuleDef?: NgModuleDefInternal<E>;
|
||||||
|
ngPipeDef?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Either the type is a module, a pipe, or a component/directive (which may not have an
|
||||||
|
// ngComponentDef as it might be compiled asynchronously).
|
||||||
|
if (isNgModule(exportedTyped)) {
|
||||||
|
// When this module exports another, the exported module's exported directives and pipes are
|
||||||
|
// added to both the compilation and exported scopes of this module.
|
||||||
|
const exportedScope = transitiveScopesFor(exportedTyped, resolvers);
|
||||||
|
exportedScope.exported.directives.forEach(entry => {
|
||||||
|
scopes.compilation.directives.add(entry);
|
||||||
|
scopes.exported.directives.add(entry);
|
||||||
|
});
|
||||||
|
exportedScope.exported.pipes.forEach(entry => {
|
||||||
|
scopes.compilation.pipes.add(entry);
|
||||||
|
scopes.exported.pipes.add(entry);
|
||||||
|
});
|
||||||
|
} else if (exportedTyped.ngPipeDef !== undefined) {
|
||||||
|
scopes.exported.pipes.add(exportedTyped);
|
||||||
|
} else {
|
||||||
|
scopes.exported.directives.add(exportedTyped);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
def.transitiveCompileScopes = scopes;
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten<T>(values: any[]): T[] {
|
||||||
|
const out: T[] = [];
|
||||||
|
values.forEach(value => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
out.push(...flatten<T>(value));
|
||||||
|
} else {
|
||||||
|
out.push(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNgModule<T>(value: Type<T>): value is Type<T>&{ngModuleDef: NgModuleDefInternal<T>} {
|
||||||
|
return (value as{ngModuleDef?: NgModuleDefInternal<T>}).ngModuleDef !== undefined;
|
||||||
|
}
|
73
packages/core/testing/src/resolvers.ts
Normal file
73
packages/core/testing/src/resolvers.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* @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 {Component, Directive, NgModule, Pipe, Type, ɵReflectionCapabilities as ReflectionCapabilities} from '@angular/core';
|
||||||
|
|
||||||
|
import {MetadataOverride} from './metadata_override';
|
||||||
|
import {MetadataOverrider} from './metadata_overrider';
|
||||||
|
|
||||||
|
const reflection = new ReflectionCapabilities();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base interface to resolve `@Component`, `@Directive`, `@Pipe` and `@NgModule`.
|
||||||
|
*/
|
||||||
|
export interface Resolver<T> { resolve(type: Type<any>): T|null; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to override ivy metadata for tests (via the `TestBed`).
|
||||||
|
*/
|
||||||
|
abstract class OverrideResolver<T> implements Resolver<T> {
|
||||||
|
private overrides = new Map<Type<any>, MetadataOverride<T>>();
|
||||||
|
private resolved = new Map<Type<any>, T|null>();
|
||||||
|
|
||||||
|
abstract get type(): any;
|
||||||
|
|
||||||
|
setOverrides(overrides: Array<[Type<any>, MetadataOverride<T>]>) {
|
||||||
|
this.overrides.clear();
|
||||||
|
overrides.forEach(([type, override]) => this.overrides.set(type, override));
|
||||||
|
}
|
||||||
|
|
||||||
|
getAnnotation(type: Type<any>): T|null {
|
||||||
|
return reflection.annotations(type).find(a => a instanceof this.type) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(type: Type<any>): T|null {
|
||||||
|
let resolved = this.resolved.get(type) || null;
|
||||||
|
|
||||||
|
if (!resolved) {
|
||||||
|
resolved = this.getAnnotation(type);
|
||||||
|
if (resolved) {
|
||||||
|
const override = this.overrides.get(type);
|
||||||
|
if (override) {
|
||||||
|
const overrider = new MetadataOverrider();
|
||||||
|
resolved = overrider.overrideMetadata(this.type, resolved, override);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.resolved.set(type, resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class DirectiveResolver extends OverrideResolver<Directive> {
|
||||||
|
get type() { return Directive; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ComponentResolver extends OverrideResolver<Component> {
|
||||||
|
get type() { return Component; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PipeResolver extends OverrideResolver<Pipe> {
|
||||||
|
get type() { return Pipe; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NgModuleResolver extends OverrideResolver<NgModule> {
|
||||||
|
get type() { return NgModule; }
|
||||||
|
}
|
@ -6,56 +6,31 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ApplicationInitStatus, CompilerOptions, Component, Directive, InjectionToken, Injector, NgModule, NgModuleFactory, NgModuleRef, NgZone, Optional, Pipe, PlatformRef, Provider, SchemaMetadata, SkipSelf, StaticProvider, Type, ɵAPP_ROOT as APP_ROOT, ɵDepFlags as DepFlags, ɵNodeFlags as NodeFlags, ɵclearOverrides as clearOverrides, ɵgetComponentViewDefinitionFactory as getComponentViewDefinitionFactory, ɵoverrideComponentView as overrideComponentView, ɵoverrideProvider as overrideProvider, ɵstringify as stringify} from '@angular/core';
|
import {ApplicationInitStatus, CompilerOptions, Component, Directive, Injector, NgModule, NgModuleFactory, NgModuleRef, NgZone, Optional, Pipe, PlatformRef, Provider, SchemaMetadata, SkipSelf, StaticProvider, Type, ɵAPP_ROOT as APP_ROOT, ɵDepFlags as DepFlags, ɵNodeFlags as NodeFlags, ɵclearOverrides as clearOverrides, ɵgetComponentViewDefinitionFactory as getComponentViewDefinitionFactory, ɵivyEnabled as ivyEnabled, ɵoverrideComponentView as overrideComponentView, ɵoverrideProvider as overrideProvider, ɵstringify as stringify} from '@angular/core';
|
||||||
|
|
||||||
import {AsyncTestCompleter} from './async_test_completer';
|
import {AsyncTestCompleter} from './async_test_completer';
|
||||||
import {ComponentFixture} from './component_fixture';
|
import {ComponentFixture} from './component_fixture';
|
||||||
import {MetadataOverride} from './metadata_override';
|
import {MetadataOverride} from './metadata_override';
|
||||||
|
import {TestBedRender3, _getTestBedRender3} from './r3_test_bed';
|
||||||
|
import {ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, TestComponentRenderer, TestModuleMetadata} from './test_bed_common';
|
||||||
import {TestingCompiler, TestingCompilerFactory} from './test_compiler';
|
import {TestingCompiler, TestingCompilerFactory} from './test_compiler';
|
||||||
|
|
||||||
const UNDEFINED = new Object();
|
const UNDEFINED = new Object();
|
||||||
|
|
||||||
/**
|
|
||||||
* An abstract class for inserting the root test component element in a platform independent way.
|
|
||||||
*
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export class TestComponentRenderer {
|
|
||||||
insertRootElement(rootElementId: string) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let _nextRootElementId = 0;
|
let _nextRootElementId = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export const ComponentFixtureAutoDetect =
|
|
||||||
new InjectionToken<boolean[]>('ComponentFixtureAutoDetect');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export const ComponentFixtureNoNgZone = new InjectionToken<boolean[]>('ComponentFixtureNoNgZone');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export type TestModuleMetadata = {
|
|
||||||
providers?: any[],
|
|
||||||
declarations?: any[],
|
|
||||||
imports?: any[],
|
|
||||||
schemas?: Array<SchemaMetadata|any[]>,
|
|
||||||
aotSummaries?: () => any[],
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description
|
* @description
|
||||||
* Configures and initializes environment for unit testing and provides methods for
|
* Configures and initializes environment for unit testing and provides methods for
|
||||||
* creating components and services in unit tests.
|
* creating components and services in unit tests.
|
||||||
*
|
*
|
||||||
* TestBed is the primary api for writing unit tests for Angular applications and libraries.
|
* `TestBed` is the primary api for writing unit tests for Angular applications and libraries.
|
||||||
|
*
|
||||||
|
* Note: Use `TestBed` in tests. It will be set to either `TestBedViewEngine` or `TestBedRender3`
|
||||||
|
* according to the compiler used.
|
||||||
*/
|
*/
|
||||||
export class TestBed implements Injector {
|
export class TestBedViewEngine implements Injector {
|
||||||
/**
|
/**
|
||||||
* Initialize the environment for testing with a compiler factory, a PlatformRef, and an
|
* Initialize the environment for testing with a compiler factory, a PlatformRef, and an
|
||||||
* angular module. These are common to every test in the suite.
|
* angular module. These are common to every test in the suite.
|
||||||
@ -70,8 +45,9 @@ export class TestBed implements Injector {
|
|||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
static initTestEnvironment(
|
static initTestEnvironment(
|
||||||
ngModule: Type<any>|Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): TestBed {
|
ngModule: Type<any>|Type<any>[], platform: PlatformRef,
|
||||||
const testBed = getTestBed();
|
aotSummaries?: () => any[]): TestBedViewEngine {
|
||||||
|
const testBed = _getTestBedViewEngine();
|
||||||
testBed.initTestEnvironment(ngModule, platform, aotSummaries);
|
testBed.initTestEnvironment(ngModule, platform, aotSummaries);
|
||||||
return testBed;
|
return testBed;
|
||||||
}
|
}
|
||||||
@ -81,10 +57,10 @@ export class TestBed implements Injector {
|
|||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
static resetTestEnvironment() { getTestBed().resetTestEnvironment(); }
|
static resetTestEnvironment(): void { _getTestBedViewEngine().resetTestEnvironment(); }
|
||||||
|
|
||||||
static resetTestingModule(): typeof TestBed {
|
static resetTestingModule(): typeof TestBed {
|
||||||
getTestBed().resetTestingModule();
|
_getTestBedViewEngine().resetTestingModule();
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +69,7 @@ export class TestBed implements Injector {
|
|||||||
* which are defined in test_injector.js
|
* which are defined in test_injector.js
|
||||||
*/
|
*/
|
||||||
static configureCompiler(config: {providers?: any[]; useJit?: boolean;}): typeof TestBed {
|
static configureCompiler(config: {providers?: any[]; useJit?: boolean;}): typeof TestBed {
|
||||||
getTestBed().configureCompiler(config);
|
_getTestBedViewEngine().configureCompiler(config);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +78,7 @@ export class TestBed implements Injector {
|
|||||||
* which are defined in test_injector.js
|
* which are defined in test_injector.js
|
||||||
*/
|
*/
|
||||||
static configureTestingModule(moduleDef: TestModuleMetadata): typeof TestBed {
|
static configureTestingModule(moduleDef: TestModuleMetadata): typeof TestBed {
|
||||||
getTestBed().configureTestingModule(moduleDef);
|
_getTestBedViewEngine().configureTestingModule(moduleDef);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,29 +90,29 @@ export class TestBed implements Injector {
|
|||||||
static compileComponents(): Promise<any> { return getTestBed().compileComponents(); }
|
static compileComponents(): Promise<any> { return getTestBed().compileComponents(); }
|
||||||
|
|
||||||
static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): typeof TestBed {
|
static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): typeof TestBed {
|
||||||
getTestBed().overrideModule(ngModule, override);
|
_getTestBedViewEngine().overrideModule(ngModule, override);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static overrideComponent(component: Type<any>, override: MetadataOverride<Component>):
|
static overrideComponent(component: Type<any>, override: MetadataOverride<Component>):
|
||||||
typeof TestBed {
|
typeof TestBed {
|
||||||
getTestBed().overrideComponent(component, override);
|
_getTestBedViewEngine().overrideComponent(component, override);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>):
|
static overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>):
|
||||||
typeof TestBed {
|
typeof TestBed {
|
||||||
getTestBed().overrideDirective(directive, override);
|
_getTestBedViewEngine().overrideDirective(directive, override);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): typeof TestBed {
|
static overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): typeof TestBed {
|
||||||
getTestBed().overridePipe(pipe, override);
|
_getTestBedViewEngine().overridePipe(pipe, override);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static overrideTemplate(component: Type<any>, template: string): typeof TestBed {
|
static overrideTemplate(component: Type<any>, template: string): typeof TestBed {
|
||||||
getTestBed().overrideComponent(component, {set: {template, templateUrl: null !}});
|
_getTestBedViewEngine().overrideComponent(component, {set: {template, templateUrl: null !}});
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,11 +124,10 @@ export class TestBed implements Injector {
|
|||||||
*/
|
*/
|
||||||
static overrideTemplateUsingTestingModule(component: Type<any>, template: string):
|
static overrideTemplateUsingTestingModule(component: Type<any>, template: string):
|
||||||
typeof TestBed {
|
typeof TestBed {
|
||||||
getTestBed().overrideTemplateUsingTestingModule(component, template);
|
_getTestBedViewEngine().overrideTemplateUsingTestingModule(component, template);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overwrites all providers for the given token with the given provider definition.
|
* Overwrites all providers for the given token with the given provider definition.
|
||||||
*
|
*
|
||||||
@ -168,7 +143,7 @@ export class TestBed implements Injector {
|
|||||||
useValue?: any,
|
useValue?: any,
|
||||||
deps?: any[],
|
deps?: any[],
|
||||||
}): typeof TestBed {
|
}): typeof TestBed {
|
||||||
getTestBed().overrideProvider(token, provider as any);
|
_getTestBedViewEngine().overrideProvider(token, provider as any);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,16 +162,16 @@ export class TestBed implements Injector {
|
|||||||
useValue?: any,
|
useValue?: any,
|
||||||
deps?: any[],
|
deps?: any[],
|
||||||
}): typeof TestBed {
|
}): typeof TestBed {
|
||||||
getTestBed().deprecatedOverrideProvider(token, provider as any);
|
_getTestBedViewEngine().deprecatedOverrideProvider(token, provider as any);
|
||||||
return TestBed;
|
return TestBed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND) {
|
static get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND) {
|
||||||
return getTestBed().get(token, notFoundValue);
|
return _getTestBedViewEngine().get(token, notFoundValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static createComponent<T>(component: Type<T>): ComponentFixture<T> {
|
static createComponent<T>(component: Type<T>): ComponentFixture<T> {
|
||||||
return getTestBed().createComponent(component);
|
return _getTestBedViewEngine().createComponent(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _instantiated: boolean = false;
|
private _instantiated: boolean = false;
|
||||||
@ -243,7 +218,7 @@ export class TestBed implements Injector {
|
|||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
initTestEnvironment(
|
initTestEnvironment(
|
||||||
ngModule: Type<any>|Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]) {
|
ngModule: Type<any>|Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): void {
|
||||||
if (this.platform || this.ngModule) {
|
if (this.platform || this.ngModule) {
|
||||||
throw new Error('Cannot set base providers because it has already been called');
|
throw new Error('Cannot set base providers because it has already been called');
|
||||||
}
|
}
|
||||||
@ -259,14 +234,14 @@ export class TestBed implements Injector {
|
|||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
resetTestEnvironment() {
|
resetTestEnvironment(): void {
|
||||||
this.resetTestingModule();
|
this.resetTestingModule();
|
||||||
this.platform = null !;
|
this.platform = null !;
|
||||||
this.ngModule = null !;
|
this.ngModule = null !;
|
||||||
this._testEnvAotSummaries = () => [];
|
this._testEnvAotSummaries = () => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
resetTestingModule() {
|
resetTestingModule(): void {
|
||||||
clearOverrides();
|
clearOverrides();
|
||||||
this._aotSummaries = [];
|
this._aotSummaries = [];
|
||||||
this._templateOverrides = [];
|
this._templateOverrides = [];
|
||||||
@ -300,12 +275,12 @@ export class TestBed implements Injector {
|
|||||||
this._activeFixtures = [];
|
this._activeFixtures = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
configureCompiler(config: {providers?: any[], useJit?: boolean}) {
|
configureCompiler(config: {providers?: any[], useJit?: boolean}): void {
|
||||||
this._assertNotInstantiated('TestBed.configureCompiler', 'configure the compiler');
|
this._assertNotInstantiated('TestBed.configureCompiler', 'configure the compiler');
|
||||||
this._compilerOptions.push(config);
|
this._compilerOptions.push(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
configureTestingModule(moduleDef: TestModuleMetadata) {
|
configureTestingModule(moduleDef: TestModuleMetadata): void {
|
||||||
this._assertNotInstantiated('TestBed.configureTestingModule', 'configure the test module');
|
this._assertNotInstantiated('TestBed.configureTestingModule', 'configure the test module');
|
||||||
if (moduleDef.providers) {
|
if (moduleDef.providers) {
|
||||||
this._providers.push(...moduleDef.providers);
|
this._providers.push(...moduleDef.providers);
|
||||||
@ -336,7 +311,7 @@ export class TestBed implements Injector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initIfNeeded() {
|
private _initIfNeeded(): void {
|
||||||
if (this._instantiated) {
|
if (this._instantiated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -425,7 +400,7 @@ export class TestBed implements Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND) {
|
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
|
||||||
this._initIfNeeded();
|
this._initIfNeeded();
|
||||||
if (token === TestBed) {
|
if (token === TestBed) {
|
||||||
return this;
|
return this;
|
||||||
@ -574,13 +549,32 @@ export class TestBed implements Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _testBed: TestBed = null !;
|
/**
|
||||||
|
* @description
|
||||||
|
* Configures and initializes environment for unit testing and provides methods for
|
||||||
|
* creating components and services in unit tests.
|
||||||
|
*
|
||||||
|
* `TestBed` is the primary api for writing unit tests for Angular applications and libraries.
|
||||||
|
*
|
||||||
|
* Note: Use `TestBed` in tests. It will be set to either `TestBedViewEngine` or `TestBedRender3`
|
||||||
|
* according to the compiler used.
|
||||||
|
*/
|
||||||
|
export const TestBed = ivyEnabled ? TestBedRender3 : TestBedViewEngine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns a singleton of the applicable `TestBed`.
|
||||||
|
*
|
||||||
|
* It will be either an instance of `TestBedViewEngine` or `TestBedRender3`.
|
||||||
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export function getTestBed(): TestBed {
|
export const getTestBed: () => TestBedRender3 | TestBedViewEngine =
|
||||||
return _testBed = _testBed || new TestBed();
|
ivyEnabled ? _getTestBedRender3 : _getTestBedViewEngine;
|
||||||
|
|
||||||
|
let testBed: TestBedViewEngine;
|
||||||
|
|
||||||
|
function _getTestBedViewEngine(): TestBedViewEngine {
|
||||||
|
return testBed = testBed || new TestBedViewEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
40
packages/core/testing/src/test_bed_common.ts
Normal file
40
packages/core/testing/src/test_bed_common.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* @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 {InjectionToken, SchemaMetadata} from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract class for inserting the root test component element in a platform independent way.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export class TestComponentRenderer {
|
||||||
|
insertRootElement(rootElementId: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export const ComponentFixtureAutoDetect =
|
||||||
|
new InjectionToken<boolean[]>('ComponentFixtureAutoDetect');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export const ComponentFixtureNoNgZone = new InjectionToken<boolean[]>('ComponentFixtureNoNgZone');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export type TestModuleMetadata = {
|
||||||
|
providers?: any[],
|
||||||
|
declarations?: any[],
|
||||||
|
imports?: any[],
|
||||||
|
schemas?: Array<SchemaMetadata|any[]>,
|
||||||
|
aotSummaries?: () => any[],
|
||||||
|
};
|
@ -16,6 +16,9 @@ export * from './async';
|
|||||||
export * from './component_fixture';
|
export * from './component_fixture';
|
||||||
export * from './fake_async';
|
export * from './fake_async';
|
||||||
export * from './test_bed';
|
export * from './test_bed';
|
||||||
|
export * from './test_bed_common';
|
||||||
|
export * from './r3_test_bed';
|
||||||
export * from './before_each';
|
export * from './before_each';
|
||||||
export * from './metadata_override';
|
export * from './metadata_override';
|
||||||
|
export * from './metadata_overrider';
|
||||||
export * from './private_export_testing';
|
export * from './private_export_testing';
|
||||||
|
@ -1,27 +1,31 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig-build.json",
|
"extends": "../tsconfig-build.json",
|
||||||
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"rootDir": "../",
|
"rootDir": "../",
|
||||||
"paths": {
|
"paths": {
|
||||||
"rxjs/*": ["../../../node_modules/rxjs/*"],
|
"rxjs/*": [
|
||||||
"@angular/core": ["../../../dist/packages/core"]
|
"../../../node_modules/rxjs/*"
|
||||||
|
],
|
||||||
|
"@angular/core": [
|
||||||
|
"../../../dist/packages/core"
|
||||||
|
],
|
||||||
|
"@angular/compiler": [
|
||||||
|
"../../../dist/packages/compiler"
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"outDir": "../../../dist/packages/core"
|
"outDir": "../../../dist/packages/core"
|
||||||
},
|
},
|
||||||
|
|
||||||
"files": [
|
"files": [
|
||||||
"public_api.ts",
|
"public_api.ts",
|
||||||
"../../../node_modules/zone.js/dist/zone.js.d.ts",
|
"../../../node_modules/zone.js/dist/zone.js.d.ts",
|
||||||
"../../system.d.ts",
|
"../../system.d.ts",
|
||||||
"../../types.d.ts"
|
"../../types.d.ts"
|
||||||
],
|
],
|
||||||
|
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"strictMetadataEmit": false,
|
"strictMetadataEmit": false,
|
||||||
"skipTemplateCodegen": true,
|
"skipTemplateCodegen": true,
|
||||||
"flatModuleOutFile": "testing.js",
|
"flatModuleOutFile": "testing.js",
|
||||||
"flatModuleId": "@angular/core/testing"
|
"flatModuleId": "@angular/core/testing"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,22 +1,26 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig-build.json",
|
"extends": "../tsconfig-build.json",
|
||||||
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"rxjs/*": ["../../node_modules/rxjs/*"],
|
"rxjs/*": [
|
||||||
"@angular/core": ["."]
|
"../../node_modules/rxjs/*"
|
||||||
|
],
|
||||||
|
"@angular/core": [
|
||||||
|
"."
|
||||||
|
],
|
||||||
|
"@angular/compiler": [
|
||||||
|
"../../dist/packages/compiler"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"outDir": "../../dist/packages/core"
|
"outDir": "../../dist/packages/core"
|
||||||
},
|
},
|
||||||
|
|
||||||
"files": [
|
"files": [
|
||||||
"public_api.ts",
|
"public_api.ts",
|
||||||
"../../node_modules/zone.js/dist/zone.js.d.ts",
|
"../../node_modules/zone.js/dist/zone.js.d.ts",
|
||||||
"../system.d.ts"
|
"../system.d.ts"
|
||||||
],
|
],
|
||||||
|
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"annotateForClosureCompiler": true,
|
"annotateForClosureCompiler": true,
|
||||||
"strictMetadataEmit": false,
|
"strictMetadataEmit": false,
|
||||||
@ -24,4 +28,4 @@
|
|||||||
"flatModuleOutFile": "core.js",
|
"flatModuleOutFile": "core.js",
|
||||||
"flatModuleId": "@angular/core"
|
"flatModuleId": "@angular/core"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,6 +18,7 @@ jasmine_node_test(
|
|||||||
bootstrap = ["angular/tools/testing/init_node_spec.js"],
|
bootstrap = ["angular/tools/testing/init_node_spec.js"],
|
||||||
data = [
|
data = [
|
||||||
"//packages/common:npm_package",
|
"//packages/common:npm_package",
|
||||||
|
"//packages/compiler:npm_package",
|
||||||
"//packages/core:npm_package",
|
"//packages/core:npm_package",
|
||||||
"//packages/forms:npm_package",
|
"//packages/forms:npm_package",
|
||||||
],
|
],
|
||||||
|
@ -6,126 +6,5 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ɵstringify as stringify} from '@angular/core';
|
// `MetadataOverrider` has been moved to core to allow using it from the render3 TestBed
|
||||||
import {MetadataOverride} from '@angular/core/testing';
|
export {MetadataOverrider} 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;
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {NgModule, createPlatformFactory} from '@angular/core';
|
import {NgModule, PlatformRef, StaticProvider, createPlatformFactory} from '@angular/core';
|
||||||
import {TestComponentRenderer} from '@angular/core/testing';
|
import {TestComponentRenderer} from '@angular/core/testing';
|
||||||
import {ɵINTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS as INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from '@angular/platform-browser-dynamic';
|
import {ɵINTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS as INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from '@angular/platform-browser-dynamic';
|
||||||
import {BrowserTestingModule} from '@angular/platform-browser/testing';
|
import {BrowserTestingModule} from '@angular/platform-browser/testing';
|
||||||
|
@ -56,7 +56,7 @@ if [[ ${TRAVIS} &&
|
|||||||
travisFoldStart "yarn-install.aio"
|
travisFoldStart "yarn-install.aio"
|
||||||
(
|
(
|
||||||
# HACK (don't submit with this): Build Angular
|
# HACK (don't submit with this): Build Angular
|
||||||
./build.sh --packages=core,elements --examples=false
|
./build.sh --packages=compiler,core,elements --examples=false
|
||||||
|
|
||||||
cd ${PROJECT_ROOT}/aio
|
cd ${PROJECT_ROOT}/aio
|
||||||
yarn install --frozen-lockfile --non-interactive
|
yarn install --frozen-lockfile --non-interactive
|
||||||
|
81
tools/public_api_guard/core/testing.d.ts
vendored
81
tools/public_api_guard/core/testing.d.ts
vendored
@ -1,3 +1,5 @@
|
|||||||
|
export declare function _getTestBedRender3(): TestBedRender3;
|
||||||
|
|
||||||
export declare function async(fn: Function): (done: any) => any;
|
export declare function async(fn: Function): (done: any) => any;
|
||||||
|
|
||||||
export declare class ComponentFixture<T> {
|
export declare class ComponentFixture<T> {
|
||||||
@ -37,7 +39,7 @@ export declare function flush(maxTurns?: number): number;
|
|||||||
export declare function flushMicrotasks(): void;
|
export declare function flushMicrotasks(): void;
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare function getTestBed(): TestBed;
|
export declare const getTestBed: () => TestBedRender3 | TestBedViewEngine;
|
||||||
|
|
||||||
export declare function inject(tokens: any[], fn: Function): () => any;
|
export declare function inject(tokens: any[], fn: Function): () => any;
|
||||||
|
|
||||||
@ -54,10 +56,83 @@ export declare type MetadataOverride<T> = {
|
|||||||
set?: Partial<T>;
|
set?: Partial<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export declare class MetadataOverrider {
|
||||||
|
overrideMetadata<C extends T, T>(metadataClass: {
|
||||||
|
new (options: T): C;
|
||||||
|
}, oldMetadata: C, override: MetadataOverride<T>): C;
|
||||||
|
}
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare function resetFakeAsyncZone(): void;
|
export declare function resetFakeAsyncZone(): void;
|
||||||
|
|
||||||
export declare class TestBed implements Injector {
|
export declare const TestBed: typeof TestBedRender3 | typeof TestBedViewEngine;
|
||||||
|
|
||||||
|
export declare class TestBedRender3 {
|
||||||
|
ngModule: Type<any> | Type<any>[];
|
||||||
|
platform: PlatformRef;
|
||||||
|
compileComponents(): Promise<any>;
|
||||||
|
configureCompiler(config: {
|
||||||
|
providers?: any[];
|
||||||
|
useJit?: boolean;
|
||||||
|
}): void;
|
||||||
|
configureTestingModule(moduleDef: TestModuleMetadata): void;
|
||||||
|
createComponent<T>(type: Type<T>): ComponentFixture<T>;
|
||||||
|
deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useValue: any;
|
||||||
|
}): void;
|
||||||
|
/** @deprecated */ deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useFactory: Function;
|
||||||
|
deps: any[];
|
||||||
|
}): void;
|
||||||
|
execute(tokens: any[], fn: Function, context?: any): any;
|
||||||
|
get(token: any, notFoundValue?: any): any;
|
||||||
|
/** @experimental */ initTestEnvironment(ngModule: Type<any> | Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): void;
|
||||||
|
overrideComponent(component: Type<any>, override: MetadataOverride<Component>): void;
|
||||||
|
overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): void;
|
||||||
|
overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): void;
|
||||||
|
overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): void;
|
||||||
|
overrideProvider(token: any, provider: {
|
||||||
|
useFactory?: Function;
|
||||||
|
useValue?: any;
|
||||||
|
deps?: any[];
|
||||||
|
}): void;
|
||||||
|
overrideTemplateUsingTestingModule(component: Type<any>, template: string): void;
|
||||||
|
/** @experimental */ resetTestEnvironment(): void;
|
||||||
|
resetTestingModule(): void;
|
||||||
|
static compileComponents(): Promise<any>;
|
||||||
|
static configureCompiler(config: {
|
||||||
|
providers?: any[];
|
||||||
|
useJit?: boolean;
|
||||||
|
}): typeof TestBedRender3;
|
||||||
|
static configureTestingModule(moduleDef: TestModuleMetadata): typeof TestBedRender3;
|
||||||
|
static createComponent<T>(component: Type<T>): ComponentFixture<T>;
|
||||||
|
static deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useValue: any;
|
||||||
|
}): void;
|
||||||
|
/** @deprecated */ static deprecatedOverrideProvider(token: any, provider: {
|
||||||
|
useFactory: Function;
|
||||||
|
deps: any[];
|
||||||
|
}): void;
|
||||||
|
static get(token: any, notFoundValue?: any): any;
|
||||||
|
/** @experimental */ static initTestEnvironment(ngModule: Type<any> | Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): TestBedRender3;
|
||||||
|
static overrideComponent(component: Type<any>, override: MetadataOverride<Component>): typeof TestBedRender3;
|
||||||
|
static overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): typeof TestBedRender3;
|
||||||
|
static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): typeof TestBedRender3;
|
||||||
|
static overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): typeof TestBedRender3;
|
||||||
|
static overrideProvider(token: any, provider: {
|
||||||
|
useFactory: Function;
|
||||||
|
deps: any[];
|
||||||
|
}): typeof TestBedRender3;
|
||||||
|
static overrideProvider(token: any, provider: {
|
||||||
|
useValue: any;
|
||||||
|
}): typeof TestBedRender3;
|
||||||
|
static overrideTemplate(component: Type<any>, template: string): typeof TestBedRender3;
|
||||||
|
static overrideTemplateUsingTestingModule(component: Type<any>, template: string): typeof TestBedRender3;
|
||||||
|
/** @experimental */ static resetTestEnvironment(): void;
|
||||||
|
static resetTestingModule(): typeof TestBedRender3;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare class TestBedViewEngine implements Injector {
|
||||||
ngModule: Type<any> | Type<any>[];
|
ngModule: Type<any> | Type<any>[];
|
||||||
platform: PlatformRef;
|
platform: PlatformRef;
|
||||||
compileComponents(): Promise<any>;
|
compileComponents(): Promise<any>;
|
||||||
@ -106,7 +181,7 @@ export declare class TestBed implements Injector {
|
|||||||
deps: any[];
|
deps: any[];
|
||||||
}): void;
|
}): void;
|
||||||
static get(token: any, notFoundValue?: any): any;
|
static get(token: any, notFoundValue?: any): any;
|
||||||
/** @experimental */ static initTestEnvironment(ngModule: Type<any> | Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): TestBed;
|
/** @experimental */ static initTestEnvironment(ngModule: Type<any> | Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): TestBedViewEngine;
|
||||||
static overrideComponent(component: Type<any>, override: MetadataOverride<Component>): typeof TestBed;
|
static overrideComponent(component: Type<any>, override: MetadataOverride<Component>): typeof TestBed;
|
||||||
static overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): typeof TestBed;
|
static overrideDirective(directive: Type<any>, override: MetadataOverride<Directive>): typeof TestBed;
|
||||||
static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): typeof TestBed;
|
static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): typeof TestBed;
|
||||||
|
Reference in New Issue
Block a user