Motomichi Works Blog

その日学習したことについて書いている日記です。誰かの役に立ったらそれはそれで嬉しいです。

package.jsonのあるディレクトリパスを指定してnpm installを実行する

参考にさせて頂いたページ

はじめに

CircleCIで自動的に実行されるコマンドで、npm installしたいときに調べました。

npm installをオプションを付けずに実行したい場合

package.jsonにdependenciesやdevDependenciesが既に記述されている場合です。

例えばsome_projectディレクトリの中にpackage.jsonがある場合は以下のコマンドです。

npm --prefix ./some_project install ./some_project

--save-devなどのオプションを付けて実行したい場合

同じくsome_projectディレクトリの中にpackage.jsonがある場合に、jqueryをインストールするには以下のコマンドです。

npm install --prefix ./some_project --save-dev jquery

JSでテストコードを書く その0003-02 package.jsonをリポジトリのrootに配置せずにCircleCI上でユニットテストを実行する

参考にさせて頂いたページ

package.jsonをroot以外のディレクトリに置いてnpm installする方法について

karmaのconfファイルを指定して--single-runする方法について

circle.ymlの書き方について

package.jsonをrootに配置して良い場合

package.jsonリポジトリのrootに配置して良い場合について先日書きました。

はじめに

前回の記事では、リポジトリのrootにpackage.jsonとかkarma.conf.jsとか色々置いていました。

業務など実際のプロジェクトでは、jsのユニットテストを実行するためだけにpackage.jsonやkarma.confなどを色々とrootディレクトリに追加すると散らかるので、jsのユニットテストに関連するファイルは、frontendディレクトリを作成してこの中に収めようと思います。

前提として、前回書いた以下の記事の続きとして書いていきます。

frontendディレクトリを作成してjsのユニットテスト関連ファイルを全て格納する

まずforntendディレクトリを作成します。

次に./gitと.gitignoreとREADME.mdはそのまま残して、テストに関係するファイルを全てfronendディレクトリに格納します。

以下のような構造になります。

practice_circle_ci_karma/
  ├─.gitignore
  ├─.git/
  │  └─(略)
  ├─README.md
  └─frontend
    ├─karma.conf.js
    ├─package.json
    ├─js/
    │  └─application-xxx.js
    ├─node_modules/
    │  └─(略)
    └─spec/
       └─application.spec.js

circle.ymlの作成

リポジトリのrootにcircle.ymlファイルを作成します。

以下のようになります。

practice_circle_ci_karma/
  ├─.gitignore
  ├─.git/
  │  └─(略)
  ├─circle.yml
  ├─README.md
  └─frontend
    ├─karma.conf.js
    ├─package.json
    ├─js/
    │  └─application-xxx.js
    ├─node_modules/
    │  └─(略)
    └─spec/
       └─application.spec.js

circle.ymlの記述内容

dependencies:
  pre:
    - npm --prefix ./frontend install ./frontend

test:
  pre:
    - ./frontend/node_modules/karma/bin/karma start ./frontend/karma.conf.js --single-run

npm --prefix ./frontend install ./frontendで、frontendディレクトリ内のpackage.jsonの記述内容に基づいて、frontend/node_modulesにパッケージがインストールされます。

./frontend/node_modules/karma/bin/karma start ./frontend/karma.conf.js --single-runでfrontend/karma.conf.jsの記述内容に基づいて、karmaによるユニットテストが実行されます。

.gitignoreのnode_modulesを無視する記述を修正する

node_modulesディレクトリもリポジトリのrootに配置しなくなったので、前回の記述を以下のように修正しました。

*/node_modules

リポジトリをpushして、CircleCIのビルドを実行する

pushします。

circle.ymlに記述されたコマンドが実行されて、前回のようにテスト結果が緑になったら成功です。

JSでテストコードを書く その0003-01 karma+mocha+chaiの組み合わせでCircleCI上でユニットテストを実行する

参考にさせて頂いたページ

全体的なこと

karmaのこと

はじめに

Railsで生成されるapplication-xxxxxxxx.jsみたいなのをテストしたい目的があり、テスト対象のファイル名がapplication-xxx.jsですが、色々応用が利くかと思います。

リモートとローカルのリポジトリを作成する

package.jsonを作成していくつかのパッケージをインストールする

  • npm initして、今回はデフォルトのままenterしていって、yesで大丈夫。
  • npm install --save-dev phantomjs karma karma-cli karma-mocha karma-phantomjs-launcher karma-mocha-reporter mocha chai

.gitにnode_modulesディレクトリをpushしないようにする

  • .gitignoreファイルが無かったら作成する。
  • .gitignoreファイルに/node_modulesを追記する。

js/application-xxx.jsを作成する

自分が作っているwebアプリケーションのjsファイルを想定しています。

window.addNumbers = function(a, b) {
  return a + b;
};

spec/application.spec.jsを作成する

自分が作っているwebアプリケーションの関数を検証するためのソースコードです。

describe('addNumbers', function() {
  it('2 つの数値が加算できる', function() {
    chai.assert.strictEqual(window.addNumbers(1, 2), 3);
  });
});

karma.conf.jsを作成する

./node_modules/karma/bin/karma init karma.conf.jsを実行して対話形式で作成するか、手で作成する

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    browsers: ['PhantomJS'],
    files: [
      'js/application*.js',
      'node_modules/chai/chai.js',
      'spec/**/*.spec.js',
    ],
    reporters: ['mocha'],
  });
};

以下のことを設定しています。

  • フレームワークはmocha
  • ブラウザはPhantomJS
  • filesでテスト対象ファイルと、テストで使用するファイルを読み込み
  • reportersでコンソールのテスト結果出力フォーマットを指定

package.jsonのscriptsのtestを編集する

"scripts": {
  "test": "./node_modules/karma/bin/karma start --single-run"
},

コマンドでテストを実行してみる

  • ./node_modules/karma/bin/karma start --single-runユニットテストが実行できます。
  • package.jsonの設定によってnpm run testでも同じように実行できるはずですが、windowsだとエラーが出ました。CircleCIはこのコマンドを自動で実行してくれます。

pushしてCircleCIによるビルドを実行する

リポジトリにpushすることでCircleCIによるビルドが始まります。

CircleCIはnpm installを自動でやってくれるので、package.jsonに書いてあるdevDependenciesが予めインストールしたうえで、npm run testコマンドが実行されます。

ユニットテストが全て成功して、CircleCIのステータスが「SUCCESS」になったら自動テストの設定は成功ですね。

pushする前には./node_modules/karma/bin/karma start --single-runを一度実行して、ローカルでユニットテストが成功してからpushするのが良いですね。

まとめ

今回の最終的なディレクトリ構造

practice_circle_ci_karma/
  ├─.gitignore
  ├─karma.conf.js
  ├─package.json
  ├─README.md
  ├─.git/
  │  └─(略)
  ├─js/
  │  └─application-xxx.js
  ├─node_modules/
  │  └─(略)
  └─spec/
     └─application.spec.js

karma.conf.jsの記述内容

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],
    browsers: ['PhantomJS'],
    files: [
      'js/application*.js',
      'node_modules/chai/chai.js',
      'spec/**/*.spec.js',
    ],
    reporters: ['mocha'],
  });
};

package.jsonの記述内容

{
  "name": "practice_circle_ci_karma",
  "version": "1.0.0",
  "description": "karmaを導入して、CircleCIで実行するサンプルを作成してみます。",
  "main": "index.js",
  "scripts": {
    "test": "./node_modules/karma/bin/karma start --single-run"
  },
  "repository": {
    "type": "git",
    "url": "xxxxxx/practice_circle_ci_karma.git"
  },
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "xxxxxx/practice_circle_ci_karma/issues"
  },
  "homepage": "xxxxxx/practice_circle_ci_karma#readme",
  "devDependencies": {
    "chai": "^4.0.1",
    "karma": "^1.7.0",
    "karma-cli": "^1.0.1",
    "karma-mocha": "^1.3.0",
    "karma-mocha-reporter": "^2.2.3",
    "karma-phantomjs-launcher": "^1.0.4",
    "mocha": "^3.4.2",
    "phantomjs": "^2.1.7"
  }
}

JSでテストコードを書く その0002-01 mochaとchaiでテストを書いてブラウザでテストを実行する

参考にさせて頂いたページ

日本語の参考ページ

mocha公式

chai公式

はじめに

日本語の情報を読んで書いてみましたが、最新の情報を公式でチェックすると良いでしょう。

jsのテストを手軽に導入する方向で、最も簡易的な方法に着手してみました。

js_testing_0001.htmlを作成して、ブラウザで開くとテストが実行できます。

mocha.js mocha.css chai.jsをダウンロードする

  • とりあえずjs_testingフォルダを作りました。
  • js_testingフォルダの中でnpm initします。今回はデフォルトのままenterしていって、yesで良いです。
  • mocha.js mocha.css chai.jsの3つが欲しいのでnpm install --save-dev mocha chaiでダウンロードします。
  • これらはのちほどhtmlファイルの中で読み込みます。

js_testing/js/application.js を作成する

自分が作っているwebアプリケーションのjsを想定しています。
記述内容は例として以下の通りです。

window.addNumbers = function(a, b) {
  return a + b;
};

js_testing/spec/add_numbers.spec.js を作成する

上記したaddNumbers()関数が意図どおり動いているか検証するためのコードを書きます。
例として以下の通りです。
引数1と2を与えると3がreturnされることを検証しています。

describe('addNumbers', function() {
  it('2 つの数値が加算できる', function() {
    chai.assert.strictEqual(window.addNumbers(1, 2), 3);
  });
});

js_testing/js_testing_0001.html を作成する

今回は、ブラウザでこのhtmlファイルを開くとテストの実行結果が表示されます。
例として以下の通りです。

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--mochaによるテストの実行結果用cssを読み込み-->
<link rel="stylesheet" href="node_modules/mocha/mocha.css">
<link rel="shortcut icon" href="">
</head>
<body>

<!--mochaによるテストの実行結果が出力されるdiv-->
<div id="mocha">
</div>

<!--mochaとchaiを読み込み-->
<script src="node_modules/chai/chai.js"></script>
<script src="node_modules/mocha/mocha.js"></script>

<script>
//BDDスタイルを使用するので設定
mocha.setup('bdd');
</script>

<!--自分が作っているwebアプリケーションのjsを読み込み-->
<script src="js/application.js"></script>

<!--テストコードを読み込み-->
<script src="spec/add_numbers.spec.js"></script>

<script>
// テストを実行
mocha.run();
</script>

</body>
</html>

テスト結果を見る

上記で作成したjs_testing/js_testing_0001.htmlをブラウザで開くとテストが実行されて、検証結果が表示されます。

検証は成功しました。

関数を壊して再度テストを実行してみる

リファクタリングしてみたら関数が壊れてしまった。という状況を想定します。
returnされる値がリファクタリングする前と変わってしまったことを検知します。

js_testing/js/application.js を以下のように編集します。

window.addNumbers = function(a, b) {
  return (a + b) + '';
};

もう一度テストを実行すると検証が失敗しました。
3ではなく'3'がreturnされている旨が表示されます。

関数を直します。
これでリファクタリングに安心感が出てきそうです。

vuex2.xその0005 namespaced:trueにしたmodule用のオブジェクト構造をひとつ定義して使いまわす

参考にさせて頂いたページ

はじめに

namespaced:trueにプロパティ設定したオブジェクトをstore.registerModule()で複数回登録します。

ひとつのmodule用オブジェクト、ひとつのcomponent用オブジェクトを使いまわしできるようにしてみます。

今回のバージョン

  • Vue.js v2.1.10
  • vuex v2.3.0

サンプルソースコード

以下の通りです。

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/style.css">
<link rel="shortcut icon" href="">
</head>
<body>

<div id="app">
  <div>
    <counter :namespace="'firstCounter'" />
  </div>
  <div>
    <counter :namespace="'secondCounter'" />
  </div>
</div>

<script src="js/lodash.js"></script>
<script src="js/vue.js"></script>
<script src="js/vuex.js"></script>
<script>
const components = {};
const store = new Vuex.Store({
  strict: true,
});

/**
 * counter
 */
(function(){
  const counter = {
    strict: true,
    namespaced: true,
    state(){
      return {
        count: 0
      }
    },
    mutations: {
      increment: state => state.count++ ,
      decrement: state => state.count-- ,
    },
    getters: {
      counterState: state => state ,
    }
  };

  store.registerModule('firstCounter', counter);
  store.registerModule('secondCounter', counter);

  components.counter = {
    props: ['namespace'],
    template: `
      <div>
        <div>{{counterState}}</div>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
      </div>
    `,
    methods: {
      increment() {
        this.$store.commit(this.namespace + '/increment');
      },
      decrement() {
        this.$store.commit(this.namespace + '/decrement');
      }
    },
    computed: {
      counterState() {
        return this.$store.getters[this.namespace + '/counterState'];
      }
    },
  };

})();

/**
 * VueModel
 */
const app = new Vue({
  el: '#app',
  store,
  components,
});
</script>

</body>
</html>
  • もっと上手い方法は無いものかと思いつつ、コミットするときのnamespaceはpropsで渡しています。
  • computedについてはmapState()やmapGetters()などを使って上手く書く方法がわからず、this.$store.gettersを使っています。

vuex2.xその0004 modulesによるstoreの分割と、mapGetters()でmoduleを跨いだgettersやstateの参照をしやすくする

参考にさせて頂いたページ

はじめに

babelは使用せずに、Chromeで動作確認をしています。 参考ページのmapGetters()のサンプルで、オブジェクトのスプレッド演算子(Spread Operator)が使用されていますが、エラーが出たのでObject.assign()を使用しています。

storeがすごく大きくなったりしないようにとか、機能ごとに分割する方が管理がしやすいだろうということでmodulesとかmapGetters()の使い方を学習しました。

今回のバージョン

  • Vue.js v2.1.10
  • vuex v2.3.0

サンプルソースコード

以下の通りです。

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/style.css">
<link rel="shortcut icon" href="">
</head>
<body>

<div id="app">
</div>

<script src="js/vue.js"></script>
<script src="js/vuex.js"></script>
<script>
const mapGetters = Vuex.mapGetters;

/**
 * Store
 */
const moduleA = {
  strict: true,
  state: {
    count: 0
  },
  mutations: {
    incrementA: state => state.count++ ,
    decrementA: state => state.count-- ,
  },
  getters: {
    moduleAState: state => state ,
  }
};

const store = new Vuex.Store({
  strict: true,
  modules: {
    a: moduleA,
  },
})

/**
 * RootComponent
 */
const RootComponent = {
  template: `
    <div>
      <div>mapState使用 : {{ moduleAState.count }}</div>
      <div>this.$state.getters.moduleAStateの方 : {{ count }}</div>
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
    </div>
  `,
  methods: {
    increment() {
      this.$store.commit('incrementA')
    },
    decrement() {
      this.$store.commit('decrementA')
    }
  },
  computed: Object.assign(mapGetters([
      'moduleAState',
    ]),
    {
      count() {
        return this.$store.getters.moduleAState.count;
      }
    }
  ),
  created() {
    console.log('this.moduleAState.count : ' + this.moduleAState.count);
  }
};

/**
 * VueModel
 */
const app = new Vue({
  el: '#app',
  store,
  components: { RootComponent },
  template: `
    <div class="app">
      <root-component />
    </div>
  `,
});

</script>

</body>
</html>

modulesとmapGettersを使ってみて個人的要点

  • modulesに分割しても、this.$store.commit('hoge')で全てのコンポーネントから全てのmutationsが呼び出せる
  • actions、gettersについても同様にthis.$store.dispatch('hoge')this.$store.getters.hogeなどで全てのコンポーネントから呼び出せる
  • this.$store.getters.moduleAState.countと記述すると冗長ですが、mapGetters()を使用するとそのコンポーネントのcomputedのgetterとして簡潔な記述で呼び出せるようになる

公式ドキュメントに書いてありますが、グローバルな空間にactionsなどもろもろの名前が定義されるので、どのコンポーネントからでもthis.$storeのプロパティとして呼び出せます。 namespaced: trueを設定すると名前空間を切ることができます。

CLIP STUDIO PAINT DEBUT その0001 タブレットPCで線の入り抜きができない問題を解消する raytrektab DG-D08IWP

参考にさせて頂いたページ

解決したいこと

ドスパラで raytrektab DG-D08IWP を購入して、CLIP STUDIO PAINT DEBUT が付属していたので使ってみたら線の入り抜きができない設定でした。

機種にかかわらずタブレットPCだと同様の事象が発生するようですね。

解決方法

私は以下の方法で解決できました。

  1. [ファイル]メニュー → [環境設定]を選択します。
  2. [タブレット]のカテゴリを選択します。
  3. [TabletPC]にチェックを入れてOKします。

非常に基本的かつ重要なことなのに、意外と必要な情報にたどり着けませんでしたが公式ページで解決されていました。

ついでに調整の方法

上記で入り抜きができるようになったら以下のページにある手順で細かな調整ができます。