我们使用Gitlab CI(Runner)来测试我们的Rails应用程序,但是,当我们使用RSpec + Capybara +:chrome_headless时,它只会显示以下错误消息:
$ bundle exec rspec spec/features
Puma starting in single mode...
* Version 3.10.0 (ruby 2.4.3-p205), codename: Russell's Teapot
* Min threads: 0, max threads: 1
* Environment: test
* Listening on tcp://0.0.0.0:36354
Use Ctrl-C to stop
2018-07-27 05:01:00 DEBUG Selenium Executing Process ["/usr/local/bin/chromedriver", "--port=9515"]
2018-07-27 05:01:00 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
/home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/spec_set.rb:91:in `block in materialize': Could not find nokogiri-1.8.2 in any of the sources (Bundler::GemNotFound)
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/spec_set.rb:85:in `map!'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/spec_set.rb:85:in `materialize'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/definition.rb:171:in `specs'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/definition.rb:238:in `specs_for'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/definition.rb:227:in `requested_specs'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/runtime.rb:108:in `block in definition_method'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/runtime.rb:20:in `setup'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler.rb:107:in `setup'
from /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.3/lib/bundler/setup.rb:20:in `<top (required)>'
from /usr/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /usr/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
2018-07-27 05:01:00 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:01:00 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:01:01 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:01:01 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
.......
2018-07-27 05:01:19 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:01:19 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:01:19 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:01:20 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
F
Failures:
1) User auth. Login when locale is :en user login & logout
Failure/Error: visit "client/login?locale=en"
Selenium::WebDriver::Error::WebDriverError:
unable to connect to chromedriver 127.0.0.1:9515
# ./spec/features/user_auth_spec.rb:13:in `block (3 levels) in <top (required)>'
Finished in 20.71 seconds (files took 5.77 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/features/user_auth_spec.rb:12 # User auth. Login when locale is :en user login & logout
ERROR: Job failed: exit status 1
但是,我可以在同一服务器上运行irb + Capybara + Selenium + chromedriver,而不会出现错误:
$ irb
irb(main):001:0> require 'capybara'
=> true
irb(main):002:0> require 'selenium-webdriver'
=> true
irb(main):003:0> Capybara.register_driver :chrome_headless do |app|
irb(main):004:1* options = ::Selenium::WebDriver::Chrome::Options.new
irb(main):005:1> options.add_argument('--headless')
irb(main):006:1> options.add_argument('--disable-gpu')
irb(main):007:1> options.add_argument('--no-sandbox')
irb(main):008:1> options.add_argument('--disable-dev-shm-usage')
irb(main):009:1> options.add_argument('--window-size=1300,800')
irb(main):010:1> Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
irb(main):011:1> end
=> #<Proc:0x000055c907680210@(irb):3>
irb(main):012:0> session = Capybara::Session.new(:chrome_headless)
=> #<Capybara::Session>
irb(main):013:0> session.visit('http://www.google.com')
=> nil
irb(main):014:0> session.fill_in('q', with: 'Capybara')
=> #<Capybara::Node::Element tag="input" path="/HTML/BODY/DIV/DIV[3]/FORM/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[2]/DIV/DIV/DIV[2]/DIV/INPUT[1]">
irb(main):015:0> session.click_button("I'm Feeling Lucky")
Capybara::Ambiguous: Ambiguous match, found 2 elements matching visible button "I'm Feeling Lucky"
还有一件事...当我尝试在同一台服务器上手动运行测试时,出现了其他错误Could not find nokogiri-1.8.4
(但是GitLab CI bundle install
没问题,关于nokogiri的错误):>
$ bundle exec rspec spec/features
Capybara starting Puma...
* Version 3.12.0 , codename: Llamas in Pajamas
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:45802
2018-07-27 05:46:49 DEBUG Selenium Executing Process ["/usr/local/bin/chromedriver", "--port=9515"]
2018-07-27 05:46:49 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
Could not find nokogiri-1.8.4 in any of the sources
Run `bundle install` to install missing gems.
2018-07-27 05:46:50 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:46:50 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:46:50 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:46:50 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:46:51 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
2018-07-27 05:46:51 DEBUG Selenium polling for socket on ["127.0.0.1", 9515]
我还尝试将chromedriver降级到2.39,但仍然是相同的错误。
请帮助,我用Google搜索了很多,但是没有运气。谢谢。
顺便说一句,我没有使用gem chromedriver-helper
,并且在我的开发人员上进行的本地测试没有错误。
更新:
更改为Firefox后,它仍然显示错误:
$ bundle exec rspec spec/features
Puma starting in single mode...
* Version 3.10.0 (ruby 2.4.3-p205), codename: Russell's Teapot
* Min threads: 0, max threads: 1
* Environment: test
* Listening on tcp://0.0.0.0:34093
Use Ctrl-C to stop
2018-07-27 09:09:47 DEBUG Selenium Executing Process ["/home/gitlab-runner/.rbenv/versions/2.4.3/bin/geckodriver", "--binary=/usr/bin/firefox", "--port=4444"]
2018-07-27 09:09:47 DEBUG Selenium polling for socket on ["127.0.0.1", 4444]
2018-07-27 09:09:47 DEBUG Selenium polling for socket on ["127.0.0.1", 4444]
1532682587782 geckodriver INFO geckodriver 0.21.0
1532682587787 geckodriver INFO Listening on 127.0.0.1:4444
2018-07-27 09:09:47 INFO Selenium Skipping handshake as we know it is W3C.
2018-07-27 09:09:47 INFO Selenium -> POST session
2018-07-27 09:09:47 INFO Selenium >>> http://127.0.0.1:4444/session | {"desiredCapabilities":{"unexpectedAlertBehaviour":"ignore","moz:firefoxOptions":{"args":["--headless","--window-size=1300,800"]}},"capabilities":{"firstMatch":[{"moz:firefoxOptions":{"args":["--headless","--window-size=1300,800"]}}]}}
2018-07-27 09:09:47 DEBUG Selenium > {"Accept"=>"application/json", "Content-Type"=>"application/json; charset=UTF-8", "User-Agent"=>"selenium/3.13.1 (ruby linux)", "Content-Length"=>"235"}
1532682587980 mozrunner::runner INFO Running command: "/usr/bin/firefox" "-marionette" "--headless" "--window-size=1300,800" "-foreground" "-no-remote" "-profile" "/tmp/rust_mozprofile.UXuoXoODlZKn"
*** You are running in headless mode.
1532682589509 Marionette INFO Listening on port 42912
1532682589639 Marionette DEBUG [2147483649] Frame script loaded
1532682589646 Marionette DEBUG [2147483649] Frame script registered
2018-07-27 09:09:49 INFO Selenium <- {"value": {"sessionId":"8028cc40-8b67-410c-9102-9cae185a3d23","capabilities":{"acceptInsecureCerts":false,"browserName":"firefox","browserVersion":"62.0","moz:accessibilityChecks":false,"moz:headless":true,"moz:processID":13154,"moz:profile":"/tmp/rust_mozprofile.UXuoXoODlZKn","moz:useNonSpecCompliantPointerOrigin":false,"moz:webdriverClick":true,"pageLoadStrategy":"normal","platformName":"linux","platformVersion":"4.4.0-1041-aws","rotatable":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000}}}}
2018-07-27 09:09:49 INFO Selenium Detected W3C dialect.
2018-07-27 09:09:49 INFO Selenium -> POST session/8028cc40-8b67-410c-9102-9cae185a3d23/url
2018-07-27 09:09:49 INFO Selenium >>> http://127.0.0.1:4444/session/8028cc40-8b67-410c-9102-9cae185a3d23/url | {"url":"http://127.0.0.1:34093/client/login?locale=en"}
2018-07-27 09:09:49 DEBUG Selenium > {"Accept"=>"application/json", "Content-Type"=>"application/json; charset=UTF-8", "User-Agent"=>"selenium/3.13.1 (ruby linux)", "Content-Length"=>"55"}
1532682589668 Marionette DEBUG [2147483649] Received DOM event beforeunload for about:blank
2018-07-27 09:10:49 INFO Selenium -> DELETE session/8028cc40-8b67-410c-9102-9cae185a3d23/cookie
F
Failures:
1) User auth. Login when locale is :en user login & logout
Got 0 failures and 2 other errors:
1.1) Failure/Error: visit "client/login?locale=en"
Net::ReadTimeout:
Net::ReadTimeout
# ./spec/features/user_auth_spec.rb:13:in `block (3 levels) in <top (required)>'
1.2) Failure/Error: @io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
Net::ReadTimeout:
Net::ReadTimeout
# /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
# /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
# /home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
这里是环境:
Ubuntu 16.04
rbenv 1.1.1-28-gb943955
ruby 2.4.3p205(2017-12-14修订版61247)[x86_64-linux]
(/home/gitlab-runner/.rbenv/shims/ruby)
捆绑程序1.16.3 (/home/gitlab-runner/.rbenv/shims/bundle)
Rspec 3.7.0
selenium-webdriver(3.13.1)
水豚(2.15.4)
chromedriver 2.40.565383(76257d1ab79276b2d53ee976b2c3e3b9f335cde7)
(/usr/local/bin/chromedriver)
Google Chrome 68.0.3440.75 (/usr/bin/google-chrome-stable)
nokogiri(1.8.2,1.8.4)都尝试过。
ENV ['PATH']:/home/gitlab-runner/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/bin:/home/gitlab-runner/.rbenv/versions/2.4.3/bin:/home/gitlab-runner/.rbenv/libexec:/home/gitlab-runner/.rbenv/plugins/ruby-build/bin:/home/gitlab-runner/bin:/home/gitlab-runner/.local/bin:/home/gitlab-runner/.rbenv/shims:/home/gitlab-runner/.rbenv/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/snap/bin
spec / rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'factory_bot_rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'webmock/rspec'
require 'vcr'
WebMock.disable_net_connect!(allow_localhost: true)
I18n.locale = :en
ERROR = ActiveRecord::RecordInvalid
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# Devise setting
config.include Devise::Test::ControllerHelpers, type: :controller
config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: /spec\/api/
config.include(Shoulda::Matchers::ActiveModel, type: :model)
config.include(Shoulda::Matchers::ActiveRecord, type: :model)
config.use_transactional_fixtures = true
config.include FactoryBot::Syntax::Methods
VCR.configure do |c|
c.cassette_library_dir = Rails.root.join("spec", "vcr")
c.hook_into :webmock
c.configure_rspec_metadata!
c.ignore_localhost = true
end
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end
spec / support / capybara.rb
require 'capybara/rspec'
require 'capybara/rails'
Capybara.default_max_wait_time = 15
# define server port
# Capybara.server_port = 3333
# define browser go to where (with port)
# Capybara.app_host = 'http://localhost:3333'
Capybara.register_driver :chrome_headless do |app|
::Selenium::WebDriver.logger.level = :debug
options = ::Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--window-size=1300,800')
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
# :selenium :selenium_chrome and :selenium_chrome_headless are also registered
Capybara.javascript_driver = :chrome_headless
spec / features / user_auth_spec.rb:
require 'rails_helper'
RSpec.feature "User auth.", js: true do
let!(:company) { FactoryBot.create :my_com }
let!(:user) { FactoryBot.create :login_user, company: company }
before(:each) { COMPANY = company }
before(:all) { VCR.turn_off! }
after(:all) { VCR.turn_on! }
feature "Login when locale is :en" do
scenario "user login & logout" do
visit "client/login?locale=en"
within('.modal-info') do
fill_in "log-in", with: "test001"
fill_in "log-in-pwd", with: "12345678"
click_on 'Login'
end
expect(page).to have_text "Signed in successfully."
expect(page).to have_text "test001"
visit "/"
find('.logout-btn').click
expect(page).to have_text "Signed out successfully."
expect(page).not_to have_text "test001"
end
end
end
Gemfile(部分):
gem 'rails', '~> 5.1.5'
group :test do
gem 'rails-controller-testing'
gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5'
gem 'capybara'
gem 'selenium-webdriver'
gem 'webmock'
gem 'vcr'
gem 'factory_bot_rails'
gem 'rspec-rails'
gem 'ffaker'
end
.gitlab-ci.yml:
......
bin/rails db:test:prepare
bundle exec rspec
......