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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions packages/core/src/view/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,6 @@ function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition {
return;
}
if (nodeDef.flags & NodeFlags.CatProviderNoDirective) {
// Make all providers lazy, so that we don't get into trouble
// with ordering problems of providers on the same element
nodeDef.flags |= NodeFlags.LazyProvider;
const provider = nodeDef.provider !;
const override = providerOverrides.get(provider.token);
if (override) {
Expand All @@ -228,7 +225,8 @@ function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition {
// We only create new datastructures if we need to, to keep perf impact
// reasonable.
function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefinition {
if (providerOverrides.size === 0 || !hasOverrrides(def)) {
const {hasOverrides, hasDeprecatedOverrides} = calcHasOverrides(def);
if (!hasOverrides) {
return def;
}
// clone the whole view definition,
Expand All @@ -237,18 +235,32 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi
applyProviderOverrides(def);
return def;

function hasOverrrides(def: NgModuleDefinition): boolean {
return def.providers.some(
node =>
!!(node.flags & NodeFlags.CatProviderNoDirective) && providerOverrides.has(node.token));
function calcHasOverrides(def: NgModuleDefinition):
{hasOverrides: boolean, hasDeprecatedOverrides: boolean} {
let hasOverrides = false;
let hasDeprecatedOverrides = false;
if (providerOverrides.size === 0) {
return {hasOverrides, hasDeprecatedOverrides};
}
def.providers.forEach(node => {
const override = providerOverrides.get(node.token);
if ((node.flags & NodeFlags.CatProviderNoDirective) && override) {
hasOverrides = true;
hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior;
}
});
return {hasOverrides, hasDeprecatedOverrides};
}

function applyProviderOverrides(def: NgModuleDefinition) {
for (let i = 0; i < def.providers.length; i++) {
const provider = def.providers[i];
// Make all providers lazy, so that we don't get into trouble
// with ordering problems of providers on the same element
provider.flags |= NodeFlags.LazyProvider;
if (hasDeprecatedOverrides) {
// We had a bug where me made
// all providers lazy. Keep this logic behind a flag
// for migrating existing users.
provider.flags |= NodeFlags.LazyProvider;
}
const override = providerOverrides.get(provider.token);
if (override) {
provider.flags = (provider.flags & ~NodeFlags.CatProviderNoDirective) | override.flags;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/view/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ export interface ProviderOverride {
flags: NodeFlags;
value: any;
deps: ([DepFlags, any]|any)[];
deprecatedBehavior: boolean;
}

export interface Services {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/testing/src/test_bed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ export class TestBed implements Injector {
}
return [depFlags, depToken];
});
overrideProvider({token, flags, deps, value});
overrideProvider({token, flags, deps, value, deprecatedBehavior: deprecated});
}

createComponent<T>(component: Type<T>): ComponentFixture<T> {
Expand Down
40 changes: 40 additions & 0 deletions packages/platform-browser/test/testing_public_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,46 @@ export function main() {
expect(modFactory.create(getTestBed()).injector.get('a')).toBe('mockA: parentDepValue');
});

it('should keep imported NgModules eager', () => {
let someModule: SomeModule|undefined;

@NgModule()
class SomeModule {
constructor() { someModule = this; }
}

TestBed.configureTestingModule({
providers: [
{provide: 'a', useValue: 'aValue'},
],
imports: [SomeModule]
});
TestBed.overrideProvider('a', {useValue: 'mockValue'});

expect(TestBed.get('a')).toBe('mockValue');
expect(someModule).toBeAnInstanceOf(SomeModule);
});

it('should keep imported NgModules lazy with deprecatedOverrideProvider', () => {
let someModule: SomeModule|undefined;

@NgModule()
class SomeModule {
constructor() { someModule = this; }
}

TestBed.configureTestingModule({
providers: [
{provide: 'a', useValue: 'aValue'},
],
imports: [SomeModule]
});
TestBed.deprecatedOverrideProvider('a', {useValue: 'mockValue'});

expect(TestBed.get('a')).toBe('mockValue');
expect(someModule).toBeUndefined();
});

describe('injecting eager providers into an eager overwritten provider', () => {
@NgModule({
providers: [
Expand Down