diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 485bf2a..de964ac 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -5,6 +5,8 @@ require "./support/**" include LuckyFlow::Expectations +LuckyFlow::Spec.setup + server = TestServer.new(3002) Spec.before_each do @@ -16,8 +18,9 @@ LuckyFlow.configure do |settings| settings.stop_retrying_after = 40.milliseconds end +Habitat.raise_if_missing_settings! + Spec.after_suite do - LuckyFlow.shutdown server.close end diff --git a/src/ext/spec/item.cr b/src/ext/spec/item.cr new file mode 100644 index 0000000..43a7449 --- /dev/null +++ b/src/ext/spec/item.cr @@ -0,0 +1,13 @@ +module Spec + module Item + # :nodoc: + def _lucky_flow_all_tags : Set(String) + all_tags = tags || Set(String).new + temp = parent + if temp.is_a?(Spec::Item) + all_tags += temp._lucky_flow_all_tags + end + all_tags + end + end +end diff --git a/src/lucky_flow.cr b/src/lucky_flow.cr index c1db4e3..93381f0 100644 --- a/src/lucky_flow.cr +++ b/src/lucky_flow.cr @@ -6,10 +6,14 @@ class LuckyFlow; end require "./lucky_flow/**" require "file_utils" +require "./ext/spec/item" class LuckyFlow include LuckyFlow::Expectations - SERVER = LuckyFlow::Server::INSTANCE + + @@driver : LuckyFlow::Driver? + + class_property default_driver : String = "headless_chrome" Habitat.create do setting screenshot_directory : String = "./tmp/screenshots" @@ -17,12 +21,30 @@ class LuckyFlow setting retry_delay : Time::Span = 10.milliseconds setting stop_retrying_after : Time::Span = 1.second setting driver_path : String? - setting browser_binary : String? = nil - setting driver : LuckyFlow::Driver.class = LuckyFlow::Drivers::HeadlessChrome end - def HabitatSettings.chromedriver_path=(_chromedriver_path) - {% raise "'chromedriver_path' has been renamed to 'driver_path'" %} + def self.driver : LuckyFlow::Driver + @@driver ||= LuckyFlow::Registry.get_driver(self.default_driver) + end + + def self.driver(name : String) : LuckyFlow::Driver + @@driver = LuckyFlow::Registry.get_driver(self.default_driver) + end + + def self.session : Selenium::Session + driver.session + end + + def self.shutdown : Nil + LuckyFlow::Registry.shutdown_all + end + + def self.use_default_driver + @@driver = nil + end + + def self.reset : Nil + @@driver.try(&.reset) end def visit(path : String) @@ -52,9 +74,9 @@ class LuckyFlow def take_screenshot(filename : String = generate_screenshot_filename, fullsize : Bool = true) if fullsize - with_fullsized_page { session.screenshot(filename) } + with_fullsized_page { driver.screenshot(filename) } else - session.screenshot(filename) + driver.screenshot(filename) end end @@ -188,19 +210,11 @@ class LuckyFlow STDIN.gets end - def session + def session : Selenium::Session self.class.session end - def self.session - SERVER.session - end - - def self.shutdown - SERVER.shutdown - end - - def self.reset - SERVER.reset + def driver : LuckyFlow::Driver + self.class.driver end end diff --git a/src/lucky_flow/driver.cr b/src/lucky_flow/driver.cr index 133a431..ce01ce4 100644 --- a/src/lucky_flow/driver.cr +++ b/src/lucky_flow/driver.cr @@ -1,7 +1,24 @@ abstract class LuckyFlow::Driver @retry_limit : Time = 2.seconds.from_now + getter session : Selenium::Session { start_session } + abstract def start_session : Selenium::Session + abstract def stop + + def reset : Nil + @session.try &.cookie_manager.delete_all_cookies + end + + def shutdown : Nil + @session.try &.delete + stop + end + + def screenshot(path : String) + FileUtils.mkdir_p(File.dirname(path)) + session.screenshot(path) + end protected def retry_start_session(e) if Time.utc <= @retry_limit diff --git a/src/lucky_flow/drivers/chrome.cr b/src/lucky_flow/drivers/chrome.cr index 7461e93..c09a004 100644 --- a/src/lucky_flow/drivers/chrome.cr +++ b/src/lucky_flow/drivers/chrome.cr @@ -1,9 +1,18 @@ class LuckyFlow::Drivers::Chrome < LuckyFlow::Driver + private getter driver : Selenium::Driver do + service = Selenium::Service.chrome(driver_path: driver_path) + Selenium::Driver.for(:chrome, service: service) + end + + @capabilities : Selenium::Chrome::Capabilities + + def initialize(&block) + @capabilities = Selenium::Chrome::Capabilities.new + yield @capabilities + end + def start_session : Selenium::Session - capabilities = Selenium::Chrome::Capabilities.new - capabilities.chrome_options.args = args - capabilities.chrome_options.binary = browser_binary - driver.create_session(capabilities) + driver.create_session(@capabilities) rescue e : IO::Error retry_start_session(e) end @@ -12,26 +21,19 @@ class LuckyFlow::Drivers::Chrome < LuckyFlow::Driver @driver.try(&.stop) end - protected def args : Array(String) - [] of String - end - - @driver : Selenium::Driver? - - private def driver : Selenium::Driver - @driver ||= begin - service = Selenium::Service.chrome(driver_path: driver_path) - Selenium::Driver.for(:chrome, service: service) - end - end - private def driver_path LuckyFlow.settings.driver_path || Webdrivers::Chromedriver.install rescue err raise DriverInstallationError.new(err) end +end + +LuckyFlow::Registry.register :chrome do + LuckyFlow::Drivers::Chrome.new { } +end - private def browser_binary : String? - LuckyFlow.settings.browser_binary +LuckyFlow::Registry.register :headless_chrome do + LuckyFlow::Drivers::Chrome.new do |config| + config.chrome_options.args = ["no-sandbox", "headless", "disable-gpu"] end end diff --git a/src/lucky_flow/drivers/headless_chrome.cr b/src/lucky_flow/drivers/headless_chrome.cr deleted file mode 100644 index 9e8d8e5..0000000 --- a/src/lucky_flow/drivers/headless_chrome.cr +++ /dev/null @@ -1,5 +0,0 @@ -class LuckyFlow::Drivers::HeadlessChrome < LuckyFlow::Drivers::Chrome - protected def args : Array(String) - ["no-sandbox", "headless", "disable-gpu"] - end -end diff --git a/src/lucky_flow/registry.cr b/src/lucky_flow/registry.cr new file mode 100644 index 0000000..9f8bcfe --- /dev/null +++ b/src/lucky_flow/registry.cr @@ -0,0 +1,21 @@ +class LuckyFlow::Registry + @@registry = Hash(String, Proc(LuckyFlow::Driver)).new + @@running_registry = Hash(String, LuckyFlow::Driver).new + + def self.register(name : String | Symbol, &block : -> LuckyFlow::Driver) + @@registry[name.to_s] = block + end + + def self.available : Set(String) + Set.new(@@registry.keys) + end + + def self.get_driver(name : String) : LuckyFlow::Driver + @@running_registry[name] ||= @@registry[name].call + end + + def self.shutdown_all + @@running_registry.values.each(&.shutdown) + @@running_registry.clear + end +end diff --git a/src/lucky_flow/server.cr b/src/lucky_flow/server.cr deleted file mode 100644 index 99005ac..0000000 --- a/src/lucky_flow/server.cr +++ /dev/null @@ -1,44 +0,0 @@ -# Handles starting and stopping server sessions -class LuckyFlow::Server - # This is used so that only one server instance is started - INSTANCE = new - - @session : Selenium::Session? - @driver : LuckyFlow::Driver? - - # Use LuckyFlow::Server::INSTANCE instead - private def initialize - end - - # Start a new selenium session - def session : Selenium::Session - @session ||= begin - prepare_screenshot_directory - driver.start_session - end - end - - private def prepare_screenshot_directory - FileUtils.rm_rf(screenshot_directory) - FileUtils.mkdir_p(screenshot_directory) - end - - private def screenshot_directory - LuckyFlow.settings.screenshot_directory - end - - def reset - @session.try &.cookie_manager.delete_all_cookies - end - - def shutdown - @session.try &.delete - @driver.try &.stop - end - - private def driver - @driver ||= begin - LuckyFlow.settings.driver.new - end - end -end diff --git a/src/lucky_flow/spec.cr b/src/lucky_flow/spec.cr new file mode 100644 index 0000000..316e858 --- /dev/null +++ b/src/lucky_flow/spec.cr @@ -0,0 +1,18 @@ +module LuckyFlow::Spec + macro setup + Spec.around_each do |spec| + if driver_name = (spec.example._lucky_flow_all_tags & LuckyFlow::Registry.available).first? + LuckyFlow.driver(driver_name) + end + + spec.run + + LuckyFlow.reset + LuckyFlow.use_default_driver + end + + Spec.after_suite do + LuckyFlow.shutdown + end + end +end