-1

Our application after a certain transaction need to login to a third party system and enter some data. Made a system test with Capybara and selenium and that works great, however that's when running it at a test. I'd like to create a class/service that will run in an ActiveJob to do the same so after the save of the transaction I'd like to call ActiveJob.perform_later(params) and the params should pass to the 'external_system_integration' class and run headless to login to the third party site and enter the data received in params.

How to do this?

My Class

require 'capybara/dsl'
require 'capybara/rspec'
require "selenium/webdriver"

class OrderDeskService
    Capybara.default_driver = :webkit
    include Capybara::DSL


    def self.login
        Capybara.register_driver :chrome do |app|
            profile = Selenium::WebDriver::Chrome::Profile.new
            profile["download.default_directory"] = DOWNLOAD_PATH
            Capybara::Selenium::Driver.new(app, :browser => :chrome, :profile => profile)
        end

        Capybara.configure do |config|
            config.run_server = false
            config.app_host = 'https://app.orderdesk.me'
        end
        visit '/login'
        sleep 10
    end
end

EDIT after the feedback:


Capybara.configure do |c|
    c.run_server = false
    c.app_host = 'https://app.orderdesk.me'
end

#Configure
Capybara.register_driver :selenium do |app|
    profile = Selenium::WebDriver::Chrome::Profile.new
    profile["download.default_directory"] = DOWNLOAD_PATH
    Capybara::Selenium::Driver.new(app, :browser => :chrome, :profile => profile)
end
#headless
Capybara.register_driver :headless_chrome do |app|
    capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
        chromeOptions: {
            args: %w[headless disable-gpu enable-features=NetworkService,NetworkServiceInProcess]
        }
    )
    Capybara::Selenium::Driver.new app,
                                                                 browser: :chrome,
                                                                 desired_capabilities: capabilities
end



#make it thread safe
Capybara.threadsafe = true

Capybara.default_driver = Capybara.javascript_driver = :headless_chrome


class OrderDeskService
    include Capybara::DSL

    def self.login
        session = Capybara::Session.new(:selenium)
        session.visit '/login'
        sleep 3
        session.quit
    end
end

Trying to run in headless mode but it still opens Chrome browser.

Peter Van de Put
  • 878
  • 10
  • 26
  • Just create a class, put the code you already have in a class method and create an ActiveJob worker that simply calls that class method. – arieljuod Oct 27 '19 at 14:03
  • Thanks, Ive tried that first but then i get this error undefined method `visit' for OrderDeskService:Class – Peter Van de Put Oct 27 '19 at 14:16
  • Ok, I understand now, you shouldn't do that, your test shouldn't do real requests to external sites, it's a really bad practice. If you need to do something with an external site on your production code use an HTTP request with whatever you need using the Net::HTTP module https://ruby-doc.org/stdlib-2.6.5/libdoc/net/http/rdoc/Net/HTTP.html, don't use selenium for that's. – arieljuod Oct 27 '19 at 15:28

1 Answers1

2

It's definitely possible to use Capybara in a class but doing the way you're attempting (calling Capybaras class methods) is going to conflict with your system tests and give you all sorts of headaches. Instead you want to use manual session management in your class, and call on the capybara methods on that session.

Capybara.register_driver :my_driver do |app|
  # Only needs to be done once
  ...
end

class OrderDeskService
  def self.login
    session = Capybara::Session.new(:my_driver)
    session.visit('https://app.orderdesk.me/login')
    ,,,
    session.quit
  end
end

If you want the session to last more than the one method call save it in a class variable and call quit at the required time. If you want more than one session to be able to be active at a time then use instance variables/methods instead. More advanced would be to enable Capybaras "threadsafe" mode which makes most config options session/thread specific

Capybara.register_driver :my_driver do |app|
  # Only needs to be done once
  ...
end

Capybara.threadsafe = true

class OrderDeskService
  def self.login
    session = Capybara::Session.new(:my_driver) do |c|
      c.app_host = 'https://app.orderdesk.me'
      c.... # any other Capybara session configs that need to apply to this session
    end
    session.visit('/login')
    ,,,
    session.quit
  end
end    
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • It works . When configuring for headless chrome however it opens Firefox ? What am I doing wrong ? – Peter Van de Put Oct 27 '19 at 16:06
  • 1
    @PeterVandePut how are you registering your driver – Thomas Walpole Oct 27 '19 at 16:07
  • Probably wrong currently on mobile don’t have it with me so you have a working example ? – Peter Van de Put Oct 27 '19 at 16:53
  • Updated the post with the headless configuration, it now doesn't open firefox but still opens Chrome where expecting not to open the browser – Peter Van de Put Oct 28 '19 at 07:58
  • @PeterVandePut That's because you're not configuring Selenium correctly. See https://github.com/teamcapybara/capybara/blob/master/lib/capybara/registrations/drivers.rb#L27 for an up to date example of registering a headless Chrome driver, and then rather than setting `default_driver` and `javascript_driver` you specify the name of the driver to use when creating the session - `Capybara::Session.new(:headless_chrome) # whatever driver name you've registered`. Also don't specify `run_server` (unnecessary when creating your own sessions) or `app_host` globally (do it session specific) – Thomas Walpole Oct 28 '19 at 14:57