かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JavaScript モジュールを Travis CI でテストして Coveralls でカバレッジを計測してバッヂを貼りたい。

GitHub の README とかによくあるバッヂをペタペタ貼ってみたかったので、CIのテストとカバレッジ計測をやってみました。
Travis CI は OSS (GitHub で public repo ならOKっぽい) なら無料っぽいという事だったので選びました。カバレッジの表示は Codecov の方が良いみたいな記事も見たのですが、ぶっちゃげJavaScript のプロジェクトならカバレッジも Jest で良い感じに表示できるから何でもいいやって感覚で Travis CI から楽につなげそうだったので Coveralls を使ってみました。(GitHubにペタペタ貼りたいって目的なのでまぁ何でもいいのです…)

貼ってみたやつ 引数で何やかんや渡すと一意な文字列として返すだけのモジュールです。

テストを実行するコマンドを作成

package.json にテストコマンドを実行する npm script を作成する
テストには Jest を使っているので Jest を実行するだけ

"scripts": {
  "test": "jest",
  "test:coverage": "jest --coverage"
},

Travis CI にリポジトリを登録する

Sign in with GitHubGitHub アカウントで登録。
CIでテストしたいリポジトリをONにする。
Travas CI settings
設定はデフォルトのまま。リポジトリに push した時と PR が push された時に CI が実行される

実行するテストの設定

.travis.yml というファイルを作成してテストの設定を書く

language: node_js
node_js:
  - "11.4.0"
  - "10.16.0"

JavaScript (node.js) で、v11.4.0 と v10.16.0 でテストを行う設定にした。特に設定がない場合 JavaScript (node.js) だと npm test が実行される。
各言語の設定は Travis CI User Documentation の Language-specific Guides を参考に

.travis.yml を add して GitHub にpush する。
Travis のサイトでテストが実行されていればOK。

Coveralls との連携

SIGN IN から GitHub アカウントで登録。
ADD REPOS から対象のリポジトリを探して ON にする。

Travis でテスト後にカバレッジを Coveralls に渡す

Coveralls にカバレッジを渡すライブラリをインストール

$ npm install --save-dev coveralls

Travisからカバレッジを渡す設定を追加
.travis.yml

language: node_js
node_js:
  - "11.4.0"
  - "10.16.0"
script: npm run test:coverage && cat ./coverage/lcov.info | ./node_modules/.bin/coveralls

script キーに Travis で実行するスクリプトを指定。
これでブランチに push すれば Travis でテストを実行してテストのカバレッジが Coveralls で表示されるようになる。

テスト結果とカバレッジのバッヂを README に貼る

メイン。

Travis CI

  1. テスト結果のページにあるバッヂをクリック
  2. モーダルが表示されるので FORMAT を Markdown を選択
  3. RESULT に表示されるコードを README.md にコピペ

f:id:kikiki-kiki:20190717164340p:plain

Coveralls

  1. カバレッジが表示されているページに有るバッジ右上の EMBED をクリック
  2. モーダルが表示されるので、Markdown のコードをコピー
  3. README.md に貼り付け

f:id:kikiki-kiki:20190717164942p:plain

 
後は README.md をGitHub に push すればバッヂが表示されている。 f:id:kikiki-kiki:20190717165342p:plain
おわり。

ポエム

ライセンスのバッヂとかは Shields IO で作るのが簡単でした。

他にもいろいろバッヂ作れるっぽいし、結局は markdown で画像表示してるだけだから好き勝手なバッヂも作れるっぽい!
Markdown だからはてなブログにも貼れる。

ソレイユ 星宮いちご 霧矢あおい 紫吹蘭

お子様なので冷蔵庫感覚でバッヂやシール貼りまくるのが好きなのだ。

cf.


[参考]

Babel + Jest で JavaScript のテストをする

Babel のインストールと設定ファイルの作成

$ yarn add -D @babel/core @babel/cli @babel/preset-env

babel.config.js

module.exports = {
  presets: [
    [
      "@babel/preset-env"
    ]
  ],
};

Jest のインストール

$ yarn add -D jest

公式ドキュメントによると babel-jestjest をインストールすると自動的にインストールされるようなので別途インストールする必要はなくなったっぽい。

Jest の設定

Jestの設定ファイルは下記の4つの方法で作成できる

  1. jest --init コマンドで生成する
  2. package.json"jest": {} で設定を書く
  3. jest.config.js ファイルを作成して設定を書く
  4. 適当な.js.jsonファイルを作成して、実行時に --config <設定ファイル> で設定ファイルを指定する

設定方法については公式ドキュメントが充実しているのでこれを参考にすれば良さそう

jest.config.js

module.exports = {
  // テストファイルは tests ディレクトリに指定
  // テストファイルには `spec` か `test` を付けるように指定
  testMatch: [
    "**/tests/**/?(*.)+(spec|test).[tj]s?(x)"
  ],
  // src ディレクトリ内の .js ファイルは babel-jest で変換する
  // babel-jest での変換だけならもしかしたら指定しなくても良いかも知れない
  transform: {
    "^.+\\.js$": '<rootDir>/node_modules/babel-jest',
  },
  // カバレッジの対象ファイルを `**/src/**/*.js` にして `node_modules` を除外
  collectCoverageFrom: [
    "**/src/**/*.js",
    "!**/node_modules/**",
  ],
};
注意 ディレクトリを指定する正規表現**/ で始める必要がある

testMatch などでディレクトリを指定するばあいは先頭に **/ が無いとマッチするファイルがないというエラーになる。恐らくmonorepo構成に対応しているから **/ が必要なのかなという印象。

テスト時は Babel で import 文を require に変更するプラグインを導入

Jest は node の世界でテストを行うので ES Module の import をそのまま扱うことができないので、CommonJS の require に変更する必要があります。
ref. Using with webpack · Jest

Jest は実行時にデフォルトで process.env.NODE_ENVtest をセットするので、test の時 Babel で importrequire に変換するようにする。

変換するプラグインのインストール
$ yarn add -D transform-es2015-modules-commonjs
Babelの設定を追加

babel.config.js

module.exports = {
  presets: [
    [
      "@babel/preset-env"
    ]
  ],
  env: {
    test: {
      plugins: [
        "transform-es2015-modules-commonjs",
      ],
    },
  },
};

テスト用の npm script の作成

package.json

"scripts": {
  "test": "jest",
  "test:w": "jest --watch",
  "test:coverage": "jest --coverage"
},
options
  • --watch ... テストファイルが変更されるごとにテストを実行してくれる。
  • --coverage ... テスト終了時にカバレッジが表示され /coverage ディレクトリに情報が吐き出される

Jest でテストが実行できるか試す

tests ディレクトリ内にindex.test.jsのような適当なテストファイルを作成して作成した npm script でテストを実行する

$ yarn run test
 RUNS  tests/index.test.js
 ...

Jest が実行されテスト結果が表示されればOK

感想とまとめ

webpackを使うともう少し設定が複雑になりそうだけど、BabelだけならJestの導入はとても簡単でした。(細かい設定についてはまだ把握しきれてないですが…) 設定ファイルでディレクトリを指定する際に **/ から始める必要があるという部分くらいでしょうか。ハマりどころは。


[参考]

Node.jsデザインパターン 第2版

Node.jsデザインパターン 第2版

ambie sound earcuffs(アンビー サウンドイヤカフ) (Pop Sky)

ambie sound earcuffs(アンビー サウンドイヤカフ) (Pop Sky)

👆 ambie のイヤフォン買った。外の音が聴こえつつちゃんと曲も聞けるし、何より耳に挟んでるからポロッと落とすストレスがなくて外出用にとても良いです。音量大きくすると流石にシャカシャカ音漏れしてましたが思ったより音漏れして無い感じでした。(白色の在庫復活してる買い増ししようかな)

JavaScript &nbsp; なスペースのあるHTMLの扱い

先に JSX 内で &nbsp; が含まれる場合のテストのハマりどころ書いてしまったけど、改めて JavaScript での扱いをメモ。

JavaScript での取得

<p id="elm">星宮&nbsp;いちご</p>
const elm = document.getElementById('elm');

elm.innerText; // 星宮 いちご
elm.firstChild.nodeValue; // 星宮 いちご
elm.textContent; // 星宮 いちご
elm.innerHTML; // 星宮&nbsp;いちご

&nbsp;を含むテキストのマッチ

通常のスペース 文字コード\u0020
&nbsp;なスペース 文字コード\u00A0

const testTest = [
  "星宮 いちご", // 通常のスペース
  "星宮 いちご"; // &nbsp; なスペース
  "星宮&nbsp;いちご",
  "星宮\u0020いちご", // 通常のスペースを文字コードに
  "星宮\u00A0いちご", // `&nbsp;`なスペースを文字コードに
];
const matchText = (str) => {
  testTest.forEach((val, i) => {
    console.log( str === val );
  });
};

const str1 = elm.innerText; // 星宮 いちご
matchText(str1);
// str1 === "星宮 いちご" => false 
// str1 === "星宮 いちご" => true
// str1 === "星宮&nbsp;いちご" => false
// str1 === "星宮\u0020いちご" => false
// str1 === "星宮\u00A0いちご" => true

const str2 = elm.firstChild.nodeValue; 星宮 いちご
matchText(str2);
// str2 === "星宮 いちご" => false 
// str2 === "星宮 いちご" => true
// str2 === "星宮&nbsp;いちご" => false
// str2 === "星宮\u0020いちご" => false
// str2 === "星宮\u00A0いちご" => true

const str3 === elm.textContent; // 星宮 いちご
matchText(str3);
// str3 === "星宮 いちご" => false 
// str3 === "星宮 いちご" => true
// str3 === "星宮&nbsp;いちご" => false
// str3 === "星宮\u0020いちご" => false
// str3 === "星宮\u00A0いちご" => true

const str4 === elm.innerHTML; // 星宮&nbsp;いちご
matchText(str4);
// str4 === "星宮 いちご" => false 
// str4 === "星宮 いちご" => false
// str4 === "星宮&nbsp;いちご" => true
// str4 === "星宮\u0020いちご" => false
// str4 === "星宮\u00A0いちご" => false

JavaScriptのテキストノードで取得した &nbsp; なスペースは (&nbsp; なスペース) または \u00A0 と同じ扱いになり、通常のスペースや &nbsp; という文字列とは同じには扱われません。

&nbsp; なスペースの操作

テキストノードで取得した &nbsp; なスペースは \s にマッチする

.replace(/\s/g, ' ') で通常のスペースに置き換えることが出来る

// HTML <p id="elm">星宮&nbsp;いちご</p>
const elm = document.getElementById('elm');

elm.textContent.replace(/\s/g, ' ') === "星宮 いちご"; // 通常のスペース
// => true
elm.textContent.replace(/\s/g, ' ') === "星宮\u0020いちご"; 
// => true

テキストノードで取得した &nbsp; なスペースは trim() で除去できる

\s にマッチするからだと思うが、空白扱いになり前後にあるものなら trim() で除去することが出来る。

// HTML <p id="elm">&nbsp;星宮 いちご&nbsp;</elm>
const elm = document.getElementById('elm');

elm.textContent.trim() === "星宮 いちご";
// => true
まとめ

文字列のマッチなどを行う時に、 を見分けるのは困難なので、マッチを行うときは .replace(/\s/g, ' ') で置き換えてしまうのが良さそうだと思いました。
それ以前に必然性のない不要な箇所で &nbsp; を使わないようにするのが間違いなく一番だと思います。


[参考]

スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)

スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)