Skip to content

Commit f3e5fd9

Browse files
committed
fix(a14): injecting mock components in vcr.createComponent #333
1 parent 79a3785 commit f3e5fd9

File tree

3 files changed

+88
-10
lines changed

3 files changed

+88
-10
lines changed

libs/ng-mocks/src/lib/common/ng-mocks-global-overrides.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import { Component, Directive, NgModule, Pipe } from '@angular/core';
1+
import { Component, Directive, NgModule, Pipe, ViewContainerRef } from '@angular/core';
22
import { getTestBed, MetadataOverride, TestBed, TestBedStatic, TestModuleMetadata } from '@angular/core/testing';
33

44
import funcExtractTokens from '../mock-builder/func.extract-tokens';
55
import getOverrideDef from '../mock-builder/promise/get-override-def';
66
import { ngMocks } from '../mock-helper/mock-helper';
77
import mockHelperFasterInstall from '../mock-helper/mock-helper.faster-install';
88
import { MockProvider } from '../mock-provider/mock-provider';
9+
import helperCreateClone from '../mock-service/helper.create-clone';
910

1011
import coreDefineProperty from './core.define-property';
1112
import { flatten, mapEntries, mapValues } from './core.helpers';
13+
import coreInjector from './core.injector';
1214
import coreReflectMeta from './core.reflect.meta';
1315
import coreReflectModuleResolve from './core.reflect.module-resolve';
1416
import coreReflectProvidedIn from './core.reflect.provided-in';
15-
import { NG_MOCKS_TOUCHES } from './core.tokens';
17+
import { NG_MOCKS, NG_MOCKS_TOUCHES } from './core.tokens';
1618
import { AnyType } from './core.types';
1719
import funcGetProvider from './func.get-provider';
1820
import { isNgDef } from './func.is-ng-def';
@@ -226,10 +228,57 @@ const resetTestingModule =
226228
return original.call(TestBed);
227229
};
228230

231+
const viewContainerInstall = () => {
232+
const vcr: any = ViewContainerRef;
233+
234+
// istanbul ignore else
235+
if (!vcr.ngMocksOverridesInstalled) {
236+
const ngElementId = vcr.__NG_ELEMENT_ID__;
237+
238+
// istanbul ignore else
239+
if (ngElementId) {
240+
coreDefineProperty(
241+
vcr,
242+
'__NG_ELEMENT_ID__',
243+
helperCreateClone(ngElementId, undefined, undefined, (...ngElementIdArgs: any[]) => {
244+
const vcrInstance = ngElementId.apply(ngElementId, ngElementIdArgs);
245+
246+
const createComponent = vcrInstance.createComponent;
247+
coreDefineProperty(
248+
vcrInstance,
249+
'createComponent',
250+
helperCreateClone(
251+
createComponent,
252+
undefined,
253+
undefined,
254+
(component: any, ...createComponentArgs: any[]) => {
255+
const map = coreInjector(NG_MOCKS, vcrInstance.injector);
256+
257+
return createComponent.apply(vcrInstance, [
258+
map?.get(component) ?? component,
259+
...createComponentArgs,
260+
] as any);
261+
},
262+
),
263+
true,
264+
);
265+
266+
return vcrInstance;
267+
}),
268+
true,
269+
);
270+
}
271+
272+
coreDefineProperty(ViewContainerRef, 'ngMocksOverridesInstalled', true);
273+
}
274+
};
275+
229276
const install = () => {
230-
const hooks = mockHelperFasterInstall();
231277
// istanbul ignore else
232278
if (!(TestBed as any).ngMocksOverridesInstalled) {
279+
const hooks = mockHelperFasterInstall();
280+
viewContainerInstall();
281+
233282
// istanbul ignore else
234283
if (hooks.before.indexOf(configureTestingModule) === -1) {
235284
hooks.before.push(configureTestingModule);
@@ -238,6 +287,7 @@ const install = () => {
238287
if (hooks.after.indexOf(resetTestingModule) === -1) {
239288
hooks.after.push(resetTestingModule);
240289
}
290+
241291
coreDefineProperty(TestBed, 'ngMocksOverridesInstalled', true);
242292
}
243293
};

libs/ng-mocks/src/lib/mock-builder/promise/handle-entry-components.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ import helperCreateClone from '../../mock-service/helper.create-clone';
1717
import { NgMeta } from './types';
1818

1919
class EntryComponentsModule {
20-
protected origin: module.ComponentFactoryResolver['resolveComponentFactory'];
20+
protected originCFR: module.ComponentFactoryResolver['resolveComponentFactory'];
2121

2222
public constructor(map: Map<any, any>, protected componentFactoryResolver: module.ComponentFactoryResolver) {
23-
this.origin = componentFactoryResolver.resolveComponentFactory;
23+
this.originCFR = componentFactoryResolver.resolveComponentFactory;
2424
componentFactoryResolver.resolveComponentFactory = helperCreateClone(
25-
this.origin,
25+
this.originCFR,
2626
undefined,
2727
undefined,
28-
(component: any) => this.origin.call(componentFactoryResolver, map.get(component) ?? component) as any,
28+
(component: any, ...args: any[]) =>
29+
this.originCFR.apply(componentFactoryResolver, [map.get(component) ?? component, ...args] as any),
2930
);
3031
}
3132
}
@@ -39,11 +40,11 @@ export default (ngModule: NgMeta): void => {
3940
}
4041
}
4142
// the way to cause entryComponents to do its work
42-
const entryComponent = extendClass(EntryComponentsModule);
43+
const entryModule = extendClass(EntryComponentsModule);
4344
module.NgModule({
4445
// Ivy knows how to make any component an entry point,
4546
// but we still would like to patch resolveComponentFactory in order to provide mocks.
4647
entryComponents: isIvy ? [] : /* istanbul ignore next */ entryComponents,
47-
})(entryComponent);
48-
ngModule.imports.push(entryComponent);
48+
})(entryModule);
49+
ngModule.imports.push(entryModule);
4950
};

tests/issue-333/test.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CommonModule } from '@angular/common';
22
import * as core from '@angular/core';
3+
import { TestBed } from '@angular/core/testing';
34
import { isMockOf, MockBuilder, MockRender, ngMocks } from 'ng-mocks';
45

56
@core.Component({
@@ -36,6 +37,14 @@ class MockComponent {
3637
public flag = true;
3738
}
3839

40+
@core.NgModule({
41+
declarations: [MockComponent, DepComponent],
42+
entryComponents: [MockComponent],
43+
exports: [MockComponent],
44+
imports: [CommonModule],
45+
})
46+
class MockModule {}
47+
3948
// @see https://github.com/ike18t/ng-mocks/issues/333
4049
describe('issue-333', () => {
4150
describe('1:keep', () => {
@@ -127,4 +136,22 @@ describe('issue-333', () => {
127136
);
128137
});
129138
});
139+
140+
// Ensuring that everything has been reset properly
141+
describe('real', () => {
142+
beforeEach(async () =>
143+
TestBed.configureTestingModule({
144+
imports: [MockModule, OverlayModule],
145+
}).compileComponents(),
146+
);
147+
148+
it('renders all components', () => {
149+
const fixture = MockRender(DynamicOverlayComponent);
150+
expect(ngMocks.formatText(fixture)).toEqual(``);
151+
152+
fixture.point.componentInstance.attachComponent(MockComponent);
153+
fixture.detectChanges();
154+
expect(ngMocks.formatText(fixture)).toEqual(`Dependency`);
155+
});
156+
});
130157
});

0 commit comments

Comments
 (0)