Github Actions で Selenium を動かしてみる

Advent Calendarネタがないよーと思っていたら、
ちょうど[最近Github Actionsがpublic repositoryでも設定できるようになった]()ので、
格好のネタだなぁと思ったので触ってみました。

# Github Actions って何？

Githubがレポジトリのイベントをhookとしてさまざまなことを自動化できますよっていっている新機能です。
詳しくはググってください。

# 動かしてみたいSeleniumのテスト

```js:tests/google.js
describe("Google Test", function() {
  it("Shows Google", function() {
    browser.url("/");

    browser.addValue('input[name="q"]', "DeNA SW");

    browser.waitForVisible('ul[role="listbox"]', 3000);

    browser.elements('ul[role="listbox"]').click("div=dena swet");

    expect(browser.elements("body").getText()).to.include("DeNA Testing Blog");
  });
});
```

僕がいつもブラウザ自動化スクリプトでサンプルにしているコードです。
Googleにアクセスして、"DeNA SW"までを入力して、サジェストされてでてきた"dena swet"という文字列をクリックし、
[SWET Testing Blog](https://swet.dena.com/)の検索結果が出てくることを確認しています。

Googleがサジェストするところとかが非同期なので、ちゃんと待つ必要があります。

# Github Actions の作り方

Github Actionsは未だにlimited public betaで、順番に招待されます。
僕は、Github Actionsが発表されてこれはマーケットプレイス殺しにきたな、面白そうだと野次馬根性で割と早い目に申し込んだためにもう使えています。
ですが、同僚とかにまだまだinvitationきてない人もいるらしいです。なので、この記事を見て申し込んでもすぐには使えないかもしれないです。

使えるよってメールがGithubからくると、レポジトリにこんな感じで Action というタブが追加されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5664/f600ff9e-d382-6de8-038b-08c7b6cb1b19.png)

Actionタブをクリックして、ワークフローを作ると、Visual Editorでworkflowを作れます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5664/61f75b62-4941-c1bc-093e-924618f53693.png)

が、まぁこの程度のVisual Editorは最近のRPA的なサービスから比べると劣る感じで、今後に期待ですね。

Visual Editor以外にも独自のDSL(*.workflowファイル)でかけます（Visual Editorを使うと、 *.workflowが作られます）

書き方とかは https://developer.github.com/actions/creating-workflows/ をみてください。
やりたいことをやるには、ゴリゴリスクリプトを書いてかなり頑張らないとダメ感があります。。

# Selenium をDockerで動かす

Github Actions は Docker コンテナを使います。
簡単にブラウザを動かすのにぱっとおもいついたのは、普段使い慣れているcircleciのコンテナでしたw
（多分、、、ライセンス違反とかではないはず。。。）

ただ、 `circleci:node/latest-browsers`とかは日本語フォントは入ってないので、自前で Dockerfile を書いて拡張します。
（フォントがなくても問題ないんですが、スクリーンショット等の見栄えで重要なのです）

# Github Actions を書く

ローカルのDockerfileを使うworkflowはこんな感じでなります。

日本語フォントとかいらないよ？とかテスト動かすのは別でやるよってのであれば、
かわりに `docker://circleci/node:latest-browsers`とかを指定してください。

```.github/main.workflow
workflow "workflow-test" {
  on = "push"
  resolves = ["action-test"]
}

action "action-test" {
  uses = "./"
  runs = ".github/action-test/entrypoint.sh"
}
```

ちなみに、`uses` は `.` とかくと、 「The `uses` attribute must be a path, a Docker image, or owner/repo@ref」 と怒られます。
`.`でも意味通じるし、`docker build .`とかするのが多いのにねぇ。。。

`runs` は Docker コンテナの entrypoint を差し替えます。
ここはコマンドもかけるのですが、テストの前処理後処理を考えると、ファイルにしておいたほうがよいと思います。

で、おそらく、Github Action では、
`docker run -v $(pwd):/github/home --workdir=/github/home -e HOME=/gihtub/home {CONTAINER_NAME} --entrypoint {RUNS}`
的なことをやっているんだと思います。（特に -v のところは想像）

でも、それが Selenium のコンテナとの相性の悪さを発揮することに。。。（つらい

# Selenium コンテナの特徴

多くの Selenium というかブラウザのコンテナは非rootユーザが設定されています。
例えば、 puppeteer の[推奨コンテナ](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-in-docker)は pptruser ですし、
Seleniumの公式コンテナもseluserが使われています。
今回の、circleci は狙ってではないですが（ブラウザを使わないのもcircleciユーザ）ですので、ご多分にもれずそうなっています。
（たしかブラウザ自体のセキュリティ的な理由でrootで動かさない方法が推奨だったと思うのですが、あまり詳しくないです）

つまり、非rootユーザでブラウザを動かしたいし、そういうコンテナのユーザ設定になっているのに、volume mount的なことをされるために、
rootでmountされ、permission的に困ったことになるのです。。

# どうするか

今回は自動でmountされるソースディレクトを捨て、
Dockerfileの中で COPY をすることにしました。
そして、entrypoint.sh の中で Dockerfile の WORKDIR に cd をしてテスト実行という涙ぐましい努力をしました。
（ここらへんスマートな解決策教えてください ><;）

* https://github.com/okitan/example-github-actions-selenium/blob/add_action/Dockerfile
* https://github.com/okitan/example-github-actions-selenium/blob/add_action/.github/action-test/entrypoint.sh


# さらなる問題

という感じでめでたくテストが実行された（ブラウザがようやくたちあがった）のですが、[見事にテストが通りません](https://github.com/okitan/example-github-actions-selenium/runs/42791630)。。。


"DeNA SW" といれても、"DeNA SWET" がサジェッションされないのです。。
なぜ。。。
で、それをデバッグしようと思うのですが、Github Actionsはデバッグ via SSHとかないので、デバッグ不能です。。。

当然、テストが落ちたらスクリーンショットを取るとかやっているのですが、アーティファクト等もなく、
撮ったスクリーンショットをどうやって外部にもっていくかという問題が。。。
本当は成功したスクショものせたりしたかったのですが(checksにのっけるとかできたらしたかった？）Advent Calendarには間に合いそうもなかったので断念しました。
（なんせこのテーマを思いついたのが前日の夕方くらいなので）

そもそもコンテナってどの環境で実行しても一緒のはずなんですが、渡されるコンテナに渡される環境変数とかがなんかあるんですかね？？
ローカルでは当然通るんですが、Gihtub Actionsでは通らずこれつらいやつやー感。。

[結局](https://github.com/okitan/example-github-actions-selenium/runs/42794115)、原始的に `console.log(browser.getText("body"));` とかしましたwww

デバッグの結果、ブラウザのlocaleがLANGとかLC_CTYPEとかの環境変数では制御できてないことがわかり、ブラウザの起動の引数として`--lang=ja-JP`として解決した感じです。。

最終的にこのように無事テストが通りました。。

* https://github.com/okitan/example-github-actions-selenium/pull/1/checks

# まとめ

Github ActionsでSeleniumを動かすのにはまだいくつもブレイクスルーが必要そうでした。
特にデバッグをどう簡単にするかが課題ですね。。。（まぁこれはSelenium系サービスすべての課題ですが）

今回はGithub ActionsでもSeleniumが動くことがわかったので、今後の発展に期待ですね。

Selenium/Appium Advent Calendar には空きがあるので、ぜひこの記事を上回る記事を期待しています。