Spring Boot + npm + Geb で入力フォームを作ってテストする ( その70 )( 完了画面を作成する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その69 )( 再び eslint-config-airbnb-base をインストールする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Geb のテストを作成するつもりでしたが、完了画面で「入力画面へ」ボタンをクリックして入力画面1へ戻った時にデータがクリアされていないことに気づきましたので、完了画面の処理を実装します。
参照したサイト・書籍
目次
手順
InquiryCompleteController クラスを変更する
完了画面が表示された時にセッションのデータをクリアするようにします。src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryCompleteController.java の以下の点を変更します。
package ksbysample.webapp.bootnpmgeb.web.inquiry; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; /** * 完了画面用 Controller クラス */ @Controller @RequestMapping("/inquiry/complete") public class InquiryCompleteController { private static final String TEMPLATE_BASE = "web/inquiry"; private static final String TEMPLATE_COMPLETE = TEMPLATE_BASE + "/complete"; /** * 完了画面 初期表示処理 * * @return 完了画面の Thymeleaf テンプレートファイルのパス */ @GetMapping public String index(HttpSession session) { session.invalidate(); return TEMPLATE_COMPLETE; } }
- index メソッドの以下の点を変更します。
- 引数に
HttpSession session
を追加します。 session.invalidate();
を追加します。
- 引数に
動作確認
動作確認します。npm run springboot コマンドを実行し Tomcat と smtp4dev を起動した後、ブラウザで http://localhost:9080/inquiry/input/01/ にアクセスします。
入力画面1~3でデータを入力して確認画面を表示します。
「送信する」ボタンを押すと完了画面が表示されます。
「入力画面へ」ボタンを押して入力画面1へ戻ります。修正前は入力したデータが表示されていましたが、セッションをクリアするようにしたので表示されなくなりました。
InquiryCompleteController クラスのテストを作成する
src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryCompleteController.java で Ctrl+Shift+T を押して「Create Test」ダイアログを表示してから、以下の画像の値にした後「OK」ボタンをクリックします。「Testing Library」では「Spock」を選択していますが、 Spring Boot + npm + Geb で入力フォームを作ってテストする ( その64 )( 入力画面3を作成する6、@SpringBootTest のテストは Spock+Groovy より JUnit4+Groovy の方が速い? ) で JUnit4+Groovy の方が実行は速いことに気づいたので、テストは JUnit4+Groovy で実装します(「Spock」を選択したのはテストクラスの拡張子を .groovy にしたいためです)。
src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/InquiryCompleteControllerTest.groovy が新規作成されるので、以下の内容を記述します。
package ksbysample.webapp.bootnpmgeb.web.inquiry import ksbysample.common.test.helper.TestHelper import ksbysample.common.test.rule.mail.MailServerResource import ksbysample.webapp.bootnpmgeb.values.Type1Values import ksbysample.webapp.bootnpmgeb.values.Type2Values import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput01Form import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput02Form import ksbysample.webapp.bootnpmgeb.web.inquiry.form.InquiryInput03Form import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.http.MediaType import org.springframework.mock.web.MockHttpSession import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MvcResult import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.web.context.WebApplicationContext import org.yaml.snakeyaml.Yaml import static ksbysample.common.test.matcher.HtmlResultMatchers.html import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status @RunWith(SpringRunner) @SpringBootTest class InquiryCompleteControllerTest { InquiryInput01Form inquiryInput01Form_001 = (InquiryInput01Form) new Yaml().load(getClass().getResourceAsStream("InquiryInput01Form_001.yaml")) InquiryInput02Form inquiryInput02Form_001 = new InquiryInput02Form( zipcode1: "102" , zipcode2: "0072" , address: "東京都千代田区飯田橋1-1" , tel1: "03" , tel2: "1234" , tel3: "5678" , email: "taro.tanaka@sample.co.jp") InquiryInput03Form inquiryInput03Form_001 = new InquiryInput03Form( type1: Type1Values.PRODUCT.value , type2: [Type2Values.ESTIMATE.value, Type2Values.CATALOGUE.value, Type2Values.OTHER.value] , inquiry: "これはテストです" , survey: ["1", "2", "3", "4", "5", "6", "7", "8"]) @Rule public MailServerResource mailServerResource = new MailServerResource() @Autowired WebApplicationContext context MockMvc mockMvc @Before void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(context) .apply(springSecurity()) .build() } @Test void "完了画面で「入力画面へ」ボタンをクリックして入力画面1へ戻ると入力していたデータがクリアされる"() { when: "入力画面1で項目全てに入力して「次へ」ボタンをクリックする" MvcResult result = mockMvc.perform(TestHelper.postForm("/inquiry/input/01?move=next", inquiryInput01Form_001).with(csrf())) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/02")) .andReturn() MockHttpSession session = result.getRequest().getSession() and: "入力画面2で項目全てに入力して「次へ」ボタンをクリックする" mockMvc.perform(TestHelper.postForm("/inquiry/input/02?move=next", inquiryInput02Form_001).with(csrf()).session(session)) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/input/03")) and: "入力画面3で項目全てに入力して「次へ」ボタンをクリックする" mockMvc.perform(TestHelper.postForm("/inquiry/input/03?move=next", inquiryInput03Form_001).with(csrf()).session(session)) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/confirm")) and: "確認画面で「送信」ボタンをクリックする" mockMvc.perform(post("/inquiry/confirm/send").contentType(MediaType.APPLICATION_FORM_URLENCODED).with(csrf()).session(session)) .andExpect(status().isFound()) .andExpect(redirectedUrlPattern("**/inquiry/complete/")) and: "完了画面を表示する" mockMvc.perform(get("/inquiry/complete/").session(session)) .andExpect(status().isOk()) expect: "完了画面で「入力画面へ」ボタンをクリックする(入力画面1に単にアクセスする)と入力したデータはクリアされている" mockMvc.perform(get("/inquiry/input/01/").session(session)) .andExpect(status().isOk()) .andExpect(html("#lastname").val("")) .andExpect(html("#firstname").val("")) .andExpect(html("#lastkana").val("")) .andExpect(html("#firstkana").val("")) .andExpect(html("input[name='sex'][checked='checked']").notExists()) .andExpect(html("#age").val("")) .andExpect(html("select[name='job'] option[selected]").notExists()) } }
テストを実行して成功することを確認します。
履歴
2018/07/18
初版発行。
IntelliJ IDEA を 2018.1.5 → 2018.1.6 へ、Git for Windows を 2.17.1(2) → 2.18.0 へバージョンアップ
IntelliJ IDEA を 2018.1.5 → 2018.1.6 へバージョンアップする
IntelliJ IDEA の 2018.1.6 がリリースされているのでバージョンアップします。
- IntelliJ IDEA 2018.1.6 is released!
https://blog.jetbrains.com/idea/2018/07/intellij-idea-2018-1-6-is-released/
※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。
IntelliJ IDEA のメインメニューから「Help」-「Check for Updates...」を選択します。
「IDE and Plugin Updates」ダイアログが表示されます。左下に「Update and Restart」ボタンが表示されていますので、「Update and Restart」ボタンをクリックします。
Plugin の update も表示されました。このまま「Update and Restart」ボタンをクリックします。
Patch がダウンロードされて IntelliJ IDEA が再起動します。
IntelliJ IDEA が起動すると画面下部に「Indexing…」のメッセージが表示されます。。。のはずでしたが、今回は頻繁にメッセージが切り替わって終わりました。「Indexing…」のメッセージが出ていたのかもちょっと分かりませんでした。
IntelliJ IDEA のメインメニューから「Help」-「About」を選択し、2018.1.6 へバージョンアップされていることを確認します。
Gradle Tool Window のツリーを見ると「Tasks」の下に「other」しかない状態になっているので、左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。
Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run 'All Tests' with Coverage」を選択し、テストが全て成功することを確認します。
Git for Windows を 2.17.1(2) → 2.18.0 へバージョンアップする
Git for Windows の 2.18.0 がリリースされていたのでバージョンアップします。
https://git-for-windows.github.io/ の「Download」ボタンをクリックして Git-2.18.0-64-bit.exe をダウンロードします。
Git-2.18.0-64-bit.exe を実行します。
「Git 2.18.0 Setup」ダイアログが表示されます。[Next >]ボタンをクリックします。
「Select Components」画面が表示されます。「Git LFS(Large File Support)」だけチェックした状態で [Next >]ボタンをクリックします。
「Choosing the default editor used by Git」画面が表示されます。「Use Vim (the ubiquitous text editor) as Git's default editor」が選択された状態で [Next >]ボタンをクリックします。
「Adjusting your PATH environment」画面が表示されます。中央の「Use Git from the Windows Command Prompt」が選択されていることを確認後、[Next >]ボタンをクリックします。
「Choosing HTTPS transport backend」画面が表示されます。「Use the OpenSSL library」が選択されていることを確認後、[Next >]ボタンをクリックします。
「Configuring the line ending conversions」画面が表示されます。一番上の「Checkout Windows-style, commit Unix-style line endings」が選択されていることを確認した後、[Next >]ボタンをクリックします。
「Configuring the terminal emulator to use with Git Bash」画面が表示されます。「Use Windows'default console window」が選択されていることを確認した後、[Next >]ボタンをクリックします。
「Configuring extra options」画面が表示されます。「Enable file system caching」だけがチェックされていることを確認した後、[Install]ボタンをクリックします。
インストールが完了すると「Completing the Git Setup Wizard」のメッセージが表示された画面が表示されます。中央の「View Release Notes」のチェックを外した後、「Finish」ボタンをクリックしてインストーラーを終了します。
コマンドプロンプトを起動して
git --version
を実行し、git のバージョンがgit version 2.18.0.windows.1
になっていることを確認します。git-cmd.exe を起動して日本語の表示・入力が問題ないかを確認します。
特に問題はないようですので、2.18.0 で作業を進めたいと思います。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その69 )( 再び eslint-config-airbnb-base をインストールする )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その68 )( Spring Boot を 1.5.10 → 1.5.14 へバージョンアップする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Prettier をインストールした時に ESLint の rule を Prettier のもののみに変更したのですが、それだとフォーマットの rule しかチェックされないことに気づいたので、eslint-config-airbnb-base をインストールし直します。
参照したサイト・書籍
目次
手順
動作確認1
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その67 )( Prettier のインストール+Jest Each を試してみる ) で .eslintrc.js を以下の内容に変更しましたが、
module.exports = { "extends": "plugin:prettier/recommended" };
Prettier はフォーマットしか見ないはずなので、これだと eslint-config-airbnb-base を入れていたことで検知できていたフォーマット以外の問題点が検知できなくなっている気がするんですよね。。。 ということで、試してみます。
まずは src/main/assets/js/lib/util/validator.js の checkRequired 関数を以下のように修正します。
checkRequired: function(form, idFormGroup, idList, errmsg) { if (this.ignoreCheckRequired === true) return; var a = "1" console.log("test"); this.forceCheckRequired(form, idFormGroup, idList, errmsg); },
eslint-config-airbnb-base を入れていた時は以下の問題点が指摘されたはずですが、
- 変数 a が定義されているが未使用。
var a = "1"
の最後に;
がない。console.log
が記述されている。
npm run build
コマンドを実行してみると、指摘されたのは ;
がないの1点だけでした。
やっぱり懸念した通りでした。。。 eslint-config-airbnb-base をインストールして設定し直すことにします。
再び eslint-config-airbnb-base をインストールする
npm install --save-dev eslint-config-airbnb-base
コマンドを実行してインストールします。
.eslintrc.js を変更する
.eslintrc.js を変更します。フォーマットは Prettier に任せるのは変わらないので、以前 eslint-config-airbnb-base を導入した時に書いていた rule からフォーマット関連の rule は削除します。
module.exports = { extends: ["airbnb-base/legacy", "plugin:prettier/recommended"], env: { 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", // 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 }], // disallow use of variables before they are defined "no-use-before-define": [ "error", { functions: false, classes: true, variables: true } ] } };
動作確認2
npm run build
コマンドを実行してみると、今度は3点とも指摘されるようになりました。
src/main/assets/js/lib/util/validator.js を元に戻して、再び npm run build
コマンドを実行してみます。
今度はエラーなしに終了しました。
履歴
2018/07/16
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その68 )( Spring Boot を 1.5.10 → 1.5.14 へバージョンアップする )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その67 )( Prettier のインストール+Jest Each を試してみる ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Java 側のライブラリ/モジュールをバージョンアップします。
参照したサイト・書籍
目次
手順
Spring Boot を 1.5.10 → 1.5.14 へバージョンアップする(他のライブラリもバージョンアップする)
build.gradle の以下の点を変更します。
buildscript { ext { group "ksbysample" version "1.0.1-RELEASE" springBootVersion = "1.5.14.RELEASE" } } plugins { id "java" id "eclipse" id "idea" // plugins {} block 内では ${springBootVersion} が使用できないので、バージョンを直接記述している id "org.springframework.boot" version "1.5.14.RELEASE" id "groovy" id "net.ltgt.errorprone" version "0.0.14" id "checkstyle" id "findbugs" id "pmd" id "com.moowork.node" version "1.2.0" } .......... dependencyManagement { imports { // mavenBom は以下の URL のものを使用する // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/1.5.10.RELEASE/ // bomProperty に指定可能な property は以下の URL の BOM に記述がある // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/1.5.10.RELEASE/spring-boot-dependencies-1.5.10.RELEASE.pom mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}") { bomProperty 'thymeleaf.version', '3.0.9.RELEASE' bomProperty 'thymeleaf-extras-springsecurity4.version', '3.0.2.RELEASE' bomProperty 'thymeleaf-layout-dialect.version', '2.2.2' bomProperty 'thymeleaf-extras-data-attribute.version', '2.0.1' bomProperty 'thymeleaf-extras-java8time.version', '3.0.1.RELEASE' } } } dependencies { def spockVersion = "1.1-groovy-2.4" def domaVersion = "2.19.2" def lombokVersion = "1.18.0" def errorproneVersion = "2.3.1" def powermockVersion = "1.7.4" def seleniumVersion = "3.13.0" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") { exclude group: "org.codehaus.groovy", module: "groovy" } implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-freemarker") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-devtools") implementation("org.springframework.session:spring-session") implementation("org.codehaus.janino:janino") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") testImplementation("org.yaml:snakeyaml") testImplementation("org.mockito:mockito-core") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2") implementation("org.flywaydb:flyway-core:5.1.4") implementation("com.h2database:h2:1.4.192") implementation("com.github.rozidan:modelmapper-spring-boot-starter:1.0.0") implementation("com.google.guava:guava:25.1-jre") implementation("org.apache.commons:commons-lang3:3.7") testImplementation("org.dbunit:dbunit:2.5.4") testImplementation("org.assertj:assertj-core:3.10.0") testImplementation("org.spockframework:spock-core:${spockVersion}") testImplementation("org.spockframework:spock-spring:${spockVersion}") testImplementation("com.google.code.findbugs:jsr305:3.0.2") testImplementation("org.jsoup:jsoup:1.11.3") testImplementation("com.icegreen:greenmail:1.5.7") // for lombok annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") // for Doma annotationProcessor("org.seasar.doma:doma:${domaVersion}") implementation("org.seasar.doma:doma:${domaVersion}") domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}") domaGenRuntime("com.h2database:h2:1.4.192") // for Error Prone ( http://errorprone.info/ ) errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}") // PowerMock testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}") testImplementation("org.powermock:powermock-api-mockito:${powermockVersion}") // for Geb + Spock testImplementation("org.gebish:geb-spock:2.1") testImplementation("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-support:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-api:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}") }
- buildscript の以下の点を変更します。
springBootVersion = "1.5.10.RELEASE"
→springBootVersion = "1.5.14.RELEASE"
に変更します。
- plugins の以下の点を変更します。
id "org.springframework.boot" version "1.5.10.RELEASE"
→id "org.springframework.boot" version "1.5.14.RELEASE"
に変更します。
- dependencies の以下の点を変更します。
def domaVersion = "2.19.1"
→def domaVersion = "2.19.2"
に変更します。def lombokVersion = "1.16.20"
→def lombokVersion = "1.18.0"
に変更します。def powermockVersion = "1.7.3"
→def powermockVersion = "1.7.4"
に変更します。def seleniumVersion = "3.9.1"
→def seleniumVersion = "3.13.0"
に変更します。implementation("org.flywaydb:flyway-core:5.0.7")
→implementation("org.flywaydb:flyway-core:5.1.4")
に変更します。implementation("com.google.guava:guava:22.0")
→implementation("com.google.guava:guava:25.1-jre")
に変更します。testImplementation("org.assertj:assertj-core:3.9.1")
→testImplementation("org.assertj:assertj-core:3.10.0")
に変更します。testImplementation("org.jsoup:jsoup:1.11.2")
→testImplementation("org.jsoup:jsoup:1.11.3")
に変更します。testImplementation("com.icegreen:greenmail:1.5.7")
を2回記述していたので削除します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージが出力されました。
IntelliJ IDEA から Tomcat を起動して npm run springboot で browser-sync を起動して動作確認しても問題ありませんでした(画面キャプチャなし)。
Spring Boot を含む Java 側のライブラリ/モジュールのバージョンアップは何かあっさり終わりました。。。
履歴
2018/07/15
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その67 )( Prettier のインストール+Jest Each を試してみる )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Prettier をインストールします。Jest Each のデータテーブル定義を綺麗にフォーマットしたいのがインストールの動機でしたが、最近の Javascript は Prettier でフォーマットするのが当たり前のようなのと、IntelliJ IDEA でも Prettier によるフォーマットがサポートされたので、IDE 上でのフォーマットも Prettier で行えるようにします。
- Jest 23 からの新機能 Jest Each (Spock みたいなデータテーブルを定義して Parameterized test ができる機能)を試してみます。
参照したサイト・書籍
Prettier
https://prettier.io/prettier/eslint-plugin-prettier
https://github.com/prettier/eslint-plugin-prettierJest 23: 🔥 Blazing Fast Delightful Testing
https://jestjs.io/blog/2018/05/29/jest-23-blazing-fast-delightful-testingJest 22: Refinements & Custom Runners
https://jestjs.io/blog/2017/12/18/jest-22
目次
手順
Prettier をインストールする
方針
- コードフォーマットは Prettier に完全に任せる。
- ESLint は airbnb-base/legacy のルールや独自に定義したルールは全て破棄し、prettier のルールに従うようにする。airbnb-base/legacy のルールを使用しなくなるので、eslint-config-airbnb-base はアンインストールする。
- IntelliJ IDEA に Prettier プラグインをインストールして、IDE 上でフォーマットできるようにする。
npm test
コマンド実行時に全ての js ファイルが自動でフォーマットされるようにする。npm run build
コマンドの前にはnpm test
コマンドを実行して必ずテストする想定なので、npm run build
コマンド実行時は何もしない。
prettier、eslint-plugin-prettier、eslint-config-prettier をインストールする
Install のページの記述に従い、npm install --save-dev --save-exact prettier
を実行して prettier をインストールします。
Integrating with ESLint のページの記述に従い、npm install --save-dev eslint-plugin-prettier eslint-config-prettier
を実行します。
.eslintrc.js を変更する
.eslintrc.js の記述を以下の内容に入れ替えます。
module.exports = { "extends": "plugin:prettier/recommended" };
eslint-config-airbnb-base をアンインストールする
npm uninstall --save-dev eslint-config-airbnb-base
を実行します。
IntelliJ IDEA に Prettier プラグインをインストールする
IntelliJ IDEA のメインメニューから「File」-「Settings...」メニューを選択し、「Settings」ダイアログを表示します。
ダイアログの左側のリストから「Plugins」を選択した後、画面右側の「Browse repositories...」ボタンをクリックして「Browse Repositories」ダイアログを表示します。
「Browse Repositories」ダイアログが表示されたら検索フィールドに "Prettier" と入力します。リストに "Prettier" プラグインが表示されますので、選択して画面右側の「Install」ボタンをクリックします。
プラグインがダウロードされた後「Install」ボタンが「Restart IntelliJ IDEA」に変わるのでクリックします。
「Browse Repositories」ダイアログに戻るので「OK」ボタンをクリックします。ダイアログが閉じた後「IDE and Plugin Updates」ダイアログが表示されるので「Restart」ボタンをクリックして IntelliJ IDEA を再起動します。
これで IDE 上で Prettier でフォーマットできるようになりました。試してみます。
src/main/assets/js/lib/util/delayExecutor.js は現在以下のフォーマットですが、
Reformat with Prettier (Ctrl+Alt+Shift+P) を押すと以下のようにフォーマットされます。
package.json を変更する
package.json の以下の点を変更します。
"scripts": { "test": "run-s prettier:format prettier:format-test jest", "jest": "jest --config=jest.config.json --coverage", "postinstall": "run-s clean:static-dir copy:all", .......... "postcss:watch": "postcss src/main/assets/css/**/* -d src/main/resources/static/css -x .min.css -w --poll", "prettier:format": "prettier --write src/main/assets/js/**/*.js", "prettier:format-test": "prettier --write src/test/assets/__tests__/**/*.js", "webpack:build": "webpack --mode production", .......... },
- 以下の3行を追加します。
"jest": "jest --config=jest.config.json --coverage",
"prettier:format": "prettier --write src/main/assets/js/**/*.js",
"prettier:format-test": "prettier --write src/test/assets/__tests__/**/*.js",
test
をjest --config=jest.config.json --coverage
→run-s prettier:format prettier:format-test jest
に変更します。
動作確認
確認前に先程 IDE 上でフォーマットした src/main/assets/js/lib/util/delayExecutor.js を元に戻します。
npm test
コマンドを実行してみます。テスト実行前に js ファイルをフォーマットしていることが確認でき、テストも全て成功しました。
src/main/assets/js/lib/util/delayExecutor.js を開いてみると、IDE 上でフォーマットした時と同じようにフォーマットされていました。
Jest Each を試してみる
Jest Each のデータテーブル定義が Spock みたいだな、と思っていたら、Blog の文章に Spock Data Tables
とはっきり書かれていました。Spock を使っているのもデータテーブルによる Parameterized test が楽だからなので、やっぱりこの機能追加は嬉しいですね。
では試してみましょう。src/test/assets/tests/lib/util/converter.test.js で convertHiragana のテストを以下のように記述していますが、
describe("convertHiragana のテスト", () => { beforeEach(() => { document.body.innerHTML = ` <input type="text" name="sample" id="sample" value=""/> `; }); test("全角カタカナはひらがなに変更される", () => { $("#sample").val("アイウエオ"); converter.convertHiragana(["#sample"]); expect($("#sample").val()).toBe("あいうえお"); }); test("半角カタカナはひらがなに変更される", () => { $("#sample").val("アイウエオ"); converter.convertHiragana(["#sample"]); expect($("#sample").val()).toBe("あいうえお"); }); });
これを Jest Each の機能で書き換えてみます。
describe("convertHiragana のテスト(Jest Each版)", () => { beforeEach(() => { document.body.innerHTML = ` <input type="text" name="sample" id="sample" value=""/> `; }); test.each` str | expected ${"アイウエオ"} | ${"あいうえお"} ${"アイウエオ"} | ${"あいうえお"} `("$str --> $expected", ({ str, expected }) => { $("#sample").val(str); converter.convertHiragana(["#sample"]); expect($("#sample").val()).toBe(expected); }); });
IDE からテストを実行すると無事成功しました。
わざと1件だけ失敗するようにデータテーブルを変更してみます。
describe("convertHiragana のテスト(Jest Each版)", () => { beforeEach(() => { document.body.innerHTML = ` <input type="text" name="sample" id="sample" value=""/> `; }); test.each` str | expected ${"アイウエオ"} | ${"あいうえお"} ${"アイウエオ"} | ${"あいうえおx"} `("$str --> $expected", ({ str, expected }) => { $("#sample").val(str); converter.convertHiragana(["#sample"]); expect($("#sample").val()).toBe(expected); }); });
IDE からテストを実行すると1件失敗しました。右側の青色でリンク表示されているパスをクリックすると、ソースでエラーになったところへジャンプします。
またコマンドラインで npm test
コマンドで実行した場合には、失敗したテストは以下のように表示されます。以前より何かとても分かりやすくなっているような。。。 調べてみたら Jest 22 の Codeframe in test failures のようですね。分かりやすい表示になるよう変更されていました。
最後に
Javascript のフォーマットは Prettier に任せて独自定義はなしにする方が全然楽ですね。What is Prettier? を見ると json もフォーマットできるので、package.json や webpack.config.js 等の設定ファイルも Prettier でフォーマットし直しました。
Jest は Jest 22、Jest 23 の変更内容を見ましたが、Jest Each 以外にも便利そうな機能が追加されているようです。自分としては Javascript のテストは Jest 一択ですね。
履歴
2018/07/15
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その66 )( Node.js を 8.9.4 → 8.11.3 へ、npm を 5.6.0 → 6.2.0 へ+ Javascript のライブラリをバージョンアップする )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Javascript 側のライブラリ/モジュールをバージョンアップします。Node.js や npm も最新版にバージョンアップします。
参照したサイト・書籍
nodist では、まだ npm@6.0.0 がインストールできない(2018年5月4日からインストールできます)
https://qiita.com/horihiro/items/b26463364c59df8d210fpackage.json のチルダ(~) とキャレット(^)
https://qiita.com/sotarok/items/4ebd4cfedab186355867Viewing All Versions of an NPM Package (Including Pre-Release)
https://willi.am/blog/2015/07/17/viewing-all-versions-of-an-npm-package-including-pre-release/Jest 23: 🔥 Blazing Fast Delightful Testing
https://jestjs.io/blog/2018/05/29/jest-23-blazing-fast-delightful-testing
目次
- Node.js を 8.9.4 → 8.11.3 へ、npm を 5.5.1 → 6.2.0 へバージョンアップする
- モジュールを最新版にバージョンアップする
- eslint-config-airbnb-base を 12.1.0 → 13.0.0 へ、eslint を 4.18.1 → 4.19.1 へバージョンアップする
- windows-build-tools を 2.2.1 → 3.0.1 へ、jest を 22.4.2 → 23.4.1 へバージョンアップする
手順
Node.js を 8.9.4 → 8.11.3 へ、npm を 5.5.1 → 6.2.0 へバージョンアップする
https://nodejs.org/ja/ を見ると推奨版は 8.11.3 LTS でした。
nodist dist
コマンドを実行して 8.11.3 がインストール可能か確認します。
8.11.3 が表示されていますので、8.11.3 へバージョンアップします。
npm も最新版にバージョンアップします。npm の最新バージョンは https://docs.npmjs.com/ の一番下を見ると 6.2.0 とありましたので、
6.2.0 にバージョンアップします。。。と思いましたが、Cannot read property 'trim' of null.
というメッセージが出てバージョンアップできませんでした。
調べると nodist では、まだ npm@6.0.0 がインストールできない(2018年5月4日からインストールできます) という記事を見つけました。なるほど、https://github.com/npm/npm/releases のページの文字列を指定しないといけないのか。。。 最新版だと 6.2.0-next.1
でした。
バージョン番号を 6.2.0-next.1
にすると、今度は無事バージョンアップできました。
モジュールを最新版にバージョンアップする
バージョンアップ可能なモジュールを確認します。IntelliJ IDEA のメインメニューから「File」-「Settings...」を選択して「Settings」ダイアログを開き、画面左側で「Language & Frameworks」-「Node.js and NPM」を選択します。
画面右側にモジュールの一覧と現行バージョン、最新バージョン一覧が表示されます。
今回モジュール一覧には以下のように表示されました。
今回は以下の方針でバージョンアップします。
- admin-lte、bootstrap、ionicons は現行のまま。
- postcss-cli、xhr-mock は 以前 正常にバージョンアップできなかったので今回もバージョンしない。
- mobx、mobx-utils は少し触ってみただけなのでバージョンアップしない。
- バージョンアップは
npm update
ではなくnpm install --save-dev autoprefixer@8.0.0
(package.json の dependencies に記載されているものは --save、devDependencies に記載されているものは --save-dev にする) のようにバージョンを指定しながらバージョンアップする。 - 1つずつ上からバージョンアップする。関連しそうなところを動作確認しながら進める。
- eslint、jest + widows-build-tools は別に章を分けてバージョンアップする。
特に問題がでなければ画面キャプチャは撮りません。
npm install --save-dev autoprefixer@8.6.5
npm install --save-dev browser-sync@2.24.5
npm install --save computed-async-mobx@4.1.0
npm install --save-dev cssnano@4.0.2
npm install --save-dev http-proxy-middleware@0.18.0
npm install --save-dev jquery-mockjax@2.4.0
npm install --save-dev nock@9.4.2
npm install --save-dev npm-run-all@4.1.3
npm install --save-dev stylelint@9.3.0
npm install --save-dev stylelint-config-standard@18.2.0
npm install --save-dev uglifyjs-webpack-plugin@1.2.7
npm install --save-dev webpack@4.16.0
npm install --save-dev webpack-cli@3.0.8
npm install --save-dev xhr-mock@2.4.1
コマンドラインから npm test
コマンドを実行すると、テストは全て成功しました。
npm run build
コマンドも特にエラーは出ずに終了しました。
IntelliJ IDEA から Tomcat を起動して npm run springboot
で browser-sync を起動して動作確認しても問題ありませんでした(画面キャプチャなし)。
eslint-config-airbnb-base を 12.1.0 → 13.0.0 へ、eslint を 4.18.1 → 4.19.1 へバージョンアップする
以下のコマンドを実行します。
npm install --save-dev eslint-config-airbnb-base@13.0.0
eslint-config-airbnb-base@13.0.0
は eslint@^4.19.1
、eslint-plugin-import@^2.12.0
が必要のようです。
npm show eslint@* version
コマンドでインストール可能なバージョン一覧を確認します。メジャーバージョン番号が 4 だと 4.19.1
が最新でした。
npm show eslint-plugin-import@* version
コマンドでインストール可能なバージョン一覧を確認します。メジャーバージョン番号が 2 だと 2.13.0
が最新でした。
以下のコマンドを実行して eslint-config-airbnb-base に対応する eslint、eslint-plugin-import の最新バージョンにバージョンアップします。
npm install --save-dev eslint@4.19.1
npm install --save-dev eslint-plugin-import@2.13.0
npm run build
コマンドを実行してみると、特にエラーは出ずに終了しました。
windows-build-tools を 2.2.1 → 3.0.1 へ、jest を 22.4.2 → 23.4.1 へバージョンアップする
コマンドプロンプトを「管理者として実行...」で起動した後、npm install --global --production windows-build-tools@3.0.1
を実行します。
All done!
のメッセージが出た後、いつまで経っても終わらないので Ctrl+C を押して強制終了した後、タスクマネージャから BuildTools_Full のプロセスを落としました。windows-build-tools はインストールの動作がおかしかったのでいろいろ試したのですが、何をやってもコマンドプロンプトに戻ってこなくて、今回きちんとインストールできているのか良く分からないんですよね。。。 どうしようもなかったので先に進めることにします。
次に普通に起動したコマンドプロンプトで npm install --save-dev jest@23.4.1
を実行します。
npm install --save-dev jest-html-reporter@2.4.1
も実行します。
npm WARN jest-html-reporter@2.0.0 requires a peer of jest@19.x - 22.x but none is installed.
のメッセージが出ていますが、実際には Jest 23 でも動作するので無視します。
npm test
コマンドを実行するとテストは全て成功し、
build/reports/jest/jest-html-reporter.html も問題なく生成されていました。
Jest 23: 🔥 Blazing Fast Delightful Testing を見ましたが、Spock みたいな Parameterized Test が書ける Jest Each という機能が追加されていました。データを記述するテーブルレイアウトが少し独特ですが、Prettier を入れれば綺麗にフォーマットしてくれるらしいです。
次は Java のモジュールのバージョンアップの予定でしたが、先に Jest Each を試してみます。欲しかった機能なんですよね。期待大です。
履歴
2018/07/15
初版発行。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( その65 )( Gradle を 4.6 → 4.8.1 へ、Checkstyle を 8.8 → 8.11 へ、PMD を 6.4.0 → 6.5.0 へ、error-prone を 2.2.0 → 2.3.1 へバージョンアップする )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Gradle を 4.6 → 4.8.1 へバージョンアップします。また
compile
等が非推奨の書き方になっていたので、build.gradle を変更します。 - Checkstyle を 8.8 → 8.11、PMD を 6.4.0 → 6.5.0、error-prone を 2.2.0 → 2.3.1 へバージョンアップします。
- Gradle を 4.6 → 4.8.1 へバージョンアップします。また
参照したサイト・書籍
Regarding the “annotation processors” on compile classpath warning in Gradle 4.6
https://discuss.gradle.org/t/regarding-the-annotation-processors-on-compile-classpath-warning-in-gradle-4-6/26144The Java Plugin - Dependency configurations
https://docs.gradle.org/current/userguide/java_plugin.html#tab:configurationsGradle の compile, api, implementation とかについて
https://qiita.com/opengl-8080/items/6ad642e0b016465891de
目次
- Gradle を 4.6 → 4.8.1 へバージョンアップする
- build.gradle で
compile
→implementation
に変更する - Checkstyle を 8.8 → 8.11、PMD を 6.4.0 → 6.5.0 へバージョンアップする
- error-prone を 2.2.0 → 2.3.1 へバージョンアップする
手順
Gradle を 4.6 → 4.8.1 へバージョンアップする
build.gradle の以下の点を変更します。
task wrapper(type: Wrapper) {
gradleVersion = '4.8.1'
}
gradleVersion = '4.6'
→gradleVersion = '4.8.1'
に変更します。
コマンドプロンプトを起動し、gradlew wrapper
コマンドを実行します。
gradle/wrapper/gradle-wrapper.properties を開くと gradle-4.8.1-bin.zip に変更されています。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
というメッセージが出たので、https://docs.gradle.org/4.8.1/userguide/command_line_interface.html#sec:command_line_warnings の記述を参考に gradlew --warning-mode=all
コマンドを実行してみます。
1件メッセージが出ていました。wrapper
という task はもうNGなので wrapper { ... }
syntax を使え、ということらしいです。
Customizing the Gradle Wrapper を参考に build.gradle の以下の点を変更して、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
wrapper {
gradleVersion = '4.8.1'
distributionType = Wrapper.DistributionType.ALL
}
task wrapper(type: Wrapper)
→wrapper
に変更します。distributionType = Wrapper.DistributionType.ALL
を追加します。
再度 gradlew --warning-mode=all
コマンドを実行すると、今度は何も出ませんでした。
clean タスク実行 → Rebuild Project → build タスクを実行すると BUILD SUCCESSFUL のメッセージが出ましたが、Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
のメッセージがまた出ました。。。
コマンドラインから gradlew -Dfile.encoding=UTF-8 --warning-mode=all build
コマンドを実行してみます。
Doma 2 と Lombok の annotaion processor が compile classpath にあるのは Gradle 5.0 から非推奨になるので、Please add them to the annotation processor path instead.
ということらしいです。何のことか分からなかったので調べてみたところ、以下のページを見つけました。annotaion processor は annotationProcessor
で指定することになったようです。あと compile(Deprecated)
とかありますね。。。
- Regarding the “annotation processors” on compile classpath warning in Gradle 4.6
- The Java Plugin - Dependency configurations
compile
の方は一旦無視して annotationProcessor
の方から反映してみます。build.gradle の以下の点を変更します。
dependencies { .......... // for lombok annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") // for Doma annotationProcessor("org.seasar.doma:doma:${domaVersion}") compile("org.seasar.doma:doma:${domaVersion}") domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}") domaGenRuntime("com.h2database:h2:1.4.192")
annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
を追加します。testCompileOnly("org.projectlombok:lombok:${lombokVersion}")
を削除します。annotationProcessor("org.seasar.doma:doma:${domaVersion}")
を追加します。
gradlew -Dfile.encoding=UTF-8 --warning-mode=all build
コマンドを実行しますが、まだ警告が出たままでした。Lombok はメッセージに出なくなりましたが、Doma 2 の方が出たままですね。Doma 2 はさすがに compile
→ compileOnly
に変更する訳にもいかないので、ここまでにします。
build.gradle で compile
→ implementation
に変更する
Gradle の compile, api, implementation とかについて という記事を見つけました。やっぱり非推奨になったようです。
ライブラリではないので api
を使用する必要はなさそうなので、build.gradle で以下のように変更します。
compile
→implementation
runtime
→runtimeOnly
testCompile
→testImplementation
dependencies { def spockVersion = "1.1-groovy-2.4" def domaVersion = "2.19.1" def lombokVersion = "1.16.20" def errorproneVersion = "2.2.0" def powermockVersion = "1.7.3" def seleniumVersion = "3.9.1" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/html/appendix-dependency-versions.html ) 参照 implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") { exclude group: "org.codehaus.groovy", module: "groovy" } implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-freemarker") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-devtools") implementation("org.springframework.session:spring-session") implementation("org.codehaus.janino:janino") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") testImplementation("org.yaml:snakeyaml") testImplementation("org.mockito:mockito-core") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2") implementation("org.flywaydb:flyway-core:5.0.7") implementation("com.h2database:h2:1.4.192") implementation("com.github.rozidan:modelmapper-spring-boot-starter:1.0.0") implementation("com.google.guava:guava:22.0") implementation("org.apache.commons:commons-lang3:3.7") testImplementation("org.dbunit:dbunit:2.5.4") testImplementation("com.icegreen:greenmail:1.5.7") testImplementation("org.assertj:assertj-core:3.9.1") testImplementation("org.spockframework:spock-core:${spockVersion}") testImplementation("org.spockframework:spock-spring:${spockVersion}") testImplementation("com.google.code.findbugs:jsr305:3.0.2") testImplementation("org.jsoup:jsoup:1.11.2") testImplementation("com.icegreen:greenmail:1.5.7") // for lombok annotationProcessor("org.projectlombok:lombok:${lombokVersion}") compileOnly("org.projectlombok:lombok:${lombokVersion}") // for Doma annotationProcessor("org.seasar.doma:doma:${domaVersion}") implementation("org.seasar.doma:doma:${domaVersion}") domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}") domaGenRuntime("com.h2database:h2:1.4.192") // for Error Prone ( http://errorprone.info/ ) errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}") // PowerMock testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}") testImplementation("org.powermock:powermock-api-mockito:${powermockVersion}") // for Geb + Spock testImplementation("org.gebish:geb-spock:2.1") testImplementation("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-support:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-api:${seleniumVersion}") testImplementation("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}") }
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL のメッセージが出ることを確認します。
Checkstyle を 8.8 → 8.11、PMD を 6.4.0 → 6.5.0 へバージョンアップする
build.gradle の以下の点を変更します。
checkstyle { configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml") toolVersion = '8.11' sourceSets = [project.sourceSets.main] } .......... pmd { toolVersion = "6.5.0" sourceSets = [project.sourceSets.main] ignoreFailures = true consoleOutput = true ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml") ruleSets = [] }
- checkstyle で
toolVersion = '8.8'
→toolVersion = '8.11'
に変更します。 - pmd で
toolVersion = "6.4.0"
→toolVersion = "6.5.0"
に変更します。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL のメッセージが出ることを確認します。
error-prone を 2.2.0 → 2.3.1 へバージョンアップする
gradle-errorprone-plugin を見ると最新バージョンは 0.0.14、mvnrepository.com の error_prone_core のページ を見ると最新バージョンは 2.3.1 でした。
build.gradle の以下の点を変更します。
plugins { id "java" id "eclipse" id "idea" // plugins {} block 内では ${springBootVersion} が使用できないので、バージョンを直接記述している id "org.springframework.boot" version "1.5.10.RELEASE" id "groovy" id "net.ltgt.errorprone" version "0.0.14" id "checkstyle" id "findbugs" id "pmd" id "com.moowork.node" version "1.2.0" } .......... dependencies { def spockVersion = "1.1-groovy-2.4" def domaVersion = "2.19.1" def lombokVersion = "1.16.20" def errorproneVersion = "2.3.1" def powermockVersion = "1.7.3" def seleniumVersion = "3.9.1" ..........
id "net.ltgt.errorprone" version "0.0.13"
→id "net.ltgt.errorprone" version "0.0.14"
に変更します。def errorproneVersion = "2.2.0"
→def errorproneVersion = "2.3.1"
に変更します。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project → build タスクを実行して BUILD SUCCESSFUL のメッセージが出ることを確認します。今回はエラーは出ませんでした。
また build.gradle で以下の定義を記述していますが、
compileJava.options.compilerArgs += [ '-Xep:RemoveUnusedImports:WARN' , '-Xep:NestedInstanceOfConditions:OFF' , '-Xep:InstanceOfAndCastMatchWrongType:OFF' , '-Xep:ParameterName:OFF' ]
, '-Xep:NestedInstanceOfConditions:OFF'
と , '-Xep:InstanceOfAndCastMatchWrongType:OFF'
はコメントアウトしてもエラーは出なかったので削除します。
履歴
2018/07/14
初版発行。