Usage of block in hooks.rb

131 views
Skip to first unread message

NaviHan

unread,
Jan 29, 2019, 12:47:10 AM1/29/19
to Watir General
Hi all

Im just looking for some good documentation which explains the usage of blocks in hooks.rb

For example "Before", "After" , "AfterStep" etc...

Thanks in advance

Lakshya Kapoor

unread,
Jan 29, 2019, 3:06:19 AM1/29/19
to Watir General
You are confusing Cucumber hooks with Watir hooks.


Anyway, here is how you can use the 3 hooks you mentioned:

Before: Do something before the test starts (before first step). For example: Launch browser, log into the application, or to setup Watir's AfterHook to check for errors (see the link above).

After: Do something after the test finishes (after last step). For example: Log out of the application, close browser, or data cleanup.

AfterStep: Do something after each step in the Scenario. For example: Take a screenshot if the step fails.

NaviHan

unread,
Jan 29, 2019, 5:01:06 AM1/29/19
to Watir General
Thanks Laskhya. Im aware of the use of the hooks. But rathet confused by the syntax.. Here are the blocks in my projects hooks.rb

Sometimes "scenario" is passed, Sometimes "scenario" and "block" are passed. Its quite confusing how exactly its doing?

Before do
 
@browser = browser
end
Before do|scenario|
 ENV
['HTTP_PROXY'] = ENV['http_proxy'] = nil
 
DataMagic.load('order_details.yml')
 
DataMagic.load_for_scenario(scenario)
end
After do |scenario|
 
@browser.execute_script("javascript:localStorage.clear();")
 
@browser.cookies.clear
 
if (scenario.passed?)
 puts
'Scenario Passed !'
 
else
 puts
'Scenario Failed !'
 
end
end
AfterStep('@screen') do
 filename
= DateTime.now.strftime("%d%b%Y%H%M%S")
 
@browser.screenshot.save ("C:/Users/lohit.kotian/Documents/Automation/screenshots-cucumber/#{filename}.png")
 
#@browser.screenshot.save ("C:/Jenkins/workspace/screenshots-cucumber/#{filename}.png")
end
Around('@multipletimes') do |scenario, block|
 $counter
= 0
 $total_times_to_run
= 6
 
while $counter < $total_times_to_run do
 block
.call
 puts
("Total times scripts were repeated = #$counter" )
 $counter
+=1
 
end
end
After do |scenario|
 take_screenshot
(@browser, scenario)
end



Lakshya Kapoor

unread,
Jan 31, 2019, 1:05:02 PM1/31/19
to Watir General
Sorry, I assumed otherwise because you posted in the Watir group :).

I haven't used the Around hook before, so I decided to figure it out and explain it here. Hopefully someone more experienced can chime in if my answer is incomplete or incorrect. 

So, it appears that the Around hook is specifically designed to provide access to the scenario (Cucumber::Core::Test::Case) object and a block (Proc). The block is what holds the execution logic/steps in your Scenario (source) AND the Before/After hooks. If you don't call the block, the Before/After hooks and the Scenario steps will not execute. This establishes the execution order as Around hook > Before/After hook > Scenario steps. You can test this by printing something from the Before/After hooks and commenting out block.call in your Around hook. You'll see that nothing is printed, including the Scenario steps, until you uncomment block.call.

Now that we know the Before/After hooks are invoked by the block from the Around hook, there is no further use of the block once it is called. Therefore, the Before/After hooks only allow us to work with the scenario object.

Hope this explains the reasoning behind the difference in the syntax.

Lakshya Kapoor

unread,
Jan 31, 2019, 1:09:39 PM1/31/19
to Watir General
Also, I would recommend joining the Cucumber channels on Slack (https://cucumber.io/support#slack) if you have more questions.

Lakshya Kapoor

unread,
Jan 31, 2019, 1:13:48 PM1/31/19
to Watir General
Since we can't edit our posts, here is a quick update to my answer: Technically, the correct execution order is Around hook > Before hook > Scenario > After hook.



NaviHan

unread,
Feb 1, 2019, 12:25:11 AM2/1/19
to Watir General
Thanks Lakshya for the detailed explanation.

So if I want to execute a scenario 3 times, here is the order of execution

iteration 1 -> Before Hook   Scenario Steps  After Hook
iteration 2 -> Before Hook   Scenario Steps  After Hook
iteration 3 -> Before Hook   Scenario Steps  After Hook

Or is it

Before Hook
iteration 1 -> Scenario Steps
iteration 2 -> Scenario Steps
iteration 3 -> Scenario Steps
After Hook

Also what is the difference between

Before do
 
@browser = browser
end

and


Before do |scenario|
 
@browser = browser
end



On Tuesday, 29 January 2019 16:47:10 UTC+11, NaviHan wrote:

Lakshya Kapoor

unread,
Feb 1, 2019, 1:17:56 AM2/1/19
to Watir General
You are welcome!

The order of execution will always be:

iteration 1 -> Before Hook   Scenario Steps  After Hook
iteration 2 -> Before Hook   Scenario Steps  After Hook
iteration 3 -> Before Hook   Scenario Steps  After Hook

This is also a good practice, so that your Scenarios always start from a clean state - new browser instance, new login session, etc.

The difference between the two Before hooks you shared is that you are getting access the scenario object in the second one. This object allows you to get info such as Scenario title, description, tags, pass/fail status in After hook, and so on. This doc will help you figure out all the methods you can use on that object - https://www.rubydoc.info/github/cucumber/cucumber-ruby/

NaviHan

unread,
Feb 1, 2019, 7:07:08 AM2/1/19
to Watir General
Hi Lakshya

Here is the hooks.rb used in our project..

Eventhough the the browser is assigned to instance variable @browser we still get to see all the details you mentioned. So Im not quite getting the difference between the two Before hooks

require 'rubygems'
require 'page-object'
require 'watir'
require 'page-object/page_factory'
require 'log4r'
require 'cucumber'
require 'selenium-webdriver'
require 'fig_newton'
require 'watir-screenshot-stitch'
require 'mini_magick'

args = ['--allow-running-insecure-content']
browser = Watir::Browser.new :chrome, options: {args: args}
$code_retry = 30

Before do
 @browser = browser
end


Before do|scenario|
        ENV['HTTP_PROXY'] = ENV['http_proxy'] = nil
        DataMagic.load_for_scenario(scenario)
        @browser.window.maximize
        @browser.driver.manage.timeouts.implicit_wait = 0
        @browser.cookies.clear
        @browser.driver.manage.window.maximize
        PageObject.default_element_wait=(10)
        PageObject.javascript_framework = :jquery
        #Selenium::WebDriver.logger.level = :info
end #before scenario




# "after all"
at_exit do
 browser.close
end

# need to check this code for the full page screenshots as a part of the enhancement

  def take_screenshot(browser, scenario)
    time = Time.now.strftime("%Y-%m-%d_%H%M")
    opts = {:page_height_limit => 5000}
    if scenario.failed?
      scenario_name = scenario.name.gsub(/[^\w\-]/, ' ')
      screenshot_path =  "#{scenario_name}" + "_failure_" + time
      @browser.screenshot.save_stitch("./screenshots/#{screenshot_path}.png", browser, opts)
    end
  end





On Tuesday, 29 January 2019 16:47:10 UTC+11, NaviHan wrote:

Lakshya Kapoor

unread,
Feb 1, 2019, 4:35:45 PM2/1/19
to Watir General
There is no difference in functionality from a Hooks perspective. They both work the same way, except that the in the second one you are getting access to the Scenario details (object).

Actually, you can come both the Before hooks to achieve the same result:

Before do|scenario|
       @browser = browser

       ENV['HTTP_PROXY'] = ENV['http_proxy'] = nil
       DataMagic.load_for_scenario(scenario)
       @browser.window.maximize
       @browser.driver.manage.timeouts.implicit_wait = 0
       @browser.cookies.clear
       @browser.driver.manage.window.maximize
       PageObject.default_element_wait=(10)
       PageObject.javascript_framework = :jquery
       #Selenium::WebDriver.logger.level = :info
end #before scenario
Reply all
Reply to author
Forward
0 new messages