このプロジェクトの目標は、次のすべてを実行できる TypeScript プロジェクトを作成することです。
jest
とts-jest
使用するまず、これをnpm
プロジェクトとして初期化します。
$ yarn init .
次に、 typescript
、 jest
、 ts-jest
、 @types/jest
依存関係としてインストールします。
$ yarn add -D typescript jest ts-jest @types/jest
この記事の執筆時点では、これは[email protected]
、 [email protected]
、および[email protected]
を意味します。
次に、以下を使用してこれを TypeScript プロジェクトとして初期化します。
$ npx tsc --init .
TypeScript で生成されたコードを./lib
に保存し、宣言を生成したいと考えています。そこで、 tsconfig.json
のoutDir
./lib
になるように構成します。
私の.gitignore
は次のように構成されます。
/node_modules
/lib
...一方、私の.npmignore
次のとおりです。
/node_modules
同じ理由で、 tsconfig.json
内のfiles
のデフォルト値を削除し、次のように置き換えます。
"exclude" : [ " node_modules " , " lib " ]
まず、単純な関数を含むsrc/index.ts
を作成します。
export function sampleFunction ( x : string ) : string {
return x + x ;
}
簡単なjest
テストも追加します。私はテストを完全に別の場所に保存したいので、すべてのテストを__tests__
に置きます。そこで、次のテスト ケースを__tests__/base.spec.ts
に作成します。
import { sampleFunction } from "../src" ;
describe ( "This is a simple test" , ( ) => {
test ( "Check the sampleFunction function" , ( ) => {
expect ( sampleFunction ( "hello" ) ) . toEqual ( "hellohello" ) ;
} ) ;
} ) ;
この時点で、そのテストを実行したいと思います。ただし、最初にすべてのjest
設定用のjest.config.js
ファイルを作成する必要があります。これには、 ts-jest
使用しているという事実と、テストが__tests__
に保存されているという事実を考慮する必要があります。したがって、結果のファイルは次のようになります。
module . exports = {
transform : {
"^.+\.tsx?$" : "ts-jest" ,
} ,
testRegex : "(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$" ,
moduleFileExtensions : [ "ts" , "tsx" , "js" , "jsx" , "json" , "node" ] ,
} ;
次に、次のスクリプトをpackage.json
に追加します。
"scripts" : {
"compile" : " tsc " ,
"test" : " jest "
}
この時点で、 yarn test
実行すると、まさに期待していたものが得られます。
PASS __tests__/base.spec.ts
This is a simple test
✓ Check the sampleFunction function (3ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
コード カバレッジを有効にするには、 jest.config.js
ファイルを次のように更新します。
module . exports = {
transform : {
"^.+\.tsx?$" : "ts-jest" ,
} ,
testRegex : "(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$" ,
moduleFileExtensions : [ "ts" , "tsx" , "js" , "jsx" , "json" , "node" ] ,
collectCoverage : true ,
} ;
また、 jest
によって生成されたcoverage
ディレクトリのバージョン管理や公開を避けるために、 .gitignore
ファイルと.npmignore
ファイルを更新する必要もあります。
この時点で、プロジェクトにサブモジュールの導入を開始します。そこで、物事を少しだけ現実的にするために、 src/core
とsrc/utils
モジュールを追加します。次に、これら両方の内容をエクスポートして、 src/index.ts
次のようにします。
export * from "./core" ;
export * from "./utils" ;
次に、さまざまなタイプと機能を含む特定のファイルをインポートします。最初に、リテラルと二項演算+
、 -
、 *
、 /
のみを使用して非常に単純な式を表すための、非常に単純な型のセットを作成します。次に、次のようないくつかのテストを作成します。
import { evaluate , Expression } from "../src" ;
describe ( "Simple expression tests" , ( ) => {
test ( "Check literal value" , ( ) => {
expect ( evaluate ( { type : "literal" , value : 5 } ) ) . toBeCloseTo ( 5 ) ;
} ) ;
test ( "Check addition" , ( ) => {
let expr : Expression = {
type : "binary" ,
operator : "+" ,
left : {
type : "literal" ,
value : 5 ,
} ,
right : {
type : "literal" ,
value : 10 ,
} ,
} ;
expect ( evaluate ( expr ) ) . toBeCloseTo ( 15 ) ;
} ) ;
} ) ;
ここまでは順調ですね。ただし、これらのテストを実際に実行すると、次のような結果が得られることに注意してください。
PASS __tests__/base.spec.ts
Simple expression tests
✓ Check literal value (4ms)
✓ Check addition
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.048s
Ran all test suites.
---------------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
---------------|----------|----------|----------|----------|----------------|
All files | 66.67 | 37.5 | 50 | 66.67 | |
src | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
src/core | 61.54 | 37.5 | 100 | 61.54 | |
functions.ts | 54.55 | 37.5 | 100 | 54.55 | 14,16,18,20,25 |
index.ts | 100 | 100 | 100 | 100 | |
src/utils | 66.67 | 100 | 0 | 66.67 | |
checks.ts | 50 | 100 | 0 | 50 | 2 |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|----------------|
コードカバレッジが不足していることに注意してください。いくつかの/* istanbul ignore ... */
コメントとともにいくつかのテスト ケースを追加して、無視しても安全なものをistanbul
知らせると、次のようになります。
PASS __tests__/base.spec.ts
Simple expression tests
✓ Check literal value (3ms)
✓ Check addition
✓ Check subtraction
✓ Check multiplication (1ms)
✓ Check division
Test Suites: 1 passed, 1 total
Tests: 5 passed, 5 total
Snapshots: 0 total
Time: 1.353s
Ran all test suites.
---------------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
---------------|----------|----------|----------|----------|----------------|
All files | 100 | 100 | 100 | 100 | |
src | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
src/core | 100 | 100 | 100 | 100 | |
functions.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
src/utils | 100 | 100 | 100 | 100 | |
checks.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|----------------|
ここで、テストが失敗するようにテストを変更すると、次のような結果が得られます。
● Simple expression tests › Check division
expect(received).toBeCloseTo(expected, precision)
Expected value to be close to (with 2-digit precision):
1
Received:
2
19 | test("Check division", () => {
20 | let expr = bin("/", 10, 5);
> 21 | expect(evaluate(expr)).toBeCloseTo(1);
22 | });
23 | });
24 |
at Object.<anonymous> (__tests__/base.spec.ts:21:32)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 4 passed, 5 total
Snapshots: 0 total
Time: 1.535s
Ran all test suites.
---------------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
---------------|----------|----------|----------|----------|----------------|
All files | 100 | 100 | 100 | 100 | |
src | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
src/core | 100 | 100 | 100 | 100 | |
functions.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
src/utils | 100 | 100 | 100 | 100 | |
checks.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|----------------|
スタック トラックが正しいことに注意してください。これはTypeScript コードの問題を示しています。
package.json
にcompile
スクリプトを追加したことを思い出してください。コードはyarn compile
を使用してコンパイルできます。これにより、 lib
ディレクトリにsrc
と__tests__
2 つのサブディレクトリが追加されたことがわかります。
ただし、これらのディレクトリを調べてみると、生成された Javascript コードのみが含まれていることがわかります。型定義は含まれません。他の TypeScript ユーザーがコードに追加したすべての型情報を利用できるように型定義 ( .d.ts
ファイル) を生成するには、 tsconfig.json
ファイルのdeclaration
フィールドをtrue
に設定する必要があります。
また、他のユーザーがこのパッケージを NPM モジュールとして使用するには、 package.json
のmain
フィールドをlib/src/index.js
に設定する必要があることにも注意してください。さらに、他のユーザーがこのモジュールの型にアクセスできるようにするには、 package.json
のtypings
フィールドをlib/src/index.d.ts
に設定する必要もあります。言い換えると、
"main" : " lib/src/index.js " ,
"typings" : " lib/src/index.d.ts " ,
適切に構成されていれば、 node
セッションを起動して新しいパッケージをインポートできます。
$ node
> var me = require( " . " )
undefined
> me
{ evaluate: [Function: evaluate],
assertNever: [Function: assertNever] }
>
ここで、必ずjest.config.js
更新して次の設定を含めるようにしてください。そうしないと、 jest
lib/__tests__
ディレクトリ内のコードとの照合を開始します。
testPathIgnorePatterns: ["/lib/", "/node_modules/"],
いよいよデバッグに入ります。私は Visual Studio Code を使用しているので、そこでデバッグを実行する方法を説明します。この情報の一部は他の IDE にも応用できる可能性があります。
VSCode では、デバッグ サイドバーに移動できます。最初は、「再生」ボタンの横に「構成なし」という文字が表示されます。それをクリックすると、「構成の追加...」オプションを含むプルダウン メニューが表示されます。
私は TypeScript が大好きですが、デバッグはまさにそのアキレス腱です。デバッグできないのではなく、動作させるのが難しいだけです。 [構成の追加...] を選択してから [Node.js] を選択すると、 mocha
用の構成を含むいくつかの事前構成が表示されます。しかし、 jest
のためのものはありません。したがって、独自の.vscode/launch.json
ファイルを作成する必要があります。幸いなことに、 jest
ページでは、次のような.vscode/launch.json
ファイルを作成することが推奨されています。
{
"version" : " 0.2.0 " ,
"configurations" : [
{
"name" : " Debug Jest Tests " ,
"type" : " node " ,
"request" : " launch " ,
"runtimeArgs" : [ " --inspect-brk " , " ${workspaceRoot}/node_modules/.bin/jest " , " --runInBand " ],
"console" : " integratedTerminal " ,
"internalConsoleOptions" : " neverOpen "
}
]
}
いつものようにテストを実行してコード カバレッジを取得できるだけでなく、テスト (つまり__tests__/base.spec.ts
) とコード (例: src/core/functions.ts
)、デバッガーがそれらを見つけます。
これらすべてを Node 8.x でテストしたことに注意してください。 Node 6.x を使用したデバッグで問題が発生していることが確認されているため、そこで問題が発生した場合は、アップグレードを検討してください (または、なんとか修正できた場合は、修正を説明するこの README の PR を送信してください)。