Skip to content
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
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["teppeis/node-v6", "teppeis/+prettier", "teppeis/+mocha"]
}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
test/**/*.js
/node_modules
test/test-outdir/**/*.js
18 changes: 4 additions & 14 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,12 @@ node_js:
- "10"
sudo: false
script:
- npm install --no-save typescript@2.2
- npm install -D typescript@2.4
- npm test
- npm install --no-save typescript@2.3
- npm install -D typescript@2.8
- npm test
- npm install --no-save typescript@2.4
- npm test
- npm install --no-save typescript@2.5
- npm test
- npm install --no-save typescript@2.6
- npm test
- npm install --no-save typescript@2.7
- npm test
- npm install --no-save typescript@2.8
- npm test
- npm install --no-save typescript@latest
- npm install -D typescript@2.9
- npm test
cache:
directories:
- node_modules
- $HOME/.npm
75 changes: 47 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
espower-typescript
====
# espower-typescript

> power-assert instrumentor for TypeScript

Expand All @@ -11,44 +10,57 @@ espower-typescript

## TypeScript versions

* espower-typescript v8.x uses TypeScript from v2.2 to v2.9
* espower-typescript v7.x uses TypeScript v2.1
* espower-typescript v6.x uses TypeScript v2.0
* espower-typescript v5.x uses TypeScript v1.8
* espower-typescript v4.x uses TypeScript v1.7
* espower-typescript v2.x and v3.x uses TypeScript v1.6
* espower-typescript v1.x uses TypeScript v1.5
espower-typescript v9.x is compatible with TypeScript v2.4+

## Usage
## Usage (zero-config mode)

### Install
NOTE: If you use older version than v9, see [older document](https://github.com/power-assert-js/espower-typescript/blob/v8.1.3/README.md).

Install

```console
$ npm install -D espower-typescript power-assert mocha
$ npm install -D espower-typescript power-assert mocha typescript @types/node @types/mocha
```

### Zero-config mode
Create a test file (intensionally failed)

```typescript
// test/test.ts
import assert = require('assert');

describe('Array#join', () => {
it('joins all elements into a string with separator', () => {
assert(['a', 'b', 'c'].join(':') === 'a:b:c');
assert(['a', 'b', 'c'].join(':') === 'a:b:c:');
});
});
```

Run test

```console
// for mocha version >= 4
$ ./node_modules/.bin/mocha --require espower-typescript/guess "test/**/*.ts"
```

Output

```
1) Array#join
joins all elements into a string with separator:

AssertionError [ERR_ASSERTION]: # test.ts:6

// for mocha version < 4 (deprecated)
$ ./node_modules/.bin/mocha --compilers ts:espower-typescript/guess "test/**/*.ts"
assert(['a','b','c'].join(':') === 'a:b:c:')
| | |
["a","b","c"] "a:b:c" false
```

### CAUTION: don't use `import 'assert' from 'assert'`

Just use old style `import 'assert' = require('assert')` for assert module.
This is limitation.

## Configure

### If your tests are not in `test` directory

You can set test directory in your `package.json`
Expand All @@ -68,36 +80,43 @@ You can set test directory in your `package.json`
Then, run mocha with `--require espower-typescript/guess`

```console
// for mocha version >= 4
$ ./node_modules/.bin/mocha --require espower-typescript/guess "spec/**/*.ts"

// for mocha version < 4 (deprecated)
$ ./node_modules/.bin/mocha --compilers ts:espower-typescript/guess "spec/**/*.ts"
```

Note: `'espower-typescript/guess'` is inspired by [intelli-espower-loader](https://github.com/azu/intelli-espower-loader)

### tsconfig.json and CompilerOptions
### ts-node and `tsconfig.json`

espower-typescript uses [ts-node](https://github.com/TypeStrong/ts-node) internally.
It loads your [tsconfig.json](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json) automatically.

### Disable type check (transpile only)

If [tsconfig.json](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json) is in your prject root, `'espower-typescript/guess'` loads it automatically.
Use `TS_NODE_TRANSPILE_ONLY` env of ts-node

Note: only `compilerOptions` field in tsconfig.json is applied.
```console
$ TS_NODE_TRANSPILE_ONLY=1 ./node_modules/.bin/mocha --require espower-typescript/guess "test/**/*.ts"
```

### JSX/React

`.tsx` files are supported.

### `allowJs`

If `allowJs: true` in your `tsconfig.json`, assertions in `test/**/*.(js|jsx)` are empowered.

## License

* MIT License: Teppei Sato &lt;teppeis@gmail.com&gt;
* Includes [yosuke-furukawa/espower-traceur](https://github.com/yosuke-furukawa/espower-traceur)
* Includes [azu/espower-babel](https://github.com/azu/espower-babel)
- MIT License: Teppei Sato &lt;teppeis@gmail.com&gt;
- Includes [yosuke-furukawa/espower-traceur](https://github.com/yosuke-furukawa/espower-traceur)
- Includes [azu/espower-babel](https://github.com/azu/espower-babel)

[npm-image]: https://img.shields.io/npm/v/espower-typescript.svg
[npm-url]: https://npmjs.org/package/espower-typescript
[travis-image]: https://travis-ci.org/power-assert-js/espower-typescript.svg?branch=master
[travis-url]: https://travis-ci.org/power-assert-js/espower-typescript
[deps-image]: https://david-dm.org/power-assert-js/espower-typescript.svg
[deps-url]: https://david-dm.org/power-assert-js/espower-typescript
[node-version]: https://img.shields.io/badge/Node.js%20support-v4,v6,v8-brightgreen.svg
[node-version]: https://img.shields.io/badge/Node.js%20support-v6,v8,v10-brightgreen.svg
[license]: https://img.shields.io/npm/l/espower-typescript.svg
65 changes: 32 additions & 33 deletions guess.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
var fs = require('fs');
var path = require('path');
'use strict';

var ts = require('typescript');
const path = require('path');
const ts = require('typescript');

var pattern = 'test/**/*.@(ts|tsx)';
var cwd = process.cwd();
var packageData = require(path.join(cwd, 'package.json'));

if (packageData &&
typeof packageData.directories === 'object' &&
typeof packageData.directories.test === 'string') {
var testDir = packageData.directories.test;
pattern = testDir + ((testDir.lastIndexOf('/', 0) === 0) ? '' : '/') + '**/*.@(ts|tsx)';
const cwd = process.cwd();
const compilerOptions = loadCompilerOptions(cwd) || {};
const extensions = ['ts', 'tsx'];
if (compilerOptions.allowJs) {
extensions.push('js');
extensions.push('jsx');
}

var tsconfigPath = ts.findConfigFile(cwd, fs.existsSync);
var tsconfigBasepath = null;
var compilerOptions = null;
if (tsconfigPath) {
compilerOptions = parseTsConfig(tsconfigPath);
tsconfigBasepath = path.dirname(tsconfigPath);
let testDir = 'test';
const packageData = require(path.join(cwd, 'package.json'));
if (
packageData &&
typeof packageData.directories === 'object' &&
typeof packageData.directories.test === 'string'
) {
testDir = packageData.directories.test;
}
const pattern = path.join(testDir, `**/*.@(${extensions.join('|')})`);

require('./index')({
cwd: cwd,
pattern: pattern,
compilerOptions: compilerOptions,
basepath: tsconfigBasepath
});

function parseTsConfig(tsconfigPath) {
var parsed = ts.parseConfigFileTextToJson(tsconfigPath, fs.readFileSync(tsconfigPath, 'utf8'));
if (parsed.error) {
throw new Error(parsed.error.messageText);
}
require('./index')({cwd, pattern, extensions});

if (!parsed.config || !parsed.config.compilerOptions) {
function loadCompilerOptions(cwd) {
const tsconfigPath = ts.findConfigFile(cwd, ts.sys.fileExists);
if (!tsconfigPath) {
return null;
}

return parsed.config.compilerOptions;
const result = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
if (result.error) {
throw new Error(result.error.messageText);
}
if (result.config && result.config.compilerOptions) {
const basepath = path.dirname(tsconfigPath);
const {options} = ts.parseJsonConfigFileContent(result.config, ts.sys, basepath);
return options;
}
return null;
}
60 changes: 26 additions & 34 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,35 @@
'use strict';
/* eslint node/no-deprecated-api: [error, {ignoreGlobalItems: ["require.extensions"]}] */

var fs = require('fs');
var path = require('path');
'use strict';

var espowerSource = require('espower-source');
var minimatch = require('minimatch');
var ts = require('typescript');
var TypeScriptSimple = require('typescript-simple').TypeScriptSimple;
const path = require('path');
const espowerSource = require('espower-source');
const minimatch = require('minimatch');
const tsNodeRegister = require('ts-node').register;

function espowerTypeScript(options, tsNodeOptions) {
tsNodeRegister(tsNodeOptions);
const {extensions = ['ts', 'tsx']} = options;
extensions.forEach(ext => {
espowerTsRegister(`.${ext}`, options);
});
}

function espowerTypeScript(options) {
var cwd = options.cwd || process.cwd();
var separator = (options.pattern.lastIndexOf('/', 0) === 0) ? '' : '/';
var pattern = cwd + separator + options.pattern;
var compilerOptions = convertCompilerOptions(options.compilerOptions, options.basepath || cwd);
var tss = new TypeScriptSimple(compilerOptions, false);
function espowerTsRegister(ext, options) {
const cwd = options.cwd || process.cwd();
const pattern = path.join(cwd, options.pattern);

function loadTypeScript(localModule, filepath) {
var result = tss.compile(fs.readFileSync(filepath, 'utf-8'), path.relative(cwd, filepath));
if (minimatch(filepath, pattern)) {
result = espowerSource(result, filepath, options);
const originalExtension = require.extensions[ext];
require.extensions[ext] = (module, filepath) => {
if (!minimatch(filepath, pattern)) {
return originalExtension(module, filepath);
}
localModule._compile(result, filepath);
const originalCompile = module._compile;
module._compile = function(code, filepath) {
return originalCompile.call(this, espowerSource(code, filepath, options), filepath);
};
return originalExtension(module, filepath);
};

require.extensions['.ts'] = loadTypeScript;
require.extensions['.tsx'] = loadTypeScript;
}

function convertCompilerOptions(compilerOptions, basepath) {
if (!compilerOptions) {
return null;
}

var converted = ts.convertCompilerOptionsFromJson(compilerOptions, basepath);
if (converted.errors && converted.errors.length > 0) {
var msg = converted.errors.map(function(e) {return e.messageText}).join(', ');
throw new Error(msg);
}
return converted.options;
}

module.exports = espowerTypeScript;
Loading