-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce driver registration #133
Conversation
Could delete screenshots taken from different driver in same suite
@@ -5,6 +5,8 @@ require "./support/**" | |||
|
|||
include LuckyFlow::Expectations | |||
|
|||
LuckyFlow::Spec.setup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sets up the lucky flow driver if one is requested through tags on the spec, and then resets back to the default driver after the spec is run.
It also has a callback for shutting down the drivers once all specs finish.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if there would be a way to force people to call this... Or like, you try to run some specs, but you forgot to add this so you get a compile-time error telling you to add it 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know about "force", but another option would be to have luckyflow/spec
unrequired by the library but requires luckyflow and does the Spec setup right in the file. Then we document that in order to use the library in your specs, you must require "lucky_flow/spec"
after you require "spec"
and it will just work. It could potentially be a pattern that we could support spectator in the future if we want to (just require "lucky_flow/spectator"
). Thoughts on that?
src/ext/spec/item.cr
Outdated
@@ -0,0 +1,12 @@ | |||
module Spec | |||
module Item | |||
def all_tags : Set(String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tags on a spec don't include parent contexts (context
, describe
) so this monkey-patched method is to facilitate that.
@@ -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) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to the driver instead of the session so that the driver could make the screenshot directory if it's missing
abstract def stop | ||
|
||
def reset : Nil | ||
@session.try &.cookie_manager.delete_all_cookies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we use @session
instead of the getter so that it doesn't start a session if there wasn't one already
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if this is called before session
is set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be nil, so the .try
will avoid an error
|
||
private def browser_binary : String? | ||
LuckyFlow.settings.browser_binary | ||
LuckyFlow::Registry.register :headless_chrome do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't like this config? Just call LuckyFlow::Registry.register :headless_chrome do ... end
with your own setup and it will overwrite this one 👍
@@ -0,0 +1,21 @@ | |||
class LuckyFlow::Registry | |||
@@registry = Hash(String, Proc(LuckyFlow::Driver)).new | |||
@@running_registry = Hash(String, LuckyFlow::Driver).new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@registry
is for drivers that can be used but aren't made yet,
@@running_registry
are drivers that have been created and should be used before making a new one
src/lucky_flow/spec.cr
Outdated
module LuckyFlow::Spec | ||
macro setup | ||
Spec.around_each do |spec| | ||
if driver_name = (spec.example.all_tags & LuckyFlow::Registry.available).first? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Rspec, you can pass key-value pairs in it
's but in Crystal you only have tags which are a list of strings. So instead of requiring passing something like driver: :chrome
, you have to do tags: "chrome"
instead and then we take the overlap of the tags you passed with the available browsers you can use. If for some reason you do tags: ["headless_chrome", "chrome"]
, there'd be an overlap of 2 but we take the first
|
||
def screenshot(path : String) | ||
FileUtils.mkdir_p(File.dirname(path)) | ||
session.screenshot(path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this also use the instance variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the only places I used the instance variable was places where if it was never started, there's nothing to stop/reset
module Item | ||
def all_tags : Set(String) | ||
all_tags = tags || Set(String).new | ||
temp = parent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this include all parents, or just the direct parent?
describe Thing do
context "when thing", tags: ["chrome"] do
describe "is a thing" do
it "does stuff" do
end
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in the if
below I call all_tags
on the parent which means it will fetch all tags of ever parent until it reaches the Spec::RootContext
which is not a Spec::Item
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, ok. I see what it's doing now. Can we rename the internal variable so it doesn't shadow the method name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up using the same naming convention we were recommended to use over here https://github.com/luckyframework/avram/blob/ac281f490a85283eaf8b74fd23357dd70a6d7f22/src/ext/db/connection.cr#L7
with an underscore and the name of the shard so in this case _lucky_flow_all_tags
. I also added # :nodoc:
. It's not a very clear name but it doesn't need to be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks good!
Fixes #132
This adds in the concept of registering drivers and also allows different drivers to be used in a test suite. The end goal is to allow for an in-memory driver alternative to be used as the default and any that need it can be set to use headless chrome.
This is a breaking change:
LuckyFlow::Server
was deleted as it didn't serve well in this modelLuckyFlow::Spec.setup
must be used to correctly configure LuckyFlow for use in specsLuckyFlow::Drivers::HeadlessChrome
was deleted as it is now just a chrome driver with slightly different configThere are also bugs in the underlying Selenium library that I found when trying to run specs with headless and non-headless chrome. This are not blocking from the default path of using this library (single driver for all specs).
With the goal of allowing for an in-memory driver alternative, the next step is to remove all direct access to the underlying selenium library since the new driver won't be provided through selenium.