Capybara Selenium WebDriver does not see my test data - selenium-webdriver

My test database objects are not viewable by Capybara Selenium WebDriver. Does anyone see an issue with my setup or what I might be missing?
rails_helper.rb
...
RSpec.configure do |config|
config.use_transactional_fixtures = false
...
end
database_clearner.rb
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:all) do
DatabaseCleaner.start
end
config.before(:each, type: :feature) do
# :rack_test driver's Rack app under test shares database connection
# with the specs, so continue to use transaction strategy for speed.
driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test
if !driver_shares_db_connection_with_specs
# Driver is probably for an external browser with an app
# under test that does *not* share a database connection with the
# specs, so use truncation strategy.
DatabaseCleaner.strategy = :truncation
end
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
config.after(:all) do
DatabaseCleaner.clean
end
end
external_user_viewing_resources_sel_spec.rb
require 'rails_helper'
require 'support/selenium_helper'
RSpec.feature "External user " do
before(:all) do
get_driver
login_user(:external_user)
end
after(:all) do
##driver.find_element(:id, "logout").click()
#quit_driver
end
scenario "can view and click resources (helpful links)", js: true do
#d1_inst_resource = create(:d1_inst_resource)
puts #d1_inst_resource.inspect
#driver.find_element(:id, 'helpful_links_panel')
#driver.find_element(:id, "#{#d1_inst_resource.id}").click();
end
end
selenium_helper.rb
require 'selenium-webdriver'
def get_driver
Capybara.current_driver = Selenium::WebDriver.for :firefox #:chrome
#driver = Capybara.current_driver
end
def quit_driver
#driver.quit
Capybara.use_default_driver
end
def login_user(user)
#user = build_stubbed(user)
#driver.get "http://localhost:3000"
#driver.find_element(:id, "username").send_keys("#{#user.email}")
#driver.find_element(:id, "password").send_keys("#{#user.password}")
#driver.find_element(:css, "button[type='submit']").click()
end
error
..............#<Resource id: 10534, text: "Text1", url: "MyText", position: 1, d1: true, d2: false, d3: false, conference: false, institution: true, start_date: "2016-10-06", end_date: "2020-10-06", created_at: "2016-10-21 13:28:15", updated_at: "2016-10-21 13:28:15">
F...*
Failures:
1) External user can view and click resources (helpful links)
Failure/Error: #driver.find_element(:id, "#{#d1_inst_resource.id}").click();
Selenium::WebDriver::Error::NoSuchElementError:
Unable to locate element: {"method":"id","selector":"10534"}
I've seen other articles but they do not solve my issue. I understand that they run in different threads, but I feel like the configuration above has taken care of that...
Capybara with :js => true causes test to fail
*****UPDATED CODE*****
selenium_helper.rb
def login_user(user)
#user = build_stubbed(user)
page.visit "/"
page.fill_in "username", with: #user.email
page.fill_in "password", with: #user.password
page.find("button[type='submit']").click()
end
external_user_viewing_resources_sel_spec.rb
require 'rails_helper'
require 'support/selenium_helper'
RSpec.feature "External user " do
before(:each) do
Capybara.current_driver = :selenium
#d1_inst_resource = create(:d1_inst_resource)
puts Resource.count
login_user(:external_user)
puts 'test script count'
puts Resource.get_resource_by_member_type_and_division(#user).count
end
scenario "can view and click resources (helpful links)", js: true do
puts page.first('.userName').text
expect(page.first('.userName').text).to eq("#{#user.first_name.upcase} #{#user.last_name.upcase}")
page.find(:id, "#{#d1_inst_resource.id}")
page.find(:id, "#{#d1_inst_resource.id}").click()
end
end
main_controller.rb
def index
#resources = Resource.get_resource_by_member_type_and_division(#user)
puts 'index query count'
puts #resources.count
#resources
end
error
1
index query count
0
test script count
1
REVDIST TUSER1
F
Failures:
1) External user can view and click resources (helpful links)
Failure/Error: page.find(:id, "#{#d1_inst_resource.id}")
Capybara::ElementNotFound:
Unable to find id "11060"
# /Users/meffinger1/.rvm/gems/ruby-2.2.5/gems/capybara-2.9.1/lib/capybara/node/finders.rb:44:in `block in find'
# /Users/meffinger1/.rvm/gems/ruby-2.2.5/gems/capybara-2.9.1/lib/capybara/node/base.rb:85:in `synchronize'
# /Users/meffinger1/.rvm/gems/ruby-2.2.5/gems/capybara-2.9.1/lib/capybara/node/finders.rb:33:in `find'
# /Users/meffinger1/.rvm/gems/ruby-2.2.5/gems/capybara-2.9.1/lib/capybara/session.rb:735:in `block (2 levels) in <class:Session>'
# ./spec/features/selenium/external_user_viewing_resources_sel_spec.rb:28:in `block (2 levels) in <top (required)>'
Finished in 56.01 seconds (files took 6.33 seconds to load)
1 example, 1 failure

You're not seeing the resource because it isn't being created until after the page has already been loaded, however you're also not really using Capybara in your examples since you're bypassing it completely and using selenium instances directly.
In get_driver you're setting Capybara.current_driver to an instance of Selenium::WebDriver when it's expecting a symbol matching one of the drivers registered with Capybara. In `login_user' you're creating a stubbed object (ie. not real/saved to the database) and then using that to login which won't work since theres no user in the database for the app thread to load. I may not be understanding exactly what you're trying to do but I would expect your files to look more like
external_user_viewing_resources_sel_spec.rb
require 'rails_helper'
require 'support/selenium_helper'
RSpec.feature "External user " do
before(:each) do
login_user(:external_user)
end
scenario "can view and click resources (helpful links)", js: true do
#d1_inst_resource = create(:d1_inst_resource)
page.visit("whatever page should should show the record")
page.find(:id, #d1_inst_resource.id").click();
# some check for what should happen based on the click
end
end
selenium_helper.rb
def login_user(user)
#user = create(user)
page.visit "http://localhost:3000" #Is this meant to be a different system than the app under test? if not it should just be page.visit '/'
page.fill_in("username", with: #user.email)
page.fill_in("password", with: #user.password)
page.find(:css, "button[type='submit']").click()
#some check for whatever happens on the page to show the user has logge in
end

Changing my database_cleaner.rb file to this fixed the issue, they are no longer running in two different threads.
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :each do
if Capybara.current_driver == :rack_test
DatabaseCleaner.strategy = :transaction
else
DatabaseCleaner.strategy = :truncation
end
DatabaseCleaner.start
end
config.after do
DatabaseCleaner.clean
end
end

Related

Losing Auth when navigating to different part of page-RoR, React

This is my first ever question.
I'm using react/vite and Rails 7 to build a firehouse management web app. I originally set up rails as an api with --api. Right now, I can log in but when the user clicks home, or any other link on the page, I loose the authorization(or thats what I'm thinking). I'm using the Bcrypt gem. The console.log(user) on my other pages is returning null, but on the inital login it returns the user object. Now, I have another issue with the logging in all together.
I'm getting a 422 'Unprocessable entity' where my request.base_url doesnt match the localhost:3000. I'm assuming thats because vite is running on 5173?
Here is the error
{status: 422, error: 'Unprocessable Entity', exception: '#<ActionController::InvalidAuthenticityToken: HTTP…t match request.base_url (http://localhost:3000)>', traces: {…}}
error
:
"Unprocessable Entity"
exception
:
"#<ActionController::InvalidAuthenticityToken: HTTP Origin header (http://127.0.0.1:5173) didn't match request.base_url (http://localhost:3000)>"
status
:
422
puma.rb
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
I tried to convert rails to the full framework because I thought it was something with the session and cookies. I added a cookie serializer and a session_store.
application.rb
class Application < Rails::Application
# Adding cookies and session middleware
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
config.api_only = false
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
# This will allow any origin to make requests to any resource on your server, using any HTTP method.
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: %i[get post put patch delete options head]
end
end
end
end
cookie_serializer.rb
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
session_store.rb
if Rails.env === 'production'
Rails.application.config.session_store :cookie_store, key: '_fire-sphere', domain: '_fire-sphere-json-api'
else
Rails.application.config.session_store :cookie_store, key: '_fire-sphere'
end
Here is my application_controller.rb
class ApplicationController < ActionController::Base
include ActionController::Cookies
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity
def authorized
return render json: {error: "Not Authorized"}, status: :unauthorized unless session.include? :current_user
end
private
def render_unprocessable_entity(invalid)
render json: {errors: invalid.record.errors.full_messages}, status: :unprocessable_entity
end
def render_not_found(error)
# byebug
render json: {error: "#{error.model} Not Found"}, status: :not_found
end
end
show method in users_controller.rb
def show
# using session to find user in question. sessions are in user browser
# if session for user currently happening, set our user to that user and render json
# byebug
current_user = User.find_by(id: session[:current_user])
render json: current_user
end
I think somehow the user isn't getting stored in the session. I was able to check the params on my initial problem and the user was in there but not when I navigated away. I think I've shnaged somthething somewhere and caused a whole other problem now. Thank you for taking a look! I hope it is something simple..

Deploying contract to Kadena localdevnet error: "Cannot resolve 'validate-principle'"

I'm following https://github.com/thomashoneyman/real-world-pact/ to deploy my contract on local devnet.
I've updated the deployment script as
const deployK = async () => {
const detailArgs = ["--local", "k-contract-details"];
const contractDetails = await parseArgs(detailArgs).then(runRequest);
if (contractDetails.status === "failure") {
console.log(
"K contract not found on local Chainweb node. Deploying contract..."
);
const deployArgs = [
"--send",
"deploy-k-contract",
"--signers",
"kazora",
];
const deployResult = await parseArgs(deployArgs).then(runRequest);
if (deployResult.status === "success") {
console.log(`Deployed! Cost: ${deployResult.gas} gas.`);
} else {
throw new Error(
`Failed to deploy contract: ${JSON.stringify(
deployResult.error,
null,
2
)}`
);
}
}
};
The deploy-k-contracty.yaml is
# This YAML file describes a transaction that, when executed, will deploy the
# faucet contract to Chainweb.
#
# To execute this request (you must have funded the faucet account):
# faucet-request --send deploy-faucet-contract --signers k
#
# Alternately, to fund the faucet account _and_ deploy the contract:
# faucet-deploy
networkId: "development"
type: "exec"
# To deploy our contract we need to send its entire contents to Chainweb as a
# transaction. When a Chainweb node receives a module it will attempt to
# register it in the given namespace.
codeFile: "../../k.pact"
# The 'data' key is for JSON data we want to include with our transaction. As a
# general rule, any use of (read-msg) or (read-keyset) in your contract
# indicates data that must be included here.
#
# Our contract reads the transaction data twice:
# - (read-keyset "k-keyset")
# - (read-msg "upgrade")
data:
k-admin-keyset:
# On deployment, our contract will register a new keyset on Chainweb named
# 'k-keyset. We'll use this keyset to govern the faucet
# contract, which means the contract can only be upgraded by this keyset.
#
# We want the contract to be controlled by our faucet account, which means
# our keyset should assert that the k.yaml keys were used to
# sign the transaction. The public key below is from the k.yaml
# key pair file.
keys:
- "1b54c9eac0047b10f7f6a6f270f7156fb519ef02c9bb96dc28a4e50c48a468f4"
pred: "keys-all"
# Next, our contract looks for an 'upgrade' key to determine whether it should
# initialize data (for example, whether it should create tables). This request
# deploys the contract, so we'll set this to false.
upgrade: false
signers:
# We need the Goliath faucet account to sign the transaction, because we want
# the faucet to deploy the contract. This is the Goliath faucet public key. It
# should match the keyset above.
- public: "1b54c9eac0047b10f7f6a6f270f7156fb519ef02c9bb96dc28a4e50c48a468f4"
publicMeta:
# The faucet contract only works on chain 0, so that's where we'll deploy it.
chainId: "0"
# The contract should be deployed by the faucet account, which means the
# faucet account is responsible for paying the gas for this transaction. You
# must have used the 'fund-faucet-account.yaml' request to fund the faucet
# account before you can use this deployment request file.
sender: "k"
# To determine the gas limit for most requests you can simply execute the Pact
# code in the REPL, use (env-gaslog) to measure consumption, and round up the
# result. However, deployment is different; you can't simply measure a call to
# (load "faucet.pact") as it will provide an inaccurate measure.
#
# Instead, I first set the gas limit to 150000 (the maximum) and deploy the
# contract to our local simulation Chainweb. Then, I recorded the gas
# consumption that the node reported and round it up.
gasLimit: 65000
gasPrice: 0.0000001
ttl: 600
It complains about validate-principal function, however it's defined as pact built-in function.
https://pact-language.readthedocs.io/en/stable/pact-functions.html?highlight=validate-principal#validate-principal
./kazora/run-deploy-contract.js
-----
executing 'local' request: kazora-details.yaml
-----
Kazora account 1b54c9eac0047b10f7f6a6f270f7156fb519ef02c9bb96dc28a4e50c48a468f4 found with 999.9935 in funds.
-----
executing 'local' request: kazora-contract-details.yaml
-----
Kazora contract not found on local Chainweb node. Deploying contract...
-----
executing 'send' request: deploy-kazora-contract.yaml
-----
Received request key: vm4O3YKKj7Ea9nR8D8nPSHuVI7OtHPJzQjk7RA7XZLI
Sending POST request with request key to /poll endpoint.
May take up to 1 minute and 30 seconds to be mined into a block.
Polling every 5 seconds until the transaction has been processed...
Waiting (15 seconds elapsed)...
Waiting (30 seconds elapsed)...
Waiting (45 seconds elapsed)...
/home/ripple/git/web3/kazora/run-deploy-contract.js:66
throw new Error(
^
Error: Failed to deploy contract: {
"callStack": [
"<interactive>:0:102: module"
],
"type": "EvalError",
"message": "Cannot resolve \"validate-principal\"",
"info": "<interactive>:0:8052"
}
at deployKazora (/home/ripple/git/web3/kazora/run-deploy-contract.js:66:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async main (/home/ripple/git/web3/kazora/run-deploy-contract.js:81:3)
Make sure you are using version 4.3.1 of pact or later.
The build-in function was only added at that point:
https://github.com/kadena-io/pact/releases/tag/v4.3.1

How can I fix this Rails minitest & Capybara mailer testing ActionView::Template host error?

I'm trying to test mailers in some system tests. I'm using Ruby 3.0.2, Rails 6.1.4, Capybara 3.26, Selenium-webdriver and I'm writing tests in Minitest. The below tests fails when it gets to the assert_equal ['dave#example.com'], mail.to line:
orders_test.rb:
test "check full payment with cheque flow" do
LineItem.delete_all
Order.delete_all
visit store_index_url
click_on 'Add to cart', match: :first
click_on 'Checkout'
fill_in 'order_name', with: 'Dave Thomas'
fill_in 'order_address', with: '123 Main Street'
fill_in 'order_email', with: 'dave#example.com'
assert_no_selector "#order_routing_number"
select 'Cheque', from: 'Pay type'
fill_in 'Routing #', with: '123456'
fill_in 'Account #', with: '678901'
assert_selector "#order_routing_number"
assert_selector "#order_account_number"
perform_enqueued_jobs do
click_button 'Place order'
end
orders = Order.all
assert_equal 1, orders.size
order = orders.first
assert_equal 'Dave Thomas', order.name
assert_equal '123 Main Street', order.address
assert_equal 'dave#example.com', order.email
assert_equal 'Cheque', order.pay_type
assert_equal 1, order.line_items.size
mail = ActionMailer::Base.deliveries.last
assert_equal ['dave#example.com'], mail.to
assert_equal 'James Kemp<from#example.com>', mail[:from].value
assert_equal 'Order received; thanks', mail.subject
end
With the following error:
Error:
OrdersTest#test_check_full_payment_with_cheque_flow:
NoMethodError: undefined method `to' for nil:NilClass
test/system/orders_test.rb:62:in `block in <class:OrdersTest>'
Error:
OrdersTest#test_check_full_payment_with_cheque_flow:
ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
Reading error message suggestion and googling others' solutions suggests to put config.action_mailer.default_url_options = { :host => 'www.example.com' } in config/environments/test. When I put this line in it then throws an error from the same assert_equal ... mail.to line as the above error throws this error:
Error:
OrdersTest#test_check_full_payment_with_cheque_flow:
DRb::DRbRemoteError: undefined method `to' for nil:NilClass (NoMethodError)
test/system/orders_test.rb:62:in `block in <class:OrdersTest>'
Error:
OrdersTest#test_check_full_payment_with_cheque_flow:
DRb::DRbRemoteError: No route matches {:action=>"show", :controller=>"line_items", :locale=>#<LineItem id: 1, product_id: 298486374, cart_id: nil, created_at: "2021-11-07 16:53:19.133389000 +0000", updated_at: "2021-11-07 16:53:19.966253000 +0000", quantity: 1, order_id: 980190963>}, missing required keys: [:id]
Did you mean? line_items_url
line_item_path
line_items_path
edit_line_item_url (ActionView::Template::Error)
app/views/line_items/_line_item.html.erb:13
The code works fine in development mode, without any default_url_options explicitly specified in config anywhere.
Can anyone advise what the issue is here and how I should correct it?
(FYI - This is from the Agile Web Development with Rail 6 tutorial, ch.17.)
You are being told that the to method is getting called on a nil, so mail is nil. Hence there is no mail in the deliveries array.
The reason this would be occurring is that when using a Javascript driver, the Capybara tests and the Rails server run in different processes and communicate asynchronously. Hence they will each have a different deliveries array, and you cannot check emails this way.
Normally you stick to the contents of the webpage when using Capybara. You can check the database if you like, because the tests and server communicate through the database, and Capybara maintains two connections to the same database, however even there if you use database transactions and such you can get into trouble.
However in general you can't check anything that isn't the webpage or database.
You might choose to check emails through unit or request/integration tests instead, or look for a solution like the capybara-email gem if you wish to do it in a system/feature test, which does add that functionality, although I haven't used it in a while and I'm not sure how up to date it is.

Automatic failover - Mongoid 4.0.2

Trying to test automatic failover using Mongoid 4.0.2 gem and using MongoDB 2.4.3
To simulate this I'm using this test code:
require 'mongoid'
class TestClass
include Mongoid::Document
store_in collection: "test", database: "test"
field :uuid, type: String
end
Mongoid.load!("config/mongoid.yml", :test)
batch = (1..100).map { |x| TestClass.new({ uuid: x }) }
batch.each_with_index { |x, i|
begin
x.save
sleep(5.seconds)
puts "Saved #{i} records" if i%10 == 0
rescue Exception => e
puts e.message
end
}
In between saves, I jumped on my MongoDB and did rs.stepDown() on the primary node of my Mongo cluster, unfortunately this results in the following errors in my test app:
See https://github.com/mongodb/mongo/blob/master/docs/errors.md
for details about this error.
Moped::Errors::OperationFailure
The operation: #<Moped::Protocol::Command
#length=68
#request_id=192
#response_to=0
#op_code=2004
#flags=[]
#full_collection_name="test.$cmd"
#skip=0
#limit=-1
#selector={:getlasterror=>1, :w=>1}
#fields=nil>
failed with error 10058: "not master"
My Mongoid configuration looks like thus:
test:
sessions:
default:
database: test_db
hosts:
- 192.168.1.10:27017
- 192.168.1.11:27017
options:
max_retries: 10
retry_interval: 1
Any idea what I'm doing wrong here? I thought the Mongoid driver would automatically detect changes in the cluster and automatically retry the request after it updates the cluster state on the client / Ruby side?

Transaction in Capistrano not working

I have an issue with transaction in Capistrano.
The error I am getting is:
NoMethodError: undefined method `transaction' for #<SSHKit::Backend::Netssh:0x24
08b20>
Capistrano version is: 3.4.0 (Rake Version: 10.4.2).
Code is as below:
namespace :fun do
desc "Sample showing rescue, ensure, and on_rollback inside a transaction"
task :stuff do
on roles :all do
transaction do
on_rollback { logger.debug "my rollback" }
begin
logger.debug "main"
# Either run or run_locally will work the same
# run_locally "false"
run "false"
rescue => e
logger.debug "rescue #{e.class}"
raise e
ensure
logger.debug "ensure"
end
end
end
end
end
Where is the issue?
The transaction keyword was removed in Capistrano 3.
The developers recommend using the new flow control to handle this case: https://github.com/capistrano/capistrano/issues/860

Resources