80786
ローカル環境では `rails test`
が成功するのですが、GitHubにpushしてCircleCiのテスト中に高確率でエラーが発生してしまいます。ですが何回かリトライしてるとエラーが発生せずにテストが成功することもあります。  
何が原因でこのような状態になっているのでしょうか？

また、同じテスト内容でもリトライするごとにエラーの発生箇所が変わったりもします。

Railsのテストコード自体はしっかりしたものなのに、CircleCiでのテストでのみエラーがランダムに発生してしまい時間がかかって困っています。

**エラー内容の例1**

```

    #!/bin/bash -eo pipefail
    bundle exec rails test
    Running via Spring preloader in process 269
    Started with run options --seed 53502
    
    ERROR["test_invalid_signup_information", #<Minitest::Reporters::Suite:0x0000560b6b9513d0 @name="UsersSignupTest">, 10.051366892999795][0m==========         ] 76% Time: 00:00:10,  ETA: 00:00:03
     test_invalid_signup_information#UsersSignupTest (10.05s)
    ActionView::Template::Error:         ActionView::Template::Error: 783: unexpected token at ''
                app/views/layouts/application.html.erb:9
                app/controllers/users_controller.rb:18:in `create'
                test/integration/users_signup_test.rb:10:in `block (2 levels) in <class:UsersSignupTest>'
                test/integration/users_signup_test.rb:9:in `block in <class:UsersSignupTest>'
    
    ERROR["test_login_with_valid_information", #<Minitest::Reporters::Suite:0x0000560b6b75f3d8 @name="UsersLoginTest">, 10.13947368600202][0m==========         ] 76% Time: 00:00:10,  ETA: 00:00:03
     test_login_with_valid_information#UsersLoginTest (10.14s)
    ActionView::Template::Error:         ActionView::Template::Error: 783: unexpected token at ''
                app/views/layouts/application.html.erb:9
                test/integration/users_login_test.rb:24:in `block in <class:UsersLoginTest>'
    
      21/21: [=================================] 100% Time: 00:00:10, Time: 00:00:10
    
    Finished in 10.41909s
    21 tests, 44 assertions, 0 failures, 2 errors, 0 skips
    
    Exited with code exit status 1
    CircleCI received exit code 1
    
```

**エラー内容の例2**

```

    #!/bin/bash -eo pipefail
    bundle exec rails test
    Running via Spring preloader in process 252
    Started with run options --seed 40275
    
    ERROR["test_login_with_valid_email/invalid_password", #<Minitest::Reporters::Suite:0x000055f679eeb658 @name="UsersLoginTest">, 17.182131017001666]m===               ] 57% Time: 00:00:00,  ETA: 00:00:00
     test_login_with_valid_email/invalid_password#UsersLoginTest (17.18s)
    ActionView::Template::Error:         ActionView::Template::Error: 783: unexpected token at ''
                app/views/layouts/application.html.erb:9
                test/integration/users_login_test.rb:11:in `block in <class:UsersLoginTest>'
    
      21/21: [=================================] 100% Time: 00:00:17, Time: 00:00:17
    
    Finished in 17.58606s
    21 tests, 56 assertions, 0 failures, 1 errors, 0 skips
    
    Exited with code exit status 1
    CircleCI received exit code 1
    
```

* * *

### ソースコード

src/Gemfile

```

    source 'https://rubygems.org'
    git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
    ruby '2.7.4'
    
    gem 'rails', '~> 6.1.4'
    gem 'mysql2', '~> 0.5'
    gem 'puma', '~> 5.0'
    gem 'sass-rails', '>= 6'
    gem 'webpacker', '~> 5.0'
    gem 'turbolinks', '~> 5'
    gem 'jbuilder', '~> 2.7'
    gem 'bcrypt', '~> 3.1.7'
    gem 'bootsnap', '>= 1.4.4', require: false
    
    group :development, :test do
      gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
    end
    
    group :development do
      gem 'web-console', '>= 4.1.0'
      gem 'listen', '~> 3.3'
      gem 'spring'
      gem 'spring-watcher-listen', '~> 2.0.0'
    end
    
    group :test do
      gem 'capybara', '>= 3.26'
      gem 'selenium-webdriver'
      gem 'webdrivers'
      gem 'rails-controller-testing', '~> 1.0.4'
      gem 'minitest',                 '~> 5.11.3'
      gem 'minitest-reporters',       '~> 1.3.8'
    end
    
    gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
    
```

docker-compose.yml

```

    version: '3'
    services:
      db:
        image: mysql:8.0
        command: --default-authentication-plugin=mysql_native_password
        volumes:
          - ./src/db/mysql_data:/var/lib/mysql
        environment:
          MYSQL_ROOT_PASSWORD: パスワード
      web:
        build: .
        stdin_open: true
        tty: true
        command: bundle exec rails s -p 3000 -b '0.0.0.0'
        volumes:
          - ./src:/app
        ports:
          - "3000:3000"
        environment:
          RAILS_ENV: development
        depends_on:
          - db
    
```

Dockerfile

```

    FROM ruby:2.7
    
    ENV RAILS_ENV=production
    
    RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
      && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
      && apt-get update -qq \
      && apt-get install -y nodejs yarn
    WORKDIR /app
    COPY ./src /app
    RUN bundle config --local set path 'vendor/bundle' \
      && bundle install -j4
    
    COPY start.sh /start.sh
    RUN chmod 744 /start.sh
    CMD ["sh", "/start.sh"]
    
```

start.sh

```

    #!/bin/sh
    
    if [ "${RAILS_ENV}" = "production" ]
    then
        bundle exec rails assets:precompile
    fi
    
    bundle exec rails s -p ${PORT:-3000} -b 0.0.0.0
    
```

.circleci/config.yml

```

    version: 2.1
    orbs:
      ruby: circleci/ruby@1.1.2
      heroku: circleci/heroku@1.2.3
    
    jobs:
      build:
        docker:
          - image: circleci/ruby:2.7-node
        working_directory: ~/プロジェクトフォルダ名/src
        steps:
          - checkout:
              path: ~/プロジェクトフォルダ名
          - ruby/install-deps
    
      test:
        docker:
          - image: circleci/ruby:2.7-node
          - image: circleci/mysql:5.5
            environment:
              MYSQL_ROOT_PASSWORD: パスワード
              MYSQL_DATABASE: app_test
              MYSQL_USER: root
        environment:
          BUNDLE_JOBS: "3"
          BUNDLE_RETRY: "3"
          APP_DATABASE_HOST: "127.0.0.1"
          RAILS_ENV: test
        working_directory: ~/プロジェクトフォルダ名/src
        steps:
          - checkout:
              path: ~/プロジェクトフォルダ名
          - ruby/install-deps
          - run:
              name: Database setup
              command: bundle exec rails db:migrate
          - run: yarn install
          - run:
              name: test
              command: bundle exec rails test
    
      deploy:
        docker:
          - image: circleci/ruby:2.7-node
        steps:
          - checkout
          - setup_remote_docker:
              version: 19.03.13
          - heroku/install
          - run:
              name: heroku login
              command: heroku container:login
          - run:
              name: push docker image
              command: heroku container:push web -a $HEROKU_APP_NAME
          - run:
              name: release docker image
              command: heroku container:release web -a $HEROKU_APP_NAME
          - run:
              name: database setup
              command: heroku run bundle exec rake db:migrate RAILS_ENV=production -a $HEROKU_APP_NAME
    
    workflows:
      version: 2
      build_test_and_deploy:
        jobs:
          - build
          - test:
              requires:
                - build
          - deploy:
              requires:
                - test
              filters:
                branches:
                  only: main
    
```

src/app/views/layouts/application.html.erb

```

    <!DOCTYPE html>
    <html>
      <head>
        <title><%= full_title(yield(:title)) %></title>
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>
        <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
        <%= render 'layouts/shim' %>
      </head>
      <body>
    
      <% #ヘッダー▼ %>
      <%= render 'layouts/header' %>
      <% #ヘッダー▲ %>
    
        <% #コンテンツ▼ %>
        <main>
          <article class="contents">
            <%= yield %>
          </article>
        </main>
        <% #コンテンツ▲ %>
    
        <% #フッター▼ %>
        <%= render 'layouts/footer' %>
        <% #フッター▲ %>
    
        <% #ドロワー▼ %>
        <%= render 'layouts/drawer' %>
        <% #ドロワー▲ %>
    
        <%= debug(params) if Rails.env.development? %>
    
      </body>
    </html>
    
```

src/test/integration/users_signup_test.rb

```

    require "test_helper"
    
    class UsersSignupTest < ActionDispatch::IntegrationTest
    
      #無効なアカウント作成のテスト
      test "invalid signup information" do
        get signup_path
        #users_pathへ無効な情報でPostリクエストを送ってもデータベースの数が増えてないことを確認
        assert_no_difference 'User.count' do
          post users_path, params: { user: { name:  "",
                                             email: "user@invalid",
                                             password:              "foo",
                                             password_confirmation: "bar" } }
        end
        assert_template 'users/new'
        #エラーメッセージが表示されていることを確認
        assert_select 'div#error_explanation'
        assert_select 'div.alert_danger'
      end
    
      test "valid signup information" do
        get signup_path
        assert_difference 'User.count', 1 do
          post users_path, params: { user: { name:  "Example User",
                                             email: "user@example.com",
                                             password:              "password",
                                             password_confirmation: "password" } }
        end
        # follow_redirect!
        # assert_template 'users/show'
        assert_redirected_to root_path
        follow_redirect!
        assert_template 'static_pages/home'
        assert_not flash.empty?
        assert is_logged_in?
      end
    
    end
    
```
CC BY-SA 4.0
2021-08-14T01:19:32.700
80784
2021-08-15T10:48:48.347
2021-08-15T10:48:48.347
3060
44197
question
ruby-on-rails テスト circleci
CircleCiでのRailsテスト実行時ランダムにエラーが発生してしまいます: ActionView::Template::Error: 783: unexpected token at ''
このエラーの原因の一端は [webpacker](https://railsguides.jp/webpacker.html)
です。私の知る限り未解決で、関連する issue はこの回答が書かれた時点で open のままです:
<https://github.com/rails/webpacker/issues/2860>。

具体的には、アセットのコンパイルが行われていない状態でテストが並列に走る際に、webpacker
がレースコンディションに陥っているのだと思われます。手元でテストを走らせた際にエラーが起こらなかったのは、ローカル環境にコンパイル済みのファイルがあるか、テストが並列になっていないかしたためでしょう。

webpacker 側で対処が行われるまでの間、以下のいずれかのワークアラウンドで対処できるはずです。

  * test 環境でもテスト前に `assets:precompile` する、もしくは、
  * Webpacker の利用をやめる。

なお、英語版 Stack Overflow にも同様の Q&A がありました:
<https://stackoverflow.com/q/58621271/5989200>

## 推測の過程

今回の問題では複数の箇所でエラーが出ていますが、出ているエラーはどれも `ActionView::Template::Error: 783:
unexpected token at ''` です。つまり、色々な view の処理に失敗している原因はどれも同じ可能性があります。

この推測のもとエラーのスタックトレースと view のプログラムを突き合わせると、javascript_pack_tag
が使われている行でエラーが出ています。

```

    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    
```

javascript_pack_tag は webpacker を使うためのメソッドです。Webpacker
は動的にファイルを変換したりキャッシュしたりする仕組みを持っており、CI
環境などのまっさらな環境で実行したときのみエラーが起こるという挙動に関連している可能性は高そうです。

そこで `webpacker ActionView::Template::Error: 783: unexpected token at ''`
で検索したところ、先人の知恵を見つけ、この回答を投稿するに至りました。

テストの実行の仕方や実際のテストに使われているソースコードが具体的に質問文に書かれていたため、比較的素早く原因らしきものを見つけることができました。ありがとうございます。
CC BY-SA 4.0
2021-08-14T05:22:38.093
80786
2021-08-14T05:22:38.093
19110
80784
answer