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: alternative setup with babel/typescript #317

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
16 changes: 12 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,27 @@ jobs:
at: .
# skipping cache here as it created issues with the preset in the root
# not being used, as older version in cache was available
- run: 'sudo yarn global add greenkeeper-lockfile@2'
- run: 'greenkeeper-lockfile-update'
- run:
name: Greenkeeper - update lockfile
command: |
sudo yarn global add greenkeeper-lockfile@2
greenkeeper-lockfile-update
- run:
name: Install Example Dependencies
command: |
cd example
yarn install --frozen-lockfile
- run:
name: Test Example
name: Test Example - ts-jest preset
command: |
cd example
yarn test:ci
yarn test:ci:ts-jest
yarn test:coverage
- run:
name: Test Example - babel preset
command: |
cd example
yarn test:ci:babel
workflows:
version: 2
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## Changelog (master)

### v8.1.0

#### Features
* Add preset `babel` as transpilation alternative to `ts-jest` ([#317](https://github.com/thymikee/jest-preset-angular/pull/317)).
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
* Add preset `babel` as transpilation alternative to `ts-jest` ([#317](https://github.com/thymikee/jest-preset-angular/pull/317)).
* Expose a new preset `jest-preset-angular/build/babel` for transforming files with Babel instead of `ts-jest` ([#317](https://github.com/thymikee/jest-preset-angular/pull/317)).

Side note: would be nice if we could get rid of build part, just jest-preset-angular/babel – easy enough with re-exporting from top-level.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree. Maybe we can just publish the build folder with the package.json? Have to check out how other projects solve this.


#### Migration Guide
* The preset reference in the jest config has to be updated from `"jest-preset-angular"` to `"jest-preset-angular/build/ts-jest"`. To use babel, replace `ts-jest` with `babel`. Furthermore, when using `ts-jest`, it has to be added as `devDependency` to the project, or `babel` packages alternatively (see README.md).
Copy link
Owner

Choose a reason for hiding this comment

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

This is not relevant now


### v8.0.0

#### Features
Expand Down
47 changes: 45 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ This is a part of the article: [Testing Angular faster with Jest](https://www.xf

_Note: This preset does not suport AngularJS (1.x). If you want to set up Jest with AngularJS, please see [this blog post](https://medium.com/aya-experience/testing-an-angularjs-app-with-jest-3029a613251)._

This package actually contains two presets, one for `ts-jest`, which uses the official TypeScript compiler internally, and one for `babel`, which strips away the type annotations and simply transforms the JavaScript. If you are not sure, try to use `ts-jest`, to also type-check your test files.


## Installation

```bash
Expand All @@ -19,6 +22,19 @@ npm install -D jest jest-preset-angular @types/jest

This will install `jest`, `@types/jest`, `ts-jest` as dependencies needed to run with Angular projects.

Additionally you need `babel` packages if you want to use `babel`.
Copy link
Owner

Choose a reason for hiding this comment

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

Please remove, no need to mention it here

Suggested change
Additionally you need `babel` packages if you want to use `babel`.


### babel
Copy link
Owner

Choose a reason for hiding this comment

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

How about:

Suggested change
### babel
### jest-preset-angular/babel

`babel` uses the babel compiler to generate JavaScript, without type-checking your test files before doing so. This might result in a different test run performance. You can still run type-checking using `tsc --noEmit`. For additional TypeScript-supported language features you might have to install more babel packages. Note that `babel` also can differ slightly from `tsc`, e. g. in compiling a class to a function.
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
`babel` uses the babel compiler to generate JavaScript, without type-checking your test files before doing so. This might result in a different test run performance. You can still run type-checking using `tsc --noEmit`. For additional TypeScript-supported language features you might have to install more babel packages. Note that `babel` also can differ slightly from `tsc`, e. g. in compiling a class to a function.
`babel` preset uses the Babel compiler to generate JavaScript without type-checking your test files before doing so. This might result in a different test run performance. You can still run type-checking using `tsc --noEmit`. For additional TypeScript-supported language features you might have to install more babel packages. Note that `babel` also can differ slightly from `tsc`, e.g. in compiling a class to a function.


To evaluate test performance, try to set [`isolatedModules: true` in the `ts-jest`-config](https://kulshekhar.github.io/ts-jest/user/config/isolatedModules), and compare it with the babel setup. Feedback of the transformer comparison in your project is welcome, see [#336](https://github.com/angular/angular/issues/336).

```bash
yarn add -D @babel/core @babel/preset-typescript @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators babel-plugin-transform-typescript-metadata babel-plugin-const-enum
#or
npm install -D @babel/core @babel/preset-typescript @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators babel-plugin-transform-typescript-metadata babel-plugin-const-enum
```

## Usage

In `src` directory create `setupJest.ts` file with following contents:
Expand All @@ -41,11 +57,36 @@ _Note: feel free to copy the [`jestGlobalMocks.ts`](https://github.com/thymikee/
}
```

or for `babel`:
```json
{
"jest": {
"preset": "jest-preset-angular/build/babel",
"setupFilesAfterEnv": ["<rootDir>/src/setupJest.ts"]
}
}
```

When using babel, also a `babel.config.js` on the project root level is required:
```js
const { babelAngularConfig } = require('jest-preset-angular/build/babel/babel.config')
module.exports = api => {
api.cache(false)
return {
presets: babelAngularConfig.presets,
plugins: [
...babelAngularConfig.plugins,
// additional plugins
]
}
}
```

### Avoid karma conflicts
By Angular CLI defaults you'll have a `src/test.ts` file which will be picked up by jest. To circumvent this you can either rename it to `src/karmaTest.ts` or hide it from jest by adding `<rootDir>/src/test.ts` to jest `testPathIgnorePatterns` option.


## Exposed [configuration](https://github.com/thymikee/jest-preset-angular/blob/master/jest-preset.js)
## Exposed [`ts-jest` configuration](https://github.com/thymikee/jest-preset-angular/blob/master/src/ts-jest/jest-preset.js)

```js
module.exports = {
Expand Down Expand Up @@ -78,11 +119,13 @@ module.exports = {
};
```

Note that the [`babel` configuration](https://github.com/thymikee/jest-preset-angular/blob/master/src/babel/jest-preset.js) looks different.

### Brief explanation of config

- `<rootDir>` is a special syntax for root of your project (here by default it's project's root /)
- we're using some `"globals"` to pass information about where our tsconfig.json file is that we'd like to be able to transform HTML files through ts-jest
- `"transform"` – run every TS, JS, or HTML file through so called _preprocessor_ (we'll get there); this lets Jest understand non-JS syntax
- `"transform"` – run every TS, JS, or HTML file through so called _preprocessor_, in our case just `ts-jest` or `babel-jest`; this lets Jest understand non-JS syntax
- `"testMatch"` – we want to run Jest on files that matches this glob
- `"moduleFileExtensions"` – our modules are TypeScript and JavaScript files
- `"moduleNameMapper"` – if you're using absolute imports here's how to tell Jest where to look for them; uses regex
Expand Down
12 changes: 12 additions & 0 deletions example/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { babelAngularConfig } = require('jest-preset-angular/build/babel/babel.config')
module.exports = api => {
api.cache(false)
return {
presets: babelAngularConfig.presets,
plugins: [
...babelAngularConfig.plugins,
// your plugins
]
}
}

11 changes: 11 additions & 0 deletions example/get-test-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const defaultTestMode = 'ts-jest';
const envTestModeKey = 'JPA_TEST_MODE';

module.exports = {
getTestMode() {
if (process.env && envTestModeKey in process.env && typeof process.env[envTestModeKey] === 'string') {
return process.env[envTestModeKey];
}
return defaultTestMode;
}
}
4 changes: 3 additions & 1 deletion example/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const { getTestMode } = require('./get-test-mode');

module.exports = {
preset: "jest-preset-angular",
preset: `jest-preset-angular/build/${getTestMode()}`,
snapshotSerializers: [
"jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js",
"jest-preset-angular/build/AngularSnapshotSerializer.js",
Expand Down
17 changes: 15 additions & 2 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
"build": "ng build",
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --runInBand",
"test:coverage": "jest --coverage"
"test:ci": "yarn test:ci:ts-jest && yarn test:ci:babel",
"test:ci:babel": "cross-env JPA_TEST_MODE=babel jest --runInBand",
"test:ci:ts-jest": "cross-env JPA_TEST_MODE=ts-jest jest --runInBand",
"test:coverage": "cross-env JPA_TEST_MODE=ts-jest jest --coverage"
},
"private": true,
"dependencies": {
Expand All @@ -30,10 +32,21 @@
"@angular/cli": "~8.3.4",
"@angular/compiler-cli": "~8.2.5",
"@angular/language-service": "~8.2.5",
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-decorators": "^7.6.0",
"@babel/preset-env": "^7.6.2",
"@babel/preset-typescript": "^7.6.0",
"@types/jest": "^24.0.0",
"@types/node": "^11.0.0",
"babel-jest": "^24.9.0",
"babel-plugin-const-enum": "^0.0.2",
"babel-plugin-transform-typescript-metadata": "^0.2.2",
"cross-env": "^6.0.3",
"jest": "^24.0.0",
"jest-preset-angular": "file:../",
"prettier": "^1.18.2",
"ts-jest": "^24.1.0",
"ts-node": "^8.0.3",
"typescript": "~3.5.3"
}
Expand Down
15 changes: 0 additions & 15 deletions example/src/app/calc/__snapshots__/calc.component.spec.ts.snap

This file was deleted.

59 changes: 43 additions & 16 deletions example/src/app/calc/calc.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { async, ComponentFixture } from '@angular/core/testing';

import { configureTests, ConfigureFn } from '@lib/testing';

Expand All @@ -8,23 +8,50 @@ describe('CalcComponent', () => {
let component: CalcComponent;
let fixture: ComponentFixture<CalcComponent>;

beforeEach(
async(() => {
const configure: ConfigureFn = testBed => {
testBed.configureTestingModule({
declarations: [CalcComponent]
});
};

configureTests(configure).then(testBed => {
fixture = testBed.createComponent(CalcComponent);
component = fixture.componentInstance;
fixture.detectChanges();
beforeEach(async(() => {
const configure: ConfigureFn = testBed => {
testBed.configureTestingModule({
declarations: [CalcComponent]
});
})
);
};

configureTests(configure).then(testBed => {
fixture = testBed.createComponent(CalcComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
}));

it('should snap', () => {
expect(fixture).toMatchSnapshot();
if (global['JpaTestMode'] === 'ts-jest') {
expect(fixture).toMatchInlineSnapshot(`
<app-calc
hasAClass="false"
image={[Function String]}
prop1={[Function Number]}
>
<p
class="a-default-class"
>
calc works! 1337 another text node test-image-stub
</p>
</app-calc>
`);
} else {
expect(fixture).toMatchInlineSnapshot(`
<app-calc
hasAClass="false"
image={[Function String]}
observable$="undefined"
prop1={[Function Number]}
>
<p
class="a-default-class"
>
calc works! 1337 another text node test-image-stub
</p>
</app-calc>
`);
}
});
});
31 changes: 31 additions & 0 deletions example/src/app/hero-category/hero-category.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { HeroCategory, HeroColor } from './hero-properties';

@Injectable({
providedIn: 'root'
})
export class HeroCategoryService {
getCategoryForHero(heroName: string): HeroCategory {
switch (heroName) {
case 'Joker':
return HeroCategory.Evil;
case 'Batman':
return HeroCategory.Good;
default:
return HeroCategory.Neutral;
}
}

getColorForHero(heroName: string): HeroColor {
switch (heroName) {
case 'Joker':
return HeroColor.Purple;
case 'Batman':
return HeroColor.Black;
case 'Catwoman':
return HeroColor.Black;
default:
return HeroColor.Transparent;
}
}
}
25 changes: 25 additions & 0 deletions example/src/app/hero-category/hero-category.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { HeroCategoryService } from './hero-category.service';
import { HeroCategory, HeroColor } from './hero-properties';

describe('HeroCategoryService', () => {
let service: HeroCategoryService;

beforeEach(() => (service = new HeroCategoryService()));

it('should create', () => {
expect(service).toBeTruthy();
});

it('should return the right category for heroes', () => {
expect(service.getCategoryForHero('Batman')).toEqual(HeroCategory.Good);
expect(service.getCategoryForHero('Joker')).toEqual(HeroCategory.Evil);
expect(service.getCategoryForHero('Catwoman')).toEqual(HeroCategory.Neutral);
});

it('should return the right color for heroes', () => {
expect(service.getColorForHero('Batman')).toEqual(HeroColor.Black);
expect(service.getColorForHero('Joker')).toEqual(HeroColor.Purple);
expect(service.getColorForHero('The Penguin')).toEqual(HeroColor.Transparent);
});

});
12 changes: 12 additions & 0 deletions example/src/app/hero-category/hero-properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

export enum HeroCategory {
Evil,
Good,
Neutral
}

export const enum HeroColor {
Black = "#000000",
Purple = "#551A8B",
Transparent = "#00000000"
}
4 changes: 4 additions & 0 deletions example/src/setupJest.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
import 'jest-preset-angular';
import './jestGlobalMocks';

// for example app testing only
import { getTestMode } from '../get-test-mode';
global['JpaTestMode'] = getTestMode()
Loading