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

feat: angular ctor params transformer #406

Closed
wants to merge 1 commit into from

Conversation

wtho
Copy link
Collaborator

@wtho wtho commented Jul 7, 2020

Introduces the usage of the @ngtools/webpack ctor-params transformer to
downlevel angular decorators to static properties

This also is the first usage of an Angular transformer in our setup. By using the compilation tools provided by the Angular Team to compile the code, we ensure the tests treat the code like production code. Furthermore this facilitates keeping up with the Angular Team.

Checklist

  • Transformer using Angular's ctor-params
  • documentation in README.md regarding isolatedModules: true
  • update CHANGELOG.md
  • Test for the transformer

Closes #288.

Further Discussion

While we are finally able to include Angular transformers, and in this case to circumvent the issue with emitting more metadata than Angular itself, we are still behind Angular Ivy compilation in jest + angular. This could change if we take a better look at the compilation behavior of the AngularCompilerPlugin as well as the used transformers. While partial functionality is definitely not interesting in test scenarios, other features are necessary. There might also be more compiling functionality in @angular/compiler-cli. More research has to be done in this field.

Note for Compatibility with Angular v10

In Angular v10 the ctor-parameters.js disappeared (in this commit). The reference in the AngularConstructorParameters has to be updated to be compatible with Angular v10 (and therefore incompatible with Angular v9). The current transformer handles both scenarios by trying to load ctor-parameters first and then falling back to the newer compiler-cli transformer.

@wtho wtho requested a review from ahnpnl July 7, 2020 22:23
wtho added a commit to wtho/jest-preset-angular that referenced this pull request Jul 7, 2020
this introduces the usage of the @ngtools/webpack ctor-params transformer to
downlevel angular decorators to static properties
@wtho wtho force-pushed the feat/angular-transformer branch from dca54f8 to e157b78 Compare July 7, 2020 22:27
src/AngularConstructorParametersTransformer.ts Outdated Show resolved Hide resolved
src/TransformUtils.ts Outdated Show resolved Hide resolved
@@ -5,6 +5,11 @@ import * as TS from 'typescript';
// inside the ConfigSet right
export interface ConfigSet {
compilerModule: typeof TS;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the const ts = configSet.compilerModule above is redundant and can be removed, this compilerModule can be removed too. In the latest version of ts-jest, this property is no longer exposed as public typings.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean by this that configSet.compilerModule equals configSet.tsCompiler?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually those return 2 different things, compilerModule returns the current typescript package of the project while tsCompiler returns the compiler instance created internally in ts-jest.

But in AngularConstructorParametersTransformers.ts, compilerModule isn't used anywhere so I think this property compilerModule can be removed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the other transformers we still need functionality like configSet.compilerModule.getMutableClone(node), which was usually injected by the compilerModule, being an instance of typescript.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so I think ts-jest should expose that one again in public typings 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this would be great: compilerModule: typeof TypeScript where import * as TypeScript from 'typescript'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will be like this

export declare class ConfigSet {
    readonly parentOptions?: TsJestGlobalOptions | undefined;
    get versions(): Record<string, string>;
    get compilerModule(): TTypeScript;
    get tsCompiler(): TsCompiler;
    get tsJestDigest(): string;
    readonly logger: Logger;
    constructor(jestConfig: Config.ProjectConfig, parentOptions?: TsJestGlobalOptions | undefined, parentLogger?: Logger);
}

where TTypeScript is

import * as _ts from 'typescript';
export declare type TTypeScript = typeof _ts;

It was public before but then marked as internal 😃

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you assume, that only ts-jest authors transformers, it is correctly marked as internal 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I will extend the type with the compilerModule inline. Let me know when there's a new version out with the public typings!

Copy link
Collaborator

@ahnpnl ahnpnl Jul 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, ts-jest 26.1.2 released. It includes the exposed typing for compileModule.

src/InlineFilesTransformer.ts Outdated Show resolved Hide resolved
src/StripStylesTransformer.ts Outdated Show resolved Hide resolved
example/jest.config.js Show resolved Hide resolved
src/AngularConstructorParametersTransformerv10.ts Outdated Show resolved Hide resolved
src/AngularConstructorParametersTransformerv10.ts Outdated Show resolved Hide resolved
src/AngularConstructorParametersTransformerv8v9.ts Outdated Show resolved Hide resolved
src/AngularConstructorParametersTransformerv8v9.ts Outdated Show resolved Hide resolved
Copy link
Collaborator

@ahnpnl ahnpnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beautiful !

@wtho
Copy link
Collaborator Author

wtho commented Jul 8, 2020

I tried to setup a test, but this requires fiddling a lot with module mocks, specifically to handle the different scenarios of require(@ngtools/webpack/...) and require(@angular/compiler-cli/...) which is not easy, as the test still tries to load the package, even if jest.mock('@ngtools/webpack/...', () => ...) is called. I would need more help with this if you think this is required.

The transformer passes with Angular v9 and v10 projects, so it is sufficient in my opinion.

Introduces the usage of the @ngtools/webpack ctor-params transformer to
downlevel angular decorators to static properties

This makes `emitDecoratorMetadata: true` in `tsconfig.spec.json`
redundant, but is not compatible with `isolatedModules: true`.
@wtho wtho force-pushed the feat/angular-transformer branch from 80cdd4d to 0b5c315 Compare July 8, 2020 11:39
@wtho
Copy link
Collaborator Author

wtho commented Jul 8, 2020

It's ready to merge. Would you like to have a quick look, @thymikee?

@wtho wtho requested a review from thymikee July 8, 2020 11:42
@ahnpnl
Copy link
Collaborator

ahnpnl commented Jul 8, 2020

Ya I think the unit tests can be added later.

I ran into similar thing when trying to mock typescript. Ended up I used this way https://github.com/ahnpnl/ts-jest/blob/ec15732c29c6cc2767ef10029f417b50990a6b26/src/compiler/language-service.spec.ts#L114

@ahnpnl
Copy link
Collaborator

ahnpnl commented Jul 10, 2020

what do you think about in the meantime, we can have 1 example app is ng 9, 1 example app is ng 10 to run the tests for this change ?

@wtho
Copy link
Collaborator Author

wtho commented Jul 10, 2020

I think that's a good workaround.

But instead of introducing e. g. /example9/ and /example10/, I would prefer to setup a conventional monorepo (and also rename example to test-app, as there was often confusion, that example is the default example of this library):

github.com/thymikee/jest-preset-angular
├──jest-preset-angular
├──test-app-v9
└──test-app-v10

Or in lerna-fashion:

github.com/thymikee/jest-preset-angular
└──packages
    ├──jest-preset-angular
    ├──test-app-v9
    └──test-app-v10

What do you think? I'd tackle this in a different PR, and this one would be rebased on top of it.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Jul 10, 2020

I like the version like lerna but since the preset is only on its own but not exposing anything so I think it should be like this

github.com/thymikee/jest-preset-angular
└──packages
   ├──jest-preset-angular

while we treat test apps as e2e tests which should be in e2e folder

ya it's wise to do in another PR

@wtho
Copy link
Collaborator Author

wtho commented Jul 10, 2020

Ok, so in this case I would prefer the setup

github.com/thymikee/jest-preset-angular
├──jest-preset-angular
└──e2e
    ├──test-app-v9
    └──test-app-v10

just to avoid unnecessary folder nesting. The container-folder packages could be added at any later time, if required one day.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Jul 11, 2020

ok let's proceed like that

/**
* The factory of hoisting transformer factory
* @internal
*/
export function factory(cs: ConfigSet) {
export function factory(cs: ConfigSet & { compilerModule: TTypeScript }) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This factory type isn’t the same as the one in AngularConstructorParametersTransformer.ts. Is it intended ?

/**
* The factory of hoisting transformer factory
* @internal
*/
export function factory(cs: ConfigSet) {
export function factory(cs: ConfigSet & { compilerModule: TTypeScript }) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This factory type isn’t the same as the one in AngularConstructorParametersTransformer.ts. Is it intended ?

@ahnpnl
Copy link
Collaborator

ahnpnl commented Aug 14, 2020

we might need to postpone this, see my comment #409 (comment)

@ahnpnl
Copy link
Collaborator

ahnpnl commented Aug 21, 2020

@wtho do you want to include this in 8.3.0 release ? In the meanwhile we are still figuring how to use Angular Compiler API, maybe this can be a quick win ?

@wtho
Copy link
Collaborator Author

wtho commented Aug 21, 2020

No, I prefer to not merge it, as there is an easy workaround and we would have to remove everything added in this PR again.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Aug 21, 2020

ok 👍

@ahnpnl
Copy link
Collaborator

ahnpnl commented Oct 27, 2020

is taken care in #562

@ahnpnl ahnpnl closed this Oct 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

After upgrade Angular to v8: Can't resolve all parameters for Component: (?).
2 participants