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(transformers): add path-mapping custom AST transformer #1927

Merged
merged 1 commit into from Sep 4, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintrc.js
Expand Up @@ -41,6 +41,8 @@ module.exports = {
'getter-return': 'warn',
'guard-for-in': 'error',
'id-match': 'error',
'jest/valid-title': 'off',
'jest/no-conditional-expect': 'off',
'jsdoc/check-alignment': 'error',
'jsdoc/check-indentation': 'error',
'jsdoc/newline-after-description': 'warn',
Expand Down
48 changes: 48 additions & 0 deletions docs/user/config/astTransformers.md
Expand Up @@ -50,6 +50,54 @@ module.exports = {

</div></div>

### Public transformers

`ts-jest` is able to expose transformers for public usage to provide the possibility to opt-in/out for users. Currently
the exposed transformers are:

- `path-mapping` convert alias import/export to relative import/export path base on `paths` in `tsconfig`.
This transformer works similar to `moduleNameMapper` in `jest.config.js`. When using this transformer, one might not need
`moduleNameMapper` anymore.

#### Example of opt-in transformers

<div class="row"><div class="col-md-6" markdown="block">

```js
// jest.config.js
module.exports = {
// [...]
globals: {
'ts-jest': {
astTransformers: {
before: ['ts-jest/dist/transformers/path-mapping'],
},
}
}
};
```

</div><div class="col-md-6" markdown="block">

```js
// OR package.json
{
// [...]
"jest": {
"globals": {
"ts-jest": {
astTransformers: {
"before": ["ts-jest/dist/transformers/path-mapping"]
}
}
}
}
}
```

</div></div>


### Writing custom TypeScript AST transformers

To write a custom TypeScript AST transformers, one can take a look at [the one](https://github.com/kulshekhar/ts-jest/tree/master/src/transformers) that `ts-jest` is using.
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/direct-import.spec.ts
@@ -0,0 +1,7 @@
import { getWelcomeMessage } from '@share/foo'

test('should return welcome message', () => {
const userName = 'github-user'

expect(getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
6 changes: 6 additions & 0 deletions e2e/__cases__/path-mapping/dynamic-import.spec.ts
@@ -0,0 +1,6 @@
test('should return welcome message', async () => {
const userName = 'github-user'
const foo = await import('@share/foo')

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/export.spec.ts
@@ -0,0 +1,7 @@
import { getWelcomeMessage } from '@share/export'

test('should return welcome message', async () => {
const userName = ''

expect(getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-default.spec.ts
@@ -0,0 +1,7 @@
import foo from '@share/foo'

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo(userName)).toBe(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-legacy.spec.ts
@@ -0,0 +1,7 @@
import foo = require('@share/foo')

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-require.spec.ts
@@ -0,0 +1,7 @@
const foo = require('@share/foo')

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
7 changes: 7 additions & 0 deletions e2e/__cases__/path-mapping/import-star.spec.ts
@@ -0,0 +1,7 @@
import * as foo from '@share/foo'

test('should return welcome message', () => {
const userName = 'github-user'

expect(foo.getWelcomeMessage(userName)).toEqual(`yolo ${userName}`)
})
9 changes: 9 additions & 0 deletions e2e/__cases__/path-mapping/import-type.spec.ts
@@ -0,0 +1,9 @@
import type { Foo } from '@share/foo'

test('should work', () => {
const a: Foo = {
bar: 1,
}

expect(a).toBeTruthy()
})
1 change: 1 addition & 0 deletions e2e/__cases__/path-mapping/share/export.ts
@@ -0,0 +1 @@
export { getWelcomeMessage } from '@share/foo'
13 changes: 13 additions & 0 deletions e2e/__cases__/path-mapping/share/foo.ts
@@ -0,0 +1,13 @@
export function getWelcomeMessage(username: string): string {
return `yolo ${username}`;
}

function getMessage(username: string) {
return getWelcomeMessage(username)
}

export interface Foo {
bar: number
}

export default getMessage
12 changes: 12 additions & 0 deletions e2e/__cases__/path-mapping/tsconfig.json
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es5",
"baseUrl": ".",
"paths": {
"@share/*": ["share/*"]
}
},
"exclude": [
"node_modules"
]
}
2 changes: 1 addition & 1 deletion e2e/__external-repos__/custom-typings/jest.config.js
@@ -1,4 +1,4 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testEnvironment: 'node'
}
2 changes: 2 additions & 0 deletions e2e/__external-repos__/path-mapping/.gitignore
@@ -0,0 +1,2 @@
.idea
node_modules
9 changes: 9 additions & 0 deletions e2e/__external-repos__/path-mapping/README.md
@@ -0,0 +1,9 @@
# A project to demonstrate how to setup `ts-jest` only to work together with `jest`

## Installation
Run `yarn` to install dependencies

## Overview about configuration
The project contains:
- A `jest.config.js` which contains config for `ts-jest`.
- A `tsconfig.json` which contains config for `typescript`.
23 changes: 23 additions & 0 deletions e2e/__external-repos__/path-mapping/foo.spec.ts
@@ -0,0 +1,23 @@
import { isStoreOwner } from './foo';
import { getWelcomeMessage } from '@share/get-welcome-message';
import type { Foo } from '@share/typings'

describe('Test optional chaining', () => {
test(`should work`, () => {
expect(isStoreOwner({
isStoreOwner: false,
})).toEqual(false)
})

test(`test export *`, () => {
expect(getWelcomeMessage('foo')).toEqual('yolo foo')
})

test(`test import type`, () => {
const foo: Foo = {
bar: 1,
}

expect(foo).toBeTruthy()
})
});
5 changes: 5 additions & 0 deletions e2e/__external-repos__/path-mapping/foo.ts
@@ -0,0 +1,5 @@
interface User {
isStoreOwner: boolean
}

export const isStoreOwner = (user: User) => user?.isStoreOwner;
16 changes: 16 additions & 0 deletions e2e/__external-repos__/path-mapping/jest.config.js
@@ -0,0 +1,16 @@
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
/** @typedef {import('ts-jest')} */
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
preset: 'ts-jest',
globals: {
'ts-jest': {
astTransformers: {
before: [
'ts-jest/dist/transformers/path-mapping'
]
}
}
}
};
14 changes: 14 additions & 0 deletions e2e/__external-repos__/path-mapping/package.json
@@ -0,0 +1,14 @@
{
"name": "ts-jest-example",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"@types/jest": "26.x",
"jest": "26.x",
"ts-jest": "26.x",
"typescript": "~4.0.2"
},
"scripts": {
"test": "jest"
}
}
@@ -0,0 +1,21 @@
import { getWelcomeMessage } from './get-welcome-message';

describe(`getWelcomeMessage()`, (): void => {
let username: string;

describe(`when the given username is a simple string`, (): void => {
beforeEach(
(): void => {
username = `C0ZEN`;
}
);

it(`should return a message for this username`, (): void => {
expect.assertions(1);

const result = getWelcomeMessage(username);

expect(result).toStrictEqual(`yolo C0ZEN`);
});
});
});
@@ -0,0 +1,3 @@
export function getWelcomeMessage(username: string): string {
return `yolo ${username}`;
}
3 changes: 3 additions & 0 deletions e2e/__external-repos__/path-mapping/src/share/typings.ts
@@ -0,0 +1,3 @@
export interface Foo {
bar: number
}
16 changes: 16 additions & 0 deletions e2e/__external-repos__/path-mapping/tsconfig.json
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"baseUrl": ".",
"declaration": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"paths": {
"@share/*": ["src/share/*"]
}
},
"exclude": [
"node_modules"
]
}