mochaでテスト実行時にflowの記述を自動で取り除く
はじめに
mochaでテスト実行するときに、flowの記述が残されたままだとテストできない。
だから、前までは前処理としてflowの記述を取り除いたフォルダを作成し、
そのディレクトリに対してテストを実行させていた。
しかし、余計なフォルダを作成させずにmochaを実行できる方法をたまたま見付けたので、 残しておこうと思う。
流れ
- テスト環境の容易
- flowのインストール
- flowの記述追加
- テスト失敗の確認
- flow-remove-typesの追加と設定
- テスト成功
0. テスト環境の用意
mochaとpowerassertを使ったテスト環境構築方法は、以前作成した記事power-assertとmochaを使ったnodejsのテストを参考にしてください。 今回もこの環境を使用します。
1. flowのインストール
前の記事では, flowをインストールしてなかったので追加します。
npm install --save-dev flow-bin ./node_moduleds/.bin/flow init
2. flowの記述追加
前回作成したファイルにflowの記述を追加
// @flow class Calc { // flowの記述追加 static add(x: number, y: number): number { return x + y; } // flowの記述追加 static sub(x: number, y: number): number { return x - y; } } module.exports = Calc
3. テスト失敗の確認
npm test
と叩くと下図の通り。
Unexpected token :と表示されてる通り、余計なコロンがあるのでテストは失敗します。
4. flow-remove-typesの追加と設定
npm install --save-dev flow-remove-types
package.jsonの修正
//package.json scripts: { "test": "mocha --require intelli-espower-loader --require flow-remove-types/register ./test/" }
複数のモジュールを--requireしたい時は、モジュールごとに--requireをつければよいよう。これで問題なくテストは動きます。
5. テスト成功
electronでReactを使うためのwebpackの設定
はじめに
electron。javascriptでデスクトップアプリケーションを作れるフレームワーク。
使ってみたかったけど、なかなかよい作りたいものも思いつかずsample demo appで遊ぶくらいでした。
最近ちょっと良いアイデアも思いついたので、思い切ってelectronを触ってみました。
また合わせてreactの勉強もしてみたかったので、React x electronの環境構築の備忘録を残しておこうと思います。
reduxは使いません。まだ扱えきれるレベルじゃないないので。。。
ポイント
- node_modulesを呼び出せるelectronのjsをどうやってバンドルするの?
- main・rendererプロセス用の2種類のjsが必要
electronのjsはfsなどnodeで使えるモジュールを呼び出せるので、
webのReactと同様にimportできるのか。。。
またelectronには、mainプロセスとrendererプロセスが存在し、それぞれにjsファイルがあるのに対して、多分普通のReactのプロジェクトでは、htmlで読み込むのは、一つのjsだけ。
この違いをどうやって、対応するか。。。
結論急げば、webpackの設定でどちらの問題も解決できます。まじ優秀!!
流れ
- electronのインストール
- electron起動
- reactの環境構築
- build失敗の確認
- webpackの設定(nodeモジュールをimportさせる)
- webpackの設定(2つのjsファイルを作成)
- buildしてみる
1. electronのインストール
これだけ。はは、便利
npm install -g electron
2. electron起動
プロジェクトを作って、mainプロセス用のjsと、rendererプロセスで必要なhtmlとそれが呼び出すrenderer.jsを作成します。 js,htmlが用意できたら、electronコマンドでmain.jsを指定します
mkdir sampleApp cd sampleApp npm init -y touch main.js touch index.html electron main.js
作成したhtml,jsは、tutorialのWriting Your First Electron Appからコピペしてます。
こんな感じ。
3. reactの環境構築
他の色々なサイトに導入方法は書いてあるが、自分は【Reactではじめるフロントエンド開発入門】1 を参考にさせてもらいました。npm, yarn両方の構築方法が丁寧に書かれてあるので、勉強になりました。
// react npm install react react-dom // webpack npm install -D webpack webpack-cli // babel npm i babel-core -D npm i babel-preset-es2015 -D npm i babel-preset-react -D npm i babel-loader -D
webpackの設定も最低限
// webpack.config.js const webpack = require("webpack"); const path = require('path'); const config = { entry: './src/app.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'app.js' }, module: { rules: [{ test: /\.js$/, exclude: path.resolve(__dirname, 'node_modules'), loader: 'babel-loader', query:{ presets: ['react', 'es2015'], } }] } }; module.exports = config;
npm build
でapp.jsができると、後はindex.htmlでロードすればおしまい。
4. build失敗の確認
では、webのプロジェクト同じやり方でjsファイルを作成しトランスパイルさせてみます
nodeモジュールfsを利用した以下のファイルを作成する。
import React, { Component } from 'react'; import ReactDom from 'react-dom'; // 追加: nodeのモジュールfsをimportする import fs from 'fs' export default class App extends Component { constructor(props) { super(props); this.state = { file : '' } } componentWillMount() { // fsモジュールを使用する this.setState({file:fs.readFileSync('index.html','utf8')}) } render() { return <h1>{this.state.file}</h1> } } ReactDom.render( <App />, document.getElementById('root') );
npm build
するとこちら。
はい、失敗します! fsが読み込めませんと。 なので、これの対応がwebのときと異なり必要となってきます。
5. webpackの設定(nodeモジュールをimportさせる)
google先生に聞いてみると、ここに electron + webpack + react + sass ほとんど書いてました。targetプロパティなるものが、重要ということ。 webpack公式targetによると、targetには,electron-mainとelectron-rendererを 指定できるようなので、これを使いましょう。
では、targetプロパティを追加して、electron用であることを指定します。
// webpack.config.js const webpack = require("webpack"); const path = require('path'); const config = { entry: './src/app.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'app.js' }, target:'electron-renderer', // 追加 renderer用 module: { rules: [{ test: /\.js$/, exclude: path.resolve(__dirname, 'node_modules'), loader: 'babel-loader', query:{ presets: ['react', 'es2015'], } }] } }; module.exports = config;
6. buildしてみる
build成功
electron起動
7. webpackの設定(2つのjsファイルを作成)
もう一つ課題が残っていました。
mainプロセスとrendererプロセス用の二つのjsをトランスパイルさせましょう。
renderer用のみトランスパイルするなら特に不要な作業だが、main.jsだけはcommonjs記法を採用するという
気持ちの悪い感じがするので、自分はmain.jsもトランスパイルさせました。
設定方法は実に簡単。
main用とrenderer用の設定を記述して、配列にしたものをconfigに格納するだけになります。
// webpack.config.js const config = [ { // mainプロセス用 entry: './src/main/main.js', output: { path: path.resolve(__dirname, 'dist/main'), filename: 'main.js' }, target: 'electron-main', module: { rules:[ { test: /\.js$/, exclude: path.resolve(__dirname, 'node_modules'), loader: 'babel-loader', query: { presets: ['react', 'es2015'] } } ] } }, { // renderer用 entry: './src/renderer/renderer.js', output: { path: path.resolve(__dirname, 'dist/renderer'), filename: 'renderer.js' }, target: 'electron-renderer', module: { rules:[ { test: /\.js$/, exclude: path.resolve(__dirname, 'node_modules'), loader: 'babel-loader', query: { presets: ['react', 'es2015'], plugins:['transform-class-properties'] }, } ] } } ]
その結果、main用とrenderer用の二つのjsファイルを作成されます。
dist ├─main │ main.js │ └─renderer index.html renderer.js
最後に
webpackの設定は奥が深い...。
フロントエンドの勉強は学習範囲が多すぎて、どこか不安になってしまう。
これが仕事となると、本当に効率よい学習が必要なんだろうな~と思う。
けど、jqueryも使う気がしないのは確かだ。
-
↩
- 作者: 中野仁
- 発売日: 2017/11/14
- メディア: Kindle版
- この商品を含むブログを見る
eslintでflowの検証結果も表示させる
そんなにプログラミングするわけではないが、
javascriptは本当に色々変更が激しいなと最近感じてる。
今回は、eslintとflowを使って静的検証が行える環境構築手順を残そう。
eslintを実行させると、flowのチェックと結果を取得できるようにする
目次
- eslintを使ってみる
- flowを使ってみる
- npm run lintでflowの検証結果も表示
- npm run lintでflowのエラー結果も表示
- flow-remove-typesで実行用ファイルを作成する
1. eslintを使ってみる
npm install --save-dev eslint // .eslintrcを作成 ./node_modules/.bin/eslint --init
あとはコマンドライン上の質問に答えると、.eslintrc.jsonなどの設定ファイルができる
npm run lintでeslintが起動できるようにpackage.jsonの修正
package.json scripts : { lint: "eslint ./src" }
ディレクトリ、ファイルを作成する
mkdir src touch eslinttest.js
eslinttest.js function sum(x,y) { return x+y; } let result = sum(1,1);
これでnpm run lintと入力すると検証結果が表示される
3:11 error Infix operators must be spaced space-infix-ops 7:5 error 'result' is assigned a value but never used no-unused-vars 7:5 error 'result' is never reassigned. Use 'const' instead prefer-const 7:27 error A space is required after ',' comma-spacing 7:31 error Newline required at end of file but not found eol-last
2. flowを使ってみる
// npmで追加 npm install --save-dev flow-bin // .flowconfigを作成する ./node_modules/.bin/flow --init
npm run flowでflowが起動できるようにpackage.jsonの修正
package.json ... scripts :{ flow : "flow" } ...
touch ./src/flowtest.js
flowtest.js //@flow function sum(x: number, y: number): number { return x+y; } // あえて間違える let result: string = sum(1,1);
npm run flowでflowの検証結果が表示される
Error ---------------------------------------------------------- Cannot assign `sum(...)` to `result` because number [1] is incompatible with string [2]. src/flowtest.js:7:24 7| const result: string = sum(1, 1); ^^^^^^^^^ References: src/flowtest.js:2:37 2| function sum(x: number, y: number): number { ^^^^^^ [1] src/flowtest.js:7:15 7| const result: string = sum(1, 1); ^^^^^^ [2]
3. npm run lintでflowの検証結果も表示
flowの記述が残されたままだと、eslintは失敗する
なので、いくつか前準備が必要になる。
npm install --save-dev babel-eslint eslint-plugin-flowtype
.eslintrc.jsonも修正し、eslint-plugin-flowtypeのconfigurationをコピペ。
これでnpm run lintを実行すると、eslint単体のときと同様のエラーが表示される。
4. npm run lintでflowのエラー結果も表示
しかし、表示されるのはeslintの結果だけで、flowのエラーはこのままでは表示されない。
なので、もう一つplugin追加が必要となる。
npm install --save-dev eslint-plugin-flowtype-errors
.eslintrc.json ... "plugins": [ "flowtype", // 追加 "flowtype-errors" ], rules: { // 追加 "flowtype-errors/show-errors": 2, "flowtype-errors/show-warnings": 1 } ...
あとはnpm run lint!
これでeslintのエラーに加えてflowのエラー内容も表示される.
5. flow-remove-typesで実行用のファイルを作成
npm installl --save-dev flow-remove-types
npm run buildで起動できるようにpackage.jsonの修正
package.json scripts: { "build": "flow-remove-types src -d lib --pretyy" }
npm run buildを実行すると、flowの型情報を削除したファイルがlibに出来る。
最後に
jsはインタプリタ言語なのに静的検証やら型検査が普通になってきているのようだ。これもCIなどでbuildまでの時間を短くできるようになったのが、背景なのかもなと感じた。 これでバシバシ書いていけるぞ
async/awaitの学習
以前Promiseを使ったループ処理について記述したが、これは再帰関数を利用していた。
普段扱いなれているfor文でループ処理はかけるのかなと感じていたが、
どうやらasync/awaitを使えばできることがわかったので、残しておく。
jQueryの$.ajaxからPromiseへの理解に時間を要したので、async/awaitも同様理解するのに
時間がかかるのかと予想していたのだが、この技術はPromiseをさらに便利にする仕組みだ。
だから、Promiseの使い方がわかっていれば簡単に理解できるし、便利になる。
目次
- asyncを関数名につけるとreturnされるものは、必ずPromiseになる
- async/awaitを使うと、非同期処理を同期的に記述できる
- Promise.allも同期的にかける
- 前回のPromiseでのループ処理をasync/awaitで記述してみる
- 非同期処理には全てasyncをつけるのか?
asyncを関数名の前につけるとreturnされるものは、必ずPromiseになる
async function fn() { return 1; }
console > fn() > Promise {1}
async/awaitを使うと、非同期処理を同期的に記述できる
async function AsyncTest() { let result = await fn(); // awaitを使うには必ずasync関数内でないとだめ。 console.log(result); return 1; }
console > AsyncTest() > 1 > Promise {1}
Promise.allも同期的にかける
async function AsyncTest2() { let [r1, r2] = await Promise.all([fn(), fn()]); console.log(r1); console.log(r2); return r1 + r2 }
console > AsyncTest2() > 1 > 1 > Promise {2}
前回のPromiseでのループ処理をasync/awaitで記述してみる
async function fn(i) { console.log( (i+1) + '回目') } async function loop (count) { for ( let i = 0; i < count; i += 1 ) { await fn(i); } return 'end' }
console >loop(5).then(r=>{console.log(r)}) 1回目 2回目 3回目 4回目 5回目 end Promise {<resolved>: undefined}
最後に
Promiseについて理解できていたら、async/awaitはすごい便利な技である。 nodeで使う場合、v7以上であればasync/awaitがつかえる。
条件付き確率の話
今日は確率について。僕は数学は割と好きな方だったけど、確率にはあまりよい思い出はない。久しぶりに確率の勉強をしていて、気にかかることに出会ったし、数式使ってみたかったのでブログに載せようと思う。
プログラミングのための確率統計1第2章の冒頭に、以下の会話がある。
A: 私の調査によるとゲーム機所持者の犯罪者は50%以上です。何らかの規則をするべきでしょう。
B: 何そのやたら高い数字?
A: 最近の少年犯罪では犯人の半数以上がゲーム機を所持していました。
B: ええと、つっこみ所ありすぎて困るんだけど、とりあえず犯罪関係なしで最近の少年のゲーム機所持率から調べなおしてくれない?
会話の流れからAさんの主張がおかしいことは読み取れるが、
なぜ間違っているのかちゃんと説明できるだろうか?
少なくとも僕は即答できなかったので、今日はこの説明をする。
日本語を数式に
それでは会話をもう少し理解するために、これらを数式で表現してみよう。
(ややこしい問題はまず数式で表現してみるだけでも少し整理できるものだから)
「ゲーム機所持者の犯罪者が50%以上」をどう表現する?
Aさんのはじめの発言の数式表現は正直難しいと思っている。というのは、
- ゲーム機所持者でかつ犯罪をおかす確率が50%以上なのか?(同時確率)
- ゲーム機所持しているならば、その人が犯罪を犯す確率は50%以上なのか?(条件付き確率)
のどちらか判定できないからだ。
ひとまず話をこのさきを進めやすくするため、後者だと想定する。
だから、数式にすると
「最近の少年犯罪では犯人の半数以上がゲーム機を所持していました」をどう表現する?
こちらは簡単。
もう一度会話を整理
Aさんは、(1)故にゲームを所持しないように規制すべきだという。
つづいてBさんがその根拠は何かという疑問に対して、(2)が根拠だとわけだ。
もう少しシンプルに表現すれば、
がなりたつとき、
も成り立つから、ゲームを持たせるなという主張をしている。
つまり、条件付き確率の条件を入れ替えても確率が同じだという主張だ。
(もっとも少年犯罪も犯罪も同じと考えているが...)
Aさんの判断の間違いはどこか?
では、条件付き確率の条件を入れ替えても確率が同じとなるのは、
P(X=ゲーム機所持)やP(Y=犯罪をおかす)がどのような関係にあるときだろうか調べてみよう。
条件付き確率の公式
を利用すると、(1)は、
さらに変形して、
仮にP(Y=犯罪をおかす|X=ゲーム機所持)が50%であったとすると、
これは普通当てはまらないと容易に想像できる。
だからBさんが最後にゲーム機の所持率から調べなおしてというのである。
-
↩
- 作者: 平岡和幸,堀玄
- 出版社/メーカー: オーム社
- 発売日: 2009/10/20
- メディア: 単行本(ソフトカバー)
- 購入: 10人 クリック: 133回
- この商品を含むブログ (31件) を見る
power-assertとmochaを使ったnodejsのテスト
昨年decodeではじめて和田卓人さんの講演を聞いて、テスト駆動開発というものを知りとても興味が湧いた。テスト環境づくりは多くのサイトで紹介されているのだけど、自分の備忘録として環境構築手順を残しておこうと思う。もちろんアサーションツールには、power-assertを使用する。
大きな流れ
- npmで必要なモジュールのインストール
- npm scriptsでテスト実行コマンド登録
- テストコードを書く
- テスト実行
1 npmで必要なモジュールのインストール
// mochaのインストール npm install --save-dev mocha // power-assertのインストール npm install --save-dev power-assert intelli-espower-loader
2 npm scriptsでテスト実行コマンド登録
testフォルダを作成して、このフォルダをテスト対象として実行するようにnpm scriptsに記述する。
// package.json ... "scripts": { "test": "mocha --require intelli-espower-loader ./test/" }, ...
3 テストコードを書く
テスト対象のコードはただの計算クラスで、2つの引数を足したり引いたりするだけ。
class Calc { static add(x, y) { return x + y; } static sub(x, y) { return x - y; } } exports.Calc = Calc;
テストコードでは、power-assertと上記テスト対象のコードをロードして、あとはテストコードの記法通り。本筋とはずれるけど、オブジェクトの分割代入便利ですね。
const assert = require('power-assert'); const {Calc} = require('../module/Calc'); // 分割代入 describe('Calcクラス', () => { it('addメソッド', () => { assert( Calc.add(1,2) === 3 ); }); it('subメソッド', () => { assert( Calc.sub(1,2) === -1 ); }); });
4 テスト実行
あとは、npm testでテスト実行できる。
実行結果はこんな感じ
Calcクラス ✓ addメソッド ✓ subメソッド 2 passing (9ms)
疑問
- DBアクセスするコードのテストはどうすればよいのだろうか?
- テストごとにDBを初期化しテスト終了後も初期化する作業が必要なのか?
expressのルーティング共通処理
nodejsでHTTPサーバーを立てるときに利用するexpress。
色々なルーティングを記述していくと、いずれのルーティングでも共通処理を噛ませたいという気持ちになる。
共通処理というのは、セッションが切れていたときにログイン画面に戻す処理のことで、今までは下記のように個々のルーティングごとに記述するアホなことをやっていた。
app.post('/select', ( req, res ) => { // ①共通処理:セッション情報の存在判定 if ( !req.session.pass ) { res.json(440, {result:'expired', message:'セッションが切れました。ログインからやり直してください。'}); return; } // ②ルーティング固有の処理 res.header("Content-Type", "application/json; charset=utf-8"); res.json( something ); }
Nodeクックブックを読んでると、next()を使えばよいことがわかった。
// ①共通処理:セッション情報の存在判定 const checkSession = ( req, res, next) => { if ( !req.session.pass ) { res.json(440, {result:'expired', message:'セッションが切れました。ログインからやり直してください。'}); return; } next() } ; app.post('/select', checkSession, ( req, res ) => { // ②ルーティング固有の処理 res.header("Content-Type", "application/json; charset=utf-8"); res.json( something ); }
expressのpost, getなどのHTTPメソッドには、第二引数以降に複数のcallbackを指定でき、next()を使うことで順番に処理を行ってくれる。
今回では、checkSession(共通処理)がまず実行されsession状態が切れていなければ、next()により次のcallback(固有の処理)を行ってくれる。
- 作者: David Mark Clements,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/02/23
- メディア: 大型本
- 購入: 2人 クリック: 4回
- この商品を含むブログ (5件) を見る