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

Implement astTransformer - Compatibility with ts-jest 23.10 #204

Merged
merged 6 commits into from
Dec 4, 2018
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
InlineHtmlStripStylesTransformer.js
thymikee marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/example
/__tests__
/src
circle.yml
1 change: 0 additions & 1 deletion AngularSnapshotSerializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const printAttributes = (val, attributes, print, indent, colors, opts) => {
};

const print = (val, print, indent, opts, colors) => {
let result = '';
let componentAttrs = '';

const componentName = val.componentRef._elDef.element.name;
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Changelog (master)

### v7.0.0

* Feature: Support ts-jest ^23.10.4 ([#204](https://github.com/thymikee/jest-preset-angular/pull/204))

### v6.0.1

* Fix: Support backtick quoted templateUrl. ([#182](https://github.com/thymikee/jest-preset-angular/pull/182))
Expand Down
46 changes: 27 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ yarn add -D jest jest-preset-angular
This will install `jest`, `@types/jest`, `ts-jest`, `jest-zone-patch` as dependencies needed to run with Angular projects.

## Usage

In `src` directory create `setupJest.ts` file with following contents:
```js

```ts
import 'jest-preset-angular';
import './jestGlobalMocks'; // browser mocks globally available for every test
```

*Note: feel free to copy the `jestGlobalMocks.ts` file from the example directory and save it next to the `setupJest.ts` file.*

...and include this in your `package.json`:

```json
{
"jest": {
Expand All @@ -40,29 +43,30 @@ import './jestGlobalMocks'; // browser mocks globally available for every test
{
"globals": {
"ts-jest": {
"tsConfigFile": "src/tsconfig.spec.json"
},
"__TRANSFORM_HTML__": true
"tsConfig": "<rootDir>/src/tsconfig.spec.json",
"stringifyContentPathRegex": "\\.html$"
}
},
"transform": {
"^.+\\.(ts|js|html)$": "<rootDir>/node_modules/jest-preset-angular/preprocessor.js"
"^.+\\.(ts|js|html)$": "ts-jest"
},
"testMatch": [
"**/__tests__/**/*.+(ts|js)?(x)",
"**/+(*.)+(spec|test).+(ts|js)?(x)"
],
"moduleFileExtensions": [
"ts",
"js",
"html"
"**/?(*.)+(spec|test).+(ts|js)?(x)"
],
"moduleFileExtensions": ["js", "json", "jsx", "node", "ts", "tsx", "html"],
"moduleNameMapper": {
"app/(.*)": "<rootDir>/src/app/$1",
"assets/(.*)": "<rootDir>/src/assets/$1",
"environments/(.*)": "<rootDir>/src/environments/$1"
"^src/(.*)$": "<rootDir>/src/$1",
"^app/(.*)$": "<rootDir>/src/app/$1",
"^assets/(.*)$": "<rootDir>/src/assets/$1",
"^environments/(.*)$": "<rootDir>/src/environments/$1"
},
"transformIgnorePatterns": [
"node_modules/(?!@ngrx)"
],
"snapshotSerializers": [
"jest-preset-angular/AngularSnapshotSerializer.js",
"jest-preset-angular/HTMLCommentSerializer.js"
]
}
```
Expand Down Expand Up @@ -93,7 +97,7 @@ If you look at your `src/test.ts` (or similar bootstrapping test file) file you'
Example:

`calc-component.spec.ts`
```js
```ts
// some initialization code
test('renders markup to snapshot', () => {
const fixture = TestBed.createComponent(AppComponent);
Expand All @@ -120,7 +124,7 @@ exports[`CalcComponent should snap 1`] = `
`;
```

### Removing empty lines and white-spaces in component snaphots
### Removing empty lines and white-spaces in component snapshots

You will immediately notice, that your snapshot files contain a lot of white spaces and blank lines. This is not an issue with Jest, rather with Angular. It can be mitigated via Angular compiler by setting `preserveWhitespaces: false`

Expand Down Expand Up @@ -213,7 +217,7 @@ describe('Component snapshots', () => {

## Troubleshooting

Problems may arise if you're using custom builds (this preset is tailored for `angular-cli` as firsty priority). Please be adivsed that every entry in default configuration may be overriden to best suite your app's needs.
Problems may arise if you're using custom builds (this preset is tailored for `angular-cli` as firstly priority). Please be advised that every entry in default configuration may be overridden to best suite your app's needs.

### @Input() bindings are not reflected into fixture when `ChangeDetectionStrategy.OnPush` is used

Expand Down Expand Up @@ -254,15 +258,19 @@ Reference: https://github.com/angular/material2/issues/7101
### Absolute imports

TypeScript supports absolute imports. The preset (starting from v3.0.0) by default understands absolute imports referring to `src`, `app`, `assets` and `environments` directory, so instead:
```js

```ts
import MyComponent from '../../src/app/my.component';
import MyStuff from '../../src/testing/my.stuff';
```

you can use:
```js

```ts
import MyComponent from 'app/my.component';
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
Expand Down
122 changes: 122 additions & 0 deletions __tests__/InlineHtmlStripStylesTransformer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Code is inspired by
* https://github.com/kulshekhar/ts-jest/blob/25e1c63dd3797793b0f46fa52fdee580b46f66ae/src/transformers/hoist-jest.spec.ts
*
*/

import * as tsc from 'typescript'
import * as transformer from '../InlineHtmlStripStylesTransformer'

const CODE_WITH_TEMPLATE_URL = `
import { Component } from '@angular/core';

@Component({
templateUrl: './page.html'
})
export class AngularComponent {
}
`

const CODE_WITH_NON_RELATIVE_TEMPLATE_URL = `
import { Component } from '@angular/core';

@Component({
templateUrl: 'page.html'
})
export class AngularComponent {
}
`

const CODE_WITH_STYLE_URLS = `
import { Component } from '@angular/core';

@Component({
styleUrls: [
'./fancy-styles.css',
'./basic-styles.scss'
]
})
export class AngularComponent {
}
`

const CODE_WITH_STYLES = `
import { Component } from '@angular/core';

@Component({
styles: [
'body: { display: none }',
'html: { background-color: red }'
]
})
export class AngularComponent {
}
`

const CODE_WITH_ALL_DECORATOR_PROPERTIES = `
import { Component } from '@angular/core';

@SomeDecorator({
value: 'test'
})
@Component({
templateUrl: './page.html',
styleUrls: [
'./fancy-styles.css',
'./basic-styles.scss'
],
styles: [
'body: { display: none }',
'html: { background-color: red }'
],
unaffectedProperty: 'whatever'
})
@SomeOtherDecorator({
prop: 'ok'
})
export class AngularComponent {
}
`
const createFactory = () => {
return transformer.factory({ compilerModule: tsc } as any)
}
const transpile = (source: string) => tsc.transpileModule(source, { transformers: { before: [createFactory()] } })

describe('inlining template and stripping styles', () => {
it('should have correct signature', () => {
expect(transformer.name).toBe('angular-component-inline-template-strip-styles')
expect(typeof transformer.version).toBe('number')
expect(transformer.version).toBeGreaterThan(0)
expect(typeof transformer.factory).toBe('function')
})

it('should strip styleUrl assignment', () => {
const out = transpile(CODE_WITH_STYLE_URLS)

expect(out.outputText).toMatchSnapshot()
})

it('should strip styles assignment', () => {
const out = transpile(CODE_WITH_STYLES)

expect(out.outputText).toMatchSnapshot()
})

it('should inline templateUrl assignment', () => {
const out = transpile(CODE_WITH_TEMPLATE_URL)

expect(out.outputText).toMatchSnapshot()
})

it('should inline non-relative templateUrl assignment and make it relative', () => {
const out = transpile(CODE_WITH_NON_RELATIVE_TEMPLATE_URL)

expect(out.outputText).toMatchSnapshot()
})

it('should handle all transformable decorator assignments', () => {
const out = transpile(CODE_WITH_ALL_DECORATOR_PROPERTIES)

expect(out.outputText).toMatchSnapshot()
})
})
130 changes: 130 additions & 0 deletions __tests__/__snapshots__/InlineHtmlStripStylesTransformer.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`inlining template and stripping styles should handle all transformable decorator assignments 1`] = `
"\\"use strict\\";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === \\"object\\" && typeof Reflect.decorate === \\"function\\") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, \\"__esModule\\", { value: true });
var core_1 = require(\\"@angular/core\\");
var AngularComponent = /** @class */ (function () {
function AngularComponent() {
}
AngularComponent = __decorate([
SomeDecorator({
value: 'test'
}),
core_1.Component({
template: require('./page.html'),
styleUrls: [],
styles: [],
unaffectedProperty: 'whatever'
}),
SomeOtherDecorator({
prop: 'ok'
})
], AngularComponent);
return AngularComponent;
}());
exports.AngularComponent = AngularComponent;
"
`;

exports[`inlining template and stripping styles should inline non-relative templateUrl assignment and make it relative 1`] = `
"\\"use strict\\";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === \\"object\\" && typeof Reflect.decorate === \\"function\\") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, \\"__esModule\\", { value: true });
var core_1 = require(\\"@angular/core\\");
var AngularComponent = /** @class */ (function () {
function AngularComponent() {
}
AngularComponent = __decorate([
core_1.Component({
template: require(\\"./page.html\\")
})
], AngularComponent);
return AngularComponent;
}());
exports.AngularComponent = AngularComponent;
"
`;

exports[`inlining template and stripping styles should inline templateUrl assignment 1`] = `
"\\"use strict\\";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === \\"object\\" && typeof Reflect.decorate === \\"function\\") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, \\"__esModule\\", { value: true });
var core_1 = require(\\"@angular/core\\");
var AngularComponent = /** @class */ (function () {
function AngularComponent() {
}
AngularComponent = __decorate([
core_1.Component({
template: require('./page.html')
})
], AngularComponent);
return AngularComponent;
}());
exports.AngularComponent = AngularComponent;
"
`;

exports[`inlining template and stripping styles should strip styleUrl assignment 1`] = `
"\\"use strict\\";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === \\"object\\" && typeof Reflect.decorate === \\"function\\") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, \\"__esModule\\", { value: true });
var core_1 = require(\\"@angular/core\\");
var AngularComponent = /** @class */ (function () {
function AngularComponent() {
}
AngularComponent = __decorate([
core_1.Component({
styleUrls: []
})
], AngularComponent);
return AngularComponent;
}());
exports.AngularComponent = AngularComponent;
"
`;

exports[`inlining template and stripping styles should strip styles assignment 1`] = `
"\\"use strict\\";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === \\"object\\" && typeof Reflect.decorate === \\"function\\") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, \\"__esModule\\", { value: true });
var core_1 = require(\\"@angular/core\\");
var AngularComponent = /** @class */ (function () {
function AngularComponent() {
}
AngularComponent = __decorate([
core_1.Component({
styles: []
})
], AngularComponent);
return AngularComponent;
}());
exports.AngularComponent = AngularComponent;
"
`;
Loading