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: use angular compiler api to transform codes #562

Merged
merged 6 commits into from
Dec 12, 2020
Merged
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
44 changes: 19 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ module.exports = {

- or to your root `package.json`

```json
```json5
{
"jest": {
"preset": "jest-preset-angular",
Expand Down Expand Up @@ -115,21 +115,22 @@ By Angular CLI defaults you'll have a `src/test.ts` file which will be picked up
## Exposed [configuration](https://github.com/thymikee/jest-preset-angular/blob/master/jest-preset.js)

```js
const customTransformers = require('./build/transformers');
const snapshotSerializers = require('./build/serializers');

module.exports = {
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.html$',
astTransformers: {
before: [
'jest-preset-angular/build/InlineFilesTransformer',
'jest-preset-angular/build/StripStylesTransformer',
],
before: customTransformers,
},
},
},
testEnvironment: 'jsdom',
transform: {
'^.+\\.(ts|js|html)$': 'ts-jest',
'^.+\\.(ts|js|html)$': 'jest-preset-angular',
},
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
moduleNameMapper: {
Expand All @@ -139,11 +140,7 @@ module.exports = {
'^environments/(.*)$': '<rootDir>/src/environments/$1',
},
transformIgnorePatterns: ['node_modules/(?!@ngrx)'],
snapshotSerializers: [
'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js',
'jest-preset-angular/build/AngularSnapshotSerializer.js',
'jest-preset-angular/build/HTMLCommentSerializer.js',
],
snapshotSerializers,
};
```

Expand Down Expand Up @@ -293,7 +290,6 @@ describe('Component snapshots', () => {
const configure: ConfigureFn = testBed => {
testBed.configureTestingModule({
declarations: [FooComponent],
imports: [...],
schemas: [NO_ERRORS_SCHEMA],
});
};
Expand Down Expand Up @@ -388,7 +384,7 @@ import MyStuff from 'src/testing/my.stuff';

However, if your directory structure differ from that provided by `angular-cli` you can adjust `moduleNameMapper` in Jest config:

```json
```json5
{
"jest": {
"moduleNameMapper": {
Expand All @@ -403,7 +399,7 @@ However, if your directory structure differ from that provided by `angular-cli`

Override `globals` object in Jest config:

```json
```json5
{
"jest": {
"globals": {
Expand Down Expand Up @@ -462,7 +458,7 @@ A default `tsconfig.spec.json` after modifying will look like this

#### Adjust your `transformIgnorePatterns` whitelist:

```json
```json5
{
"jest": {
"transformIgnorePatterns": [
Expand All @@ -472,11 +468,11 @@ A default `tsconfig.spec.json` after modifying will look like this
}
```

By default Jest doesn't transform `node_modules`, because they should be valid JavaScript files. However, it happens that library authors assume that you'll compile their sources. So you have to tell this to Jest explicitly. Above snippet means that `@ngrx`, `angular2-ui-switch` and `ng-dynamic` will be transformed, even though they're `node_modules`.
By default, Jest doesn't transform `node_modules`, because they should be valid JavaScript files. However, it happens that library authors assume that you'll compile their sources. So you have to tell this to Jest explicitly. Above snippet means that `@ngrx`, `angular2-ui-switch` and `ng-dynamic` will be transformed, even though they're `node_modules`.

#### Allow JS files in your TS `compilerOptions`

```json
```json5
{
"compilerOptions": {
"allowJs": true
Expand All @@ -493,6 +489,7 @@ Some vendors publish their sources without transpiling. You need to say jest to
1. Install dependencies required by the official Jest documentation for [Babel integration](https://jest-bot.github.io/jest/docs/babel.html).

2. Install `@babel/preset-env` and add `babel.config.js` (or modify existing if needed) with the following content:

```js
module.exports = function(api) {
api.cache(true);
Expand All @@ -505,21 +502,18 @@ module.exports = function(api) {
plugins,
};
};

```

*Note: do not use a `.babelrc` file otherwise the packages that you specify in the next step will not be picked up. CF [Babel documentation](https://babeljs.io/docs/en/configuration#what-s-your-use-case) and the comment `You want to compile node_modules? babel.config.js is for you!`*.

3. Update Jest configuration (by default TypeScript process untranspiled JS files which is source of the problem):

```js
{
"jest": {
"transform": {
"^.+\\.(ts|html)$": "ts-jest",
"^.+\\.js$": "babel-jest"
},
}
module.exports = {
transform: {
"^.+\\.(ts|html)$": "ts-jest",
"^.+\\.js$": "babel-jest"
},
}
```

Expand Down
36 changes: 36 additions & 0 deletions e2e/test-app-v10/projects/my-lib/src/lib/disableable.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Directive, ElementRef, Input } from '@angular/core';

/**
* A base class for components that can be disabled, and that store their disabled
* state in the HTML element. This prevents the HTML element from being focused or clicked,
* and can be used for CSS selectors.
*/
@Directive()
export abstract class DisableableDirective {

/** Binds to the HTML disabled property OR disabled attribute, if present. */
@Input()
public set disabled(v: boolean) {
const elt = this.elementRef.nativeElement;
const disabledProp = (elt as any).disabled;
if (typeof (disabledProp) === 'boolean') {
// Set disabled property
(elt as any).disabled = v;
return;
}

// Set disabled attribute
elt.setAttribute('disabled', v.toString());
}
public get disabled(): boolean {
const elt = this.elementRef.nativeElement;
const disabledProp = (elt as any).disabled;
if (typeof (disabledProp) === 'boolean') {
return disabledProp;
}
const disabledAttr = elt.getAttribute('disabled');
return disabledAttr === 'true';
}

constructor(public elementRef: ElementRef<HTMLElement>) { }
}
15 changes: 12 additions & 3 deletions e2e/test-app-v10/projects/my-lib/src/lib/my-lib.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Component, ElementRef, OnInit } from '@angular/core';

import { DisableableDirective } from './disableable.directive';

@Component({
selector: 'lib-my-lib',
Expand All @@ -10,11 +12,18 @@ import { Component, OnInit } from '@angular/core';
styles: [
]
})
export class MyLibComponent implements OnInit {
export class MyLibComponent extends DisableableDirective implements OnInit {

constructor() { }
constructor(public elementRef: ElementRef) {
super(elementRef);
}

ngOnInit(): void {
}

toggle(): void {
if (!super.disabled) {
console.log('test');
}
}
}
21 changes: 21 additions & 0 deletions e2e/test-app-v10/src/app/forward-ref/forward-ref.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { forwardRef, Inject, Injector } from '@angular/core';

class Door {
lock: Lock;

// Door attempts to inject Lock, despite it not being defined yet.
// forwardRef makes this possible.
constructor(@Inject(forwardRef(() => Lock)) lock: Lock) {
this.lock = lock;
}
}

// Only at this point Lock is defined.
class Lock {}

test('should work', () => {
const injector = Injector.create({providers: [{provide: Lock, deps: []}, {provide: Door, deps: [Lock]}]});

expect(injector.get(Door) instanceof Door).toBe(true);
expect(injector.get(Door).lock instanceof Lock).toBe(true);
});
1 change: 1 addition & 0 deletions e2e/test-app-v9/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@angular/platform-browser": "~9.1.12",
"@angular/platform-browser-dynamic": "~9.1.12",
"@angular/router": "~9.1.12",
"ng2-google-charts": "^6.1.0",
"rxjs": "^6.6.3",
"tslib": "^1.14.1",
"zone.js": "~0.10.3"
Expand Down
4 changes: 4 additions & 0 deletions e2e/test-app-v9/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ import { SimpleWithStylesComponent } from './simple-with-styles/simple-with-styl
import { ChildComponent } from './medium/child.component';
import { MediumComponent } from './medium/medium.component';
import { NgReflectAsTextComponent } from './ng-reflect-as-text/ng-reflect-as-text.component';
import { GeoChartComponent } from './ngc-compiled-lib/ngc-compiled-lib.component';
import { Ng2GoogleChartsModule } from 'ng2-google-charts';

@NgModule({
declarations: [
AppComponent,
CalcComponent,
GeoChartComponent,
SimpleComponent,
OnPushComponent,
HeroesComponent,
Expand All @@ -30,6 +33,7 @@ import { NgReflectAsTextComponent } from './ng-reflect-as-text/ng-reflect-as-tex
BrowserAnimationsModule,
FormsModule,
HttpClientModule,
Ng2GoogleChartsModule,
],
providers: [],
bootstrap: [AppComponent]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CommonModule } from '@angular/common';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Ng2GoogleChartsModule } from 'ng2-google-charts';
import { GeoChartComponent } from './ngc-compiled-lib.component';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

describe('GeoChartComponent', () => {
let component: GeoChartComponent;
let fixture: ComponentFixture<GeoChartComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CommonModule,
Ng2GoogleChartsModule,
],
providers: [],
declarations: [ GeoChartComponent ],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(GeoChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { GoogleChartInterface } from 'ng2-google-charts';
import { BehaviorSubject } from 'rxjs';

@Component({
// tslint:disable-next-line:component-selector
selector: 'influo-geo-chart',
template: `
<google-chart
*ngIf="googleChartConfig$ | async as googleChartConfig; else loader"
[data]="googleChartConfig">
</google-chart>
<ng-template #loader>
<mat-spinner color="accent" diameter="80" strokeWidth="8"></mat-spinner>
</ng-template>
`,
})
export class GeoChartComponent implements OnInit, OnChanges {
@Input() columns: any;
@Input() config: GoogleChartInterface;
@Input() data: Array<Array<string | number>>;

private defaultConfig: GoogleChartInterface = {
chartType: 'GeoChart',
dataTable: [],
options: {
legend: false,
region: 155,
enableRegionInteractivity: true,
displayMode: 'region',
colors: [ '#e6e6e6', '#1672AD' ],
datalessRegionColor: '#e6e6e6',
},
};

constructor() {
}

_googleChartConfig = new BehaviorSubject<GoogleChartInterface | null>(null);

set googleChartConfig(config: GoogleChartInterface) {
const value = this._googleChartConfig.getValue() || {};

this._googleChartConfig.next(Object.assign({}, value, config));
}

get googleChartConfig$() {
return this._googleChartConfig.asObservable();
}

ngOnInit() {
}

ngOnChanges(changes: SimpleChanges): void {
if (this.columns && this.data) {
this.googleChartConfig = Object.assign({}, this.defaultConfig, this.config, {
dataTable: [
this.columns,
...this.data,
],
});
}
}
}
7 changes: 7 additions & 0 deletions e2e/test-app-v9/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6079,6 +6079,13 @@ neo-async@^2.5.0, neo-async@^2.6.1:
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==

ng2-google-charts@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/ng2-google-charts/-/ng2-google-charts-6.1.0.tgz#50a28d358d0e9cc5733f500f0ee325f67a213eda"
integrity sha512-nbxG4QdXVM8/ZsbMeMuETHYDQ8JfGDcNYBw8GjeAyZTykVjQykrjUgY+KRGIquhLJIoGMY7myCjlR4YZeKBNcQ==
dependencies:
tslib "^1.9.0"

nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
Expand Down
2 changes: 1 addition & 1 deletion jest-preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = {
},
testEnvironment: 'jsdom',
transform: {
'^.+\\.(ts|js|html)$': 'ts-jest',
'^.+\\.(ts|js|html)$': 'jest-preset-angular',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wow this is it! Haha, will have to get used to it!

},
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
moduleNameMapper: {
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
"husky": "4.x",
"jest": "26.x",
"lint-staged": "latest",
"lodash.memoize": "4.x",
"prettier": "2.x",
"rxjs": "6.x",
"typescript": "3.x",
Expand Down
Loading