Capybara no method error with sub class - ruby

require 'rubygems'
require 'capybara'
require 'capybara/dsl'
Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'http://www.domain.com'
module Test
include Capybara::DSL
class Bot
include Capybara::DSL
def login(username,password)
#STEP 1
uri = "https://www.domain.com"
visit(uri)
# LOG IN FORM
find('#username').set(username)
find('#password').set(password)
find('#submitButton').click
end
def goto_page2
#STEP 2
uri_cert = 'https://www.domain.com/page1'
visit(uri_cert)
find('#submitButton').click
end
def form(answers)
# Step 3
FormEdit.q1(answers['q1'])
end
#####################################
# Questions for the form
class FormEdit
include Capybara::DSL
#STEP 3
# true for Yes
# false for No
def self.q1(yesno)
#yesno
id = (yesno) ? '#radioyes' : '#radioNo'
find(id).set(true)
end
end
end
end
RUN SCRIPT
t = Test::Bot.new
username = 'myusername'
password = 'mypassword'
t.login(username, password)
answers = { q1:true }
t.form(answers)
ERROR WHEN RUN:
FormEdit.q1(answers['q1'])
NoMethodError: undefined method `find' for Test::Bot::FormEdit:Class
from test_script.rb:56:in `q1'
ANY SUGGESTIONS?

The solution was to change the
class FormEdit
include Capybara::DSL
to
module FormEdit
extend Capybara::DSL

Related

Uninitialized constant NameError in Rspec

When I run rails c, I can call the following class and the method works:
test = SlackService::BoardGameNotifier
test.create_alert("test")
>>method works
I'm trying to set this up in rspec like this:
require 'spec_helper'
require 'slack-notifier'
RSpec.describe SlackService::BoardGameNotifier do
describe '#notify' do
#notifier = SlackService::BoardGameNotifier
it 'pings Slack' do
error = nil
message = "test"
expect(notifier).to receive(:ping).with(message)
notifier.send_message()
end
end
end
But I keep getting the error:
NameError:
uninitialized constant SlackService
Does this have to do with how I set up the module?
My current setup:
slack_service/board_game_notifier.rb
module SlackService
class BoardGameNotifier < BaseNotifier
WEBHOOK_URL = Rails.configuration.x.slack.url
DEFAULT_OPTIONS = {
channel: "board-games-channel",
text: "board games alert",
username: "bot",
}
def create_alert(message)
message #testing
end
end
end
slack_service/base_notifier.rb
module SlackService
class BaseNotifier
include Singleton
def initialize
webhook_url = self.class::WEBHOOK_URL
options = self.class::DEFAULT_OPTIONS
#notifier = Slack::Notifier.new(webhook_url, options)
end
def self.send_message
message = instance.create_alert("test")
instance.notify(message)
end
def notify(message)
#notifier.post blocks: message
end
end
end
Add this to your spec_helper.rb
# spec_helper.rb
ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../config/environment", __dir__)
When running RSpec, Rails doesn't automatically boot up, and therefore doesn't automatically load all the libraries.
Also, I'd suggest creating a .rspec in your app's root folder with the following lines so that spec_helper is automatically loaded for all your RSpec tests:
# .rspec
--format documentation
--color
--require spec_helper
I would use the described_class from Rspec
require 'spec_helper'
require 'slack-notifier'
RSpec.describe ::SlackService::BoardGameNotifier do
describe '#notify' do
it 'pings Slack' do
error = nil
message = "test"
expect(described_class).to receive(:ping).with(message)
notifier.send_message()
end
end
end

How do I reference the Capybara driver for creating my pageobjects/specs.

I am attempting to use pageobjects along with with my Capybara specs but can't seem to properly reference the driver. Basically I want to be able to use the PageObjects to define the fields on the page (this is login_page.rb), but when I try to create the object in the spec, it is throwing errors with saying that the object is nil.
spec_helper.rb:
# frozen-string-literal: true
require 'rspec'
require 'capybara/rspec'
require 'capybara/dsl'
require 'selenium-webdriver'
require 'page-object'
# loading page object files
page_paths = File.join(Dir.pwd, 'spec', 'pages', '**', '*.rb')
puts 'foo'
Dir.glob(page_paths).each { |file| puts file}
Dir.glob(page_paths).each { |file| require file }
Capybara.register_driver :firefox do |app|
Capybara::Selenium::Driver.new(app, browser: :firefox)
end
Capybara.default_driver = :firefox
Capybara.app_host = *********** #redacted
Capybara.default_max_wait_time = 5
RSpec.configure do |config|
config.before(:all) do
#browser = Capybara::Selenium::Driver
end
config.before(:each) do
config.include Capybara::DSL
end
end
login_page.rb
class LoginPage
include Capybara::DSL
include PageObject
text_field(:username, id: 'username')
text_field(:password, id: 'password')
button(:login, id: 'loginButton')
def initialize(driver)
#driver = driver
end
end
login_spec.rb
require 'spec_helper'
describe 'On Login page' do
context 'using proper password' do
before(:each) do
visit('/')
end
it 'logs in as foo' do
login_page = LoginPage.new(#browser)
login_page.username = 'foo'
login_page.password = 'bar'
login_page.login
end
end
end
Assuming you're talking about the page-object gem - https://github.com/cheezy/page-object - it doesn't support Capybara, it supports watir-webdriver/watir and selenium-webdriver. Additionally Capybara::Selenium::Driver is a class not an object instance. As shown in the page-object readme you need to pass an object instance into your page objects constructor
#browser = Selenium::WebDriver.for :firefox
If you want a page object framework that supports Capybara you may want to look at something like site-prism instead.

assert_equal not working with selenium and ruby

I am writing a script using selenium tool in ruby. and I am trying to use assert_equal property of selenium to test pass or failure status of my test. below is my file
require 'selenium-webdriver'
require 'test-unit'
$driver = Selenium::WebDriver.for :firefox
$project_url = "http://www.example.com"
class Travelibro
def initialize
Login.run
end
end
class Login <
##pop_up_xpath = "/html/body/div[5]/div[1]/div[3]/p/a"
##email_xpath = "//input[#name='user[email]']"
##password_xpath = "//input[#name='user[password]']"
##click_button_class = "loginBtn"
##login_email = "mailtohemant#yahoo.co.in"
##login_password = "password"
def self.run
login = Login.new
login.blank_email_or_password
end
def blank_email_or_password
open_login_pop_up = $driver.find_element(:xpath,"#{##pop_up_xpath}")
open_login_pop_up.click
email = $driver.find_element(:xpath, "#{##email_xpath}")
email.send_keys "#{##login_email}"
password = $driver.find_element(:xpath, "#{##password_xpath}")
password.send_keys "#{##login_password}"
submit_form = $driver.find_element(:class,"#{##click_button_class}")
submit_form.click
isPresent = $driver.find_elements(:class,"signInError").size() > 0
assert_equal($driver.find_elements(:xpath => "/html/body/div[6]/div[2]/div/div/ul/li[1]/a")[0].text, "vin")
result = {}
result[:test_name] = "Login Test"
result[:inputs] = "blank email or password"
result[:test_result] = isPresent ? "Pass" : "Failed"
result.each do |key, value|
puts "#{key}:#{value}"
end
end
end
travelibro = Travelibro.new
what is the wrong. I am getting this error,
/gems/test-unit-3.1.8/lib/test/unit/testcase.rb:430:in `initialize': wrong number of arguments (0 for 1) (ArgumentError)
The problem is that you are trying to create instance of class inherited from Test::Unit::TestCase (I think it's typo that it's empty in code).
The right way to use test-unit gem would be removing Travelibro class, removing Login test construction and renaming blank_email_or_password method to test_black_email_or_password.
require 'selenium-webdriver'
require 'test-unit'
$driver = Selenium::WebDriver.for :firefox
$project_url = "http://www.example.com"
class Login < Test::Unit::TestCase
##pop_up_xpath = "/html/body/div[5]/div[1]/div[3]/p/a"
##email_xpath = "//input[#name='user[email]']"
##password_xpath = "//input[#name='user[password]']"
##click_button_class = "loginBtn"
##login_email = "mailtohemant#yahoo.co.in"
##login_password = "password"
def test_blank_email_or_password
open_login_pop_up = $driver.find_element(:xpath,"#{##pop_up_xpath}")
open_login_pop_up.click
email = $driver.find_element(:xpath, "#{##email_xpath}")
email.send_keys "#{##login_email}"
password = $driver.find_element(:xpath, "#{##password_xpath}")
password.send_keys "#{##login_password}"
submit_form = $driver.find_element(:class,"#{##click_button_class}")
submit_form.click
isPresent = $driver.find_elements(:class,"signInError").size() > 0
assert_equal($driver.find_elements(:xpath => "/html/body/div[6]/div[2]/div/div/ul/li[1]/a")[0].text, "vin")
result = {}
result[:test_name] = "Login Test"
result[:inputs] = "blank email or password"
result[:test_result] = isPresent ? "Pass" : "Failed"
result.each do |key, value|
puts "#{key}:#{value}"
end
end
end
Or if you are inheriting not from Test::Unit::TestCase, you can just override constructor, and class will be created successfully
def initialize
end

Unable to use any_instance on Twitter gem's user_timline

I am still quite fresh to Ruby, and especially testing in Ruby. Hopefully the code is not a trainwreck :) I am having issues using any_instance with the Twitter gem, while it works fine on my own classes.
This is (what I believe) the relevant code
require 'twitter'
require 'minitest/unit'
require 'mocha/mini_test'
omitting for brevity....
args = { id: 573536452149182464, id_str: 73536452149182464, text: 'This is an initial tweet from the user'}
initial_tweet = ::Twitter::Tweet.new(args)
::Twitter::REST::Timelines.any_instance.stubs(:user_timeline).returns(initial_tweet)
The code produces the following error:
Minitest::UnexpectedError: NoMethodError: undefined method `any_instance|' for Twitter::REST::Timelines:Module
Are principles to stubbing gems different, am I approaching it wrong?
EDIT: I have added the entire code for the two classes below.
twitter.rb
require 'rubygems'
require 'cinch'
require 'cinch/commands'
require 'twitter'
require 'shorturl'
module Gigabot
module Commands
class Twitter
include Cinch::Plugin
include Cinch::Commands
def initialize(bot)
super(bot)
#client = create_client
#follow = config[:follow]
#channels = bot.config.channels
#latest_tweets = Hash.new
set_initial_tweets
end
timer 60, method: :twitter_update
def twitter_update
#follow.each do |user|
new_tweet = #client.user_timeline(user, options = {exclude_replies: true}).first
if #latest_tweets[user] != new_tweet
short_url = ShortURL.shorten("https://twitter.com/#{user}/status/#{new_tweet.id}")
reply = Format(:bold, "<#{user}> ") + "#{new_tweet.full_text} [#{short_url}]"
reply = reply.gsub(/\n/,' ')
#channels.each {|channel| Channel(channel).send(reply)}
#latest_tweets[user] = new_tweet
end
end
end
private
def create_client
::Twitter::REST::Client.new do |c|
c.consumer_key = config[:consumer_key]
c.consumer_secret = config[:consumer_secret]
c.access_token = config[:access_token]
c.access_token_secret = config[:access_token_secret]
end
end
def set_initial_tweets
#follow.each do |user|
#latest_tweets[user] = #client.user_timeline(user, options = {exclude_replies: true}).first
end
end
end
end
end
twitter_test.rb
require 'twitter'
require 'minitest/unit'
require 'mocha/mini_test'
require File.dirname(__FILE__) + '/../../../helper'
require File.dirname(__FILE__) + '/../../../../lib/gigabot/commands/twitter'
module Gigabot
module Commands
class TwitterTest < TestCase
def setup
bot = Cinch::Bot.new
bot.loggers.level = :fatal
bot.config.plugins.options[Twitter] = {
consumer_key: 'test_key',
consumer_secret: 'test_key_secret',
access_token: 'test_access_token',
access_token_secret: 'test_access_token_secret',
follow: %w(follow1 follow2)
}
args = { id: 573536452149182464, id_str: 73536452149182464, text: 'This is an initial tweet from the user'}
initial_tweet = ::Twitter::Tweet.new(args)
::Twitter::REST::Timelines.any_instance.stubs(:user_timeline).returns(initial_tweet)
#plugin = Twitter.new(bot)
end
def test_create_twitter_client_on_initialize
refute_nil(#plugin.instance_variable_get(:#client))
end
end
end
end

Ruby: const_set outside block?

I want to mock a class with Ruby.
How do I write a method that will take care of the boilerplate code?
The following code:
module Mailgun
end
module Acani
def self.mock_mailgun(mock)
temp = Mailgun
const_set(:Mailgun, mock)
p Mailgun
yield
ensure
const_set(:Mailgun, temp)
end
end
Acani.mock_mailgun('mock') { p Mailgun }
prints:
"mock"
Mailgun
What's going on here? Why is Mailgun its original value inside the block? Does this have to do with Ruby bindings?
Ruby version: 2.1.1p76
Try putting Object. before each const_set.
The code in the question is simplified. Here is the pertinent code:
test/test_helper.rb
require 'minitest/autorun'
module Acani
def self.const_mock(const, mock)
temp = const_get(const)
const_set_silent(const, mock)
yield
ensure
const_set_silent(const, temp)
end
private
def self.const_set_silent(const, value)
temp = $VERBOSE
$VERBOSE = nil
Object.const_set(const, value)
ensure
$VERBOSE = temp
end
end
test/web_test.rb
require 'test_helper'
require 'rack/test'
require_relative '../web'
class AppTest < MiniTest::Test
include Rack::Test::Methods
def app
Sinatra::Application
end
def test_password_reset
post '/users', {email: 'user1#gmail.com', password: 'password1'}
mailgun_mock = MiniTest::Mock.new
mailgun_mock.expect(:send, 200, [Hash])
Acani.const_mock(:Mailgun, mailgun_mock) do
post '/password_resets', {email: 'user1#gmail.com'}
end
mailgun_mock.verify
assert_equal 201, last_response.status
end
end

Resources