##概要
- headlessモードでのみ再現。
- headlessモードの時だけブラウザの言語設定が英語になっている。
- 画面上の要素が英語表記になって
expect(page).to have_css('h1', text: 'あいうえお')
的なステップが落ちる。 - 原因はheadless_chromeのオプション(言語設定)
-
--lang=ja-JP
で解決した。
##経緯
色々あって自動テストのリファクタリングを始めるようになった。
テストも足りないので色々駆け足気味だが、シナリオが足りていない現状でもテストが重すぎてCIなどで定期実行できないなどあったので雑魚なりにとろとろやっていた。
##現象
headless_chromeを使用して、オプションは以下の通り。
options.add_argument("--disable-site-isolation-trials")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
テストシナリオの記述ミスで一回落ちたが、そこを修正すると20件全部通った。
が、今回はCIで定期実行するのが目標なので、 headless
オプションを追加。
options.add_argument("--disable-site-isolation-trials")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
# 追記↓
options.add_argument("--headless")
慢心で20件一気に実行してみる。
- テストシナリオ冒頭に記述しているfeatureタイトルとかdescriptionはそのまま流れていく。
- それ以降全然進まない。
- しばらく待っていると画面が真っ赤になり、以降のシナリオが水色。
そして次のfeatureを実行し始めるも、ここでもまたタイトルやdescriptionはするすると流れて、しばらくして赤→水色。
どうも背景(background)のテストステップが最初から落ちていて、それ以降のステップが飛ばされてしまっている様子。
エラーメッセージを確認すると expected to find text(〜的なテキストを探すことを期待されているようですが…)
的なことが書かれている。落ちたのは以下のようなステップ。
expect(page).to have_content('ダッシュボード')
以下のステップは通っているようなので、そもそも起動がうまくいかなかったというわけではなさそう。
page.find('#createTask').click
しかし、以下のステップではまた落ちている。
expect(page).to have_content('タスク作成')
前述の通り、テストは一回通っているので、 テキストが「ログインしました。」ではなく「ログインしました」だった的な誤字脱字だった系でもなさそう…。
と決め付けてもう一回実行しても落ちる。
そして同じエラーメッセージをもう一度確認したら、
expected to find text "ダッシュボード" in "Dashboard\nテスト 太郎\nHelp\nCreate New Task\nTask List\nEdit Task\nDelete Task" (RSpec::Expectations::ExpectationNotMetError)
これはログイン後にダッシュボードに遷移して、
「ダッシュボード」「タスク作成」などの画面名やボタンテキストなど画面の全要素をチェックして、
「ダッシュボード」というテキストは見つからなかったというもの。
\nテスト 太郎
とあるので一瞬見過ごしてしまったが、いつもなら以下のようなエラーメッセージが出てくる。
expected to find text "ダッシュボード" in "ダッシュボード\nテスト 太郎\nヘルプ\nタスク作成\nタスク一覧\nタスク編集\nタスク削除" (RSpec::Expectations::ExpectationNotMetError)
普通にスクリーンショットを撮っていれば一発でわかる話だが、なぜか全部の要素が英語になっていた。
そのため page.find('#createTask').click
のようなidやname、タグ名を探す系のステップは通り、
日本語のテキストを探す段階で画面の全要素を探して見つからない…という現象が発生しているようだった。
##対応
i18n対応によりブラウザの言語設定で英語と日本語の表記切り替えが可能なのだが、headlessモードはブラウザの言語設定を自動で英語に選択している模様。
しかしこのheadlessモードにしなければ言語設定が英語になるという現象は再現しない。
「Chrome headless capybara 英語」で調べてみる。
色々調べたが 「言語設定しないとheadlessモードではブラウザの言語設定が自動的に英語になる」 という感じ。
headlessモードとそうではない時でどうしてそうなるのかの説明を見つけられなかったが、とりあえず言語設定(オプション)をすればheadlessでも日本語設定で起動できるようなので、オプションを追加する。
options.add_argument("--disable-site-isolation-trials")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--headless")
# またまた追記↓
options.add_argument("--lang=ja-JP")
無事、解決。
これまたスクリーンショットをとればいい話なのだが、猿なのでスクリーンショットを撮るという文化的な思考にならず、確認用にテストステップを書き換え。
expected to find text "ももんが" in "ダッシュボード\nテスト 太郎\nヘルプ\nタスク作成\nタスク一覧\nタスク編集\nタスク削除" (RSpec::Expectations::ExpectationNotMetError)
多分スクリーンショット以外の方法をとるにしても、もっとマシな方法があるのだろうがとりあえず問題は解決。
再度シナリオ20件を全部headlessモードで自動テストを実行。
20 scenarios (20 passed)
解決。
##結論
今回のテスト対象のi18n対応の仕様は、ブラウザの言語設定が英語ならば英語、日本語ならば日本語で表示するようになっていた。headlessモードは自動的にブラウザの言語設定に英語を選択しているので、日本語を選択するように設定する必要があった。
###今日の学び
テストが落ちたら、
- スクリーンショットを撮る。
- エラーメッセージを読む。
###捕捉
今回の場合は --lang=ja-JP
で解決したが、以下のように解決しない場合もある模様。
https://qiita.com/jhanyu/items/e2f467684873d806ad00
###追記
circleCIでe2eテストの定期実行を試みたところ、上記の記事のように対応しないと、うまくいかなかった。
.circleci/config.yml
に以下の設定を行ったところ、無事日本語環境でe2eテストが実行できた。
environment:
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
LANGUAGE: ja_JP:ja