rspecでhtmlのmarkup validationを行う


# 使用したGEM

[w3c-validators/w3c_validators](https://github.com/w3c-validators/w3c_validators)を使ってrspec時にhtmlのバリデーションを行いました。
https://validator.nu/ へアクセスしてそのサイトのAPIを利用してバリデーションを行っていました。

# 準備

Gemfileにw3c_validatorsを追加し、spec_helperにカスタムマッチャを用意しました。

```Gemfile
 gem "w3c_validators"
```

```ruby:spec/spec_helper.rb 
require 'w3c_validators'
RSpec::Matchers.define :html_validate do
  match do |response|
    if response.is_a?(ActionDispatch::TestResponse)
      response = response.body
    end 
    @html_validater = W3CValidators::NuValidator.new
    @html_validater_result = @html_validater.validate_text(response)
    @html_validater_result.errors.empty?
  end 
  failure_message do |response|
    @html_validater_result.errors.map{|e| e.to_s}.join("\n")
  end 
end
```

しかし、毎回実行するとrspecが重くなるのと、外部のサービスにリンクしてしまうので、実行したい時にHTML_VALIDATE=trueと言う環境変数をつける事で切り分けられる様にして以下の様にしてます。

```ruby:spec/spec_helper.rb
if ENV["HTML_VALIDATE"]
  require 'w3c_validators'
  RSpec::Matchers.define :html_validate do
    match do |response|
      if response.is_a?(ActionDispatch::TestResponse)
        response = response.body
      end 
      @html_validater = W3CValidators::NuValidator.new
      @html_validater_result = @html_validater.validate_text(response)
      @html_validater_result.errors.empty?
    end 
    failure_message do |response|
      @html_validater_result.errors.map{|e| e.to_s}.join("\n")
    end 
  end 
else
  RSpec::Matchers.define :html_validate do
    match do |response|
      true
    end 
  end 
end
```

# 利用方法

準備のコードを用意するとexpect(response).to html_validate でテスト出来る様になります。

```ruby:spec/controllers/nantoka_controller_spec.rb
    it "html_validate" do
      get :index
      expect(response).to html_validate
    end
```

# ローカルでvalidationサーバを立てる

The Nu Html Checkerをローカルで立ち上げると外部にネットワーク接続に行かないで済みます。
ローカルで立てるにはJAVAとPythonをインストールして[こちら](https://validator.github.io/validator/#build-instructions)を参考にすると作れます。

```インストール方法
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64    #<-- Ubuntu, etc.
export JAVA_HOME=$(/usr/libexec/java_home)            #<-- MacOS
git clone https://github.com/validator/validator.git
cd validator
python ./build/build.py all
python ./build/build.py run # 2回目以降
```

その後、spec_helperでNuValidator.new時にvalidator_uriを指定してあげることでローカルのアドレスを使います。

```ruby:spec/spec_helper.rb
if ENV["HTML_VALIDATE"]
  require 'w3c_validators'
  RSpec::Matchers.define :html_validate do
    match do |response|
      if response.is_a?(ActionDispatch::TestResponse)
        response = response.body
      end 
      @html_validater = W3CValidators::NuValidator.new(validator_uri: "http://localhost:8888/")
      @html_validater_result = @html_validater.validate_text(response)
      @html_validater_result.errors.empty?
    end 
    failure_message do |response|
      @html_validater_result.errors.map{|e| e.to_s}.join("\n")
    end 
  end 
else
  RSpec::Matchers.define :html_validate do
    match do |response|
      true
    end 
  end 
end
```


# その他のGem 

[ericbeland/html_validation](https://github.com/ericbeland/html_validation) という物もあり、これはGemをインストール後、最新版のHTML tidyをインストールして使う事で、ローカルで外部に通信せずHTML5の検証ができます。
ただ、今回は以下の様なケースのHTMLで警告が出た為、対応から除外しました。

```html
<a>
  <h1>test</h1>
  <div>testtest</div>
</a>
```


# 参考
 
RSpecでカスタムマッチャを作る: http://qiita.com/kozy4324/items/9a6530736be7e92954bc
W3C Markup ValidatorでWebサイトを検証する: http://knowledge.sakura.ad.jp/tech/1246/
The Nu Html Checker: https://validator.github.io/validator/#build-instructions