How can I configure puma when running Capybara? - ruby-on-rails

I'd like to adjust the puma configuration when running Capybara tests. Changing settings in .env, .env.test (I use dotenv), or config/puma.rb has no effect.
Where can I change the configuration?
Rails 5.1, poltergeist 1.15.0, capybara 2.14.0, puma 2.8.2

Generally with Capybara you configure the server in a register_server block. The :puma server definition Capybara provides is
Capybara.register_server :puma do |app, port, host|
require 'rack/handler/puma'
Rack::Handler::Puma.run(app, Host: host, Port: port, Threads: "0:4")
end
If you're using Rails 5.1 system testing it has added a layer of abstraction on top of that with server configuration being done in
ActionDispatch::SystemTesting::Server#register which is defined as
def register
Capybara.register_server :rails_puma do |app, port, host|
Rack::Handler::Puma.run(app, Port: port, Threads: "0:1")
end
end
Either way you should be able to either overwrite one of the current server registrations
Capybara.register_server :rails_puma do |app, port,host|
Rack::Handler::Puma.run(app, ...custom settings...)
end
or configure your own
Capybara.register_server :my_custom_puma do |app, port, host|
Rack::Handler::Puma.run(app, ...custom settings...)
end
Capybara.server = :my_custom_puma

In ApplicationSystemTestCase, you can configure by passing options to the default :puma server used by Rails in setup.
AFAIK, this will work for any options, but I've only used
Silent: true to silence the puma startup output
Thread: '1:1' to configure the puma process to only use one thread
Here's how I've setup up rails systems tests to run inside docker containers:
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :chrome, screen_size: [1400, 1400], options: { url: "http://selenium:4444/wd/hub" }
def setup
Capybara.server_host = '0.0.0.0' # bind to all interfaces
Capybara.server = :puma, { Silent: true, Threads: '1:1' }
host! "http://#{IPSocket.getaddress(Socket.gethostname)}"
super
end
end

Related

set Rails environment url for selenium remote

I got selenium remote configured and running. I can access my development server (deployed with 'rails s') on '192.168.1.23:3000' from my computer using test methods like 'visit root_path' on capybara with minitest.
However, when I close my development server, I can't access my test server while testing, I just get a chrome error with page not found
test file:
require "test_helper"
feature "dashboard" do
scenario "test1", :js => true do
#Rails.application.routes.default_url_options[:host]= 'http://192.168.1.23:3000'
visit root_path
end
Note: activating line 4 gives me nil when running visit root_path
test_helper.rb
Capybara.configure do |config|
config.default_host = 'http://192.168.1.23:3000'
config.app_host = 'http://192.168.1.23:3000'
end
I've also tried
test environment, test.rb
Rails.application.default_url_options = {:host => "http://192.168.1.23:3000" }
Rails.application.routes.default_url_options = {:host => "http://192.168.1.23:3000" }
Edit:
I have rails server configured to listen to external addresses:
boot.rb
#this lets listen to some interfaces,
#https://fullstacknotes.com/make-rails-4-2-listen-to-all-interface/
require 'rubygems'
require 'rails/commands/server'
module Rails
class Server
alias :default_options_bk :default_options
def default_options
default_options_bk.merge!(Host: '192.168.1.23')
end
end
end
By default Capybara runs the application on a random port, but you've set app_host to only connect on port 3000 (Which is the dev server default). Rather than setting a fixed port in app_host set
Capybara.always_include_port = true
Capybara.app_host = 'http://192.168.1.23`
Then if the random port assignment isn't working due to firewall issues between your selenium remote and local machine you can set
Capybara.server_port = <some fixed port number the test app will get run on>

Sidekiq queue failing in test - requires separate Redis process

Running an RSpec test with a Sidekiq::Queue instance is failing unless Redis is running separately.
Sidekiq::Queue.new('my-queue').select(&:item)
Raises error in test
Redis::CannotConnectError:
Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
I've added the usual to the spec helper:
require 'sidekiq/testing'
Sidekiq::Testing.inline!
And mock_redis to the gemfile.
# gemfile
gem 'mock_redis', '0.16.1'
Using sidekiq (3.4.2)
How can I update my configuration to allow this to work?
mock_redis only provides with a fake redis. It does not intercept/replace actual redis classes/connections. If you intend to use fake redis in tests, you should tell sidekiq so. In your config/initializers/sidekiq.rb (or whereever your sidekiq redis config is):
redis = if Rails.env.test?
require 'mock_redis'
MockRedis.new
else
{ url: 'redis://redis.example.com:7372/12' }
end
Sidekiq.configure_server do |config|
config.redis = redis
end
Sidekiq.configure_client do |config|
config.redis = redis
end
I solved this by mocking Redis for tagged RSpec tests in the spec_helper.rb file.
config.before(:each, redis: true) do
mock = MockRedis.new
allow(Redis).to receive(:new).and_return(mock)
end
Then in the scenario:
scenario "my scenario with redis", redis: true do
...
end

How to access Guest's port 3000 from Host?

Here's my Vagrantfile:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu-14.04-x64"
# Sync'd folders
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "~/work", "/home/vagrant/work", create: true
config.vm.synced_folder "~/apt-archives", "/var/cache/apt/archives/", create: true
# Ubuntu VM
config.vm.define "ubuntu" do |ubuntu|
ubuntu.vm.provision "shell", path: "provision.sh", privileged: false
ubuntu.vm.network "forwarded_port", guest: 3000, host: 8080 # http
ubuntu.vm.network "private_network", ip: "10.20.30.100"
ubuntu.vm.hostname = "ubuntu"
# VirtualBox Specific Stuff
# https://www.virtualbox.org/manual/ch08.html
config.vm.provider "virtualbox" do |vb|
# Set more RAM
vb.customize ["modifyvm", :id, "--memory", "2048"]
# More CPU Cores
vb.customize ["modifyvm", :id, "--cpus", "2"]
end # End config.vm.provider virtualbox
end # End config.vm.define ubuntu
end
For example, when I run rails app using port 3000, from the guest machine I would accessing http://localhost:3000.
But I'm trying to access the app via host's browser.
None of below worked:
http://10.20.30.100:8080
https://10.20.30.100:8080
http://10.20.30.100:3000
https://10.20.30.100:3000
Browser on the host's showing: ERR_CONNECTION_REFUSED
For security reasons, Rails 4.2 limits remote access while in development mode. This is done by binding the server to 'localhost' rather than '0.0.0.0' ....
To access Rails working on a VM (such as one created by Vagrant), you need to change the default Rails IP binding back to '0.0.0.0'.
See the answers on the following StackOverflow Question, there are a number of different approaches suggested.
The idea is to get Rails running either by forcing the following command:
rails s -b 0.0.0.0
Or by hardcoding the binding into the Rails app (which I found less desirable):
# add this to config/boot.rb
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0')
end
end
end
Personally, I would have probably gone with the suggestion to use foreman and a Procfile:
# Procfile in Rails application root
web: bundle exec rails s -b 0.0.0.0
This would allow, I believe, for better easier deployment synchronicity.

How to get Capybara/Selenium to play nicely with SSL in local environment

I'm using RSpec, Capybara and Selenium to test my local Rails application. Capybara by itself is working fine. My problem is that I use a forced SSL connection in most of my application.
The kind of workaround I have now is to configure Capybara for javascript testing like this:
Capybara.register_driver :selenium_profile do |app|
profile = Selenium::WebDriver::Firefox::Profile.new
profile.secure_ssl = false
profile.assume_untrusted_certificate_issuer = true
Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile)
end
Capybara.javascript_driver = :selenium_profile
Capybara.run_server = false
Capybara.server_port = 3001
Capybara.app_host = "https://localhost:%d" % Capybara.server_port
That only works if I start up a server independently on port 3001 with a valid local SSL certificate. In practice, this is annoying and is just generally a manual dependency that I don't like.
Does anyone know a cleaner workaround for this? Either:
1) How to configure Capybara's internal server to find and use my local SSL certificate?, or
2) How to disable forced SSL for javascript testing, or
3) How to automatically start that local server running before any javascript tests?
Any help would be greatly appreciated.
You can tell Capybara how to start a server, by passing a block accepting an app and a port to Capybara.server. The default just calls Rake::Handler::WEBrick.run:
# This is the default setting
Capybara.server = {|app, port| Capybara.run_default_server(app, port)}
def run_default_server(app, port)
require 'rack/handler/webrick'
Rack::Handler::WEBrick.run(app, :Port => port, :AccessLog => [], :Logger => WEBrick::Log::new(nil, 0))
end
As long as whatever you pass to server accepts an app and a port, you can define whatever server starting code you like.
Rack::Handler::WEBrick passes most of its options straight through to WEBrick::HTTPServer, so you can pass the options for SSL config (SSLEnable, SSLCertificate and SSLPrivateKey, taken from the docs) and start your server something like this:
def run_ssl_server(app, port)
require 'rack/handler/webrick'
require 'webrick/https'
certificate = OpenSSL::X509::Certificate.new File.read '/myapp/some_directory/certificate.pem'
key = OpenSSL::PKey::RSA.new File.read '/myapp/some_directory/key.pem'
opts = {
:Port => port,
:AccessLog => [],
:Logger => WEBrick::Log::new(nil, 0),
:SSLEnable => true,
:SSLCertificate => certificate,
:SSLPrivateKey => key
}
Rack::Handler::WEBrick.run(app, opts)
end
# Elsewhere in your test/spec helper
Capybara.server = {|app, port| run_ssl_server(app, port)}

How to change Rails 3 server default port in develoment?

On my development machine, I use port 10524. So I start my server this way :
rails s -p 10524
Is there a way to change the default port to 10524 so I wouldn't have to append the port each time I start the server?
First - do not edit anything in your gem path! It will influence all projects, and you will have a lot problems later...
In your project edit script/rails this way:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# THIS IS NEW:
require "rails/commands/server"
module Rails
class Server
def default_options
super.merge({
:Port => 10524,
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
:pid => File.expand_path("tmp/pids/server.pid"),
:config => File.expand_path("config.ru")
})
end
end
end
# END OF CHANGE
require 'rails/commands'
The principle is simple - you are monkey-patching the server runner - so it will influence just one project.
UPDATE: Yes, I know that the there is simpler solution with bash script containing:
#!/bin/bash
rails server -p 10524
but this solution has a serious drawback - it is boring as hell.
I like to append the following to config/boot.rb:
require 'rails/commands/server'
module Rails
class Server
alias :default_options_alias :default_options
def default_options
default_options_alias.merge!(:Port => 3333)
end
end
end
One more idea for you. Create a rake task that calls rails server with the -p.
task "start" => :environment do
system 'rails server -p 3001'
end
then call rake start instead of rails server
Combining two previous answers, for Rails 4.0.4 (and up, presumably), this suffices at the end of config/boot.rb:
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge({Port: 10524})
end
end
end
We're using Puma as a web server, and dotenv to set environment variables in development. This means I can set an environment variable for PORT, and reference it in the Puma config.
# .env
PORT=10524
# config/puma.rb
port ENV['PORT']
However, you'll have to start your app with foreman start instead of rails s, otherwise the puma config doesn't get read properly.
I like this approach because the configuration works the same way in development and production, you just change the value of the port if necessary.
Inspired by Radek and Spencer...
On Rails 4(.0.2 - Ruby 2.1.0 ), I was able to append this to config/boot.rb:
# config/boot.rb
# ...existing code
require 'rails/commands/server'
module Rails
# Override default development
# Server port
class Server
def default_options
super.merge(Port: 3100)
end
end
end
All other configuration in default_options are still set, and command-line switches still override defaults.
Solution for Rails 2.3 - script/server:
#!/usr/bin/env ruby
require 'rack/handler'
module Rack::Handler
class << WEBrick
alias_method :old_run, :run
end
class WEBrick
def self.run(app, options={})
options[:Port] = 3010 if options[:Port] == 3000
old_run(app, options)
end
end
end
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/server'
If you're using puma (I'm using this on Rails 6+):
To change default port for all environments:
The "{3000}" part sets the default port if undefined in ENV.
~/config/puma.rb
change:
port ENV.fetch('PORT') { 3000 }
for:
port ENV.fetch('PORT') { 10524 }
To define it depending on the environment, using Figaro gem for credentials/environment variable:
~/application.yml
local_db_username: your_user_name
​local_db_password: your_password
PORT: 10524
You can adapt this to you own environment variable manager.
You could install $ gem install foreman, and use foreman to start your server as defined in your Procfile like:
web: bundle exec rails -p 10524
You can check foreman gem docs here: https://github.com/ddollar/foreman for more info
The benefit of this approach is not only can you set/change the port in the config easily and that it doesn't require much code to be added but also you can add different steps in the Procfile that foreman will run for you so you don't have to go though them each time you want to start you application something like:
bundle: bundle install
web: bundle exec rails -p 10524
...
...
Cheers
For ruby > 3 and For rails > 7
in file app/config/puma.rb, update the port number.
port ENV.fetch("PORT") { 3200 }

Resources