こんにちは。 『マネーフォワード クラウド経費』のフロントエンドエンジニアをしている木村(@kimromi)です。
Ruby on Railsを利用してサービス開発を進めているプロダクトのフロントエンドの環境を整えていき、UIの改善やフロントエンド側の開発効率アップなどにつなげていくような動きを現在やっています。
なぜクロスブラウザのE2Eテストが必要になったか
ある日、IE11のみでJavaScriptエラーが起こり動作しないとの連絡が入り、慌てて対象のプルリクエストをリバートしたということが起こりました。
原因としてはライブラリの追加によるものでした。 現在フロントエンドの改修を行っていく中で、ライブラリの追加やビルド方式の変更などドラスティックな変更をすることが多くなってきています。
そのたびにMicrosoftからダウンロードできるVM環境を立ち上げ手元で確認するのは手間がかかり確認漏れも発生する可能性があるため、クロスブラウザでのE2Eテストの必要性を感じました。 また、BtoB向けのクラウドサービスという特性上、IE11からのアクセスが全体の約23%とGoogle Chromeに次ぐ2番目にアクセスが多いブラウザです。 Microsoftがサポートを切らない限りサービスとしてIE11のサポートを切ることはできないという判断で今後も付き合っていく必要があります。 IE11での自動テストを導入することでリリース前に不具合を検知することができ品質を向上させる目的もあります。
GitHub Actionsを選んだ理由
マネーフォワード クラウド経費ではBrowserStackなどのクロスブラウザのE2Eテストは導入していない状態でした。
現在ベータ版であるGitHub ActionsではWindows OSとMac OSを利用できるという情報を得ていたため、今後GitHub Actionsを使う際の素振りの意味でもGitHub Actionsを利用してみることにしました。
そういったことに対して積極的に後押ししてくれるチーム環境はとても良いと感じています。
実装例
GitHub Actions
GitHub Actionsはリポジトリの.github/workflows/
以下にYamlファイルを置くことでワークフローを実行することができます。
以下のように設定することでmasterブランチへのプルリクエストに変更があるたびにワークフローが実行されます。 構文については公式のドキュメントがあるのでそちらを参照しました。
name: cross-browser-e2e on: pull_request: branches: - master jobs: IE11: runs-on: windows-latest steps: - uses: actions/checkout@v1 - uses: actions/setup-ruby@v1 with: ruby-version: '2.6.x' - name: Setup E2E run: | # IE11でBasic認証用の https://[id]:[pass]@domain のURLに対応するためのレジストリ変更 reg add "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_HTTP_USERNAME_PASSWORD_DISABLE" /v iexplore.exe /t REG_DWORD /d 0 /f gem install bundler:2.0.1 bundle install working-directory: spec/cross-browser - name: Execute test run: bundle exec rspec working-directory: spec/cross-browser env: BROWSER: ie Firefox: runs-on: windows-latest steps: - uses: actions/checkout@v1 - uses: actions/setup-ruby@v1 with: ruby-version: '2.6.x' - name: Setup E2E run: | gem install bundler:2.0.1 bundle install working-directory: spec/cross-browser - name: Execute test run: bundle exec rspec working-directory: spec/cross-browser env: BROWSER: firefox Chrome: runs-on: windows-latest steps: - uses: actions/checkout@v1 - uses: actions/setup-ruby@v1 with: ruby-version: '2.6.x' - name: Setup E2E run: | gem install bundler:2.0.1 bundle install working-directory: spec/cross-browser - name: Execute test run: bundle exec rspec working-directory: spec/cross-browser env: BROWSER: chrome
現在IE11とFirefoxとChromeのみのテストを走らせています。 なぜEdgeとSafariは含まれていないかについては後述します。
Seleniumを使ったテストの実装
弊社はRubyでの開発中心であることや、RSpecのSystem specをチームとして導入済みなこともあり、Rubyでの実装を選択しました。
サービスのRuby on RailsのRSpec上で走らせようとしましたが、DBへのアクセスがあったり、そもそもbundle installするために色々なサーバー環境の依存がありGitHub Actions上での構築が大変であるため断念しました。
新たにディレクトリを切り(spec/cross-browser
)、Gemfileを別に用意することで既存のRSpecとは切り離した状態でテストを実行しています。
source 'https://rubygems.org' group :test do gem 'capybara' gem 'rspec' gem 'selenium-webdriver' gem 'webdrivers' gem 'ffi' # WindowsOSのために必要でした end
require 'selenium-webdriver' require 'webdrivers' require 'capybara' require 'capybara/rspec' ## ---------- 各ブラウザのドライバー設定 ---------- # Seleniumが推奨しているInternetExplorerDriverのバージョン Webdrivers::IEdriver.required_version = '3.14.0' Capybara.register_driver :selenium_ie do |app| options = Selenium::WebDriver::IE::Options.new Capybara::Selenium::Driver.new(app, browser: :ie, options: options) end Capybara.register_driver :selenium_safari do |app| options = Selenium::WebDriver::Safari::Options.new Capybara::Selenium::Driver.new(app, browser: :safari, options: options) end Capybara.register_driver :selenium_firefox do |app| options = Selenium::WebDriver::Firefox::Options.new Capybara::Selenium::Driver.new(app, browser: :firefox, options: options) end Capybara.register_driver :selenium_edge do |app| options = Selenium::WebDriver::Edge::Options.new Capybara::Selenium::Driver.new(app, browser: :edge, options: options) end Capybara.register_driver :selenium_chrome do |app| options = Selenium::WebDriver::Chrome::Options.new( args: [ '--headless', '--no-sandbox', '--disable-gpu' ] ) Capybara::Selenium::Driver.new(app, browser: :chrome, options: options) end Capybara.default_max_wait_time = 10 Capybara.app_host = "https://biz.moneyforward.com/expense" # 環境変数でどのドライバーを使うかを判定 Capybara.default_driver = case ENV['BROWSER'] when 'ie' :selenium_ie when 'safari' :selenium_safari when 'firefox' :selenium_firefox when 'edge' :selenium_edge else :selenium_chrome end RSpec.configure do |config| config.include Capybara::DSL config.before(:each) do Capybara.page.driver.browser.manage.window.maximize Capybara.page.driver.browser.manage.window.resize_to(1980, 1200) end end
あとはRSpec上でCapybaraのDSLが使えるので、visitやhave_xxxマッチャを駆使してテストを書きます。以下は例なので実際のものではないです。
describe 'トップページ' do it 'titleに間違いがないこと' do visit '/' expect(page).to have_title '経費精算システム「マネーフォワード クラウド経費」' end end
便利だった点として、System specでも利用するwebdriversというgemを使っていますが、Seleniumを使うタイミングで自動的にブラウザのドライバをダウンロードしパスを通してくれるのでワークフローの実行時にダウンロードする作業が必要ありませんでした。
webdriversは現在IE、Firefox、Chrome、Edge(Chromiumベース)に対応していますが、selenium-webdriver gemのほうがEdgeにまだ対応していませんでした。version4から対応するようです。
ワークフローが 動いた様子
苦労したこと
EdgeとSafariでテストできない
ChromiumベースのEdgeは前述の通りselenium-webdriver v4を待つとして、EdgeHTMLベースのEdgeのドライバーをダウンロードする際にMicrosoftのページにあるように DISM.exe /Online /Add-Capability /CapabilityName:Microsoft.WebDriver~~~~0.0.1.0
を実行すればよいのですが、A Windows capability name was not recognized.
のエラーが出てダウンロードできませんでした。当方Windowsに詳しくないためv4を待つかということでここで断念しました。
Safariは公式ページにあるようにsafaridriver --enable
を実行すればよいようでしたが、実行時の以下のエラーが解決できませんでした。
UnhandledPromiseRejectionWarning: SessionNotCreatedError: Could not create a session: You must enable the 'Allow Remote Automation' option in Safari's Develop menu to control Safari via WebDriver.
@mizchiさんが試していたものにて実行していたsafaridriver -p 0 &
を実行してみましたが状況はかわらずでした。
完全に推測ですが、Safari 13に上がったタイミングでこのあたりの仕様が変わってコマンドから実行しても設定が切り替わらなくなっているのではないかと思います。手元のMacではSafariの設定で [開発] -> [リモートオートメーションを許可] のチェックをONすると実行することはできました。
このあたりの知見がありましたら是非教えてください。
Basic認証を突破する
E2Eテスト対象のページにBasic認証がかけており、認証する際にはURLを https://[ID]:[Password]@url
の形式にすればFirefoxとChromeは認証できるのですが、IE10以降はレジストリを変更する必要があったため、IE11のワークフローに以下を追加することにより突破できました。
reg add "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_HTTP_USERNAME_PASSWORD_DISABLE" /v iexplore.exe /t REG_DWORD /d 0 /f
今回スキップしたSafariではプロキシサーバーを立てないと認証できないという情報もあり厳しさを感じています。
IE11だけテストが落ちる現象
JavaScriptのalert(confirm)がacceptできないということが起きたのですが、使用するIEDriverのバージョンを最新からSelenium推奨の3.14.0に落とすことでacceptできるようになり解決しました。
別の問題で、IEのみSeleniumからブラウザのサイズを最大化したり変更したりしても反映されませんでした。 デフォルトの小さいウインドウの中で表示されている要素しか見つけることができずクリックしたいボタンがクリックできないという問題が発生しています。 こちらは解決することができず、引き続き調査しなくてはテストが追加できないという状態です。 現在はクリックできる場所でのテストにとどまっています。
GitHub Actionsのワークフロー構文が共通化しにくい
ワークフロー構文のYamlにsteps
として順に実行するものを書いていきますが、steps
が配列での記述しかできないため、YamlのAnchor/Aliasが使うことができず同じsteps
のワークフローをDRYに書くことができませんでした。
このあたりはGitHub Actionsの改善してくるポイントであると思うので気長に待とうと思います。
こんな感じでかきたい(Yamlの仕様を超えているけど)。
setup: &setup - やること1 - やること2 jobs: IE11: steps: <<: *setup Firefox: steps: <<: *setup Chrome: steps: <<: *setup
まとめ、今後について
ちょうどクロスブラウザの闇と闇と闇という資料が公開され、私も本当に闇だと痛感しました。 ただもともとの目的である、IE11での意図しない不具合検知とGitHub Actionsのキャッチアップは概ね達成できたと感じています。
対応できていないブラウザの対応をしたり、ブラウザごとのビジュアルリグレッションテストなどもできていくと嬉しそうとの声もあがっていましたので、引き続きキャッチアップしていこうと思います。 メンテナンスが辛いようであれば有料サービスに切り替えていくというのももちろん視野にいれており、今回の体験は今後の技術選定に役に立つものと感じています。
マネーフォワードでは、エンジニアを募集しています。 ご応募お待ちしています。
【採用サイトのご案内】 ■マネーフォワード採用サイト ■Wantedly
【プロダクトのご紹介】 ■お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android
■ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』