Leelluu
Leelluu

Reputation: 121

Ruby Watir: cannot launch browser in a thread in Linux

I'm trying to run this code in Red Hat Linux, and it won't launch a browser. The only way I can get it to work is if i ALSO launch a browser OUTSIDE of the thread, which makes no sense to me. Here is what I mean:

require 'watir-webdriver'
$alphabet = ["A", "B", "C"]
$alphabet.each do |z|
    puts "pshaw"
    Thread.new{
        Thread.current["testPuts"] =  "ohai " + z.to_s
        Thread.current["myBrowser"] = Watir::Browser.new :ff
        puts Thread.current["testPuts"]     }

    $browser = Watir::Browser.new :ff
end

the output is:

pshaw
(launches browser)
ohai A
(launches browser)
pshaw
(launches browser)
ohai B
(launches browser)
pshaw
(launches browser)
ohai C
(launches browser)

However, if I remove the browser launch that is outside of the thread, as so:

require 'watir-webdriver'
$alphabet = ["A", "B", "C"]

    $alphabet.each do |z|
puts "pshaw"
Thread.new{
    Thread.current["testPuts"] =  "ohai " + z.to_s
    Thread.current["myBrowser"] = Watir::Browser.new :ff
    puts Thread.current["testPuts"]     }
end

The output is:

pshaw
pshaw
pshaw

What is going on here? How do I fix this so that I can launch a browser inside a thread?

EDIT TO ADD:

The solution Justin Ko provided worked on the psedocode above, but it's not helping with my actual code:

require 'watir-webdriver'
require_relative 'Credentials'
require_relative 'ReportGenerator'
require_relative 'installPageLayouts'
require_relative 'PackageHandler'
Dir[(Dir.pwd.to_s + "/bmx*")].each {|file| require_relative file } #this includes all the files in the directory with names starting with bmx


module Runner
def self.runTestCases(orgType, *caseNumbers)
    $testCaseArray = Array.new

    caseNumbers.each do |thisCaseNum|
        $testCaseArray << thisCaseNum
    end

    $allTestCaseResults = Array.new
    $alphabet = ["A", "B", "C"]
    @count = 0
    @multiOrg = 0
    @peOrg = 0
    @eeOrg = 0
    @threads = Array.new
    $testCaseArray.each do |thisCase|
        $alphabet[@count] = Thread.new {    
            puts "working one"
            Thread.current["tBrowser"] = Watir::Browser.new :ff
            puts "working two"
            if ((thisCase.declareOrg().downcase == "multicurrency") || (thisCase.declareOrg().downcase == "mc"))
                currentOrg = $multicurrencyOrgArray[@multiOrg]
                @multiOrg += 1
            elsif ((thisCase.declareOrg().downcase == "enterprise") || (thisCase.declareOrg().downcase == "ee"))
                currentOrg = $eeOrgArray[@eeOrg]
                @eeOrg += 1         
            else #default to single currency PE
                currentOrg = $peOrgArray[@peOrg]
                @peOrg += 1
            end
            setupOrg(currentOrg, thisCase.testCaseID, currentOrg.layoutDirectory)
            runningTest = thisCase.actualTest()
            if runningTest.crashed != "crashed" #changed this to read the attr_reader isntead of the deleted caseStatus method from TestCase.rb
                cleanupOrg(thisCase.testCaseID, currentOrg.layoutDirectory)
            end
                        @threads << Thread.current
        }
        @count += 1     
    end 

    @threads.each do |thisThread|           
        thisThread.join
    end
    writeReport($allTestCaseResults)
end



def self.setupOrg(thisOrg, caseID, layoutPath)
    begin
        thisOrg.logIn
        pkg = PackageHandler.new
        basicInstalled = "false"
        counter = 0
        until ((basicInstalled == "true") || (counter == 5))
            pkg.basicInstaller()
            if Thread.current["tBrowser"].text.include? "You have attempted to access a page"
                thisOrg.logIn
            else    
                basicInstalled = "true"
            end
            counter +=1
        end
        if !((caseID.include? "bmxb") || (caseID.include? "BMXB"))
            moduleInstalled = "false"
            counter2 = 0
            until ((moduleInstalled == "true") || (counter == 5))
                pkg.packageInstaller(caseID)
                if Thread.current["tBrowser"].text.include? "You have attempted to access a page"
                    thisOrg.logIn
                else    
                    moduleInstalled = "true"
                end
                counter2 +=1
            end 
        end
        installPageLayouts(layoutPath)
    rescue
        $allTestCaseResults << TestCaseResult.new(caseID, caseID, 1, "SETUP FAILED!" + "<p>#{$!}</p><p>#{$@}</p>").hashEmUp
        writeReport($allTestCaseResults)
    end
end

def self.cleanupOrg(caseID, layoutPath)
    begin
        uninstallPageLayouts(layoutPath)
        pkg = PackageHandler.new
        pkg.packageUninstaller(caseID)
        Thread.current["tBrowser"].close
    rescue
        $allTestCaseResults << TestCaseResult.new(caseID, caseID, 1, "CLEANUP FAILED!" + "<p>#{$!}</p><p>#{$@}</p>").hashEmUp
        writeReport($allTestCaseResults)
    end
end



end

The output it's generating is:

working one
working one
working one

It's not opening a browser or doing any of the subsequent code.

Upvotes: 0

Views: 280

Answers (2)

Leelluu
Leelluu

Reputation: 121

I uninstalled Watir 5.0.0 and installed Watir 4.0.2, and now it works fine.

Upvotes: 0

Justin Ko
Justin Ko

Reputation: 46846

It looks like the code is having the problem mentioned in the Thread class documentation:

If we don't call thr.join before the main thread terminates, then all other threads including thr will be killed.

Basically your main thread is finishing pretty instantaneously. However, the threads, which create browsers, take a lot longer than that. As result the threads get terminated before the browser opens.

By adding a long sleep at the end, you can see that your browsers can be opened by your code:

require 'watir-webdriver'
$chunkythread = ["A", "B", "C"]
$chunkythread.each do |z|
  puts "pshaw"
  Thread.new{
    Thread.current["testwords"] =  "ohai " + z.to_s
    Thread.current["myBrowser"] = Watir::Browser.new :ff
    puts Thread.current["testwords"]    }
end
sleep(300)

However, for more reliability, you should join all the threads at the end:

require 'watir-webdriver'
threads = []
$chunkythread = ["A", "B", "C"]
$chunkythread.each do |z|
  puts "pshaw"
  threads << Thread.new{
    Thread.current["testwords"] =  "ohai " + z.to_s
    Thread.current["myBrowser"] = Watir::Browser.new :ff
    puts Thread.current["testwords"]    }
end
threads.each { |thr| thr.join }

For the actual code example, putting @threads << Thread.current will not work. The join will be evaluating like @threads is empty. You could try doing the following:

$testCaseArray.each do |thisCase|
    @threads << Thread.new {    
        puts "working one"
        Thread.current["tBrowser"] = Watir::Browser.new :ff

        # Do your other thread stuff
    }
    $alphabet[@count] = @threads.last
    @count += 1     
end 

@threads.each do |thisThread|           
    thisThread.join
end

Note that I am not sure why you want to store the threads in $alphabet. I put in the $alphabet[@count] = @threads.last, but could be removed if not in use.

Upvotes: 2

Related Questions