Skip to content

Commit

Permalink
Merge pull request #103 from tuvistavie/search-element
Browse files Browse the repository at this point in the history
Add search_element and rename find_element! to find_element.
  • Loading branch information
Daniel Perez committed Apr 18, 2016
2 parents 1a6f6f4 + 442fb20 commit 1f6b2be
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 44 deletions.
4 changes: 4 additions & 0 deletions lib/hound/exceptions.ex
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
defmodule Hound.Error do
defexception [:message]
end

defmodule Hound.NoSuchElementError do
defexception [:strategy, :selector, :parent]

Expand Down
2 changes: 1 addition & 1 deletion lib/hound/helpers/element.ex
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ defmodule Hound.Helpers.Element do

@doc false
defp get_element({strategy, selector}),
do: Hound.Helpers.Page.find_element!(strategy, selector)
do: Hound.Helpers.Page.find_element(strategy, selector)
defp get_element(%Hound.Element{} = elem),
do: elem
end
72 changes: 37 additions & 35 deletions lib/hound/helpers/page.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ defmodule Hound.Helpers.Page do
@doc "Gets the visible text of current page."
@spec visible_page_text() :: String.t
def visible_page_text do
element = find_element!(:css, "body")
element = find_element(:css, "body")
session_id = Hound.current_session_id
make_req(:get, "session/#{session_id}/element/#{element}/text")
end
Expand All @@ -33,7 +33,7 @@ defmodule Hound.Helpers.Page do
* The second argument is the selector.
Valid selector strategies are `:css`, `:class`, `:id`, `:name`, `:tag`, `:xpath`, `:link_text` and `:partial_link_text`
`nil` will be returned if the element is not found.
`raises` if the element is not found or an error happens.
find_element(:name, "username")
Expand All @@ -43,26 +43,29 @@ defmodule Hound.Helpers.Page do
find_element(:tag, "footer")
find_element(:link_text, "Home")
"""
@spec find_element(Hound.Element.strategy, String.t, non_neg_integer) :: Hound.Element.t | nil
@spec find_element(Hound.Element.strategy, String.t, non_neg_integer) :: Hound.Element.t
def find_element(strategy, selector, retries \\ 5) do
case search_element(strategy, selector, retries) do
{:ok, element} -> element
{:error, :no_such_element} ->
raise Hound.NoSuchElementError, strategy: strategy, selector: selector
{:error, err} ->
raise Hound.Error, "could not get element {#{inspect(strategy)}, #{inspect(selector)}}: #{inspect(err)}"
end
end

@doc """
Same as `find_element/3`, but returns the a tuple with `{:error, error}` instead of raising
"""
@spec search_element(Hound.Element.strategy, String.t, non_neg_integer) :: {:ok, Hound.Element.t} | {:error, any}
def search_element(strategy, selector, retries \\ 5) do
session_id = Hound.current_session_id
params = %{using: Hound.InternalHelpers.selector_strategy(strategy), value: selector}

make_req(:post, "session/#{session_id}/element", params, %{safe: true}, retries*2)
|> process_element_response
end

@doc """
Same as `find_element/3`, but raises an exception if the element is not found.
"""
@spec find_element!(Hound.Element.strategy, String.t, non_neg_integer) :: Hound.Element.t
def find_element!(strategy, selector, retries \\ 5) do
case find_element(strategy, selector, retries) do
nil -> raise Hound.NoSuchElementError, strategy: strategy, selector: selector
element -> element
end
end


@doc """
Finds elements on current page. Returns an array of elements that can be used with other element functions.
Expand Down Expand Up @@ -112,28 +115,29 @@ defmodule Hound.Helpers.Page do
find_within_element(parent_element, :tag, "footer")
find_within_element(parent_element, :link_text, "Home")
"""
@spec find_within_element(Hound.Element.t, Hound.Element.strategy, String.t, non_neg_integer) :: Hound.Element.t | nil
@spec find_within_element(Hound.Element.t, Hound.Element.strategy, String.t, non_neg_integer) :: Hound.Element.t
def find_within_element(element, strategy, selector, retries \\ 5) do
case search_within_element(element, strategy, selector, retries) do
{:error, :no_such_element} ->
raise Hound.NoSuchElementError, strategy: strategy, selector: selector, parent: element
{:error, err} ->
raise Hound.Error, "could not get element {#{inspect(strategy)}, #{inspect(selector)}} in #{element}: #{inspect(err)}"
{:ok, element} -> element
end
end

@doc """
Same as `find_within_element/4`, but returns a `{:error, err}` tuple instead of raising
"""
@spec search_within_element(Hound.Element.t, Hound.Element.strategy, String.t, non_neg_integer) :: {:ok, Hound.Element.t} | {:error, any}
def search_within_element(element, strategy, selector, retries \\ 5) do
session_id = Hound.current_session_id
params = %{using: Hound.InternalHelpers.selector_strategy(strategy), value: selector}

make_req(:post, "session/#{session_id}/element/#{element}/element", params, %{safe: true}, retries*2)
|> process_element_response
end

@doc """
Same as `find_within_element/4`, but raises an exception if the element is not found.
"""
@spec find_within_element!(Hound.Element.t, Hound.Element.strategy, String.t, non_neg_integer) :: Hound.Element.t
def find_within_element!(element, strategy, selector, retries \\ 5) do
case find_within_element(element, strategy, selector, retries) do
nil ->
raise Hound.NoSuchElementError, strategy: strategy, selector: selector, parent: element
element -> element
end
end



@doc """
Finds elements within a specific element. Returns an array of elements that can be used with other element functions.
Expand Down Expand Up @@ -277,11 +281,9 @@ defmodule Hound.Helpers.Page do
end

defp process_element_response(%{"ELEMENT" => element_id}),
do: %Hound.Element{uuid: element_id}
defp process_element_response({:error, :no_such_element}),
do: nil
defp process_element_response({:error, err}),
do: raise err
defp process_element_response(value),
do: value
do: {:ok, %Hound.Element{uuid: element_id}}
defp process_element_response({:error, _err} = error),
do: error
defp process_element_response(unknown_error),
do: {:error, unknown_error}
end
16 changes: 8 additions & 8 deletions test/helpers/page_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ defmodule PageTest do
end


test "find_element/3 should return nil if element does not exist" do
test "search_element/3 should return {:error, :no_such_element} if element does not exist" do
navigate_to("http://localhost:9090/page1.html")
refute find_element(:css, ".i-dont-exist")
assert search_element(:css, ".i-dont-exist") == {:error, :no_such_element}
end

test "find_element!/3 should raise NoSuchElementError if element does not exist" do
test "find_element/3 should raise NoSuchElementError if element does not exist" do
navigate_to("http://localhost:9090/page1.html")
assert_raise Hound.NoSuchElementError, fn ->
find_element!(:css, ".i-dont-exist")
find_element(:css, ".i-dont-exist")
end
end

Expand All @@ -65,16 +65,16 @@ defmodule PageTest do
assert Element.element?(element)
end

test "find_within_element/4 should return nil if element is not found" do
test "search_within_element/4 should return {:error, :no_such_element} if element is not found" do
navigate_to("http://localhost:9090/page1.html")
container_id = find_element(:class, "container")
refute find_within_element(container_id, :class, "i-dont-exist")
assert search_within_element(container_id, :class, "i-dont-exist") == {:error, :no_such_element}
end

test "find_within_element!/4 should raise NoSuchElementError if element is not found" do
test "find_within_element/4 should raise NoSuchElementError if element is not found" do
navigate_to("http://localhost:9090/page1.html")
container_id = find_element(:class, "container")
assert_raise Hound.NoSuchElementError, fn -> find_within_element!(container_id, :class, "i-dont-exist") end
assert_raise Hound.NoSuchElementError, fn -> find_within_element(container_id, :class, "i-dont-exist") end
end

test "should find all elements within another element" do
Expand Down

0 comments on commit 1f6b2be

Please sign in to comment.