Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

entryComponents with Angular 9 (Ivy) #353

Closed
timdeschryver opened this issue Feb 29, 2020 · 10 comments · Fixed by #562
Closed

entryComponents with Angular 9 (Ivy) #353

timdeschryver opened this issue Feb 29, 2020 · 10 comments · Fixed by #562
Labels
ivy Ivy compatible

Comments

@timdeschryver
Copy link

With Angular 9 (Ivy), we no longer have to provide entryComponents.
This seems to fail if we're using Jest as our test runner.
The same test does pass with Jasmine/Karma.

If we run it with Jest, we're getting the following error

No component factory found for DynamicButtonComponent. Did you add it to @NgModule.entryComponents?

      at noComponentFactoryError (../packages/core/src/linker/component_factory_resolver.ts:17:17)
      at CodegenComponentFactoryResolver.Object.<anonymous>.CodegenComponentFactoryResolver.resolveComponentFactory (../packages/core/src/linker/component_factory_resolver.ts:72:13)
      at NgComponentOutlet.Object.<anonymous>.NgComponentOutlet.ngOnChanges (../packages/common/src/directives/ng_component_outlet.ts:105:36)
      at checkAndUpdateDirectiveInline (../packages/core/src/view/provider.ts:207:15)
      at checkAndUpdateNodeInline (../packages/core/src/view/view.ts:429:14)
      at checkAndUpdateNode (../packages/core/src/view/view.ts:389:12)
      at debugCheckAndUpdateNode (../packages/core/src/view/services.ts:430:44)
      at debugCheckDirectivesFn (../packages/core/src/view/services.ts:391:7)
      at Object.eval [as updateDirectives] (ng:/DynamicHostModule/DynamicHostComponent.ngfactory.js:14:9)
      at Object.debugUpdateDirectives [as updateDirectives] (../packages/core/src/view/services.ts:385:19)
      at checkAndUpdateView (../packages/core/src/view/view.ts:359:12)
      at callViewAction (../packages/core/src/view/view.ts:615:11)
      at execComponentViewsAction (../packages/core/src/view/view.ts:559:7)
      at checkAndUpdateView (../packages/core/src/view/view.ts:370:3)
      at callWithDebugContext (../packages/core/src/view/services.ts:629:23)
      at Object.debugCheckAndUpdateView [as checkAndUpdateView] (../packages/core/src/view/services.ts:346:10)
      at ViewRef_.Object.<anonymous>.ViewRef_.detectChanges (../packages/core/src/view/refs.ts:260:16)
      at ComponentFixture.Object.<anonymous>.ComponentFixture._tick (../../packages/core/testing/src/component_fixture.ts:107:28)
      at ../../packages/core/testing/src/component_fixture.ts:120:36
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:396:30)
      at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:117:43)
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:395:36)
      at Object.onInvoke (../packages/core/src/zone/ng_zone.ts:302:25)
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:395:36)
      at Zone.run (node_modules/zone.js/dist/zone.js:153:47)
      at NgZone.Object.<anonymous>.NgZone.run (../packages/core/src/zone/ng_zone.ts:178:50)
      at ComponentFixture.Object.<anonymous>.ComponentFixture.detectChanges (../../packages/core/testing/src/component_fixture.ts:120:19)
      at src/app/dynamic-host.component.spec.ts:15:13
      at node_modules/tslib/tslib.js:113:75
      at new ZoneAwarePromise (node_modules/zone.js/dist/zone.js:915:33)
      at Object.__awaiter (node_modules/tslib/tslib.js:109:16)
      at src/app/dynamic-host.component.spec.ts:13:49
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:396:30)
      at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/proxy.js:117:43)
      at ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:395:36)
      at Zone.run (node_modules/zone.js/dist/zone.js:153:47)

See https://github.com/timdeschryver/jest-dynamic-ng-repro for a reproduction.

@wtho
Copy link
Collaborator

wtho commented Feb 29, 2020

Ok, so this is related to ngComponentOutlet and dynamic components.

I think Ivy and its ASTTransformers are doing more under the hood to gather the metadata for entry components.
So we basically have two options:

  1. we wait for ts-jest to provide a better compiling runtime with ts-program capabilities so we can use the angular transformers
  2. we dig in the Angular compiler source code, understand what's happening and write our own transformer. Findings and PRs welcome!

Until then, I guess you have to declare it in .spec files as entryComponents (should work - not tested).

@ahnpnl
Copy link
Collaborator

ahnpnl commented Feb 29, 2020

FYI, according to ts-jest source code it only takes into account of transformers which are manually defined by users (via ts-jest config). It doesn’t know anything about angular.

I wonder if providing angular transformers to ts-jest can solve the issue (point 1)

I agree that we need to know what ivy does to find out a proper way. (point 2)

@LayZeeDK
Copy link

LayZeeDK commented Mar 1, 2020

Can you verify whether getTestBed (called in setupJest.ts) returns an instance of TestBedViewEngine or TestBedRender3?

@timdeschryver
Copy link
Author

It was using the TestBedViewEngine , after manually transforming the code, the test passes.
While this is a solution, it isn't optimal.
It means that after every change made to the component, we will have to run this command (which isn't fast enough to do on a regular basis imho), and that we can't use the jest watch command.

"pretest": "ngcc --properties main"

See angular/angular-cli#17110 (comment)

@ahnpnl ahnpnl added the ivy Ivy compatible label Mar 1, 2020
@ahnpnl
Copy link
Collaborator

ahnpnl commented Mar 1, 2020

related to the discussion in #347, see explanation

@LayZeeDK
Copy link

LayZeeDK commented Mar 1, 2020

It should only be necessary to run ngcc after npm install/yarn install which it already does when using ng update.

@timdeschryver
Copy link
Author

I don't know what I did wrong on Sunday, but after running ngcc --properties main it does work.
Even when the are component's modified.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Mar 3, 2020

Ngcc should only modify internal angular codes I think, so run once should be enough to be compatible with Ivy and it’s unrelated to the project’s code base.

@LayZeeDK
Copy link

LayZeeDK commented Mar 4, 2020

ngcc runs on all libraries. Our app, Angular, 3rd party dependencies. Every time a package update/addition happens, it will need to be rerun (and with the right parameters for Jest).

@mousedownmike
Copy link
Contributor

mousedownmike commented May 28, 2020

I can confirm that I was able to override entryComponents as suggested by @wtho. For context, the error I was getting was:

Error: No component factory found for VerifyLedgerComponent. Did you add it to @NgModule.entryComponents?

I added VerifyLedgerComponent to declarations and then used overrideModule to put it in the entryComponents. Here's what worked for me:

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [LedgerComponent, VerifyLedgerComponent],
      imports: [LedgerCoreModule, MatDialogModule, NoopAnimationsModule],
      schemas: [NO_ERRORS_SCHEMA]
    })
      .overrideModule(BrowserDynamicTestingModule, {
        set:
          {entryComponents: [VerifyLedgerComponent]}
      })
      .compileComponents();
  }));

@wtho wtho mentioned this issue Jul 9, 2020
@ahnpnl ahnpnl mentioned this issue Oct 8, 2020
ahnpnl added a commit that referenced this issue Dec 12, 2020
Closes #108
Closes #288
Closes #322
Closes #353
Closes #622

BREAKING CHANGE:
With the new jest transformer, `jest-preset-angular` now switches to default to use this new transformer and no longer uses `ts-jest` to transform codes.

Users who are currently doing in jest config
```
// jest.config.js
module.exports = {
    // [...]
    transform: {
      '^.+\\.(ts|js|html)$': 'ts-jest',
    },
}
```

should change to
```
// jest.config.js
module.exports = {
    // [...]
    transform: {
      '^.+\\.(ts|js|html)$': 'jest-preset-angular',
    },
}
```

`isolatedModule: true` will still use `ts-jest` to compile `ts` to `js` but you won't get full compatibility with Ivy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ivy Ivy compatible
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants