How to put asserts in Selenium webdriver Ruby script? - ruby

I wish to check value on UI with the provided value in script. And on comparing these two, it should display message "test passed" in console.
I have written following code: -
browser.find_element(:xpath,"//*[#id="total"]/tbody/tr/td[4]/span").value.should == "$466,634,599.67"
But it does not display anything on console. What could be required next?
Thanks!
Abhishek

Assertions, eg the .should==, are typically used within a test framework such as RSpec, MiniTest, Cucumber, etc. These test frameworks are designed to have reporting of the assertion's pass or fail result.
Given that you are not using a test framework, you will need to manually handle the output of results.
The most straightforward way would be to drop the assertion part and use an if statement:
element_value = browser.find_element(:xpath,"//*[#id="total"]/tbody/tr/td[4]/span").text
if element_value == "$466,634,599.67"
puts 'Test passed'
else
puts 'Test failed'
end
Note that the puts statements are used to output results to the console (unless you have changed the default output location).
Alternatively, if you do want to use the assertion, you could do:
element_value = browser.find_element(:xpath,"//*[#id="total"]/tbody/tr/td[4]/span").text
element_value.should == "$466,634,599.67"
puts 'Test passed'
In this approach, the assertion will raise an exception if the test fails. The assertion would stop the execution of the code and would therefore not output the 'Test passed' message (as expected). If the test passes, the 'Test passed' message would get outputted.

I use capybara gem for this purpose. It can check almost all front-end possibilities.
Code should look something like this:
describe "User pages" do
subject { page }
describe "index" do
before(:each) do
sign_in user
visit users_path
end
it { expect(page).to have_selector('li', text: user.name) }
end

Related

In Chef Inspec Ruby DSL, undefined method error when using a method defined earlier in the same file

I need to write several Chef Inspec controls that basically do the same checks but against different files and conditionally depending on certain factors (using the only_if syntax). I've written a method to do these checks and so I can call the method instead of repeatedly writing the same code over and over again in each control block. However this generates an error stating that the method was undefined.
I've omitted the "only_if" condition so that the control always runs
File_attribs = Struct.new(:path, :mode, :owner, :group, :sha256sum)
def file_checks (file)
describe "#{file.path}" do
subject { file(file.path) }
it "should exist" do
expect(subject).to(exist)
end
it "should be a file" do
expect(subject).to(be_file)
end
it "should have mode #{file.mode}" do
expect(subject.mode).to(cmp file.mode)
end
it "should be owned by #{file.owner} user" do
expect(subject.owner).to(eq file.owner)
end
it "should be owned by #{file.group} group" do
expect(subject.group).to(eq file.group)
end
if ! file.sha256sum.nil?
it "should match the known sha256 checksum" do
expect(subject.sha256sum).to(eq file.sha256sum)
end
end
end
end
control "test" do
impact 0.7
title "Test"
desc "Test"
test_files = [
File_attribs.new("/etc/os-release", "0644", "root", "root", "fe133101dac304ceb134e47dea186e9d74d2a439cd32ae5452cc4f5b3c1eba0e")
]
test_files.each do |test_file|
file_checks test_file
end
end
This results in the following error when I try to run it with inspec exec:
Profile: tests from /hab/svc/core-tools/test/integration/default/core-tools.rb (tests from .hab.svc.core-tools.test.integration.default.core-tools.rb)
Version: (not specified)
Target: local://
Target ID: d98404f5-a6f9-5bfb-b3ac-3e75561c700f
× test: Test
× Control Source Code Error /hab/svc/core-tools/test/integration/default/core-tools.rb:30
undefined method `file_checks' for #<Inspec::Rule:0x0000000006c0ee90 #impact=0.7, #title="Test", #descriptions={:default=>"Test"}, #refs=[], #tags={}, #resource_dsl=#<Module:0x0000000006c15cb8>, #__code=nil, #__block=#<Proc:0x0000000006c0ecd8 /hab/svc/core-tools/test/integration/default/core-tools.rb:30>, #__source_location={:ref=>"/hab/svc/core-tools/test/integration/default/core-tools.rb", :line=>30}, #__rule_id="test", #__profile_id="tests from .hab.svc.core-tools.test.integration.default.core-tools.rb", #__checks=[["describe", ["Control Source Code Error"], #<Proc:0x0000000006d24398 /hab/pkgs/chef/inspec/5.17.4/20220629103022/lib/gems/inspec-core-5.17.4/lib/inspec/rule.rb:407>]], #__skip_rule={}, #__merge_count=0, #__merge_changes=[], #__skip_only_if_eval=false, #__file="/hab/svc/core-tools/test/integration/default/core-tools.rb", #__group_title=nil>
Profile Summary: 0 successful controls, 1 control failure, 0 controls skipped
Test Summary: 0 successful, 1 failure, 0 skipped
I have tried numerous other approaches such as combining the struct members and file_checks function into a class, but then I get errors about "describe" being an undefined method.
Is it possible to define methods for use in Chef Inspec controls like this, or am I completely off base with what I'm trying to do? How can I accomplish what I want with the minimal amount of duplicated code?

Handling failures in data driven testing using rspec

I am using rspec to do some data driven testing. My test reads from a csv file, grabs an entry which is inserted into the text box on the page and is then compared to expected text which is also read from the csv file. All this is working as expected, I am able to read and compare without any issues.
Below is my code:
Method for reading csv file:
def user_data
user_data = CSV.read Dir.pwd + '/user_data.csv'
descriptor = user_data.shift
descriptor = descriptor.map { |key| key.to_sym }
user_data.map { |user| Hash[ descriptor.zip(user) ] }
end
Test:
describe "Text box tests" do
before :all do
#homepage = Homepage.new
end
it "should display the correct name" do
visit('http://my test url')
sleep 2
user_data.each do |entry|
#homepage.enter_name(entry[:name])
#homepage.click_go()
sleep 2
begin
expect(page).to have_css("#firstname", text: entry[:expected_name])
end
end
end
end
The problem is with failures. If I have a failure with one of the tests (i.e the expected text is not displayed on the page) then the test stops and all subsequent entries in the csv are not tested. If I put in a rescue after the expect statement like this:
rescue Exception => error
puts error.message
Then the error is logged to the console, however at the end of my test run it says no failures.
So basically I am looking for is, in the event of a failure for my test to keep running(until all entries in the csv have been covered), but for the test run to be marked as failed. Does anyone know how I can achieve this?
Try something like this:
context "when the user is on some page" do
before(:context) { visit('http://example.org/') }
user_data.each do |entry|
it "should display the correct name: #{entry[:name]}" do
#homepage.enter_name(entry[:name])
#homepage.click_go
expect(page).to have_css("#firstname", text: entry[:expected_name])
end
end
end
You will also need to change def user_data to def self.user_data
I would advise mapping over the entries and calling the regular capybara method has_css? instead of the rspec helper method. It would look like this:
results = user_data.map do |entry|
#homepage.enter_name(entry[:name])
#homepage.click_go()
sleep 2
page.has_css?("#firstname", text: entry[:expected_name])
end
expect(results.all?) to be_truthy
if you want to keep track of which ones failed, you cann modify it a bit:
missing_entries = []
user_data.each do |entry|
#homepage.enter_name(entry[:name])
#homepage.click_go()
sleep 2
has_entry = page.has_css?("#firstname", text: entry[:expected_name])
unless has_entry
missing_entries.push entry[:expected_name]
end
end
expect(missing_entries).to be_empty

Writing a Rspec test for an error condition finished with exit

I am writing a command line interface to a Ruby gem and I have this method exit_error, which acts as an exit error point to all validations performed while processing.
def self.exit_error(code,possibilities=[])
puts #errormsgs[code].colorize(:light_red)
if not possibilities.empty? then
puts "It should be:"
possibilities.each{ |p| puts " #{p}".colorize(:light_green) }
end
exit code
end
where #errormsgs is a hash whose keys are the error codes and whose values are the corresponding error messages.
This way I may give users customized error messages writing validations like:
exit_error(101,#commands) if not valid_command? command
where:
#errormsgs[101] => "Invalid command."
#commands = [ :create, :remove, :list ]
and the user typing a wrong command would receive an error message like:
Invalid command.
It should be:
create
remove
list
At the same time, this way I may have bash scripts detecting exactly the error code who caused the exit condition, and this is very important to my gem.
Everything is working fine with this method and this strategy as a whole. But I must confess that I wrote all this without writing tests first. I know, I know... Shame on me!
Now that I am done with the gem, I want to improve my code coverage rate. Everything else was done by the book, writing tests first and code after tests. So, it would be great having tests for these error conditions too.
It happens that I really don't know how to write Rspec tests to this particular situation, when I use exit to interrupt processing. Any suggestions?
Update => This gem is part of a "programming environment" full of bash scripts. Some of these scripts need to know exactly the error condition which interrupted the execution of a command to act accordingly.
For example:
class MyClass
def self.exit_error(code,possibilities=[])
puts #errormsgs[code].colorize(:light_red)
if not possibilities.empty? then
puts "It should be:"
possibilities.each{ |p| puts " #{p}".colorize(:light_green) }
end
exit code
end
end
You could write its rspec to be something like this:
describe 'exit_error' do
let(:errormsgs) { {101: "Invalid command."} }
let(:commands) { [ :create, :remove, :list ] }
context 'exit with success'
before(:each) do
MyClass.errormsgs = errormsgs # example/assuming that you can #errormsgs of the object/class
allow(MyClass).to receive(:exit).with(:some_code).and_return(true)
end
it 'should print commands of failures'
expect(MyClass).to receive(:puts).with(errormsgs[101])
expect(MyClass).to receive(:puts).with("It should be:")
expect(MyClass).to receive(:puts).with(" create")
expect(MyClass).to receive(:puts).with(" remove")
expect(MyClass).to receive(:puts).with(" list")
MyClass.exit_error(101, commands)
end
end
context 'exit with failure'
before(:each) do
MyClass.errormsgs = {} # example/assuming that you can #errormsgs of the object/class
allow(MyClass).to receive(:exit).with(:some_code).and_return(false)
end
# follow the same approach as above for a failure
end
end
Of course this is an initial premise for your specs and might not just work if you copy and paste the code. You will have to do a bit of a reading and refactoring in order to get green signals from rspec.

Ruby Load multiple scripts from directory with foreach loop

I'm using a loop to load and execute Ruby scripts in a directory. At the moment the script will load the script, but how do I execute it when the only reference to it is the filename in the form of a string?
Dir.foreach('tests') do |item|
next if item == '.' or item == '..' #removes extra "." or ".."
load dirname + '/' + item #successfully loads the script
if item # the scripts return true/false
numberPassed+=1
else
numberFailed+=1
failed.push(item)
end
numberTested+=1
end
For some reason I'm getting 2 Passed, but it never actually runs the scripts "item" represents.
EDIT: here is an example of a script that would need to be loaded. They all follow this format:
require "watir-webdriver"
class TestScript
puts 'Testing etc etc"...'
browser = Watir::Browser.new :ie
browser.goto "webpage.htm"
browser.text_field(:name => "j_username").set "username"
browser.text_field(:name => "j_password").set "password"
browser.link(:id, "watSubmitLogin").click
browser.wait
browser.link(:id=> 'watCommDir').fire_event("onmouseover")
browser.link(:id=> 'watAddFi').click
browser.wait
...
browser.link(:href, "javascript: submitForm();").click
browser.wait
if browser.text.include?( 'The user already Exists')
puts 'Passed'
browser.close
return true
else
puts 'Failed'
browser.close
return false
end
end
I need to somehow tell the main script whether the sub-scripts pass or fail so I can keep track of how many pass/fail/error/total and create a report of all the tests that failed.
Looks like you are doing acceptance testing with Watir and try to do custom test results reporting.
I would recommend to use existing test runners to run all your tests and build custom output formatter for your needs. Existing test runners already solve a lot of issues you will encounter during creation of your own test runner (like how to run tests from specified folder, how to identify failing/successful test etc).
One of the commmon test runners for acceptance tests in Ruby community is Cucumber. Another good alternative is RSpec. Both these libraries support custom formatters:
In RSpec you would need to subclass RSpec::Core::Formatters::BaseFormatter.
In Cucumber you would need to implement class with methods specified in this documentation.
If you want to stay with the current simple implementation, here is one possible approach that is inpired by ruby Regexps: Inside the test set global variable, e.g. $test_succeeded (like $~, $& etc. global variables generated by ruby regular expressions) and then examine this value in your test runner.
In tests
if browser.text.include?( 'The user already Exists')
puts 'Passed'
browser.close
$test_succeeded = true
# ...
In tests runner
Dir.foreach('tests') do |item|
next if item == '.' or item == '..' #removes extra "." or ".."
load dirname + '/' + item #successfully loads the script
if $test_succeeded
# ...
If you have problems running the script then I can recommend to define special method to run tests (similar to RSpec approach):
def test
test_res = yield # call test
$test_results ||= {}
$test_results << test_res # and store its result in arra of test results
end
Then your tests will look like:
require 'file_with_test_method'
require 'watir-webdriver'
test do
# your test code
browser.text.include?( 'The user already Exists') # last expression in the block will be the test result
end

Disable a group of tests in rspec?

I have a test spec which describes a class and within that has various contexts each with various it blocks.
Is there a way I can disable a context temporarily?
I tried adding a pending "temporarily disabled" call at the very top within a context I want to disable, and I did see something about pending when I ran the spec but then it just continued to run the rest of the tests.
This is what I kind of had:
describe Something
context "some tests" do
it "should blah" do
true
end
end
context "some other tests" do
pending "temporarily disabled"
it "should do something destructive" do
blah
end
end
end
but like I said it just went on to run the tests underneath the pending call.
Searching led me to this mailing list thread in which the the creator (?) of rspec says it's possible in rspec 2, which I'm running. I guess it did work but it didn't have the desired effect of disabling all of the following tests, which is what I think of when I see a pending call.
Is there an alternative or am I doing it wrong?
To disable a tree of specs using RSpec 3 you can:
before { skip }
# or
xdescribe
# or
xcontext
You can add a message with skip that will show up in the output:
before { skip("Awaiting a fix in the gem") }
with RSpec 2:
before { pending }
Use exclusion filters.
From that page:
In your spec_helper.rb (or rails_helper.rb)
RSpec.configure do |c|
c.filter_run_excluding :broken => true
end
In your test:
describe "group 1", :broken => true do
it "group 1 example 1" do
end
it "group 1 example 2" do
end
end
describe "group 2" do
it "group 2 example 1" do
end
end
When I run "rspec ./spec/sample_spec.rb --format doc"
Then the output should contain "group 2 example 1"
And the output should not contain "group 1 example 1"
And the output should not contain "group 1 example 2"
See what you think of this:
describe "something sweet", pending: "Refactor the wazjub for easier frobbing" do
it "does something well"
it "rejects invalid input"
end
I like to see reasons with my pending items when I'm disabling something for "a while". They serve as little comments/TODOs that are presented regularly rather than buried in a comment or an excluded example/file.
Changing it to pending or xit is quick and easy, but I prefer the hash construction. It gives you every-run documentation, is a drop-in (doesn't change describe/context/it so I have to decide what to use again later), and is just as easily removed if the decision is made or blocker is removed.
This works the same for groups and individual examples.
another one. https://gist.github.com/1300152
use xdescribe, xcontext, xit to disable it.
Update:
Since rspec 2.11, it includes xit by default. so the new code will be
# put into spec_helper.rb
module RSpec
module Core
module DSL
def xdescribe(*args, &blk)
describe *args do
pending
end
end
alias xcontext xdescribe
end
end
end
Usage
# a_spec.rb
xdescribe "padding" do
it "returns true" do
1.should == 1
end
end
Use pending instead of describe. If your block is:
context "some other tests" do
it "should do something destructive" do
blah
end
end
You can skip the whole block by:
pending "some other tests" do
it "should do something destructive" do
blah
end
end
describe "GET /blah" do
before(:each) { pending "Feature to be implemented..." }
it { expect(page).to have_button("Submit") }
it { expect(page).to have_content("Blah") }
end
Just to explain what's happening with your code. Including it where you have, it just gets evaluated (and hence run) when the file is loaded during startup. However you need it to be run when the tests run. That's why answers have suggested putting pending (RSpec 2) or skip (RSpec 3) into a before block.

Resources