Spring Boot + npm + Geb で入力フォームを作ってテストする ( その33 )( ESLint を導入する )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
ESLint - Pluggable JavaScript linter
https://eslint.org/愚直にESLintを導入した話
http://tech.mercari.com/entry/2017/07/31/170125eslint-config-airbnb-base
https://www.npmjs.com/package/eslint-config-airbnb-basewebpack から ESLint を使う設定
https://www.pupha.net/archives/3289/eslint-loader
https://www.npmjs.com/package/eslint-loaderESLintでReactとES2015の構文チェック(eslint-config-airbnb)
http://dackdive.hateblo.jp/entry/2016/05/13/094000ESLint - Rules
https://eslint.org/docs/rules/Can I use eslint-config-airbnb without eslint-plugin-react?
https://github.com/airbnb/javascript/issues/451ESLint dollar($) is not defined. (no-undef)
https://stackoverflow.com/questions/39510736/eslint-dollar-is-not-defined-no-undefAirbnb JavaScript Style Guide
https://github.com/airbnb/javascript
目次
- ESLint をインストールする
eslint --init
を実行する- ECMAScript 6 用の Rule を含まない
airbnb-base
→airbnb-base/legacy
に変更する - webpack から eslint が実行されるよう設定する
- 動作確認
- インデントと改行コードと文字列のクォーテーションを airbnb-base のものではなく独自ルールに変更する
- 修正を進める前に IntelliJ IDEA の ESLint の機能を有効にする
- 多めに出力されているメッセージに対応する
- jquery.autoKana.js をチェック対象から外す
- app.js を削除する
'$' is not defined
Unexpected unnamed function
All 'var' declarations must be at the top of the function scope
Expected a newline after '('
Strings must use doublequote
'errmsg' used outside of binding context
'event' is defined but never used
Missing semicolon
Unexpected use of 'location'
- 各ファイル毎の出力されているメッセージに対応する
- 最後に
手順
ESLint をインストールする
npm install --save-dev eslint
コマンドを実行してインストールします。
eslint --init
を実行する
git コマンドを実行するために使用している git-cmd.exe を起動してから ./node_modules/.bin/eslint --init
コマンドを実行します。CUI で4つ質問事項が表示されますので、下の画像の上の方に表示されている内容を回答します。
How would you like to configure ESLint?
-->Use a popular style guide
Which style guide do you want to follow?
-->Airbnb
Do you use React?
-->No
What format do you want your config file to be in?
-->JavaScript
https://eslint.org/docs/user-guide/getting-started に書かれていたコマンドが ./node_modules/.bin/eslint --init
だったので git-cmd.exe から実行しましたが、/
--> \
に変更してコマンドプロンプトから実行しても同じように動作します。
質問に回答すると npm で eslint-config-airbnb-base と eslint-plugin-import の package がインストールされて、package.json が以下のように変更され、
.......... "cssnano": "^3.10.0", "eslint": "^4.10.0", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.8.0", "http-proxy-middleware": "^0.17.4", ..........
- 以下の2行が追加されていました。
"eslint-config-airbnb-base": "^12.1.0"
"eslint-plugin-import": "^2.8.0"
プロジェクトのルート直下に以下の内容の .eslintrc.js が生成されます。
module.exports = { "extends": "airbnb-base" };
ECMAScript 6 用の Rule を含まない airbnb-base
→ airbnb-base/legacy
に変更する
node_modules/eslint-config-airbnb-base/index.js は ECMAScript 6 用の Rule が記述されている './rules/es6'
が含まれていますが、
module.exports = { extends: [ './rules/best-practices', './rules/errors', './rules/node', './rules/style', './rules/variables', './rules/es6', './rules/imports', ].map(require.resolve), parserOptions: { ecmaVersion: 2017, sourceType: 'module', ecmaFeatures: { experimentalObjectRestSpread: true, }, }, rules: { strict: 'error', }, };
'./rules/es6'
を含まない node_modules/eslint-config-airbnb-base/legacy.js というファイルもあります。
module.exports = { extends: [ './rules/best-practices', './rules/errors', './rules/node', './rules/style', './rules/variables' ].map(require.resolve), env: { browser: true, node: true, amd: false, mocha: false, jasmine: false }, rules: { 'comma-dangle': ['error', 'never'], 'prefer-numeric-literals': 'off', 'no-restricted-properties': ['error', { object: 'arguments', property: 'callee', message: 'arguments.callee is deprecated', }, { property: '__defineGetter__', message: 'Please use Object.defineProperty instead.', }, { property: '__defineSetter__', message: 'Please use Object.defineProperty instead.', }], } };
今回 ECMAScript 6 は使用していないので、legacy.js を使用するよう .eslintrc.js を以下のように変更します。
module.exports = { "extends": "airbnb-base/legacy" };
airbnb-base
→airbnb-base/legacy
に変更します。
webpack から eslint が実行されるよう設定する
npm install --save-dev eslint-loader
コマンドを実行して eslint-loader をインストールします。
webpack.config.js を以下のように変更します。
module.exports = { .......... module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: "eslint-loader" } ] }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ] };
module: { ... }
を追加します。
動作確認
npm run spingboot
コマンドを実行して webpack を実行してみると、なんか大量にメッセージが出力されました。。。
改行コードとインデントと文字列のクォーテーションで結構メッセージが表示されているようなので、まずは eslint のルールを今 js ファイルを書いているルール(4インデント+CRLF+ダブルクォーテーション)に変更できないか調べてみます。
インデントと改行コードと文字列のクォーテーションを airbnb-base のものではなく独自ルールに変更する
カスタマイズは .eslintrc.js に "rules": { ... }
で記述すればできるようなので、.eslintrc.js を以下のように変更します。
module.exports = { "extends": "airbnb-base", "rules": { // this option sets a specific tab width for your code // http://eslint.org/docs/rules/indent indent: ['error', 4, { SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1, // MemberExpression: null, FunctionDeclaration: { parameters: 1, body: 1 }, FunctionExpression: { parameters: 1, body: 1 }, CallExpression: { arguments: 1 }, ArrayExpression: 1, ObjectExpression: 1, ImportDeclaration: 1, flatTernaryExpressions: false, ignoredNodes: ['JSXElement', 'JSXElement *'] }], // disallow mixed 'LF' and 'CRLF' as linebreaks // http://eslint.org/docs/rules/linebreak-style 'linebreak-style': ['error', 'windows'], // specify whether double or single quotes should be used quotes: ['error', 'double', { avoidEscape: true }] } };
- 改行コードとインデントと文字列のクォーテーションの設定は全て node_modules/eslint-config-airbnb-base/rules/style.js の中に書かれていたので、そこからコピーして設定を変更します。
- indent の設定は 2-space indent 以外にもいろいろ設定が入っていたので、コピーして
2
→4
のみ変更します。 linebreak-style
の設定をunix
→windows
に変更します。quotes
の設定をsingle
→double
に変更します。
再度 npm run spingboot
コマンドを実行すると改行コードとインデントと文字列のクォーテーションではメッセージが出なくなりました。
修正を進める前に IntelliJ IDEA の ESLint の機能を有効にする
IntelliJ IDEA には ESLint を利用してソースコードをチェックする機能があるので、それを有効にします。
メインメニューから「File」-「Settings...」を選択します。「Settings」ダイアログを表示されるので、画面左上の検索フィールドに "eslint" と入力します。
ESLint の設定画面が表示されるので、以下の画面のように設定します。
- 「Enable」をチェックします。
- 「Node interpreter」に "node.exe" のパスを設定します。
- 「Configuration file」はデフォルトの「Automatic search」を選択したままです。
- 「Additional rules directory」「Extra eslint options」は何も設定しません。
「OK」ボタンを押してダイアログを閉じた後 js のソースコードを表示すると、以下の画像のように ESLint のチェックに引っかかった行の右側に赤線が表示され、マウスオーバーすると ESLint のメッセージが表示されます。
またエディタ上で右クリックしてコンテキストメニューを表示した後「Analyze」-「Inspect Code...」を選択し、
「Specify Inspection Scope」ダイアログが表示されたらそのまま「OK」を押すと、
画面下部に Inspection の結果が表示されます。この中に「Code quality tools」という項目があり、
展開すると ESLint のメッセージと該当箇所が表示されます。
多めに出力されているメッセージに対応する
ざっと見てまだ多めに出ているメッセージから対応します。
jquery.autoKana.js をチェック対象から外す
jquery.autoKana.js がチェックされてメッセージが出ていましたので、チェック対象から外します。webpack.config.js を以下のように変更します。
module: { rules: [ { test: /\.js$/, exclude: [ /node_modules/, /jquery.autoKana.js$/ ], loader: "eslint-loader" } ] },
- exclude に
/jquery.autoKana.js$/
を追加します。
app.js を削除する
src/main/assets/js/app.js もチェックされていましたが、このファイルは最初に作成したサンプルでもう不要なので削除します。
app.js を削除した後、webpack.config.js を以下のように変更します。
module.exports = { entry: { "js/inquiry/input01": ["./src/main/assets/js/inquiry/input01.js"], "js/inquiry/input02": ["./src/main/assets/js/inquiry/input02.js"], "js/inquiry/input03": ["./src/main/assets/js/inquiry/input03.js"], "js/inquiry/confirm": ["./src/main/assets/js/inquiry/confirm.js"] },
"js/app": ["./src/main/assets/js/app.js"]
を削除します。
'$' is not defined
ESLint dollar($) is not defined. (no-undef) を見ると "jquery": true
を定義すればチェックされないようになるようです。.eslintrc.js を以下のように変更します。
module.exports = { "extends": "airbnb-base/legacy", "env": { "jquery": true }, ..........
"env": { "jquery": true }
を追加します。
Unexpected unnamed function
無名関数は多用するので、この Rule は無効にします。.eslintrc.js を以下のように変更します。
"rules": { // require function expressions to have a name // http://eslint.org/docs/rules/func-names 'func-names': 'off',
'func-names': 'off'
を追加します。
All 'var' declarations must be at the top of the function scope
変数宣言は関数スコープ内の最初に行うこと、というメッセージのようですが、エラーが出ている原因は require("vendor/autokana/jquery.autoKana.js");
や require("jquery-ui/ui/widgets/autocomplete.js");
を上に書いているので、その下の var で宣言している部分でチェックに引っかかっているためのようです。
var より require を上にまとめておきたいので、この Rule は無効にします。.eslintrc.js を以下のように変更します。
"rules": { // requires to declare all vars on top of their containing scope 'vars-on-top': 'off',
'vars-on-top': 'off'
を追加します。
Expected a newline after '('
https://eslint.org/docs/rules/function-paren-newline を見ると、(
の後に続けて引数を記述するのではなく、一旦改行をして次の行から書くこと、というメッセージのようです。なんか縦に長くなってソースが見にくくなる気しかしないので、これは無効にします。
"rules": { .......... // require function expressions to have a name // http://eslint.org/docs/rules/func-names 'func-names': 'off', // enforce consistent line breaks inside function parentheses // https://eslint.org/docs/rules/function-paren-newline 'function-paren-newline': 'off', // this option sets a specific tab width for your code // http://eslint.org/docs/rules/indent indent: ['error', 4, {
'function-paren-newline': 'off'
を追加します。
Strings must use doublequote
文字列のクォーテーションはダブルクォーテーションを使用するルールを指定しましたが、シングルクォーテーションになっているところがありました。こちらは全てダブルクォーテーションに修正します。
'errmsg' used outside of binding context
src/main/assets/js/inquiry/input02.js で errmsg 変数を block スコープ毎に var で宣言していたので引っかかっているようです。関数の最初で var で宣言するように修正します。
'event' is defined but never used
イベントハンドラの無名関数の引数に使用している/いないに関わらず event という引数を書いていたので、そこで引っかかっているようです。使用されていない event 引数は削除します。
Missing semicolon
単純に末尾のセミコロンのつけ忘れです。修正します。
Unexpected use of 'location'
node_modules/eslint-config-airbnb-base/rules/variables.js を見ると以下のように定義されており、
const restrictedGlobals = require('eslint-restricted-globals'); module.exports = { rules: { .......... // disallow specific globals 'no-restricted-globals': ['error', 'isFinite', 'isNaN'].concat(restrictedGlobals),
node_modules/eslint-restricted-globals/index.js には以下のように定義されていました。
module.exports = [ .......... 'length', 'location', 'locationbar',
location
をグローバル変数として使用すると no-restricted-globals
の Rule に引っかかりエラーになるようです。
ソースコードを修正して対応します。location
→ window.location
に変更します。window
は node_modules/eslint-restricted-globals/index.js に定義されておらず、グローバル変数として利用しても Rule に引っかかりません。
各ファイル毎の出力されているメッセージに対応する
src/main/assets/js/inquiry/input01.js
'idList' is assigned a value but never used
は宣言した変数を関数内で使用していないことが原因なので、変数を宣言している行を削除します。'validator' is already declared in the upper scope
はソースの上で宣言しているvar validator = require("lib/util/validator.js");
と同じvalidator
という変数を使用していたので、validator
→validateFunction
に変更します。
src/main/assets/js/inquiry/input02.js
'validator' is already declared in the upper scope
は input01.js と同様にvalidator
→validateFunction
に変更します。A space is required after '{'
とA space is required before '}'
は IntelliJ IDEA のフォーマッターがスペースを入れないようになっているので、この Rule を無効に変更します。.eslintrc.js を以下のように変更します。
"rules": { .......... // require padding inside curly braces 'object-curly-spacing': ['error', 'never'] }
'event' is already declared in the upper scope
はevent
→e
に変更します。
src/main/assets/js/lib/class/Form.js
'Form' was used before it was defined
はmodule.exports = Form;
の後にfunction Form(idList) { ... }
の記述があるために出力されていますが、module.exports
の記述を先頭にしたいので .eslintrc.js にno-use-before-define
の設定を node_modules/eslint-config-airbnb-base/rules/variables.js からコピーしてfunctions: true
→functions: false
に変更します。
"rules": { .......... // disallow use of variables before they are defined 'no-use-before-define': ['error', { functions: false, classes: true, variables: true }] }
Line 21 exceeds the maximum line length of 100
は1行の最大値を 120 に変更したいので、.eslintrc.js にmax-len
の設定を node_modules/eslint-config-airbnb-base/rules/style.js からコピーして100
→120
に変更します。
"rules": { .......... // specify the maximum length of a line in your program // http://eslint.org/docs/rules/max-len 'max-len': ['error', 120, 2, { ignoreUrls: true, ignoreComments: false, ignoreRegExpLiterals: true, ignoreStrings: true, ignoreTemplateLiterals: true }] }
Assignment to property of function parameter 'form'
は関数の引数で渡された変数を変更しようとしているから出ているメッセージらしいのですが、form を引数に渡さないようにする方法が今だによく分かっていないので、ソースの先頭に/* eslint-disable no-param-reassign,lines-around-directive */
を記述して Form.js だけこの Rule を無効にします。
src/main/assets/js/lib/util/converter.js
Multiple spaces found before ...
はソースの右側にスペース複数を入れてからコメントを書いていたためでした。コメントは移動してコメントだけの行になるようにします。
以上で全ての対応が完了です。
最後に
動きはしていたので今回はリンターを導入してもそんなに指摘は受けないかな、と思っていましたが、いつものように結構エラーが出ました。。。 ESLint は eslint-config-airbnb や eslint-config-airbnb-base といった使える設定が公開されているし、導入例の記事もいろいろ公開されていたので導入しやすかったです。また Airbnb JavaScript Style Guide は有名なようなので、普段 Javascript を実装しない自分としては読んでおきたいと思います。
また今回の調査をしていた時に prettier という Javascript のフォーマッターの記事を見かけました。Using External tools: ESLint autofix, React Native and Prettier を見ると IntelliJ IDEA でもサポートされているようなので、時間があれば見てみたいと思います。
最後に .eslintrc.js の最終版を載せておきます。
module.exports = { "extends": "airbnb-base/legacy", "env": { "browser": true, "jquery": true }, "rules": { // requires to declare all vars on top of their containing scope 'vars-on-top': 'off', // require function expressions to have a name // http://eslint.org/docs/rules/func-names 'func-names': 'off', // enforce consistent line breaks inside function parentheses // https://eslint.org/docs/rules/function-paren-newline 'function-paren-newline': 'off', // this option sets a specific tab width for your code // http://eslint.org/docs/rules/indent indent: ['error', 4, { SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1, // MemberExpression: null, FunctionDeclaration: { parameters: 1, body: 1 }, FunctionExpression: { parameters: 1, body: 1 }, CallExpression: { arguments: 1 }, ArrayExpression: 1, ObjectExpression: 1, ImportDeclaration: 1, flatTernaryExpressions: false, ignoredNodes: ['JSXElement', 'JSXElement *'] }], // disallow mixed 'LF' and 'CRLF' as linebreaks // http://eslint.org/docs/rules/linebreak-style 'linebreak-style': ['error', 'windows'], // specify whether double or single quotes should be used quotes: ['error', 'double', { avoidEscape: true }], // require padding inside curly braces 'object-curly-spacing': ['error', 'never'], // disallow use of variables before they are defined 'no-use-before-define': ['error', { functions: false, classes: true, variables: true }], // specify the maximum length of a line in your program // http://eslint.org/docs/rules/max-len 'max-len': ['error', 120, 2, { ignoreUrls: true, ignoreComments: false, ignoreRegExpLiterals: true, ignoreStrings: true, ignoreTemplateLiterals: true }] } };
履歴
2017/11/05
初版発行。
2017/11/06
* "browser": true,
は node_modules/eslint-config-airbnb-base/legacy.js で設定済なので削除しました。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( 番外編 )( webpack で jQuery だけバンドルしないで外部ファイルを利用するには? )
概要
記事一覧はこちらです。
既存のページで既に jQuery を使用しており、そこに webpack でバンドルした js ファイルを導入したい場合に、jQuery だけバンドルしないで外部ファイルの jQuery を利用する方法が知りたくなったので調べてみます。
参照したサイト・書籍
webpackでCDNから取ってきたりした外部のjQueryなどを利用する方法
http://frontend-takuyan.hateblo.jp/entry/jquery-in-webpackwebpack - Externals
https://webpack.js.org/configuration/externals/
目次
本文
webpack.config.js を変更する
webpackでCDNから取ってきたりした外部のjQueryなどを利用する方法 の記事にずばりその通りの内容が記載されていました。webpack.config.js に以下の記述を追加すればいいそうです。
var webpack = require('webpack'); module.exports = { entry: { "js/app": ["./src/main/assets/js/app.js"], "js/inquiry/input01": ["./src/main/assets/js/inquiry/input01.js"], "js/inquiry/input02": ["./src/main/assets/js/inquiry/input02.js"], "js/inquiry/input03": ["./src/main/assets/js/inquiry/input03.js"], "js/inquiry/confirm": ["./src/main/assets/js/inquiry/confirm.js"] }, output: { path: __dirname + "/src/main/resources/static", publicPath: "/", filename: "[name].js" }, resolve: { modules: [ "node_modules", "src/main/assets/js" ], alias: { jquery: "jquery" } }, externals: { jquery: "jQuery" }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ] };
externals: { jquery: "jQuery" }
を追加します。ただし"jquery"
ではなく、必ず"jQuery"
と記述する必要があります。"jquery"
だと正常に動作しませんでした。
動作確認
src/main/resources/static/vendor の下に node_modules/jquery/dist/jquery.min.js をコピーします。
src/main/resources/templates/web/inquiry/input01.html, input02.html を以下のように変更します。
<!-- REQUIRED JS SCRIPTS --> <script src="/vendor/jquery.min.js"></script> <script src="/js/inquiry/input01.js"></script> </body> </html>
- 各画面用の js ファイルの上に
<script src="/vendor/jquery.min.js"></script>
を追加します。
コマンドプロンプトを起動して npm run springboot
コマンドを実行し、Tomcat も起動します。
http://localhost:9080/inquiry/input/01/ にアクセスすると入力画面1が表示されます。
「次へ」ボタンをクリックすると入力チェックのエラーメッセージが表示されます。Javascript の処理が問題なく動作していますね。
autokana も動作しており、またデータを全て入力すると入力チェックOKの状態になります。
「次へ」ボタンをクリックして入力画面2へ遷移した後、郵便番号を入力すると、ajax でデータを取得して autocomplete で住所の選択肢も表示されます。
動作も問題なさそうです。
履歴
2017/11/03
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その32 )( npm の admin-lte package から jQuery がなくなっていたので対応する )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
目次
手順
git clone から動作させようとしてエラーが出るところまでやってみる
git clone する
C:\project-test フォルダを作成して、この下に git clone します。
コマンドプロンプトを起動して C:\project-test フォルダに移動した後、git clone -b feature/1-issue https://github.com/ksby/ksbysample-boot-miscellaneous.git
コマンドを実行します。
C:\project-test の下に ksbysample-boot-miscellaneous フォルダが作成され、その下に boot-npm-geb-sample プロジェクトが出来ます。
IntelliJ IDEA で boot-npm-geb-sample プロジェクトを開く
IntelliJ IDEA の「Welcome to IntelliJ IDEA」ダイアログを表示した後、「Open」ボタンをクリックします。
「Open File or Project」ダイアログが表示されますので、C:\project-test\ksbysample-boot-miscellaneous\boot-npm-geb-sample フォルダを選択して「OK」ボタンをクリックします。
「Import Project from Gradle」ダイアログが表示されますので、「Create directories for empty content roots automatically」をチェックした後「OK」ボタンをクリックします。
IntelliJ IDEA のメイン画面が開きますので、画面右下の処理中を示すプログレスバーが消えるまで待ちます。
処理が終了すると画面右側の Gradle projects が下の画像のようになります。
npm install コマンドを実行する
コマンドプロンプトで C:\project-test\ksbysample-boot-miscellaneous\boot-npm-geb-sample へ移動した後、npm install
コマンドを実行します。
次に npm run springboot
コマンドを実行します。。。が、Module not found: Error: Can't resolve 'admin-lte/plugins/jQuery/jquery-2.2.3.min.js' in ...
というエラーメッセージが出力されました。なぜか jquery のファイルがないようです。。。
clean タスク → Rebuild Project → build タスクを実行する
IntelliJ IDEA から clean タスク → Rebuild Project → build タスクを実行してみると、こちらは BUILD SUCCESSFUL のメッセージが出力されて正常に終了しました。
エラーの原因を修正する
以前は node_modules/admin-lte/plugins/jQuery/jquery-2.2.3.min.js というファイルが存在したのですが、node_modules/admin-lte/plugins の下を見ると jQuery フォルダ自体がなくなっていました。。。 admin-lte は jQuery を同梱しなくなったんですね。
ということであれば普通に npm で jQuery をインストールして、そちらを使うように変更します。
まずは npm install --save jquery
コマンドを実行して jQuery をインストールします。
次に webpack.config.js を以下のように変更します。
var webpack = require('webpack'); module.exports = { entry: { "js/app": ["./src/main/assets/js/app.js"], "js/inquiry/input01": ["./src/main/assets/js/inquiry/input01.js"], "js/inquiry/input02": ["./src/main/assets/js/inquiry/input02.js"], "js/inquiry/input03": ["./src/main/assets/js/inquiry/input03.js"], "js/inquiry/confirm": ["./src/main/assets/js/inquiry/confirm.js"] }, output: { path: __dirname + "/src/main/resources/static", publicPath: "/", filename: "[name].js" }, resolve: { modules: [ "node_modules", "src/main/assets/js" ], alias: { jquery: "jquery" } }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ] };
"admin-lte/plugins/jQuery/jquery-2.2.3.min.js"
→"jquery"
に変更します(全部で3ヶ所)。
これで変更は完了です。再び npm run springboot
コマンドを実行してみると、今度はエラーメッセージは出ませんでした(下の方に白い文字で出ているメッセージは Tomcat が起動していないことによるものです)。
Tomcat を起動して。。。と思ったら spring.profiles.active を指定していないことによるエラーが出ました。
IntelliJ IDEA のメインメニューから「Run」-「Edit Configurations...」を選択し、「Run/Debug Configurations」ダイアログが表示されたら、画面左側の一覧から「Spring Boot」-「Application」を選択して、画面右側の「VM options」に -Dspring.profiles.active=develop -Dfile.encoding=UTF-8
を入力後「OK」ボタンをクリックします。
再度 Tomcat を起動したら、今度は問題なく起動しました。
ブラウザで http://localhost:9080/inquiry/input/01/ にアクセスすると入力画面1も表示されます。
何も入力せずに「次へ」ボタンを押すと入力エラーのある入力項目にエラーメッセージが表示されますので、Javascript も正常に動作しているようです。
ちょっとつまずきましたが、以前と比較すると試せるようになるまで全然簡単になりました。Edit Configuration の設定も何か簡単に出来る方法があるといいのですが。。。と思い Web で検索すると以下の記事を見つけました。これまで使用したことがありませんでしたが、share チェックボックスをチェックすればよいようです。そのうち試してみたいと思います。
How do I share IntelliJ Run/Debug configurations between projects? https://stackoverflow.com/questions/24642147/how-do-i-share-intellij-run-debug-configurations-between-projects
履歴
2017/11/01
初版発行。
Java SE を 8u144 → 8u152 へバージョンアップ
※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。
Java SE を 8u144 → 8u152 へバージョンアップする
Oracle の Java SE Downloads を見ると 8u152 がダウンロードできるようになっていました。以下のページに説明があります。
- [Java] Updates for Java SE Platform
https://orablogs-jp.blogspot.jp/2017/10/updates-for-java-se-platform.html
8u152 へバージョンアップします。
- [Java] Updates for Java SE Platform
jdk-8u152-windows-x64.exe をダウンロードして C:\Java\jdk1.8.0_152 へインストールした後、環境変数 JAVA_HOME のパスを C:\Java\jdk1.8.0_152 へ変更します。
コマンドプロンプトから
java -version
を実行し、1.8.0_152
に変更されていることを確認します。開いているプロジェクトを閉じて「Welcome to IntelliJ IDEA」ダイアログを表示します。
ダイアログ下部の「Configure」-「Project Defaults」-「Project Structure」を選択します。
「Default Project Structure」ダイアログが表示されます。画面左側で「Project Settings」-「Project」を選択後、画面右側の「Project SDK」の「New...」ボタンをクリックし、表示されるメニューから「JDK」を選択します。
「Select Home Directory for JDK」ダイアログが表示されます。C:\Java\jdk1.8.0_152 を選択した後、「OK」ボタンをクリックします。
「Default Project Structure」ダイアログに戻るので、今度は「Project SDK」の「Edit」ボタンをクリックします。
画面左側で「Platform Settings」-「SDKs」が選択された状態になるので、画面右上の入力フィールドで "1.8" → "1.8.0_152" へ変更します。
次に中央のリストから「1.8.0_144」を選択した後、リストの上の「-」ボタンをクリックして削除します。
「OK」ボタンをクリックして「Default Project Structure」ダイアログを閉じます。
「Welcome to IntelliJ IDEA」ダイアログに戻ったら、ksbysample-webapp-lending プロジェクトを開きます。
IntelliJ IDEA のメイン画面が開いたら、メニューから「File」-「Project Structure...」を選択します。
「Project Structure」ダイアログが表示されます。以下の画像の状態になっているので、
「Project SDK」と「Project language level」を選択し直します。
「OK」ボタンをクリックして「Project Structure」ダイアログを閉じます。
メイン画面に戻ると画面右下に「Indexing...」の表示が出るので、終了するまで待ちます。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。
Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run ‘All Tests’ with Coverage」を選択し、テストが全て成功することを確認します。
特に問題は発生しませんでした。8u152 で開発を進めます。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その31 )( テスト対象のブラウザに Headless Chrome と HtmlUnit を追加する+Chrome, Firefox, HtmlUnit で連続テストする gradle タスクを作成する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その30 )( Geb を 2.0 へバージョンアップする+Firefox headless モードを使用する ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
ヘッドレス Chrome ことはじめ
https://developers.google.com/web/updates/2017/04/headless-chrome?hl=jaHeadless Chrome and Selenium on Windows?
https://stackoverflow.com/questions/43880619/headless-chrome-and-selenium-on-windowsSeleniumHQ/htmlunit-driver
https://github.com/SeleniumHQ/htmlunit-driverWhere to find 64 bit version of chromedriver.exe for Selenium WebDriver?
https://stackoverflow.com/questions/23081507/where-to-find-64-bit-version-of-chromedriver-exe-for-selenium-webdriver【入門】Geb+SpockではじめるWebテスト~クロスブラウザテスト編~ / Setting up and running of the cross-browser test
http://yfj2.hateblo.jp/entry/2014/11/09/004011ChromeDriver - WebDriver for Chrome
https://sites.google.com/a/chromium.org/chromedriver/geb/geb-example-gradle/build.gradle
https://github.com/geb/geb-example-gradle/blob/master/build.gradle
目次
- Chrome と HtmlUnit 用の Selenium WebDriver をインストールする
- ChromeDriver をダウンロードして配置する
- GebConfig.groovy を修正する
- build.gradle にタスクを定義する
- 動作確認
手順
Chrome と HtmlUnit 用の Selenium WebDriver をインストールする
build.gradle を以下のように変更します。
dependencies { .......... // for Geb + Spock testCompile("org.gebish:geb-spock:2.0") testCompile("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}") testCompile("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}") testCompile("org.seleniumhq.selenium:htmlunit-driver:2.27") testCompile("org.seleniumhq.selenium:selenium-support:${seleniumVersion}") testCompile("org.seleniumhq.selenium:selenium-api:${seleniumVersion}") testCompile("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}") }
- 以下の行を追加します。
testCompile("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}")
testCompile("org.seleniumhq.selenium:htmlunit-driver:2.27")
- HtmlUnit 用の WebDriver として selenium-htmlunit-driver がありますが、https://mvnrepository.com/ で selenium-htmlunit-driver を見てみると最新バージョンが 2016/2 にリリースされた 2.52.0 で、3.x 系がリリースされていませんでした。さすがに 3.6.0 と組み合わせるのは無理だろうと思い Web で探してみると、WebDriver compatible を謳っている htmlunit-driver が見つかり、こちらは 2017/6 に 2.27 がリリースされていましたので、htmlunit-driver をインストールすることにします。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
ChromeDriver をダウンロードして配置する
Chrome を操作するためには Firefox の geckodriver と同じように ChromeDriver が必要です。ダウンロードして配置します。
ChromeDrive の Downloads ページ の Latest Release の右側に表示されている「ChromeDriver 2.33」リンクをクリックして次のページへ進んだ後、「chromedriver_win32.zip」リンクをクリックして chromedriver_win32.zip をダウンロードします。64bit版は提供されていませんが、chromedriver_win32.zip のファイルで 64bit の Windows + Chrome でも問題なく動作します。
ダウンロード後、C:\chromedriver\2.33 ディレクトリを作成した後、chromedriver_win32.zip を解凍して出来る chromedriver.exe をその下に配置します。
GebConfig.groovy を修正する
src/test/resources/GebConfig.groovy を以下のように変更します。
import org.openqa.selenium.chrome.ChromeDriver import org.openqa.selenium.chrome.ChromeOptions import org.openqa.selenium.firefox.FirefoxDriver import org.openqa.selenium.firefox.FirefoxOptions import org.openqa.selenium.htmlunit.HtmlUnitDriver System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.33/chromedriver.exe") driver = { FirefoxOptions firefoxOptions = new FirefoxOptions() firefoxOptions.setHeadless(true) new FirefoxDriver(firefoxOptions) } baseUrl = "http://localhost:8080" waiting { timeout = 15 } environments { chrome { driver = { ChromeOptions chromeOptions = new ChromeOptions() chromeOptions.setHeadless(true) new ChromeDriver(chromeOptions) } } firefox { driver = { FirefoxOptions firefoxOptions = new FirefoxOptions() firefoxOptions.setHeadless(true) new FirefoxDriver(firefoxOptions) } } htmlunit { new HtmlUnitDriver(true) } }
System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat")
をdriver
の中に書いていたのを外に出します。System.setProperty("webdriver.chrome.driver", "C:/chromedriver/2.33/chromedriver.exe")
を追加します。environments { ... }
の定義を追加し、この中に chrome, firefox, htmlunit の driver の定義を記述します。
build.gradle にタスクを定義する
build.gradle に各ブラウザ毎のテスト用タスクと、全てのブラウザのテスト用タスクを連続実行するためのタスクを追加します。このタスクは geb/geb-example-gradle/build.gradle からコピーしました。
.......... test { // test タスクの jvmArgs は tasks.withType(Test) { ... } で定義している exclude "geb/**" } // for Geb + Spock Integration Test def drivers = ["chrome", "firefox", "htmlunit"] drivers.each { driver -> task "${driver}Test"(type: Test) { // 前回実行時以降に何も更新されていなくても必ず実行する outputs.upToDateWhen { false } systemProperty "geb.env", driver exclude "ksbysample/**" } } task gebTest { dependsOn drivers.collect { tasks["${it}Test"] } enabled = false } tasks.withType(Test) { jvmArgs = ['-Dspring.profiles.active=unittest'] } // for Doma-Gen task domaGen { ..........
- test タスクから
jvmArgs = ['-Dspring.profiles.active=unittest']
を削除します。 - 記述していた
task gebTest(type: Test) { ... }
を削除します。 // for Geb + Spock Integration Test
から下の部分を記述します。リストからタスクを動的に作成したり、動的に作成されたタスクを依存関係に指定する方法があるとは、初めて知りました。。。tasks.withType(Test) { ... }
を追加し、Test タイプのタスク共通の設定はこちらに記述します。今回はjvmArgs
のみ記述します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
更新すると Gradle projects の other の下に chromeTest
, firefoxTest
, gebTest
, htmlunitTest
の4つのタスクが表示されます。
動作確認
最初に clean タスク → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL のメッセージが出力されることを確認します。追加した chromeTest
, firefoxTest
, gebTest
, htmlunitTest
のタスクが実行されていないことも確認できます。
chromeTest タスクを実行します。ブラウザの画面が表示されず、テストは成功します。また ChromeDriver のメッセージが出力されており、Chrome がテストに使われていることが分かります。
firefoxTest タスクを実行します。こちらもブラウザの画面は表示されず、テストは成功します。
htmlunitTest タスクを実行します。HtmlUnit はブラウザではないので当然画面は表示されず、テストは成功します。
最後に gebTest タスクを実行します。chromeTest
, firefoxTest
, htmlunitTest
の3つのタスクが実行されてそれぞれ成功し、gebTest
タスクは build.gradle 内で enabled = false
を記述しているので SKIP されることが確認できます。
ちなみに src/test/groovy/geb/gebspec/SimpleTestSpec.groovy をテストが失敗するように変更してから、
class SimpleTestSpec extends GebSpec { def "動作確認用"() { .......... then: "「お名前(漢字)」の必須チェックエラーのメッセージが表示される" $("#form-group-name .js-errmsg").displayed == true // $("#form-group-name .js-errmsg").text() == "お名前(漢字)を入力してください" $("#form-group-name .js-errmsg").text() == "エラーです" } }
gebTest タスクを実行すると chromeTest タスクでエラーが出て先に進みません。
履歴
2017/10/29
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その30 )( Geb を 2.0 へバージョンアップする+Firefox headless モードを使用する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その29 )( Geb をインストールする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
Geb - Very Groovy Browser Automation
http://www.gebish.org/Headless mode
https://developer.mozilla.org/en-US/Firefox/Headless_modeDisable HttpClient logging
https://stackoverflow.com/questions/4915414/disable-httpclient-loggingHow do I disable Firefox logging in Selenium using Geckodriver?
https://stackoverflow.com/questions/41387794/how-do-i-disable-firefox-logging-in-selenium-using-geckodriver
目次
- Geb を 2.0-rc-1 → 2.0 へバージョンアップする
- geckodriver.exe の場所は
System.setProperty("webdriver.gecko.driver", "...")
で指定する - Firefox headless モードを使用する
手順
Geb を 2.0-rc-1 → 2.0 へバージョンアップする
build.gradle の以下の点を変更します。
dependencies { .......... def seleniumVersion = "3.6.0" .......... // for Geb + Spock testCompile("org.gebish:geb-spock:2.0") testCompile("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}") testCompile("org.seleniumhq.selenium:selenium-support:${seleniumVersion}") testCompile("org.seleniumhq.selenium:selenium-api:${seleniumVersion}") testCompile("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}") }
- org.gebish:geb-spock のバージョン番号を
2.0-rc-1
→2.0
に変更します。 def seleniumVersion = "3.6.0"
を追加し、selenium のモジュールのバージョン番号を${seleniumVersion}
で指定するよう変更します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
Tomcat を起動した後、test, gebTest タスクを実行して問題ないことを確認します(画面キャプチャは省略します)。この後もテストを繰り返すので Tomcat は起動したままにします。
geckodriver.exe の場所は System.setProperty("webdriver.gecko.driver", "...")
で指定する
前回の記事では geckordriver.exe を build.gradle の gebTest タスクと、IntelliJ IDEA の「Run」-「Edit Configurations...」メニューで開いた先の JUnit の設定のところに記述しましたが、GebConfig.groovy に System.setProperty("webdriver.gecko.driver", "...")
で定義すれば利用可能になることが分かったので、設定を変更します。
src/test/resources/GebConfig.groovy を以下のように変更します。
import org.openqa.selenium.firefox.FirefoxDriver driver = { System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.exe") new FirefoxDriver() } baseUrl = "http://localhost:8080" waiting { timeout = 15 }
build.gradle の gebTest を以下のように変更します。
test { jvmArgs = ['-Dspring.profiles.active=unittest'] exclude "geb/**" } task gebTest(type: Test) { jvmArgs = ['-Dspring.profiles.active=unittest'] exclude "ksbysample/**" }
- jvmArgs の指定を
'-Dwebdriver.gecko.driver=C:/geckodriver/0.19.0/geckodriver.exe'
を削除して test タスクと同じにします。
IntelliJ IDEA のメインメニューから「Run」-「Edit Configurations...」を選択して「Run/Debug Configurations」ダイアログを表示した後、「JUnit」の「VM Options」から -Dwebdriver.gecko.driver=C:/geckodriver/0.19.0/geckodriver.exe
を削除します。
動作確認します。
最初に clean タスク → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL のメッセージが出力されることを確認します(画面キャプチャは省略します)。
次に gebTest タスクを実行すると Firefox が起動し、テストは成功します。
最後に src/test/groovy/geb/gebspec/SimpleTestSpec.groovy を開き、左側のアイコンから Run '動作確認用()'
を選択します。
こちらも Firefox が起動し、テストは成功します。
Firefox headless モードを使用する
Firefox に headless モードが実装されているらしいので、そちらを使うように設定してみます。
GebConfig.groovy を変更する
src/test/resources/GebConfig.groovy を以下のように変更します。
import org.openqa.selenium.firefox.FirefoxDriver import org.openqa.selenium.firefox.FirefoxOptions driver = { System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.exe") FirefoxOptions firefoxOptions = new FirefoxOptions() firefoxOptions.setHeadless(true) new FirefoxDriver(firefoxOptions) } baseUrl = "http://localhost:8080" waiting { timeout = 15 }
- 以下の2行を追加します。
FirefoxOptions firefoxOptions = new FirefoxOptions()
firefoxOptions.setHeadless(true)
new FirefoxDriver()
の引数にfirefoxOptions
を追加します。
動作確認
動作確認します。
最初に clean タスク → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL のメッセージが出力されることを確認します(画面キャプチャは省略します)。
次に gebTest タスクを実行してみると Firefox の画面は表示されず、テストは成功します。ただし DEBUG ログが大量に出ます。。。 これは出来れば出ないようにしたいですね。
DEBUG メッセージに対応する前に、うまく動いているのかちょっと分かりづらいので、テストの内容を少し変更してみます。
src/test/groovy/geb/page/inquiry/InquiryInput01Page.groovy を以下のように変更します。
package geb.page.inquiry import geb.Page class InquiryInput01Page extends Page { static url = "/inquiry/input/01" static at = { title == "入力フォーム - 入力画面1" } static content = { btnNext { $(".js-btn-next") } } }
static content { ... }
を追加し、その中にbtnNext { $(".js-btn-next") }
を記述します。
src/test/groovy/geb/gebspec/SimpleTestSpec.groovy を以下のように変更し、最後でテストが失敗するようにします。
package geb.gebspec import geb.page.inquiry.InquiryInput01Page import geb.spock.GebSpec class SimpleTestSpec extends GebSpec { def "動作確認用"() { given: "入力画面1へアクセスする" to InquiryInput01Page waitFor { at InquiryInput01Page } $("#form-group-name .js-errmsg").displayed == false when: "何も入力せずに「次へ」ボタンをクリックする" btnNext.click(InquiryInput01Page) then: "「お名前(漢字)」の必須チェックエラーのメッセージが表示される" $("#form-group-name .js-errmsg").displayed == true // $("#form-group-name .js-errmsg").text() == "お名前(漢字)を入力してください" $("#form-group-name .js-errmsg").text() == "エラーです" } }
gebTest タスクを実行してみると今度はエラーになりました。Spock はエラーメッセージが分かりやすくていいですね。
src/test/groovy/geb/gebspec/SimpleTestSpec.groovy を以下のように変更し、今度は成功するようにします。
package geb.gebspec import geb.page.inquiry.InquiryInput01Page import geb.spock.GebSpec class SimpleTestSpec extends GebSpec { def "動作確認用"() { given: "入力画面1へアクセスする" to InquiryInput01Page waitFor { at InquiryInput01Page } $("#form-group-name .js-errmsg").displayed == false when: "何も入力せずに「次へ」ボタンをクリックする" btnNext.click(InquiryInput01Page) then: "「お名前(漢字)」の必須チェックエラーのメッセージが表示される" $("#form-group-name .js-errmsg").displayed == true $("#form-group-name .js-errmsg").text() == "お名前(漢字)を入力してください" // $("#form-group-name .js-errmsg").text() == "エラーです" } }
gebTest タスクを実行してみると今度は成功します。headless モードでも問題なく動いているようです。
大量に出力される DEBUG ログ [Forwarding ... on session ... to remote] DEBUG org.apache.http
を抑制する
何か情報がないか Google で検索すると、stackoverflow の以下の QA を見つけました。
これを読むと logback.xml があれば抑制できるようです。
src/test/resources の下に logback.xml を新規作成し、以下の内容を記述します。色々試してみたところ <logger .../>
の定義がなくても logback.xml があれば DEBUG ログを抑制できるようです。
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- Geb+Spock で Firefox を headless モードで動かした時に大量に以下の DEBUG ログ が出力されるのを抑制するために作成しているファイルである。ファイルがあればログを抑 制できるので、特に logger の定義は記述していない。 [Forwarding ... on session ... to remote] DEBUG org.apache.http --> </configuration>
gebTest タスクを実行してみると [Forwarding ... on session ... to remote] DEBUG org.apache.http
の DEBUG メッセージは出力されました。ただし、まだ Marionette DEBUG
というログが出力されています。
Marionette DEBUG
のログを抑制する
Google で検索していろいろ見たのですが、stackoverflow の以下の QA を見て解決しました。
geckodriver.exe を配置した C:\geckodriver\0.19.0 の下に geckodriver.bat を新規作成し、以下の内容を記述します。
@echo off C:\geckodriver\0.19.0\geckodriver.exe --log info %* > NUL 2>&1
src/test/groovy/GebConfig.groovy を以下のように変更します。
import org.openqa.selenium.firefox.FirefoxDriver import org.openqa.selenium.firefox.FirefoxOptions driver = { System.setProperty("webdriver.gecko.driver", "C:/geckodriver/0.19.0/geckodriver.bat") FirefoxOptions firefoxOptions = new FirefoxOptions() firefoxOptions.setHeadless(true) new FirefoxDriver(firefoxOptions) } baseUrl = "http://localhost:8080" waiting { timeout = 15 }
System.setProperty("webdriver.gecko.driver", "...")
の第2引数に設定していたプログラム名をC:/geckodriver/0.19.0/geckodriver.exe
→C:/geckodriver/0.19.0/geckodriver.bat
に変更します。
gebTest タスクを実行すると Marionette DEBUG
のログは全く出力されなくなりました。
履歴
2017/10/28
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その29 )( Geb をインストールする )
概要
記事一覧はこちらです。
参照したサイト・書籍
Geb - Very Groovy Browser Automation
http://www.gebish.org/Web画面自動テストフレームワーク「Geb」の紹介
http://lab.astamuse.co.jp/entry/geb_test_01Geb with spock
https://www.slideshare.net/MonikaGurram/geb-with-spock-24710923mozilla/geckodriver
https://github.com/mozilla/geckodriverGradle – How to exclude some tests
https://www.mkyong.com/gradle/gradle-how-to-exclude-some-tests/Getting Started With Gradle: Integration Testing
https://www.petrikainulainen.net/programming/gradle/getting-started-with-gradle-integration-testing/Spring Boot and Gradle: Separating tests
https://moelholm.com/2016/10/22/spring-boot-separating-tests/
目次
- 方針
- Geb に必要なモジュールをインストールする
- GebConfig.groovy を作成する
- テスト用のパッケージを作成する
- 入力画面1の Page Objects を作成する
- 簡単なテストを作成する
- geckodriver をインストールする
- gebTest タスクを作成する
- 動作確認
- IntelliJ IDEA 上からテストを実行できるようにする
手順
方針
- テストは Geb + Spock の組み合わせで作成します。geb-core ではなく geb-spock を指定してインストールします。
- ブラウザは Firefox を利用します。今回テストを作成している時にインストールしている Firefox のバージョンは 56.0.2 (64ビット) です。
- Geb は現時点で最新の 2.0-rc-1、selenium は 3.6.0 をインストールします。
- Geb のテストは src/test/groovy/geb の下に作成します。src の下に main, test とは別にディレクトリは作成しません。
src/test/groovy ├ geb │ ├ gebspec │ └ page └ ksbysample └ webapp └ bootnpmgeb
Geb に必要なモジュールをインストールする
Geb + Spock でテストを作成するために必要なモジュールをインストールします。1.5. Installation & usage を参考に、build.gradle の dependencies に以下の3行を追加します。
dependencies { .......... // for Geb + Spock testCompile("org.gebish:geb-spock:2.0-rc-1") testCompile("org.seleniumhq.selenium:selenium-firefox-driver:3.6.0") testCompile("org.seleniumhq.selenium:selenium-support:3.6.0") }
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
GebConfig.groovy を作成する
共通の設定を記述するための GebConfig.groovy を src/test/resources の下に作成します。ファイルを作成した後、7. Configuration を参考に以下のように記述します。
driver = "firefox" baseUrl = "http://localhost:8080" waiting { timeout = 15 }
テスト用のパッケージを作成する
src/test/groovy の下に geb パッケージを作成し、geb の下に gebspec, page パッケージを作成します。
入力画面1の Page Objects を作成する
src/test/groovy/geb/page の下に inquiry パッケージを作成した後、inquiry の下に InquiryInput01Page.groovy を作成して以下の内容を記述します。
package geb.page.inquiry import geb.Page class InquiryInput01Page extends Page { static url = "/inquiry/input/01" static at = { title == "入力フォーム - 入力画面1" } }
簡単なテストを作成する
動作確認のために簡単なテストを作成します。src/test/groovy/geb/gebspec の下に SimpleTestSpec.groovy を作成して以下の内容を記述します。
package geb.gebspec import geb.page.inquiry.InquiryInput01Page import geb.spock.GebSpec class SimpleTestSpec extends GebSpec { def "動作確認用"() { expect: "入力画面1へアクセスする" to InquiryInput01Page waitFor { at InquiryInput01Page } } }
geckodriver をインストールする
Web画面自動テストフレームワーク「Geb」の紹介 の記事によると Firefox の 47.0以降 から geckodriver を gradle でのダウンロードとは別にインストールする必要があるとのことですので、ダウンロード&インストールします。
https://github.com/mozilla/geckodriver/releases を見ると最新バージョンは v0.19.0 です。下にある geckodriver-v0.19.0-win64.zip のリンクをクリックしてダウンロードします。
ダウンロードした geckodriver-v0.19.0-win64.zip を解凍すると geckodriver.exe が出来ますので、C:\geckodriver\0.19.0 の下に配置します。
gebTest タスクを作成する
build.gradle に gebTest タスクを追加します。また test タスクで ksbysample パッケージ配下のテストが実行されないようにします。
test { jvmArgs = ['-Dspring.profiles.active=unittest'] exclude "geb/**" } task gebTest(type: Test) { jvmArgs = [ '-Dspring.profiles.active=unittest' , '-Dwebdriver.gecko.driver=C:/geckodriver/0.19.0/geckodriver.exe' ] exclude "ksbysample/**" }
- test タスクに
exclude "geb/**"
を追加します。 - gebTest タスクを追加します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして反映します。
動作確認
Tomcat を起動した後、gebTest タスクを実行してみます。。。が、java.lang.ClassNotFoundException: org.openqa.selenium.MutableCapabilities
というエラーメッセージが出て失敗しました。
モジュールを見てみると selenium 関連で4つ表示されているのですが、selenium-api と selenium-remote-driver が 2.53.1 と古いバージョンになっています。全て 3.6.0 になるよう調整します。
build.gradle を以下のように変更します。
dependencies { .......... // for Geb + Spock testCompile("org.gebish:geb-spock:2.0-rc-1") testCompile("org.seleniumhq.selenium:selenium-firefox-driver:3.6.0") testCompile("org.seleniumhq.selenium:selenium-support:3.6.0") testCompile("org.seleniumhq.selenium:selenium-api:3.6.0") testCompile("org.seleniumhq.selenium:selenium-remote-driver:3.6.0") }
- 以下の2行を追加します。
testCompile("org.seleniumhq.selenium:selenium-api:3.6.0")
testCompile("org.seleniumhq.selenium:selenium-remote-driver:3.6.0")
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、今度は全て 3.6.0 になりました。
再度 getTest タスクを実行すると、今度は Firefox が起動して入力画面1にアクセスし、テストが成功しました。
Tomcat を停止した後、clean タスク → Rebuild Project → build タスクを実行すると BUILD SUCCESSFUL のメッセージが出力されました。test タスク中に Firefox は起動しなかったので、Geb で作成したテストは実行されませんでした。
IntelliJ IDEA 上からテストを実行できるようにする
今の設定だけでは IntelliJ IDEA のエディタの左側のメニューから Run 動作確認用()
を選択してもテストを実行できません。
Caused by: java.lang.IllegalStateException: The path to the driver executable must be set by the webdriver.gecko.driver system property; for more information, see https://github.com/mozilla/geckodriver. The latest version can be downloaded from https://github.com/mozilla/geckodriver/releases
というエラーメッセージが出力されます。
IntelliJ IDEA のメインメニューから「Run」-「Edit Configurations...」を選択して「Run/Debug Configurations」ダイアログを表示した後、「JUnit」の「VM Options」に -Dwebdriver.gecko.driver=C:/geckodriver/0.19.0/geckodriver.exe
を追加します。
再度 Run 動作確認用()
を選択してテストを実行すると Firefox が起動して入力画面1にアクセスし、テストが成功しました。
履歴
2017/10/27
初版発行。