GitHub Actionsのワークフローを利用してクロスブラウザのE2Eテストを自動化する

こんにちは。
マネーフォワード クラウド経費』のフロントエンドエンジニアをしている木村(@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

ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』

おつり貯金アプリ 『しらたま』

おトクが飛び出すクーポンサービス 『tock pop』

金融商品の比較・申し込みサイト 『Money Forward Mall』

くらしの経済メディア 『MONEY PLUS』

本業に集中できる新しいオンライン融資サービス 『Money Forward BizAccel』

Pocket