fix(ivy): fix invalid provider error messages under TestBed (#28033)

An @NgModule with invalid provider declarations produces errors under
normal circumstances. However, within the TestBed two small issues with
provider overrides interfered with the correct production of these errors:

1. a 'null' provider object caused a premature crash when the TestBed
   attempted to check for a 'provide' property on it with hasOwnProperty().
2. the array of providers would have an empty override array appended to it
   for each input provider, which would pollute the error messages produced
   down the line.

This commit fixes both of these issues, by 1) checking for null and 2)
filtering out the empty override arrays.

Testing strategy: future commits change the way the TestBed compiles
modules, causing tests to become sensitive to this bug if not fixed.

PR Close #28033
This commit is contained in:
Alex Rickabaugh 2019-01-10 13:48:29 -08:00 committed by Andrew Kushnir
parent 6c6d43086f
commit 94893accdb
1 changed files with 7 additions and 2 deletions

View File

@ -444,7 +444,7 @@ export class TestBedRender3 implements Injector, TestBed {
// get overrides for a specific provider (if any) // get overrides for a specific provider (if any)
private _getProviderOverrides(provider: any) { private _getProviderOverrides(provider: any) {
const token = typeof provider === 'object' && provider.hasOwnProperty('provide') ? const token = provider && typeof provider === 'object' && provider.hasOwnProperty('provide') ?
provider.provide : provider.provide :
provider; provider;
return this._providerOverridesByToken.get(token) || []; return this._providerOverridesByToken.get(token) || [];
@ -503,8 +503,13 @@ export class TestBedRender3 implements Injector, TestBed {
private _getMetaWithOverrides(meta: Component|Directive|NgModule, type?: Type<any>) { private _getMetaWithOverrides(meta: Component|Directive|NgModule, type?: Type<any>) {
const overrides: {providers?: any[], template?: string} = {}; const overrides: {providers?: any[], template?: string} = {};
if (meta.providers && meta.providers.length) { if (meta.providers && meta.providers.length) {
// There are two flattening operations here. The inner flatten() operates on the metadata's
// providers and applies a mapping function which retrieves overrides for each incoming
// provider. The outer flatten() then flattens the produced overrides array. If this is not
// done, the array can contain other empty arrays (e.g. `[[], []]`) which leak into the
// providers array and contaminate any error messages that might be generated.
const providerOverrides = const providerOverrides =
flatten(meta.providers, (provider: any) => this._getProviderOverrides(provider)); flatten(flatten(meta.providers, (provider: any) => this._getProviderOverrides(provider)));
if (providerOverrides.length) { if (providerOverrides.length) {
overrides.providers = [...meta.providers, ...providerOverrides]; overrides.providers = [...meta.providers, ...providerOverrides];
} }