JenkinsにHeadless Chromeを入れて定期的にスクショをSlackに投げデザイン崩れがないかチェックする

Headless Chrome（ヘッドレス Chrome)がついに、**Chrome 59**に搭載されました。
GUIのないLinux環境でも簡単にChromeが実行できるようになりました。
これでリリース後にデザイン崩れをチェックしたり、毎日のサイトチェックなんかにも利用できます。

試しに、Yahoo! JAPANのトップのニュース確認という体で毎時にスクショを撮ってみます。

## Google ChromeをUbuntuにインストール
今回はUbuntuの環境だったので`apt-get`を使います。

###`apt-get`で**Chrome**をインストールできるようにする
```bash
$ echo "deb http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee -a /etc/apt/sources.list
deb http://dl.google.com/linux/chrome/deb/ stable main
$ wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
OK
$ sudo apt-get update
```

### `apt-get`で**google-chrome-stable**をインストールする
```bash
$ sudo apt-get install google-chrome-stable
$ google-chrome-stable --version
Google Chrome 61.0.3163.100 
```
無事に最新版が入りました。

## スクリーンショットを撮る
`google-chrome --headless --screenshot` コマンドでヘッドレス Chromeのスクリーンショットを撮ることができます。
GPUのない環境なので `--disable-gpu` を付け、 `--window-size` で横ｘ高さを指定することができます。

```bash
$ google-chrome --headless --disable-gpu --screenshot --window-size=1000,800 https://www.yahoo.co.jp/
[1001/180757.875913:INFO:headless_shell.cc(468)] Written to file screenshot.png.
```

**screenshot.png** を確認してみるとこんな感じ
![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/7132/8fa54838-20b7-e2de-3279-b9caa8562c0e.png)
良い感じですが、文字化け・・・

## Headless Chromeの日本語化
日本語フォントが入っておらず文字化けしてしまっていたため、フリーで使える**IPAフォント**をインストールします。
（他にも色々使えるみたい、お好みで！ https://wiki.ubuntulinux.jp/UbuntuTips/Desktop/InstallFont）

```bash
$ sudo apt-get install fonts-ipafont fonts-ipaexfont
$ fc-list
/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf: DejaVu Serif:style=Bold
/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf: DejaVu Sans Mono:style=Book
/usr/share/fonts/truetype/liberation/LiberationSansNarrow-Italic.ttf: Liberation Sans Narrow:style=Italic
/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf: DejaVu Sans:style=Book
/usr/share/fonts/opentype/ipafont-mincho/ipam.ttf: IPAMincho,IPA明朝:style=Regular
/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf: Liberation Sans:style=Regular
/usr/share/fonts/truetype/liberation/LiberationMono-BoldItalic.ttf: Liberation Mono:style=Bold Italic
/usr/share/fonts/truetype/liberation/LiberationSerif-Italic.ttf: Liberation Serif:style=Italic
/usr/share/fonts/truetype/liberation/LiberationMono-Bold.ttf: Liberation Mono:style=Bold
/usr/share/fonts/truetype/liberation/LiberationSansNarrow-Regular.ttf: Liberation Sans Narrow:style=Regular
/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf: DejaVu Sans:style=Bold
/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf: Liberation Serif:style=Bold
/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf: IPAexGothic,IPAexゴシック:style=Regular
/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf: Liberation Mono:style=Regular
/usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf: IPAPGothic,IPA Pゴシック:style=Regular
/usr/share/fonts/truetype/liberation/LiberationSans-Italic.ttf: Liberation Sans:style=Italic
/usr/share/fonts/truetype/liberation/LiberationSerif-BoldItalic.ttf: Liberation Serif:style=Bold Italic
/usr/share/fonts/truetype/liberation/LiberationSansNarrow-BoldItalic.ttf: Liberation Sans Narrow:style=Bold Italic
/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf: DejaVu Sans Mono:style=Bold
/usr/share/fonts/opentype/ipaexfont-mincho/ipaexm.ttf: IPAexMincho,IPAex明朝:style=Regular
/usr/share/fonts/opentype/ipafont-mincho/ipamp.ttf: IPAPMincho,IPA P明朝:style=Regular
/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf: IPAGothic,IPAゴシック:style=Regular
/usr/share/fonts/truetype/fonts-japanese-mincho.ttf: IPAexMincho,IPAex明朝:style=Regular
/usr/share/fonts/truetype/fonts-japanese-gothic.ttf: IPAexGothic,IPAexゴシック:style=Regular
/usr/share/fonts/truetype/liberation/LiberationMono-Italic.ttf: Liberation Mono:style=Italic
/usr/share/fonts/truetype/liberation/LiberationSans-BoldItalic.ttf: Liberation Sans:style=Bold Italic
/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf: Liberation Serif:style=Regular
/usr/share/fonts/truetype/liberation/LiberationSansNarrow-Bold.ttf: Liberation Sans Narrow:style=Bold
/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf: Liberation Sans:style=Bold
/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf: DejaVu Serif:style=Book
```

### 再度確認
```bash
$ google-chrome --headless --disable-gpu --screenshot --window-size=1000,800 https://www.yahoo.co.jp/
```

日本語で表示されました
![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/7132/6b7f7b00-d49d-f580-3164-9e8003507d86.png)

## Slackへスクショを送る
curlからSlack APIでスクショを送ってみます。
`files.upload`へ先程の`screenshot.png`をアップロードします。
今回の例では`test`チャンネルへ送っています。

```bash
$ curl -F file=@screenshot.png -F channels=test -F token=xoxb-xxxxx-xxxxxx https://slack.com/api/files.upload
```

送られるとこんな感じで見ることができます。
<img width="483" alt="スクリーンショット 2017-10-02 4.05.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/7132/e8b4197f-cd02-2325-dcdb-a12683ac66f1.png">


## ページ全体を確認したい場合
高さ800pxに指定しているため、途中で表示が切られてしまいます。
ある程度高さ決まっているページであれば固定でもよいですが、そうもいかないサイトも多いハズ。。。

`window.document.body.offsetHeight` なんかを取得してプログラム書いて動的に指定することもできるっぽいですが、ちょっとめんどう、、、（[Puppeteer](https://github.com/GoogleChrome/puppeteer)）

PDFは扱いにくいですが、PDFでもっと簡単に書き出しすることもできます。
`--print-to-pdf` を付けるだけ

```
$ google-chrome --disable-gpu --print-to-pdf https://www.yahoo.co.jp/
$ ls output.pdf 
output.pdf 
```
`output.pdf`というファイル名で保存されました。


## スマホページのデザインを確認したい
そのままだと**Headless Chrome** 固有のUser Agentでリクエストがされるため、普通はPCページしか読み込めません。
対象のサイトがUAでページを出し分けしている場合 `--user-agent` でUAを指定することでスマホページを表示させることができあます。

```bash
google-chrome --headless --disable-gpu --screenshot --window-size=375,800 --user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1" https://www.yahoo.co.jp/
```

![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/7132/cf68e3ca-1468-6351-45cd-08074e029a73.png)


## Jenkinsのjobに登録し定期実行させる
あとはJenkinsのjobにshellscriptとして登録し、定期実行を指定するだけです。
`--screenshot` の後にファイル名を指定することができるので、実行日時を入れて、
`--dump-dom` でHTMLをログに表示させ、後から確認したときにもわかりやすくします。
また、 `--hide-scrollbars` のオプションでスクロールバーを非表示にして隠すことができます。

```bash:shell
SCREENSHOT=`date +%Y%m%d_%H%M%S-pc.png`
google-chrome --headless --disable-gpu --dump-dom --hide-scrollbars --screenshot=$SCREENSHOT --window-size=1280,800 
https://www.yahoo.co.jp/
curl -F file=@$SCREENSHOT -F channels=test -F token=xoxb-xxxxx-xxxxxx https://slack.com/api/files.upload
```

### ビルドトリガーで定期的に実行

```text:
H * * * *
```

これで毎時スクリーンショットを撮ってSlackに送るようになりました。


## おわり
複雑なSVGの表示とかCSSとか、PhantomJSではレンダリングが微妙なものも試してみたのですが、
やってみた感じまんまChromeで表示した時のスクリーンショットが作れました。当たり前ですが
ただ、helpがなかったり、ドキュメントが発見できなかったりで、 `--user-agent` や `--hide-scrollbars` のオプションを最終的にchromiumのソースコードから探し出しました。まだまだ情報が少ない・・・

最初Serverlessでやろうと思ったんですが、Chromeのサイズが大きくてLambdaにアップロードできない・・・
とりあえずJenkinsのサーバーに入れてみました、Jenkinsのリリースジョブと組み合わせて、サーバーに上がったらスクショ撮って、画像認識させて変更箇所送らせるってフローを作ればCIが捗りそうです。