Giter Site home page Giter Site logo

hound's Introduction

Hound

For browser automation and writing integration tests in Elixir.

Source | Documentation

Build Status

Features

  • Can run multiple browser sessions simultaneously. See example.

  • Supports Selenium (Firefox, Chrome), ChromeDriver and PhantomJs.

  • Supports Javascript-heavy apps. Retries a few times before reporting error.

  • Implements the WebDriver Wire Protocol.

Internet Explorer may work under Selenium, but hasn't been tested.

Example

ExUnit example
defmodule HoundTest do
  use ExUnit.Case
  use Hound.Helpers

  hound_session()

  test "the truth", meta do
    navigate_to("http://example.com/guestbook.html")

    element = find_element(:name, "message")
    fill_field(element, "Happy Birthday ~!")
    submit_element(element)

    assert page_title() == "Thank you"
  end

end

Here's another simple browser-automation example.

Setup

Hound requires Elixir 1.0.4 or higher.

  • Add dependency to your mix project
{:hound, "~> 1.0"}
  • Start Hound in your test/test_helper.exs file before the ExUnit.start() line:
Application.ensure_all_started(:hound)
ExUnit.start()

When you run mix test, Hound is automatically started. You'll need a webdriver server running, like Selenium Server or Chrome Driver. If you aren't sure what it is, then read this.

If you're using Phoenix

Ensure the server is started when your tests are run. In config/test.exs change the server option of your endpoint config to true:

config :hello_world_web, HelloWorldWeb.Endpoint,
  http: [port: 4001],
  server: true

Configure

To configure Hound, use your config/config.exs file or equivalent.

Example:

config :hound, driver: "phantomjs"

More examples here.

Usage

Add the following lines to your ExUnit test files.

# Import helpers
use Hound.Helpers

# Start hound session and destroy when tests are run
hound_session()

If you prefer to manually start and end sessions, use Hound.start_session and Hound.end_session in the setup and teardown blocks of your tests.

Helpers

The documentation pages include examples under each function.

The docs are at http://hexdocs.pm/hound.

FAQ

Can I run multiple browser sessions simultaneously

Oh yeah ~! Here is an example.

If you are running PhantomJs, take a look at the Caveats section below.

Can I run tests async?

Yes.

The number of tests you can run async at any point in time, depends on the number of sessions that your webdriver can maintain at a time. For Selenium Standalone, there seems to be a default limit of 15 sessions. You can set ExUnit's async option to limit the number of tests to run parallelly.

Will Hound guarantee an isolated session per test?

Yes. A separate session is started for each test process.

PhantomJs caveats

PhantomJs is extremely fast, but there are certain caveats. It uses Ghostdriver for its webdriver server, which currently has unimplemented features or open issues.

  • Cookie jar isn't separate for sessions - ariya/phantomjs#11417 Which means all sessions share the same cookies. Make sure you run delete_cookies() at the end of each test.
  • Isolated sessions were added to GhostDriver recently and are yet to land in a PhantomJs release.
  • Javascript alerts aren't yet supported - https://github.com/detro/ghostdriver/issues/20.

Running tests

You need a webdriver in order to run tests. We recommend phantomjs but any can be used by setting the WEBDRIVER environment variable as shown below:

$ phantomjs --wd
$ WEBDRIVER=phantomjs mix test

Maintainers

Customary proclamation...

Copyright © 2013-2015, Akash Manohar J, under the MIT License (basically, do whatever you want)

hound's People

Contributors

aaronrenner avatar allyraza avatar arathunku avatar backspace avatar danhper avatar darksheik avatar eduardodflpereira avatar efexen avatar gliwka avatar hashnuke avatar johngallagher avatar jontonsoup avatar littlekid avatar manukall avatar philipp-spiess avatar praveenperera avatar rossta avatar rrrene avatar samhamilton avatar scrogson avatar sevenseacat avatar thbar avatar theoandersen avatar tmock12 avatar ugisozols avatar vichoreyes avatar vitalis avatar wkhere avatar xvw avatar zamith avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hound's Issues

First release

TODO for the first release:

  • send_keys documentation
  • screenshot function and docs
  • blog post

select option

Does hound have a function for selecting an option from a dropdown?

Wait for javascript to finish executing on the page

I have a test that submits a form via ajax andthen does a page redirect. Is there a way to block until these actions are finished before the next hound command is run? Currently I have to throw a :timer.sleep(5000) into my code to make the tests pass.

I'm using page_source as a poor stand in for expect(page).to have_text("some_text"). If there is a more direct way of doing either of these things, I'd love to know. Thanks! :).

[error] GenServer Hound.SessionServer terminating ** (Poison.SyntaxError) Unexpected token: u

I'm trying to integration test of phoenix framework on CircleCI.
Tests has successed on my local environment(mac with chromedriver). but on CicleCi, an error has occurred.

Best regards.


ERLANG_VERSION="18.2.1"
ELIXIR_VERSION="v1.2.2"

circle.yml

...

  post:
    # selenium 
    - wget http://selenium-release.storage.googleapis.com/2.44/selenium-server-standalone-2.44.0.jar
    - java -jar selenium-server-standalone-2.44.0.jar:
        background: true
    # install chromedriver
    - wget https://chromedriver.storage.googleapis.com/2.20/chromedriver_linux64.zip
    - unzip chromedriver_linux64.zip
    # run chromedriver
    - ./chromedriver --url-base=wd/hub --port=9515  --verbose --log-path=$CIRCLE_ARTIFACTS/chromedriver.log:
        background: true

mix.exs

...
  defp deps do
    [
      {:phoenix, "~> 1.1.2"},
      {:phoenix_ecto, "~> 2.0"},
      {:postgrex, ">= 0.0.0", override: true},
      {:phoenix_html, "~> 2.3"},
      {:phoenix_live_reload, "~> 1.0", only: :dev},
      {:cowboy, "~> 1.0"},
      {:comeonin, "~> 2.0"},
      {:guardian, "~> 0.9.0"},
      {:credo, "~> 0.2", only: [:dev, :test]},
      {:ex_machina, "~> 0.6.1"},
      {:exactor, "~> 2.2.0"},
      {:hound, "~> 0.8"},
      {:mix_test_watch, "~> 0.2", only: :dev},
      {:exrm, "~> 0.19.9"}
     ]
  end
...

config.exs

...
config :hound, driver: "chrome_driver"
...

error message

[error] GenServer Hound.SessionServer terminating
** (Poison.SyntaxError) Unexpected token: u
    (poison) lib/poison/parser.ex:56: Poison.Parser.parse!/2
    (poison) lib/poison.ex:83: Poison.decode!/2
    (hound) lib/hound/response_parsers/chrome_driver.ex:7: Hound.ResponseParsers.ChromeDriver.parse/3
    (hound) lib/hound/request_utils.ex:53: Hound.RequestUtils.send_req/4
    (hound) lib/hound/session_server.ex:67: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
23:25:27.289 [error] GenServer Hound.SessionServer terminating
** (Poison.SyntaxError) Unexpected token: u
    (poison) lib/poison/parser.ex:56: Poison.Parser.parse!/2
    (poison) lib/poison.ex:83: Poison.decode!/2
    (hound) lib/hound/response_parsers/chrome_driver.ex:7: Hound.ResponseParsers.ChromeDriver.parse/3
    (hound) lib/hound/request_utils.ex:53: Hound.RequestUtils.send_req/4
    (hound) lib/hound/session_server.ex:67: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
23:25:27.290 [error] GenServer Hound.SessionServer terminating
** (Poison.SyntaxError) Unexpected token: u
    (poison) lib/poison/parser.ex:56: Poison.Parser.parse!/2
    (poison) lib/poison.ex:83: Poison.decode!/2
    (hound) lib/hound/response_parsers/chrome_driver.ex:7: Hound.ResponseParsers.ChromeDriver.parse/3
    (hound) lib/hound/request_utils.ex:53: Hound.RequestUtils.send_req/4
    (hound) lib/hound/session_server.ex:67: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
23:25:27.290 [error] GenServer Hound.SessionServer terminating
** (Poison.SyntaxError) Unexpected token: u
    (poison) lib/poison/parser.ex:56: Poison.Parser.parse!/2
    (poison) lib/poison.ex:83: Poison.decode!/2
    (hound) lib/hound/response_parsers/chrome_driver.ex:7: Hound.ResponseParsers.ChromeDriver.parse/3
    (hound) lib/hound/request_utils.ex:53: Hound.RequestUtils.send_req/4
    (hound) lib/hound/session_server.ex:67: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

Wrong description for hound_session macro

In the docs written

# Start hound session and destroy when tests are run
hound_session

But the macro only starts session.
I suggest adding on_exit fn-> Hound.end_session end to hound_session macro,
I can issue pull request if needed

Timeouts when running multiple sessions

Hey,

I'm trying to visit multiple (11 in the example) pages and getting a timeout.
Running with 10 or less works fine.
(Testing with phantomjs).

Not sure if caused by hound or a dependent application or I'm missing a configuration.

Test to reproduce here:
https://gist.github.com/orikremer/0a3a2bcd4b9ef72f231a

Output:

WEBDRIVER=phantomjs mix test test/concurrent_sessions_test.exs
"Stopping Hound and restarting with options for test suite..."

17:14:24.278 [info]  Application hound exited: :stopped

17:14:29.577 [error] Task #PID<0.174.0> started from #PID<0.169.0> terminating
** (HTTPoison.Error) :timeout
    (httpoison) lib/httpoison.ex:66: HTTPoison.request!/5
    (elixir) lib/task/supervised.ex:74: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:19: Task.Supervised.async/3
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: #Function<3.57271661/0 in ConcurrentSessionsTest.test should be able to run multiple sessions concurrently/1>
    Args: []


  1) test should be able to run multiple sessions concurrently (ConcurrentSessionsTest)
     test/concurrent_sessions_test.exs:16
     ** (EXIT from #PID<0.169.0>) an exception was raised:
         ** (HTTPoison.Error) :timeout
             (httpoison) lib/httpoison.ex:66: HTTPoison.request!/5
             (elixir) lib/task/supervised.ex:74: Task.Supervised.do_apply/2
             (elixir) lib/task/supervised.ex:19: Task.Supervised.async/3
             (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3



Finished in 5.2 seconds (0.1s on load, 5.1s on tests)
1 test, 1 failure

Hound timeout issue when using phantomjs and hound_session macro

After starting phantomjs, using hound_session will cause all tests using the navigate_to function to timeout. However if you do:

setup do
 Hound.start_session
   on_exit fn ->
     Hound.end_session
   end
end

The tests will only timeout the first time. After the tests pass the first time they will keep working even if you switch back to using hound_session. However if you restart the phantomjs system process the test will start timing out again.

Here is the phantomjs log, the output is the same whether it timesout or not:

[INFO  - 2015-10-28T06:11:30.620Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - page.settings - {"XSSAuditingEnabled":false,"javascriptCanCloseWindows":true,"javascriptCanOpenWindows":true,"javascriptEnabled":true,"loadImages":true,"localToRemoteUrlAccessEnabled":false,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.8 Safari/534.34","webSecurityEnabled":true}
[INFO  - 2015-10-28T06:11:30.620Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - page.customHeaders:  - {}
[INFO  - 2015-10-28T06:11:30.620Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - Session.negotiatedCapabilities - {"browserName":"phantomjs","version":"1.9.8","driverName":"ghostdriver","driverVersion":"1.1.0","platform":"mac-unknown-32bit","javascriptEnabled":true,"takesScreenshot":true,"handlesAlerts":false,"databaseEnabled":false,"locationContextEnabled":false,"applicationCacheEnabled":false,"browserConnectionEnabled":false,"cssSelectorsEnabled":true,"webStorageEnabled":false,"rotatable":false,"acceptSslCerts":false,"nativeEvents":true,"proxy":{"proxyType":"direct"}}
[INFO  - 2015-10-28T06:11:30.620Z] SessionManagerReqHand - _postNewSessionCommand - New Session Created: bb270560-7d3a-11e5-bcd6-f71c64edc7c4
[ERROR - 2015-10-28T06:11:31.031Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - page.onError - msg: TypeError: 'undefined' is not a function (evaluating 'document.querySelectorAll.bind(document)')
[ERROR - 2015-10-28T06:11:31.031Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - page.onError - stack:
  (anonymous function) (http://localhost:4001/js/vendor.js?vsn=2895CC1:2969)
  (anonymous function) (http://localhost:4001/js/vendor.js?vsn=2895CC1:3293)
[ERROR - 2015-10-28T06:11:31.032Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - page.onError - msg: Error: Cannot find module "deps/phoenix_html/web/static/js/phoenix_html" from "web/static/js/app"
[ERROR - 2015-10-28T06:11:31.032Z] Session [bb270560-7d3a-11e5-bcd6-f71c64edc7c4] - page.onError - stack:
  (anonymous function) (http://localhost:4001/js/vendor.js?vsn=2895CC1:80)
  (anonymous function) (http://localhost:4001/js/vendor.js?vsn=2895CC1:57)
  (anonymous function) (http://localhost:4001/js/app.js?vsn=654F57D:128)
  (anonymous function) (http://localhost:4001/js/vendor.js?vsn=2895CC1:64)
  (anonymous function) (http://localhost:4001/js/vendor.js?vsn=2895CC1:74)
  (anonymous function) (http://localhost:4001/js/app.js?vsn=654F57D:247)

Pass additional options to desiredCapabilities

It would be useful to be able to pass additional options to desiredCapabilities when creating a session. For example, I currently have a fork of Hound where I pass chromeOptions to the session:

diff --git a/lib/hound/json_driver.ex b/lib/hound/json_driver.ex
index f13c03b..ec61070 100644
--- a/lib/hound/json_driver.ex
+++ b/lib/hound/json_driver.ex
@@ -42,7 +42,11 @@ defmodule Hound.JsonDriver do
         cssSelectorsEnabled: true,
         browserName: browser_name,
         nativeEvents: false,
-        platform: "ANY"
+        platform: "ANY",
+        chromeOptions: [
+          excludeSwitches: ["--ignore-certificate-errors"],
+          args: ["--app=http://example.com"]
+        ]
       ]
     ]

Should be able to start Hound with :application.start

Waiting for Jose Valim's patch to land in Erlang R17. That should allow application config in :application.start. Should deprecate Hound.start when that is available.

Hound if you start it with Hound.start and not via :application.start(:hound). However, this is mostly Elixir's fault, as we don't have a way to configure applications (yet).

This issue is a fork from this - #7

Test absence of element?

Hey, thanks for creating this library. I’m new to Elixir and happy to be able to test-drive my application.

One thing I’m accustomed to is being able to assert both the presence and absence of an element. For instance, if a user logs in as an admin, they should be able to see links to admin-only pages. I’d like to test for their absence when a non-admin logs in, but I can’t find anything like that.

Am I missing something? Is there some way to accomplish this you can suggest?

Ability to make an API style POST while using Hound?

Situation

There are 2 services ("Service A" and "Service B") that coordinate together to setup a Web session for a User on Service B. I'm testing Service B.

Workflow

  • Service A POSTs a request to service B (using API credentials) to setup a session for the User.
  • Service B sets up temporary Redis tokens and provides Service A with a temporary one-time-use URL to send the User to on Service B
  • Service A opens a new browser window/tab for the User that brings them to one-time-use URL in Service B
  • Service B now handles the User's web requests for entering data, reviewing results, etc.
  • When the User has completed their task, Service B redirects the User back to Service A to resume their operations there

Problem

  • Testing the Web interface without a handy tool like Hound is unpleasant
  • When I start a hound_session, my attempts to make the API POST to setup the session are blocked
  • Hound does not provide a way to do a custom (non-HTML initiated) "POST" action

Is there a way to either make my own POST outside of Hound that won't be blocked? Do you know of a better solution?

Page not fully rendering before `page_source()` is available

I'm having an issue where content on a page I'm accessing isn't populated when I start to interact with its dom. (it's actually inconstant, sometimes it is ready, sometimes it's not).

Is this something I need to deal with at the phantomjs end, or is there something hound can do to help here? I've looked through the docs and nothing has jumped out at me. I guess I need a kind of 'when the page has finished loading' condition.

Edit: :timer.sleep(5000) does the job for me, but it feels a bit dirty. Maybe this is the best approach though?

Integration testing with phoenix framework?

Hi

are there any examples on how to run it with phoenix?

Do i need to have the phoenix app running in a separate window in order to run the integration tests?

thanks

chee

republish on Hex

Hi HashNuke!

I reproduced the problems w/ :ibrowse described in this issue

Now it's great you committed a change fixing this, but you must've messed with Hex - the 0.5.9 package published on Hex doesn't have this commit.. so again we need to use Hound via Github ref in our deps, which screws things a bit.

Please republish package on Hex and keep it in sync with your tags.

Also note that you can overwrite the same ver of the Hex package only during 1 hour after publishing, so now you'll need to make it 0.5.10 or sth.

Cheers :]

herenowcoder

Hound.SessionServer // (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :econnrefused}}

Hello,

As first mentioned in: #49 but now formally as its own issue.

Following this tutorial: https://lord.io/blog/2015/elixir-scraping/

And I'm getting this error:

:ok, []}
iex(2)> Scraper.start
Starting now...

23:11:03.991 [error] GenServer Hound.SessionServer terminating
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :econnrefused}}
    (hound) lib/hound/request_utils.ex:43: Hound.RequestUtils.send_req/4
    (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: {:find_or_create_session, #PID<0.168.0>}
State: #HashDict<[]>
** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.168.0>}, 60000)
    ** (EXIT) an exception was raised:
        ** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :econnrefused}}
            (hound) lib/hound/request_utils.ex:43: Hound.RequestUtils.send_req/4
            (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
            (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
            (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
            (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
     (stdlib) gen_server.erl:212: :gen_server.call/3
    (scraper) lib/scraper.ex:6: Scraper.start/0

With this mix.exs:

defmodule Scraper.Mixfile do
  use Mix.Project

  def project do
    [app: :scraper,
     version: "0.0.1",
     elixir: "~> 1.1",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    [applications: [:logger, :httpoison, :hound]]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    [
      {:httpoison, "~> 0.8.0"},
      {:floki,  "~> 0.7.1"},
      {:hound, "~> 0.7.6"}
    ]
  end
end

change_session_to fails with Selenium + Chrome/Firefox

Hi! Thanks for the great library.

Starting and stopping sessions this way works great, and I'm able to navigate to pages fine:

iex(1)> Hound.start_session
"a760dc48-b22f-44d5-b199-79a25e84cfaf"
iex(2)> Hound.end_session
:ok

I'm working with sessions for the first time, and when I try to use change_session_to, it launches the browser properly but then dies in an apparent attempt to store the session ID in a HashDict.

I'm using Selenium, and the error occurs with both Chrome and Firefox sessions with the same behavior.

iex(4)> change_session_to :something
[error] GenServer Hound.SessionServer terminating
** (FunctionClauseError) no function clause matching in HashDict.put/3
    (elixir) lib/hash_dict.ex:40: HashDict.put(nil, :something, "7e3ae1ce-b2d0-462b-8334-dc523b9cac28")
    (hound) lib/hound/session_server.ex:60: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: {:change_session, #PID<0.302.0>, :something}
State: #HashDict<[]>
** (exit) exited in: :gen_server.call(Hound.SessionServer, {:change_session, #PID<0.302.0>, :something}, 30000)
    ** (EXIT) an exception was raised:
        ** (FunctionClauseError) no function clause matching in HashDict.put/3
            (elixir) lib/hash_dict.ex:40: HashDict.put(nil, :something, "7e3ae1ce-b2d0-462b-8334-dc523b9cac28")
            (hound) lib/hound/session_server.ex:60: Hound.SessionServer.handle_call/3
            (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
            (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
            (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
    (stdlib) gen_server.erl:212: :gen_server.call/3

Thanks!

Drivers should be invoked from a facade API

Today, the Driver API is also the User API. This means drivers are required to be implement all user functions, even if the function implementation is going to be the same across all drivers. This leads to duplications.

For example, the session functions are not specific to the driver, and even though, it would be required to be implemented by all drivers.

I believe instead the proper solution is to have a User API (maybe under Hound.API or Hound.DSL) which defines all the user functions which are implemented on top of the Driver API. This will be bring the following benefits:

  1. It will avoid code duplication
  2. The Driver API will be smaller, making it easier to create drivers
  3. Since the Driver API is smaller, the Driver test suite can focus in smaller use cases
  4. The documentation will be easier to maintain, as users only need to worry about the User API, and drivers won't need to duplicate the docs

Thanks for the great project!

File Upload

Hi,
Any suggestions on testing file upload with hound?

Typo in Docs

Such a minor thing but I was reading the docs and saw:

fill_field(element, input)
Sets a field’s value. The difference with input_info_field is that, the field is cleared before entering the new value
input_into_field(element, input)
Enters value into field

The first one refers to input_info_field which is meant to say input_into_field

Obviously this isn't a huge issue but just making note of it :)

Session issue when working with PhantomJS

Hello! I'm using hound to write some integration tests for a Phoenix application with a React/Redux front-end. I' have configured it to use phantomjs and everything works great until I try to set a text into a form field. This is the text file:

defmodule MyApp.SignInTest do
  use MyApp.IntegrationCase

  test "GET /" do
    navigate_to "/"

    assert page_title == "Sign in"
    assert element_displayed?({:id, "sign_in_form"})
  end

  test "Sign in with wrong email/password" do
    navigate_to "/"

    user_email = find_element(:id, "user_email")

    fill_field(user_email, "[email protected]")
  end
end

The first test passes correctly but when it gets to the second one I get this error:

  1) test Sign in with wrong email/password (MyApp.SignInTest)
     test/features/sign_in_test.exs:17
     ** (RuntimeError) Element is not currently interactable and may not be manipulated
     stacktrace:
       (hound) lib/hound/response_parsers/phantom_js.ex:17: Hound.ResponseParsers.PhantomJs.parse/3
       (hound) lib/hound/request_utils.ex:53: Hound.RequestUtils.send_req/4
       (hound) lib/hound/helpers/element.ex:72: Hound.Helpers.Element.fill_field/2
       test/features/sign_in_test.exs:28

The React form is currently rendered so I don't really know if there's anything else I'm actually missing. Any idea? Thanks in advance.

Allow Element to return its html source

Hi!

I think if there's possibility to trivially add getting the html source of an element from the webdriver backend.

I'm sure webdriver protocol allows it, because I use it quite heavily in Ruby/Watir scripts.

I have an interesting set of scenarios where it is needed, maybe I drop few words on it:

I don't quite use phantomjs/hound (or other binding, like watir) for testing of long webapp flows. I rather write scripts which automate stuff. Lots of scripts. And they need to be fast.

So my typical scenario is to run a "webdriver client" like my app using Hound or a Watir script, visit some app, generate a needed state in it and then process the results, which means - read lots of DOM elements. Usually there's no need of further conversation with the webapp at that stage. But getting lots of elements via webdriver is slow. Phantomjs - and it is a fastest of the webdriver backends as they say - gives back a single element of a not-so-big page at ca 150-200 ms. If I have to iterate through tens or hundreds of them, the whole script goes painfully slow, and it's meant to be interactive.

So what I do in Ruby/Watir is to get the current source of some DOM subtree containing the results I need - webdriver gives it back with the proper current state even if it was updated via ajax - then I feed it to Hpricot or similar and I have everything parsed in fractions of the time before - like 0.1s instead of half of a minute. That is what I need. I'd like to do it in Elixir/hound as well. :)

current_path function for phoenix testing?

Hey I was doing some testing with Hound and realized that the current_url function doesn't work too well with phoenix route helpers. For example assert current_url == post_path(conn, :new)

So I created a quick function using regex to get just the path instead of the full url:

def current_path do
  Regex.run(~r/(http[s]?:\/\/)?([^\/\s]+)(\/.*)/, current_url)
  |> Enum.at(3)
end

I was wondering if there's any plans of implementing a similar function. And if you are okay with the above solution I can post a PR, I've tested it and it works:

https://gist.github.com/praveenperera/83ef46f469d64190e016#file-navigation-ex

Interaction with ExVCR

I'm building a web scraper using Hound, and it works fine, but when trying to test it using exvcr to mock the responses the responses are pretty much empty (at least no interesting data). I'm not sure if this is an exvcr or hound issue, or even if it is an issue with the way I have them set up, but hopefully you can help me.

I have opened the same issue on the exvcr repo, with the relevant code.

config [timeout: :infinity] does not seem to be working

My config:

config :hound, driver: "phantomjs"
config :hound, http: [timeout: :infinity]
config :hound, http: [recv_timeout: :infinity]

But I am still getting timeout errors when doing navigate_to:

** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :timeout}}
      (hound) lib/hound/request_utils.ex:43: Hound.RequestUtils.send_req/4

UTF-8 is scrambled in Hound

Hi!

I have one problem using Hound - when the page has some content in utf8, page_source() nor page_title() don't hold properly converted utf8 strings, but the binaries scrambled using some other encoding.
Same efect with both Phantomjs and Selenium underneath.
Tested w/ HEAD=4f4700c5.

Raised exception when `navigate_to` results in a timeout

I'm wondering if this was an intentional approach that I need to deal with another way, or something that could benefit from some improvement (still learning).

But currently in cases of a timeout (etc.) when attempting a navigate_to, an exception is raised:

** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :timeout}}
(hound) lib/hound/request_utils.ex:43: Hound.RequestUtils.send_req/4

In my case I'd much rather be getting a status tuple back, like with the built-in File module. i.e.

{:error, :timout}
:ok

(Although ultimately in such cases I just want the navigate_to to be run again… so perhaps I'm looking at the problem the wrong way anyway).

Any recommended approach to such a problem? Or is it worth looking at adding a tuple response to that function?

navigate_to url as a certain user?

@HashNuke I have seen in your own integration tests (https://github.com/HashNuke/mogo-chat/blob/108c611177363a04d278221aabc03dcd2b66597c/test/test_helper.exs#L91 for example) you sign in the user by using a method that fills out a form and signs in the user. I was wondering if there might be a way to add another function like the hound helper navigate_to but one that could take a user and store it in the hound session params? Something to the effect of navigate_to url as: user? Thanks very much!

Add helpers

Add the following helpers

  • element_html(element_id)
  • element_present?(strategy, selector)

Error when navigating to URL

Hi,

Sometimes when I run the navigate_to(url) command I get the following error:

** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :timeout}}
    (hound) lib/hound/request_utils.ex:40: Hound.RequestUtils.send_req/4
    (arbiter) lib/runner.ex:55: anonymous fn/3 in Runner.run/1
    (elixir) lib/enum.ex:1387: Enum."-reduce/3-lists^foldl/2-0-"/3
    (arbiter) lib/runner.ex:54: Runner.run/1
    (arbiter) lib/runner.ex:26: Runner.handle_cast/2
    (stdlib) gen_server.erl:615: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:681: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

tag v0.5.4 missing

Hi!

I'd like to catch your recent changes in Hound and went with following the current Readme. You say there one should use v0.5.4 tag - but haven't you missed pushing your tags to github?

Best,
Wojtek

Find element when there are multiple matching elements

I noticed that if you use find_element and there are multiple elements that match your query, it will still operate fine. This seems like it could introduce some bugs that would be hard to track down in testing. If you believe you're clicking on a link and find out that the test framework is clicking on another, it could be confusing.

Would you consider having the app raise or otherwise handle the situation where you use find_element but there are multiple elements matching? I'd be happy to start a PR for this if it's something you're interested in just didn't want to do the work if you disagree.

Could not start application ibrowse

When trying to run tests with Hound, I get the error:

=INFO REPORT==== 3-Aug-2014::09:17:59 ===
    application: jsex
    exited: stopped
    type: temporary

=INFO REPORT==== 3-Aug-2014::09:17:59 ===
    application: jsx
    exited: stopped
    type: temporary
** (Mix) Could not start application ibrowse: could not find application file: ibrowse.app

I can replicate this on a brand-new mix project:

$ mix new hound_test
$ cd hound_test

Edit mix.exs to contain:

defmodule HoundTest.Mixfile do
  use Mix.Project

  def project do
    [app: :hound_test,
     version: "0.0.1",
     elixir: "~> 0.14.3",
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type `mix help compile.app` for more information
  def application do
    [applications: app_list(Mix.env)]
  end

  defp app_list(:test), do: [:hound | app_list]
  defp app_list(_),     do: app_list
  defp app_list,        do: [:jsex, :ibrowse]

  # Dependencies can be hex.pm packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1"}
  #
  # Type `mix help deps` for more examples and options
  defp deps do
    [{:hound, "0.5.8"}]
  end
end

Run mix deps.get and mix test, and I get the error above.

If starting ibrowse is required for Hound, should it not have optional: true in hound's mix.exs maybe?

Hound chrome_driver timeout error

I'm trying to get a simple hound test working with my app, I figured out its an error with chrome_driver. I got it works perfectly fine with selenium + firefox and even with selenium + chrome.

However when using with chromedriver as the driver instead of selenium, it opens a new chrome window with data:, in the address bar and then timesout.

19:45:11.959 [error] GenServer Hound.SessionServer terminating
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :timeout}}
    (hound) lib/hound/request_utils.ex:43: Hound.RequestUtils.send_req/4
    (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3


  1) test the truth (MyApp.AuthenticationIntegrationTest)
     test/integrations/authentication_integration_test.exs:7
     ** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.563.0>}, 60000)
         ** (EXIT) an exception was raised:
             ** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :timeout}}
                 (hound) lib/hound/request_utils.ex:43: Hound.RequestUtils.send_req/4
                 (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
                 (stdlib) gen_server.erl:629: :gen_server.try_handle_call/4
                 (stdlib) gen_server.erl:661: :gen_server.handle_msg/5
                 (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
     stacktrace:
       (stdlib) gen_server.erl:212: :gen_server.call/3
       test/integrations/authentication_integration_test.exs:5: MyApp.AuthenticationIntegrationTest.__ex_unit_setup_0/1
       test/integrations/authentication_integration_test.exs:1: MyApp.AuthenticationIntegrationTest.__ex_unit__/2

Here is my test:

defmodule AuthenticationIntegrationTest do
  use ExUnit.Case
  use Hound.Helpers

  hound_session

  test "the truth" do
    navigate_to("http://localhost:4000")
    assert current_url == "http://localhost:4000"
  end

end

I'm using Hound 0.7.5, thanks

Additional information:

  • config file is as follows: config :hound, driver: "chrome_driver"
  • text.exs has been changed to start the server on test
  • chrome_driver was installed using Homebrew
  • on OSX 10.11.1 El Capitan

Have more helpful errors

Right now, all failures result in a RuntimeError, which is ok for most cases,
but not very handful when we want to handle the errors, as we must pattern
match on the error message string.

In my particular use case, I use find_element on an element that is only present during
the page loading, to be sure that the page has fully loaded.
Therefore, the element not being present is the wanted state,
and I want to handle this particular error.

There are two approaches I can think of that could work nicely:

  1. Raise NoSuchElementError or something similar for find_element and find_within_element
  2. Return {:ok, element} or {:error, the_error} and add a find_element! function which would behave as the current function does.

The second approach would be more flexible in my opinion,
but is not backward compatible.

What do you think?

If you like the idea, I will be glad to send a PR.

Response from phantomjs isn't processed properly

Testing from the refactor branch.

The problem is the initial response from :find_or_create_session. As it is, I get the following error:

  1) test Users can create new projects (CreateProject)
     test/features/create_project_test.exs:7
     ** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.346.0>}, 60000)
         ** (EXIT) an exception was raised:
             ** (Poison.SyntaxError) Unexpected end of input
                 (poison) lib/poison/parser.ex:54: Poison.Parser.parse!/2
                 (poison) lib/poison.ex:83: Poison.decode!/2
                 (hound) lib/hound/response_parsers/phantom_js.ex:5: Hound.ResponseParsers.PhantomJs.parse/3
                 (hound) lib/hound/request_utils.ex:50: Hound.RequestUtils.send_req/4
                 (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
                 (stdlib) gen_server.erl:607: :gen_server.try_handle_call/4
                 (stdlib) gen_server.erl:639: :gen_server.handle_msg/5
                 (stdlib) proc_lib.erl:237: :proc_lib.init_p_do_apply/3

With the test specified here: https://github.com/sevenseacat/ticketee-phoenix/blob/master/test/features/create_project_test.exs

After some debugging, it turns out that the params being passed to Hound.ResponseParsers.PhantomJs.parse/3 are "session", 303, "". Further up the call chain, the response from {:ok, resp} = HTTPoison.post(url, body, headers) is as follows:

pry(1)> resp
%HTTPoison.Response{body: "",
 headers: [{"Cache", "no-cache"},
  {"Content-Type", "application/json;charset=UTF-8"},
  {"Location",
   "http://localhost:8910/wd/hub/session/bff36540-0d12-11e5-af7d-d7e9deddf01f"}],
 status_code: 303}

It seems like the session ID is being returned as part of the location header, not as part of the content of the page to be parsed in the parse/3 method. This was tested with both PhantomJs 1.8.2 and 2.0.0.

How to wait for an element to be visible

I am trying to test a React app and need to wait for React to be done loading before trying to fill in a form on the page. Is there a way to make the tests wait until an element is visible on the page before the continuing?

Message under Elixir 0.13.1: The access protocol for lists expect the key to be an atom...

While running trunk with Elixir 0.13.1:

The access protocol for lists expect the key to be an atom, got: "status"
    (elixir) lib/access.ex:42: Access.List.access/2
    lib/hound/json_driver/utils.ex:27: Hound.JsonDriver.Utils.make_req/4
    test/integration_test.exs:13: IntegrationTest."test make webrtc connection"/1
    (ex_unit) lib/ex_unit/runner.ex:223: ExUnit.Runner.exec_test/2
    (ex_unit) lib/ex_unit/runner.ex:195: anonymous fn/2 in ExUnit.Runner.spawn_test/3
    (stdlib) timer.erl:165: :timer.tc/1
    (ex_unit) lib/ex_unit/runner.ex:191: anonymous fn/3 in ExUnit.Runner.spawn_test/3

Using hound for concurrent tests

Hi @HashNuke! I tried to ping you on IRC but it did not work out, let me know if you would like this discussion to be moved elsewhere.

Today hound already supports multiple sessions, which would allow us to run tests concurrently. With Ecto 2.0, we are introducing an ownership feature, that would also allow Ecto to run concurrently. The next step is to make both of them work together so we have concurrent integration tests.

Therefore, this issue is more of a question, than an actual feature. If changes need to be done in Hound, they will be minimal.

In order for Ecto tests to run concurrently, we need to tell each process which database connection they should use. For example, in your test:

:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyRepo, [])
parent = self()
Task.start_link fn ->
  :ok = Ecto.Adapters.SQL.Sandbox.allow(MyRepo, parent, self())
end

This means that, in order for this to work with integration tests, we would need to include the connection owner in the request, parse it at the beginning of the request and call allow. This means that Hound would need to support a way to send a header for every request or at least a way to uniquely identify sessions.

So that's the question: when we start a hound_session, would it be possible to configure hound to always add a header or an identifier in whatever request is made by that particular session? If we cannot identify particular sessions, can we at least identify requests?

Note this feature would also need to be supported through redirections. I.e. if the server redirects and the driver automatically redirects, we need to still be able to tag those.

I will be glad to send a PR but I need some guidance on what is and what isn't allowed on the driver side.

Tests fail on Elixir 0.15.1

Hi,

running tests on Elixir 0.15.1 on a Mac OS X system fails:

"Stopping Hound and restarting with options for test suite..."

=INFO REPORT==== 23-Aug-2014::17:33:09 ===
application: hound
exited: stopped
type: temporary

=ERROR REPORT==== 23-Aug-2014::17:33:09 ===
** Generic server 'Elixir.Hound.SessionServer' terminating
** Last message in was {find_or_create_session,<0.186.0>}
** When Server state == #{'struct' => 'Elixir.HashDict',
root => {[],[],[],[],[],[],[],[]},
size => 0}
** Reason for termination ==
** {{badmatch,{error,{conn_failed,{error,econnrefused}}}},
[{'Elixir.Hound.JsonDriver.Utils',send_req,4,
[{file,"lib/hound/json_driver/utils.ex"},
{line,39}]},
{'Elixir.Hound.SessionServer',handle_call,3,
[{file,"lib/hound/session_server.ex"},
{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,580}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}

=ERROR REPORT==== 23-Aug-2014::17:33:09 ===
** Generic server 'Elixir.Hound.SessionServer' terminating
** Last message in was {find_or_create_session,<0.192.0>}
** When Server state == #{'struct' => 'Elixir.HashDict',
root => {[],[],[],[],[],[],[],[]},
size => 0}
** Reason for termination ==
** {{badmatch,{error,{conn_failed,{error,econnrefused}}}},
[{'Elixir.Hound.JsonDriver.Utils',send_req,4,
[{file,"lib/hound/json_driver/utils.ex"},
{line,39}]},
{'Elixir.Hound.SessionServer',handle_call,3,
[{file,"lib/hound/session_server.ex"},
{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,580}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}

=ERROR REPORT==== 23-Aug-2014::17:33:09 ===
** Generic server 'Elixir.Hound.SessionServer' terminating
** Last message in was {find_or_create_session,<0.195.0>}
** When Server state == #{'struct' => 'Elixir.HashDict',
root => {[],[],[],[],[],[],[],[]},
size => 0}
** Reason for termination ==
** {{badmatch,{error,{conn_failed,{error,econnrefused}}}},
[{'Elixir.Hound.JsonDriver.Utils',send_req,4,
[{file,"lib/hound/json_driver/utils.ex"},
{line,39}]},
{'Elixir.Hound.SessionServer',handle_call,3,
[{file,"lib/hound/session_server.ex"},
{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,580}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}

  1. test should get visible text of an element (ElementTestWithIds)
    test/json_driver/element_with_ids_test.exs:7
    ** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.186.0>}, 60000)
    ** (EXIT) an exception was raised:
    ** (MatchError) no match of right hand side value: {:error, {:conn_failed, {:error, :econnrefused}}}
    (hound) lib/hound/json_driver/utils.ex:39: Hound.JsonDriver.Utils.send_req/4
    (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:580: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:239: :proc_lib.init_p_do_apply/3
    stacktrace:
    (stdlib) gen_server.erl:190: :gen_server.call/3
    test/json_driver/element_with_ids_test.exs:5: ElementTestWithIds.ex_unit_setup_0/1
    test/json_driver/element_with_ids_test.exs:1: ElementTestWithIds.__ex_unit
    /2

=ERROR REPORT==== 23-Aug-2014::17:33:09 ===
** Generic server 'Elixir.Hound.SessionServer' terminating
** Last message in was {find_or_create_session,<0.198.0>}
** When Server state == #{'struct' => 'Elixir.HashDict',
root => {[],[],[],[],[],[],[],[]},
size => 0}
** Reason for termination ==
** {{badmatch,{error,{conn_failed,{error,econnrefused}}}},
[{'Elixir.Hound.JsonDriver.Utils',send_req,4,
[{file,"lib/hound/json_driver/utils.ex"},
{line,39}]},
{'Elixir.Hound.SessionServer',handle_call,3,
[{file,"lib/hound/session_server.ex"},
{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,580}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}

  1. test should return false if item is not selected (ElementTestWithIds)
    test/json_driver/element_with_ids_test.exs:64
    ** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.192.0>}, 60000)
    ** (EXIT) an exception was raised:
    ** (MatchError) no match of right hand side value: {:error, {:conn_failed, {:error, :econnrefused}}}
    (hound) lib/hound/json_driver/utils.ex:39: Hound.JsonDriver.Utils.send_req/4
    (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:580: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:239: :proc_lib.init_p_do_apply/3
    stacktrace:
    (stdlib) gen_server.erl:190: :gen_server.call/3
    test/json_driver/element_with_ids_test.exs:5: ElementTestWithIds.ex_unit_setup_0/1
    test/json_driver/element_with_ids_test.exs:1: ElementTestWithIds.__ex_unit
    /2

  2. test should submit a form element (ElementTestWithIds)
    test/json_driver/element_with_ids_test.exs:138
    ** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.195.0>}, 60000)
    ** (EXIT) an exception was raised:
    ** (MatchError) no match of right hand side value: {:error, {:conn_failed, {:error, :econnrefused}}}
    (hound) lib/hound/json_driver/utils.ex:39: Hound.JsonDriver.Utils.send_req/4
    (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:580: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:239: :proc_lib.init_p_do_apply/3
    stacktrace:
    (stdlib) gen_server.erl:190: :gen_server.call/3
    test/json_driver/element_with_ids_test.exs:5: ElementTestWithIds.ex_unit_setup_0/1
    test/json_driver/element_with_ids_test.exs:1: ElementTestWithIds.__ex_unit
    /2

=ERROR REPORT==== 23-Aug-2014::17:33:09 ===
** Generic server 'Elixir.Hound.SessionServer' terminating
** Last message in was {find_or_create_session,<0.201.0>}
** When Server state == #{'struct' => 'Elixir.HashDict',
root => {[],[],[],[],[],[],[],[]},
size => 0}
** Reason for termination ==
** {{badmatch,{error,{conn_failed,{error,econnrefused}}}},
[{'Elixir.Hound.JsonDriver.Utils',send_req,4,
[{file,"lib/hound/json_driver/utils.ex"},
{line,39}]},
{'Elixir.Hound.SessionServer',handle_call,3,
[{file,"lib/hound/session_server.ex"},
{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,580}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}

  1. test should get css property of an element (ElementTestWithIds)
    test/json_driver/element_with_ids_test.exs:123
    ** (exit) exited in: :gen_server.call(Hound.SessionServer, {:find_or_create_session, #PID<0.198.0>}, 60000)
    ** (EXIT) an exception was raised:
    ** (MatchError) no match of right hand side value: {:error, {:conn_failed, {:error, :econnrefused}}}
    (hound) lib/hound/json_driver/utils.ex:39: Hound.JsonDriver.Utils.send_req/4
    (hound) lib/hound/session_server.ex:22: Hound.SessionServer.handle_call/3
    (stdlib) gen_server.erl:580: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:239: :proc_lib.init_p_do_apply/3
    stacktrace:
    (stdlib) gen_server.erl:190: :gen_server.call/3
    test/json_driver/element_with_ids_test.exs:5: ElementTestWithIds.ex_unit_setup_0/1
    test/json_driver/element_with_ids_test.exs:1: ElementTestWithIds.__ex_unit
    /2

=ERROR REPORT==== 23-Aug-2014::17:33:09 ===
** Generic server 'Elixir.Hound.SessionServer' terminating
** Last message in was {find_or_create_session,<0.204.0>}
** When Server state == #{'struct' => 'Elixir.HashDict',
root => {[],[],[],[],[],[],[],[]},
size => 0}
** Reason for termination ==
** {{badmatch,{error,{conn_failed,{error,econnrefused}}}},
[{'Elixir.Hound.JsonDriver.Utils',send_req,4,
[{file,"lib/hound/json_driver/utils.ex"},
{line,39}]},
{'Elixir.Hound.SessionServer',handle_call,3,
[{file,"lib/hound/session_server.ex"},
{line,22}]},
{gen_server,handle_msg,5,[{file,"gen_server.erl"},{line,580}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]}
** (EXIT from #PID<0.47.0>) shutdown

Passing elements to JS

Hi,

I was trying to pass an element to JS and got some issue.
I would expect

element = find_element(:id, "foo")
execute_script("console.log(arguments[0])", [element])

to pass the element to JS, as most selenium implementation do,
however, it passes the ID, which is not very useful.

After digging a little in other implementations, I found out that it must be sent as

{"ELEMENT": "ELEMENT_ID"}

for it to work, so

element = find_element(:id, "foo")
execute_script("console.log(arguments[0])", [%{"ELEMENT" => element}])

does the job correctly.

However, I think it would be neater if we could do this automatically.

One solution could be to stop working with ids as strings directly, but
maybe wrap them in a struct.
This would make handling this kind of case trivial, as we would only
need to define an implementation of Poison.Encoder to get things to work.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.