Code Monkey home page Code Monkey logo

wallaby's People

Contributors

aaronrenner avatar bobwaycott avatar britton-jb avatar drumusician avatar dvic avatar germsvel avatar graeme-defty avatar jaimeiniesta avatar jangromko avatar jonleighton avatar keathley avatar kianmeng avatar knewter avatar marcandre avatar marcdel avatar mhanberg avatar michallepicki avatar nathanl avatar optikfluffel avatar pragtob avatar praveenperera avatar s3cur3 avatar sevenseacat avatar steve0hh avatar stevegraham avatar stratigos avatar tmepple avatar tokafish avatar vanderhoop avatar xtian 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

wallaby's Issues

Capture JS errors and logs in the servers `handle_info` call

Blocking each webdriver call with a call to check for js errors and logs is an expensive and wasteful process. All of this same information is sent to the server process from phantom. We should be able to capture this information using the same logging capture behaviour and then print logs to the console or throw errors in our respective test. This should work correctly because each phantom is scoped to a single test at a time.

Support for multiple `Repo`s

It seems to be quite common to have multiple OTP-Apps dealing with their own Repos in in umbrella application.

According to a short talk to @keathley, this is currently not supported by wallaby.

An example of such an umbrella application is wojtekmach's acme_bank from ExConf '16. It has a Repo at least in the sub-apps bank and auth.

Ambiguous matches

We noticed some ambiguous match problems when using #find for an element - it will timeout instead of returning an error:

session |> find(".project")

# If there are two projects, this will hang

HTTPoison timeout

I'm having some tests fail intermittently because of a HTTPPoison timeout error. Would you be open to setting the HTTPoison timeout to :infinity as ExUnit.Case already has a configurable timeout with a default?

EDIT: Adding some more information.

  • This only happens when running my Wallaby tests on their own, e.g. mix test test/features
  • It's always the first or second test.

This makes me think it's actually the first test running before everything is fully initialised (phantom?), so setting HTTPoison mike not be the best way to fix in your opinion.

Simulate Drag and Drop From Filesystem

I've split this into its own issue as from what I've read its a harder issue to solve.

It'd also be very nice to be able to test drag and drop file uploaders by allowing us to easily specify that we've dropped a file onto a specific element.

Attach files via wallaby

There is a lot of ways to interact with the forms, but I haven't found a way to interact with website by attach some files to the file fields. I think this should be implemented

@keathley WDYT?

Should take_screenshot return a session?

I tried this while debugging

visit("/path")
|> take_screenshot
|> find(".my-css")

But it failed because take_screenshot did not return a session. I think it would be pretty cool if it returned a session so debugging with screenshots would be a bit simpler

Windows

Is there any chance this can be modified to run on Windows. The shall script requires a bash environment, as I understand it. Could that not be replaced with a similar batch file?

Wallaby cannot find a button

Hi there! First time using Wallaby on my first Phoenix app. I've written my first acceptance test but have run in to an issue I can't resolve on my own

It's very simple.. filling out a form to register a user.

The form

<%= form_for @changeset, organisation_path(@conn, :create), fn f -> %>
  <%= if @changeset.action do %>
    <p>Oh noes! Please check the errors below.</p>
  <% end %>

  <%= inputs_for f, :users, fn u -> %>
    <%= error_tag u, :first_name %>
    <%= text_input u, :first_name, placeholder: "First name" %>

    <%= error_tag u, :first_name %>
    <%= text_input u, :last_name, placeholder: "Last name" %>

    <%= error_tag u, :email %>
    <%= text_input u, :email, placeholder: "Email" %>
  <% end %>

  <%= error_tag f, :name %>
  <%= text_input f, :name, placeholder: "Organisation name" %>

  <div class="actions">
    <input type="submit" value="Submit" />
    <a href="#" class="forgot-password">Already signed up?</a>
  </div>
<% end %>

Acceptance test

defmodule Esteem.UserSignsUpTest do
  use Esteem.AcceptanceCase, async: true

  test "user signs up a new organisation", %{session: session} do
    welcome_message =
      session
      |> visit("/")
      |> find("form")
      |> fill_in("First name", with: "Luke")
      |> fill_in("Last name", with: "Rollans")
      |> fill_in("Email", with: "[email protected]")
      |> fill_in("Organisation name", with: "Org name")
      |> click("Submit")
      |> find("p")
      |> text

    assert welcome_message =~ "Whelp"
  end
end

Error

  1) test user signs up a new organisation (Esteem.UserSignsUpTest)
     test/acceptance/user_signs_up_test.exs:4
     ** (Wallaby.ElementNotFound) Could not find element
     stacktrace:
       (wallaby) lib/wallaby/node.ex:342: Wallaby.Node.retry/2
       (wallaby) lib/wallaby/node.ex:192: Wallaby.Node.click/2
       test/acceptance/user_signs_up_test.exs:15

Seems that Wallaby cannot find the "Submit" button (line 15). I've tried using an ID, scoping a find to the actions wrapper, and other methods of detection to no vail.

Am I doing something glaringly wrong? I've read through the docs a few times and looked at test source code.. from what I can tell, it should work.

PhantomJS crashing

I have a relatively simple sign up form (the body html):

<div id="root">
  <div data-reactroot="" class="view-container registrations new">
    <main>
      <header>
        <div class="logo"></div>
      </header>
      <form>
        <div class="field"><input type="text" name="first_name" value="" placeholder="First name" required=""></div>
        <div class="field"><input type="text" name="last_name" value="" placeholder="Last name" required=""></div>
        <div class="field"><input type="email" name="email" value="" placeholder="Email" required=""></div>
        <div class="field"><input type="text" name="password" value="" placeholder="Password" required=""></div>
        <div class="field"><input type="password" name="password_confirmation" value="" placeholder="Confirm password" required=""></div>
        <button type="submit">Sign up</button><a href="/signin">Sign in</a>
      </form>
    </main>
  </div>
</div>

When I attempt to run this test:

  test "redirect to sign in", %{session: session} do
    user = %{
      first_name: "Jane",
      last_name: "Smith",
      email: "[email protected]",
      password: "password",
      encrypted_password: Comeonin.Bcrypt.hashpwsalt("password"),
    }

    session
    |> visit("/signup")
    |> fill_in("first_name", with: user.first_name)
  end

I reproducibly get this output:

PhantomJS has crashed. Please read the bug reporting guide at
<http://phantomjs.org/bug-reporting.html> and file a bug report.


  1) test redirect to sign in (MyApp.UserRegistrationTest)
     test/acceptance/user_registration_test.exs:4
     ** (RuntimeError) There was an error calling: http://localhost:50589/session/216548c0-6af0-11e6-873a-d74ddc1e1078/element/:wdc:1472149027298/value -> closed
     stacktrace:
       (wallaby) lib/wallaby/driver.ex:302: Wallaby.Driver.make_request/3
       (wallaby) lib/wallaby/driver.ex:274: Wallaby.Driver.check_logs!/2
       (wallaby) lib/wallaby/node.ex:58: Wallaby.Node.fill_in/2
       (wallaby) lib/wallaby/dsl/actions.ex:63: Wallaby.DSL.Actions.fill_in/3
       test/acceptance/user_registration_test.exs:18: (test)



Finished in 2.2 seconds
1 test, 1 failure

Randomized with seed 380223

I have another, similar test for which this doesn't happen at all - is there something I'm missing?

Button presses via click("<button-name>") don't register

At least it didn't work for me, although my buttons had similar markup to the ones in test/support/pages/forms.html, then again there seems to be no test coverage for it either.

I wrote an xpath that is able to find the possible range of buttons with inspiration from Capybara.

An implementation similar to click_link (and as I use it) would be:

def press(session, button)
  button_xpath = ".//*[self::input | self::button][(./@type = 'submit' or ./@type = 'reset' or ./@type = 'button' or ./@type = 'image')][(((./@id = '#{button}' or ./@name = '#{button}' or ./@value = '#{button}' or ./@alt = '#{button}' or ./@title = '#{button}' or contains(normalize-space(string(.)), '#{button}'))))]"

  session
  |> Node.find({:xpath, button_xpath}
  |> Node.click
end

If desired, I can create a PR.

`click_link` does not work with `method: :delete` links

Hi,

I am trying to use Wallaby to test the user session flow, it's a Phoenix app. So for the sign out, the EEx looks like this:

<%= link "Sign Out", to: session_path(@conn, :delete), method: :delete %>

Unfortunately this doesn't appear to work. Use take_screenshot I can see that the link is not getting clicked.

If I change the implementation to either:

<%= form_tag session_path(@conn, :delete), method: :delete %>
  <%= submit "Sign Out", class: "btn btn-primary" %>
</form>

# use `click_on` in the test

Or:

<%= link "Sign Out", to: session_path(@conn, :delete) %>

# change route from :delete to :get

Then the test works.

Also, the Phoenix JS is included correctly, and JS is being executed in the test environment.

Is this a known issue, or have I somehow done this incorrectly?

Clearing localStorage on each test run

Is there a way to clear local storage for each test run? Or to specify different local storage directories?

I see that it's possible to modify phantomjs to use a different local storage path, but I'm trying to avoid tests that modify local storage from stepping on one another.

Unreliable, multiple acceptance tests when async is on

Hey there!

I've been experiencing this for a while, but given it isn't important I haven't opened an issue. I consistently get timeout issues (and sometimes other, seemingly unrelated error messages) when I run my acceptance tests asynchronously using the async option.

If I turn off the async option everything is green but my suite takes about an extra 3-4 seconds to run at its current size. Currently sitting at about 200 tests all up, so it's not huge, but will continue to grow pretty steadily so I'm hoping to fix this issue now rather than later.

Important: This only happens on CI.. which is an ec2 t2.small instance running in a Docker Compose container. Might a simply need to beef that up a bit?

Here's an example of two acceptance tests that reproduce the issue when run in isolation together.

Test that a user can log in

defmodule Sightseer.UserLogsInTest do
  use Sightseer.AcceptanceCase, async: true

  test "user logs in", %{session: session} do
    user = insert(:user, encrypted_password: Comeonin.Bcrypt.hashpwsalt("test"))

    session
    |> visit("/sessions/new")
    |> fill_in("Email address", with: user.email)
    |> fill_in("Password", with: "test")
    |> click_button("Submit")

    notice = session
    |> find(".alert-info")
    |> text

    assert notice == "Signed in successfully"
  end
end

Test that a user can register

defmodule Sightseer.UserSignsUpTest do
  use Sightseer.AcceptanceCase, async: true

  test "user signs up", %{session: session} do
    session
    |> visit("/signup")
    |> fill_in("First name", with: "Luke")
    |> fill_in("Email address", with: "[email protected]")
    |> fill_in("Password", with: "1234567madpasswordbro")
    |> click_button("Submit")

    notice = session
    |> find(".alert-info")
    |> text

    assert notice == "Successfully signed up!"
  end
end

Error thrown on CI in the environment described above, when async is on

Generated sightseer app

  1) test user logs in up (Sightseer.UserLogsInTest)
     test/acceptance/user_logs_in_test.exs:4
     ** (exit) exited in: :gen_server.call(Wallaby.ServerPool, {:checkout, #Reference<0.0.1.94027>, true}, 5000)
         ** (EXIT) time out
     stacktrace:
       (stdlib) gen_server.erl:212: :gen_server.call/3
       (poolboy) src/poolboy.erl:55: :poolboy.checkout/3
       (wallaby) lib/wallaby.ex:34: Wallaby.start_session/1
       (sightseer) test/support/acceptance_case.ex:21: Sightseer.AcceptanceCase.__ex_unit_setup_0/1
       (sightseer) test/support/acceptance_case.ex:1: Sightseer.AcceptanceCase.__ex_unit__/2
       test/acceptance/user_logs_in_test.exs:1: Sightseer.UserLogsInTest.__ex_unit__/2

...................................................................................................................................................................................

Finished in 5.9 seconds
180 tests, 1 failure

Any insight in to how I might be able improve reliability here would be very much appreciated :)

Issue getting up and running

Pretty sure I've followed everything in the README and got up to actually writing some tests; but running into issues. I'm seeing this error:

Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

test/acceptance/create_projects_test.exs:6: warning: variable session is unused

Forum.CreateProjectTest
  * alternate formatRequest to pry #PID<0.304.0> at test/acceptance/create_projects_test.exs:20

        visit session, "/"

        IEx.pry
        click_link session, "New Project"


Allow? [Yn] n
23:51:33.726 [error] Postgrex.Protocol (#PID<0.258.0>) disconnected: ** (DBConnection.Error) ownership timeout
23:51:34.456 [error] Postgrex.Protocol (#PID<0.257.0>) disconnected: ** (DBConnection.Error) ownership timeout

And then after 60 second the test times out and fails. The first visit is fine, but inspecting text(session) in the IEx.pry returns an empty string. Something is missing either in my configuration, or in the setup steps, and I'm not sure what it is :)

I've pushed my test app to GitHub here: https://github.com/sevenseacat/test_wallaby

Simulate Drag and Drop Between Elements

It would be nice to be able to test drag and drop interactions with wallaby easily by specifying a selector to drag and the selector it should be dropped upon.

Attempting to visit without setting the base_url should raise an error

At first, I missed the instructions for setting the base_url. So when I did visit("/my_path") it did not visit my app.

I think that if you use relative paths without a base_url an error should be raised

You called visit with #{relative_path}, but did not set a base_url

Set this somewhere in your app, maybe in test/test_helper.exs:

    Application.put_env(:wallaby, :base_url, "http://localhost:4001")

If using Phoenix, you could grab the url from your endpoint:

    Application.put_env(:wallaby, :base_url, YourApplication.Endpoint.url)

Return order from `find` is inconsistent

The #find method for a given selector which returns more than one result; it may not return these elements in the strictly-same order (expected to always be ordered by the DOM). This was our work-around:

projects =
  session
    |> sign_in
    |> find(".project", count: 2)

first_project = List.first(projects)

project_text =
  projects
    |> Enum.map(&text(&1))
    |> Enum.sort

assert project_text == ["Initech", "The Petty Marsh"]

Automatic screenshots don't appear to work

I've added the config

# config/test.exs
config :wallaby, screenshot_on_failure: true

to my app but when I do assert "foo" == "bar" no screenshot is taken. Screenshots in general do work though as adding take_screenshot(session) to the same test does result in a screenshot.

Let me know if there is additional debug information needed. I've just started with wallaby so it's not impossible that I'm doing something wrong.

REST API testing

Hello. I'm wondering if it makes sense to use Wallaby for REST API testing where browser testing is also needed. Doing QA (end-to-end acceptance) testing in a standing environment with a single tool has many advantages, particularly if that tool features parallelism. Thanks!

Allow "text" to receive more than one node

it would be nice to have some way to have a collection of wallaby nodes be able to return a blob (or array!) of text:

project_text = 
  session
  |> find(".project", count: 2)
  |> text

# project_text would be "project 1 project 2" or ["project 1", "project 2"]

Methods for not-finding nodes or content

In order to help write specs where nodes are removed from the DOM, we could use a method where it resolves when the pattern is not found. This would kinda be the opposite of find(pattern, count: x)

Wishful use case:

session
  |> click("remove-button")
  |> find(".new_object", count: 0)

#or
  |> wait_until_gone(".new_object")

Where a failing spec would be like:

Expected to find 'new-object' with count 0 but found 1 node

Playing nice with authentication

I can't seem to get Wallaby playing nicely with authentication. I'm using Guardian to handle sessions and authentication, which is obviously done through a conn.

Should I ...

  1. Use a helper to step Wallaby through navigating to my login form, logging in and return the altered session
  2. Or; is there a way that Wallaby can play nice with a separate conn? If I build a conn, put the session in the state I want it to be, will the Wallaby session reflect that state? (I think this is a big no)

I'm planning on blogging this once I've figured it all out.. Seems to be a bit of a hole in the Phoenix community atm :)

Update README

The README needs to be updated to include quick start information, info on the DSL, test examples, etc.

Support for getting page session source

Was wondering if you guys are ok with adding an addition API to get the page source.

This would aid developers that would like to stick with their preferred DSL like floki.

I already have the function working in my fork of this project but would need some guidance in writing the tests. (where to place them etc..)

Example of the proposed API:

iex(4)> session |> Wallaby.Driver.visit("http://www.example.com") |> Wallaby.Driver.source()

"<!DOCTYPE html><html><head>\n    <title>Example Domain</title>\n\n 
the page source of the session currently
</html>"

Visit should throw an error when loading fails

I forgot to add server: true to my endpoint so when I attempted to visit the page nothing was rendered. The visit did not fail though, it continued on as if it loaded.

I think that if loading fails it should raise. It would be extra cool if the error message said something like this:

could not load #{the_full_url}. If you are using Phoenix you may need to enable the server

# config/test.exs
config :your_app, YourApplication.Endpoint,
  server: true

Using the action fill_in takes longer than expected to complete

Seems that using

fill_in(session, "session[email]", with: "x")

Takes 300-400ms to complete.

Not sure why this is.

Here is a exprof dump (note that this is in the header, so I use the full namespace:

        profile do
            Wallaby.DSL.Actions.fill_in(session, "session[email]", with: "xxx")
        end
FUNCTION                                                      CALLS        %  TIME  [uS / CALLS]
--------                                                      -----  -------  ----  [----------]
hackney_response:stream_body/2                                    1     0.00     0  [      0.00]
hackney_response:stream_body_recv/2                               1     0.00     0  [      0.00]
'Elixir.Keyword':merge/2                                          1     0.00     0  [      0.00]
'Elixir.Keyword':'-merge/2-fun-0-'/2                              2     0.00     0  [      0.00]
'Elixir.Wallaby.Driver':clear/1                                   1     0.00     0  [      0.00]
'Elixir.Wallaby.Driver':displayed/1                               1     0.00     0  [      0.00]
'Elixir.Wallaby.Driver':request/2                                 2     0.00     0  [      0.00]
'Elixir.Wallaby.Driver':set_value/2                               1     0.00     0  [      0.00]
'Elixir.Wallaby.Driver':to_params/1                               1     0.00     0  [      0.00]
'Elixir.Wallaby.Driver':'-find_elements/1-fun-0-'/2               1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':assert_count/1                        1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':build_locator/1                       1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':default_conditions/0                  1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':fillable_field/3                      1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':find_element/3                        1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':find_field/3                          1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':retry/1                               1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':retry/2                               1     0.00     0  [      0.00]
'Elixir.Wallaby.Node.Query':'-find_element/3-fun-0-'/1            1     0.00     0  [      0.00]
'Elixir.Enum':'all?'/2                                            1     0.00     0  [      0.00]
'Elixir.Enum':'do_all?'/2                                         2     0.00     0  [      0.00]
'Elixir.Enum':map/2                                               1     0.00     0  [      0.00]
'Elixir.Enum':'-map/2-lists^map/1-0-'/2                           2     0.00     0  [      0.00]
'Elixir.Wallaby.Node':clear/1                                     1     0.00     0  [      0.00]
'Elixir.Wallaby.Node':'visible?'/1                                1     0.00     0  [      0.00]
'Elixir.Poison.Encoder.List':encode/2                             1     0.00     0  [      0.00]
'Elixir.Poison.Encoder.List':encode/3                             1     0.00     0  [      0.00]
'Elixir.Poison.Encoder.List':'-encode/3-lists^foldr/2-1-'/3       2     0.00     0  [      0.00]
'Elixir.Poison.Encoder.List':'-encode/3-fun-0-'/3                 1     0.00     0  [      0.00]
'Elixir.Map':get/2                                                1     0.00     0  [      0.00]
'Elixir.Map':get/3                                                1     0.00     0  [      0.00]
erlang:send/2                                                     1     0.00     0  [      0.00]
erlang:monotonic_time/1                                           1     0.00     0  [      0.00]
'Elixir.String.Casing':downcase/1                                 8     0.02     1  [      0.13]
'Elixir.Keyword':'-merge/2-lists^filter/1-0-'/2                   3     0.02     1  [      0.33]
hackney_manager:get_state/2                                       8     0.02     1  [      0.13]
hackney_http:ce_identity/1                                        8     0.02     1  [      0.13]
hackney_url:parse_url/2                                           8     0.02     1  [      0.13]
hackney_url:parse_addr/2                                          8     0.02     1  [      0.13]
'Elixir.Wallaby.Driver':'check_logs!'/2                           4     0.02     1  [      0.25]
'Elixir.Wallaby.Driver':find_elements/1                           1     0.02     1  [      1.00]
'Elixir.Wallaby.Driver':'-set_value/2-fun-0-'/2                   1     0.02     1  [      1.00]
'Elixir.Wallaby.Driver':'-find_elements/1-fun-1-'/3               1     0.02     1  [      1.00]
'Elixir.Wallaby.Driver':'-displayed/1-fun-0-'/1                   1     0.02     1  [      1.00]
'Elixir.Wallaby.Driver':'-clear/1-fun-0-'/1                       1     0.02     1  [      1.00]
metrics_dummy:increment_counter/1                                 8     0.02     1  [      0.13]
'Elixir.Wallaby.Node.Query':assert_text/1                         1     0.02     1  [      1.00]
'Elixir.Wallaby.Node.Query':assert_visibility/1                   1     0.02     1  [      1.00]
'Elixir.Wallaby.Node.Query':build_conditions/1                    1     0.02     1  [      1.00]
inet_parse:hex/1                                                  8     0.02     1  [      0.13]
'Elixir.Agent':get_and_update/2                                   4     0.02     1  [      0.25]
prim_inet:enc_opts/2                                              8     0.02     1  [      0.13]
'Elixir.Process':whereis/1                                        4     0.02     1  [      0.25]
'Elixir.HTTPoison':process_headers/1                              8     0.02     1  [      0.13]
'Elixir.HTTPoison':process_response_body/1                        8     0.02     1  [      0.13]
'Elixir.HTTPoison':process_status_code/1                          8     0.02     1  [      0.13]
'Elixir.Poison':'encode!'/2                                       6     0.02     1  [      0.17]
'Elixir.Enum':each/2                                              4     0.02     1  [      0.25]
'Elixir.Enum':'-each/2-lists^foreach/1-0-'/2                      4     0.02     1  [      0.25]
'Elixir.Wallaby.XPath':fillable_field/1                           1     0.02     1  [      1.00]
'Elixir.Wallaby.Node':fill_in/2                                   1     0.02     1  [      1.00]
hackney_connect:reconnect/4                                       8     0.02     1  [      0.13]
'Elixir.Poison.Parser':array_values/3                             5     0.02     1  [      0.20]
'Elixir.GenServer':call/3                                         4     0.02     1  [      0.25]
maps:get/2                                                        7     0.02     1  [      0.14]
hackney_request:perform_all/6                                     8     0.04     2  [      0.25]
hackney_headers:get_value/2                                       8     0.04     2  [      0.25]
hackney_headers:insert/3                                          8     0.04     2  [      0.25]
error_handler:undefined_function/3                                3     0.04     2  [      0.67]
hackney_http:content_decode/3                                     8     0.04     2  [      0.25]
'Elixir.Poison.Encoder.Map':encode/2                              6     0.04     2  [      0.33]
'Elixir.Poison.Encoder.Map':'-encode/3-fun-1-'/4                  7     0.04     2  [      0.29]
hackney_url:urldecode/1                                           8     0.04     2  [      0.25]
'Elixir.Poison.Decode':decode/2                                   8     0.04     2  [      0.25]
dict:fold/3                                                       8     0.04     2  [      0.25]
dict:fold_dict/3                                                  8     0.04     2  [      0.25]
'Elixir.Wallaby.Driver':cast_as_node/2                            1     0.04     2  [      2.00]
'Elixir.Wallaby.Driver':request/3                                 6     0.04     2  [      0.33]
metrics_dummy:update_histogram/2                                  8     0.04     2  [      0.25]
metrics_dummy:update_meter/2                                      8     0.04     2  [      0.25]
inet_parse:ipv4_addr/5                                            8     0.04     2  [      0.25]
inet_parse:ipv4_field/2                                           8     0.04     2  [      0.25]
inet_parse:ipv6strict_address/1                                   8     0.04     2  [      0.25]
inet_parse:ipv6_addr/1                                            8     0.04     2  [      0.25]
'Elixir.HTTPoison.Base':request/9                                 8     0.04     2  [      0.25]
'Elixir.Agent':get_and_update/3                                   4     0.04     2  [      0.50]
prim_inet:send/3                                                  8     0.04     2  [      0.25]
prim_inet:type_value_default/3                                    8     0.04     2  [      0.25]
prim_inet:enc_value/2                                             8     0.04     2  [      0.25]
prim_inet:enc_value_default/3                                     8     0.04     2  [      0.25]
prim_inet:enc_value_1/3                                           8     0.04     2  [      0.25]
prim_inet:enc_value_2/2                                           8     0.04     2  [      0.25]
prim_inet:decode_opt_val/1                                        8     0.04     2  [      0.25]
prim_inet:dec_opt_val/3                                           8     0.04     2  [      0.25]
'Elixir.Wallaby.DSL.Actions':fill_in/3                            1     0.04     2  [      2.00]
'Elixir.HTTPoison':process_request_body/1                         8     0.04     2  [      0.25]
'Elixir.Poison':'decode!'/1                                       8     0.04     2  [      0.25]
'Elixir.Poison':'encode!'/1                                       6     0.04     2  [      0.33]
hackney_connect:socket_from_pool/4                                8     0.04     2  [      0.25]
hackney_tcp_transport:send/2                                      8     0.04     2  [      0.25]
'Elixir.Poison.Parser':number_complete/2                          8     0.04     2  [      0.25]
'Elixir.Poison.Parser':number_frac/2                              8     0.04     2  [      0.25]
gen_server:do_cast/2                                              8     0.04     2  [      0.25]
'Elixir.Wallaby.Phantom.Logger':log/1                             4     0.04     2  [      0.50]
application_controller:get_key/2                                  8     0.04     2  [      0.25]
gen_tcp:send/2                                                    8     0.04     2  [      0.25]
gen_tcp:controlling_process/2                                     8     0.04     2  [      0.25]
maps:keys/1                                                       6     0.04     2  [      0.33]
maps:find/2                                                       6     0.04     2  [      0.33]
erlang:binary_to_integer/1                                        8     0.04     2  [      0.25]
lists:keymember/3                                                10     0.04     2  [      0.20]
erlang:'++'/2                                                     9     0.04     2  [      0.22]
erlang:make_ref/0                                                 8     0.04     2  [      0.25]
hackney_response:wait_headers/2                                   8     0.06     3  [      0.38]
hackney_response:end_stream_body/2                                8     0.06     3  [      0.38]
hackney_request:maybe_add_host/2                                  8     0.06     3  [      0.38]
hackney_headers:'-new/1-fun-0-'/2                                 8     0.06     3  [      0.38]
hackney_bstr:join/2                                              16     0.06     3  [      0.19]
error_handler:ensure_loaded/1                                     3     0.06     3  [      1.00]
hackney_http:transfer_decode/2                                    8     0.06     3  [      0.38]
hackney_http:'-parse_body/1-fun-3-'/1                             8     0.06     3  [      0.38]
'Elixir.Poison.Encoder.Map':encode/3                              6     0.06     3  [      0.50]
hackney_url:parse_netloc/2                                        8     0.06     3  [      0.38]
hackney_url:parse_path/1                                          8     0.06     3  [      0.38]
hackney_url:parse_fragment/1                                      8     0.06     3  [      0.38]
hackney_url:pathencode/1                                          8     0.06     3  [      0.38]
hackney:reply/2                                                   8     0.06     3  [      0.38]
hackney:'-body/1-fun-0-'/1                                        8     0.06     3  [      0.38]
code:call/1                                                      11     0.06     3  [      0.27]
dict:mk_seg/1                                                     8     0.06     3  [      0.38]
'Elixir.Wallaby.Driver':make_request/3                            8     0.06     3  [      0.38]
'Elixir.Wallaby.Driver':request/4                                 8     0.06     3  [      0.38]
inet_tcp:send/2                                                   8     0.06     3  [      0.38]
hackney_pool:find_pool/2                                          8     0.06     3  [      0.38]
'Elixir.Wallaby.Node.Query':build_query/3                         1     0.06     3  [      3.00]
unicode:characters_to_binary/1                                    8     0.06     3  [      0.38]
inet_parse:ipv4_addr/1                                            8     0.06     3  [      0.38]
inet_parse:ipv4_addr/2                                            8     0.06     3  [      0.38]
inet_parse:hex/3                                                  8     0.06     3  [      0.38]
'Elixir.HTTPoison.Base':default_process_url/1                     8     0.06     3  [      0.38]
prim_inet:setopts/2                                               8     0.06     3  [      0.38]
prim_inet:dec_opt/1                                               8     0.06     3  [      0.38]
prim_inet:type_value/2                                            8     0.06     3  [      0.38]
prim_inet:type_value_1/3                                          8     0.06     3  [      0.38]
prim_inet:type_value_2/2                                          8     0.06     3  [      0.38]
prim_inet:enc_value/3                                             8     0.06     3  [      0.38]
prim_inet:enum_name/2                                             8     0.06     3  [      0.38]
prim_inet:enc_opt_val/4                                           8     0.06     3  [      0.38]
idna_ucs:from_utf8/1                                              8     0.06     3  [      0.38]
idna_ucs:expand_utf8/1                                            8     0.06     3  [      0.38]
hackney_app:get_app_env/2                                         8     0.06     3  [      0.38]
'Elixir.HTTPoison':process_url/1                                  8     0.06     3  [      0.38]
'Elixir.Poison':'decode!'/2                                       8     0.06     3  [      0.38]
string:to_lower/1                                                 8     0.06     3  [      0.38]
inet:setopts/2                                                    8     0.06     3  [      0.38]
inet:tcp_controlling_process/2                                    8     0.06     3  [      0.38]
hackney_connect:connect/5                                         8     0.06     3  [      0.38]
'Elixir.Poison.Parser':number_exp/3                               8     0.06     3  [      0.38]
'Elixir.Poison.Parser':number_start/1                             8     0.06     3  [      0.38]
'Elixir.Poison.Parser':parse/2                                    8     0.06     3  [      0.38]
gen_server:cast/2                                                 8     0.06     3  [      0.38]
gen_server:do_send/2                                              8     0.06     3  [      0.38]
idna:utf8_to_ascii/1                                              8     0.06     3  [      0.38]
gen:'-call/4-fun-0-'/4                                           28     0.08     4  [      0.14]
application:get_key/2                                             8     0.08     4  [      0.50]
hackney_util:mod_metrics/0                                        8     0.08     4  [      0.50]
hackney_response:body/1                                           8     0.08     4  [      0.50]
hackney_request:can_perform_all/3                                 8     0.08     4  [      0.50]
hackney_request:maybe_add_cookies/2                               8     0.08     4  [      0.50]
hackney_request:default_ua/0                                      8     0.08     4  [      0.50]
hackney_headers:to_list/1                                         8     0.08     4  [      0.50]
hackney_manager:init_request/1                                    8     0.08     4  [      0.50]
hackney_manager:close_request/1                                   8     0.08     4  [      0.50]
hackney_manager:update_state/2                                   16     0.08     4  [      0.25]
hackney_http:parser/1                                             8     0.08     4  [      0.50]
hackney_http:parse_response_line/1                                8     0.08     4  [      0.50]
hackney_http:parse_reason/4                                       8     0.08     4  [      0.50]
hackney_http:'-parse_body/1-fun-2-'/2                             8     0.08     4  [      0.50]
'Elixir.Poison.Encoder.Map':encode_name/1                         7     0.08     4  [      0.57]
'Elixir.Poison.Encoder.Map':'-encode/3-lists^foldl/2-0-'/3       13     0.08     4  [      0.31]
hackney:host_header/2                                             8     0.08     4  [      0.50]
hackney:maybe_update_req/1                                        8     0.08     4  [      0.50]
dict:new/0                                                        8     0.08     4  [      0.50]
dict:fold_segs/4                                                 16     0.08     4  [      0.25]
dict:maybe_expand/2                                              38     0.08     4  [      0.11]
inet_tcp:recv/3                                                  16     0.08     4  [      0.25]
'Elixir.Fops.AcceptanceCase':'-__ex_unit_setup_0/1-fun-0-'/2      1     0.08     4  [      4.00]
'Elixir.HTTPoison.Base':build_hackney_options/2                   8     0.08     4  [      0.50]
'Elixir.HTTPoison.Base':response/6                                8     0.08     4  [      0.50]
prim_inet:recv/3                                                 16     0.08     4  [      0.25]
prim_inet:recv0/3                                                16     0.08     4  [      0.25]
prim_inet:getopt/2                                                8     0.08     4  [      0.50]
prim_inet:getopts/2                                               8     0.08     4  [      0.50]
prim_inet:type_opt_1/1                                           24     0.08     4  [      0.17]
prim_inet:type_value/3                                            8     0.08     4  [      0.50]
prim_inet:encode_opt_val/1                                        8     0.08     4  [      0.50]
prim_inet:encode_opts/1                                           8     0.08     4  [      0.50]
metrics:increment_counter/2                                       8     0.08     4  [      0.50]
'Elixir.HTTPoison':'-request/5-fun-1-'/1                          8     0.08     4  [      0.50]
'Elixir.HTTPoison':'-request/5-fun-0-'/1                          8     0.08     4  [      0.50]
string:tokens_single_1/3                                         24     0.08     4  [      0.17]
inet:tcp_sync_input/3                                             8     0.08     4  [      0.50]
hackney_connect:create_connection/5                               8     0.08     4  [      0.50]
hackney_tcp_transport:messages/1                                  8     0.08     4  [      0.50]
hackney_tcp_transport:recv/3                                     16     0.08     4  [      0.25]
'Elixir.Poison.Parser':'parse!'/2                                 8     0.08     4  [      0.50]
'Elixir.Poison.Encoder':encode/2                                 14     0.08     4  [      0.29]
'Elixir.Poison.Encoder':impl_for/1                               14     0.08     4  [      0.29]
gen_server:cast_msg/1                                             8     0.08     4  [      0.50]
'Elixir.GenServer':whereis/1                                      4     0.08     4  [      1.00]
idna:to_ascii/2                                                  32     0.08     4  [      0.13]
'Elixir.Poison.Encoder.BitString':encode/2                       14     0.11     5  [      0.36]
hackney_response:start_response/1                                 8     0.11     5  [      0.63]
hackney_request:send/2                                            8     0.11     5  [      0.63]
hackney_request:expectation/1                                     8     0.11     5  [      0.63]
hackney_request:end_stream_body/1                                 8     0.11     5  [      0.63]
'Elixir.Keyword':'has_key?'/2                                    10     0.11     5  [      0.50]
hackney_headers:new/1                                             8     0.11     5  [      0.63]
hackney_headers:to_binary/1                                      16     0.11     5  [      0.31]
hackney_manager:update_state/1                                   16     0.11     5  [      0.31]
hackney_url:parse_url/1                                           8     0.11     5  [      0.63]
hackney:send_request/2                                           16     0.11     5  [      0.31]
hackney:make_request/6                                            8     0.11     5  [      0.63]
hackney:maybe_proxy/4                                             8     0.11     5  [      0.63]
hackney:maybe_redirect/2                                          8     0.11     5  [      0.63]
dict:store/3                                                     38     0.11     5  [      0.13]
'Elixir.String':slice/3                                           8     0.11     5  [      0.63]
'Elixir.Wallaby.LogStore':append_logs/2                           4     0.11     5  [      1.25]
inet_parse:address/1                                              8     0.11     5  [      0.63]
inet_parse:ipv4_address/1                                         8     0.11     5  [      0.63]
prim_inet:enc_opt_val/2                                          16     0.11     5  [      0.31]
prim_inet:enc_opts/1                                             16     0.11     5  [      0.31]
prim_inet:dec_opt_val/1                                          16     0.11     5  [      0.31]
metrics:update_meter/3                                            8     0.11     5  [      0.63]
'Elixir.HTTPoison':process_request_headers/1                      8     0.11     5  [      0.63]
erlang:port_command/3                                             8     0.11     5  [      0.63]
erlang:port_connect/2                                             8     0.11     5  [      0.63]
hackney_connect:maybe_connect/1                                   8     0.11     5  [      0.63]
hackney_connect:check_mod_metrics/1                              16     0.11     5  [      0.31]
hackney_tcp_transport:setopts/2                                   8     0.11     5  [      0.63]
idna:label_to_ascii/1                                            16     0.11     5  [      0.31]
gen_tcp:recv/3                                                   16     0.11     5  [      0.31]
erlang:error/1                                                    8     0.11     5  [      0.63]
erlang:function_exported/3                                       11     0.11     5  [      0.45]
gen:do_for_proc/2                                                28     0.13     6  [      0.21]
hackney_response:wait_status/1                                   16     0.13     6  [      0.38]
hackney_response:stream_body1/2                                  17     0.13     6  [      0.35]
hackney_request:perform/2                                         8     0.13     6  [      0.75]
hackney_request:handle_body/4                                     7     0.13     6  [      0.86]
hackney_request:req_type/2                                        8     0.13     6  [      0.75]
hackney_headers:update/2                                         15     0.13     6  [      0.40]
hackney_headers:make_header/2                                    31     0.13     6  [      0.19]
hackney_headers:'-to_list/1-fun-0-'/3                            31     0.13     6  [      0.19]
'Elixir.Access':get/3                                            41     0.13     6  [      0.15]
hackney_bstr:'-to_upper/1-lbc$^0/2-0-'/2                         39     0.13     6  [      0.15]
hackney_manager:new_request/1                                     8     0.13     6  [      0.75]
hackney_http:parse_response_version/2                             8     0.13     6  [      0.75]
hackney_http:parse_headers/1                                     39     0.13     6  [      0.15]
hackney_http:parse_header/2                                      24     0.13     6  [      0.25]
hackney_http:parse_options/2                                     16     0.13     6  [      0.38]
hackney_url:do_partial_pathencode/2                              46     0.13     6  [      0.13]
hackney:body/1                                                    8     0.13     6  [      0.75]
code:ensure_loaded/1                                             11     0.13     6  [      0.55]
dict:get_bucket_s/2                                              39     0.13     6  [      0.15]
dict:maybe_expand_aux/2                                          38     0.13     6  [      0.16]
hackney_pool:checkout/4                                           8     0.13     6  [      0.75]
hackney_pool:checkin/2                                            8     0.13     6  [      0.75]
unicode:characters_to_list/1                                     16     0.13     6  [      0.38]
prim_inet:enc_opt/1                                              16     0.13     6  [      0.38]
metrics:init/1                                                    8     0.13     6  [      0.75]
idna_unicode:downcase/1                                          16     0.13     6  [      0.38]
'Elixir.Poison.Parser':object_name/2                             25     0.13     6  [      0.24]
'Elixir.Poison.Parser':object_pairs/3                            25     0.13     6  [      0.24]
idna:to_ascii/1                                                  16     0.13     6  [      0.38]
maps:from_list/1                                                  9     0.13     6  [      0.67]
erlang:make_fun/3                                                17     0.13     6  [      0.35]
os:timestamp/0                                                    8     0.13     6  [      0.75]
erlang:integer_to_list/1                                         23     0.13     6  [      0.26]
erlang:erase/1                                                    8     0.13     6  [      0.75]
gen:do_call/4                                                    28     0.15     7  [      0.25]
hackney_response:maybe_close/1                                    8     0.15     7  [      0.88]
hackney_request:stream_body/2                                     8     0.15     7  [      0.88]
hackney_headers:'-to_binary/1-fun-0-'/2                          31     0.15     7  [      0.23]
hackney_headers:'-update/2-fun-0-'/2                             30     0.15     7  [      0.23]
hackney_bstr:to_upper/1                                           8     0.15     7  [      0.88]
hackney:reply_response/2                                          8     0.15     7  [      0.88]
'Elixir.Wallaby.Driver':log/1                                     4     0.15     7  [      1.75]
prim_inet:dec_value/2                                             8     0.15     7  [      0.88]
metrics:update_histogram/3                                        8     0.15     7  [      0.88]
erlang:port_info/2                                                8     0.15     7  [      0.88]
re:replace/4                                                     40     0.15     7  [      0.17]
inet:'-setopts/2-lc$^0/1-0-'/1                                   16     0.15     7  [      0.44]
hackney_connect:is_pool/1                                        16     0.15     7  [      0.44]
hackney_tcp_transport:controlling_process/2                       8     0.15     7  [      0.88]
erlang:atom_to_binary/2                                          15     0.15     7  [      0.47]
lists:member/2                                                   40     0.15     7  [      0.17]
erlang:port_get_data/1                                           32     0.15     7  [      0.22]
hackney_response:read_body/3                                     16     0.17     8  [      0.50]
hackney_headers:get_value/3                                      31     0.17     8  [      0.26]
hackney_bstr:char_to_upper/1                                     31     0.17     8  [      0.26]
hackney_manager:get_state/1                                      16     0.17     8  [      0.50]
hackney_http:te_identity/2                                        8     0.17     8  [      1.00]
hackney_url:normalize/2                                           8     0.17     8  [      1.00]
dict:find_val/2                                                  47     0.17     8  [      0.17]
dict:store_bkt_val/3                                             45     0.17     8  [      0.18]
hackney_pool:sync_socket/2                                        8     0.17     8  [      1.00]
prim_inet:enum_val/2                                             16     0.17     8  [      0.50]
'Elixir.HTTPoison':request/5                                      8     0.17     8  [      1.00]
re:check_for_crlf/2                                              40     0.17     8  [      0.20]
re:do_grun/6                                                     40     0.17     8  [      0.20]
'Elixir.String.Unicode':next_extend_size/2                       64     0.17     8  [      0.13]
'Elixir.String.Unicode':split_at/2                               16     0.17     8  [      0.50]
application_controller:get_env/2                                 32     0.17     8  [      0.25]
unicode:characters_to_list/2                                     16     0.17     8  [      0.50]
erlang:list_to_binary/1                                          15     0.17     8  [      0.53]
hackney_http:parse_status/4                                      32     0.19     9  [      0.28]
dict:get_bucket/2                                                39     0.19     9  [      0.23]
prim_inet:type_opt/2                                             24     0.19     9  [      0.38]
idna_ucs:expand_utf8_1/3                                         80     0.19     9  [      0.11]
'Elixir.HTTPoison':'-request/5-fun-2-'/1                          8     0.19     9  [      1.13]
string:tokens/2                                                  24     0.19     9  [      0.38]
re:postprocess/5                                                 40     0.19     9  [      0.23]
hackney_connect:use_default_pool/0                               16     0.19     9  [      0.56]
timer:now_diff/2                                                  8     0.19     9  [      1.13]
'Elixir.Poison.Encoder':'impl_for!'/1                            14     0.19     9  [      0.64]
unicode:characters_to_binary/2                                    8     0.19     9  [      1.13]
erlang:unlink/1                                                   8     0.19     9  [      1.13]
application:get_env/2                                            32     0.21    10  [      0.31]
hackney_response:wait_headers/4                                  39     0.21    10  [      0.26]
hackney:request/5                                                16     0.21    10  [      0.63]
'Elixir.String':downcase/1                                        8     0.21    10  [      1.25]
inet_parse:ipv4_field/4                                          80     0.21    10  [      0.13]
re:grun2/3                                                       40     0.21    10  [      0.25]
'Elixir.String.Unicode':do_split_at/4                            80     0.21    10  [      0.13]
gen_server:call/3                                                24     0.21    10  [      0.42]
erlang:whereis/1                                                 15     0.21    10  [      0.67]
erlang:put/2                                                     24     0.21    10  [      0.42]
erlang:list_to_integer/1                                         32     0.21    10  [      0.31]
gen:call/4                                                       28     0.23    11  [      0.39]
'Elixir.Keyword':get/3                                           82     0.23    11  [      0.13]
hackney_bstr:join/3                                              85     0.23    11  [      0.13]
hackney_http:parse_body/1                                        25     0.23    11  [      0.44]
dict:on_bucket/3                                                 38     0.23    11  [      0.29]
prim_inet:enc_time/1                                             16     0.23    11  [      0.69]
erlang:binary_to_list/1                                          32     0.23    11  [      0.34]
'Elixir.Access':get/2                                            41     0.25    12  [      0.29]
hackney_http:execute/1                                           48     0.25    12  [      0.25]
dict:find/2                                                      39     0.25    12  [      0.31]
erlang:port_control/3                                            32     0.25    12  [      0.38]
erts_internal:port_connect/2                                      8     0.25    12  [      1.50]
erts_internal:port_info/2                                         8     0.25    12  [      1.50]
erlang:phash/2                                                   77     0.25    12  [      0.16]
'Elixir.Poison.Encoder.BitString':escape/2                       28     0.28    13  [      0.46]
hackney_response:stream_body/1                                   16     0.28    13  [      0.81]
re:grun/3                                                        40     0.28    13  [      0.33]
'Elixir.Access':fetch/2                                          41     0.30    14  [      0.34]
dict:'-store/3-fun-0-'/3                                         38     0.30    14  [      0.37]
prim_inet:ctl_cmd/3                                              32     0.30    14  [      0.44]
idna_ucs:is_ascii/1                                             144     0.30    14  [      0.10]
string:to_lower_char/1                                           72     0.30    14  [      0.19]
idna_unicode:lookup/2                                           144     0.30    14  [      0.10]
idna_unicode:'-lowercase/1-fun-0-'/2                            144     0.30    14  [      0.10]
'Elixir.Poison.Parser':value/2                                   34     0.30    14  [      0.41]
lists:foldl/3                                                   100     0.32    15  [      0.15]
hackney_bstr:trim/1                                              40     0.32    15  [      0.38]
hackney_http:parse_header/1                                      39     0.32    15  [      0.38]
string:r_pad/3                                                  144     0.32    15  [      0.10]
string:'-to_lower/1-lc$^0/1-0-'/1                                80     0.32    15  [      0.19]
'Elixir.Poison.Parser':string_continue/2                         68     0.32    15  [      0.22]
'Elixir.String.Casing':downcase/2                                72     0.34    16  [      0.22]
code_server:call/1                                               11     0.34    16  [      1.45]
hackney_http:parse_header_value/1                                48     0.34    16  [      0.33]
dict:fold_seg/4                                                 136     0.34    16  [      0.12]
erlang:list_to_integer/2                                          8     0.34    16  [      2.00]
lists:keyfind/3                                                 118     0.34    16  [      0.14]
proplists:get_value/2                                            48     0.36    17  [      0.35]
lists:reverse/2                                                 120     0.36    17  [      0.14]
'Elixir.Keyword':get/2                                           74     0.38    18  [      0.24]
dict:get_slot/2                                                  77     0.38    18  [      0.23]
string:tokens_single_2/4                                        184     0.38    18  [      0.10]
string:right/3                                                  144     0.38    18  [      0.13]
inet_db:lookup_socket/1                                          32     0.40    19  [      0.59]
re:process_parameters/6                                          80     0.40    19  [      0.24]
hackney_response:recv/1                                          16     0.42    20  [      1.25]
lists:all/2                                                     160     0.42    20  [      0.13]
hackney_url:urldecode/3                                          80     0.45    21  [      0.26]
re:do_replace/5                                                  40     0.45    21  [      0.53]
erlang:demonitor/2                                               28     0.45    21  [      0.75]
re:check_for_unicode/2                                           80     0.47    22  [      0.28]
ets:delete/2                                                      8     0.49    23  [      2.88]
erlang:monitor/2                                                 28     0.49    23  [      0.82]
hackney_trace:report_event/4                                     48     0.51    24  [      0.50]
'Elixir.String.Unicode':next_grapheme_size/1                     64     0.51    24  [      0.38]
idna_unicode_data1:l/1                                          144     0.51    24  [      0.17]
hackney_http:parse_first_line/3                                  16     0.53    25  [      1.56]
hackney_http:match_eol/2                                        144     0.55    26  [      0.18]
prim_inet:async_recv/3                                           16     0.55    26  [      1.63]
idna:'-label_to_ascii/1-fun-0-'/1                               144     0.57    27  [      0.19]
dict:fold_bucket/3                                              159     0.62    29  [      0.18]
idna_unicode:codepoint_downcase/1                               144     0.62    29  [      0.20]
idna_unicode:hex/1                                              144     0.62    29  [      0.20]
idna_unicode:'-downcase/1-lc$^0/1-0-'/1                         160     0.62    29  [      0.18]
re:loopexec/7                                                    40     0.62    29  [      0.72]
re:process_repl_params/2                                        120     0.66    31  [      0.26]
re:to_binary/2                                                  120     0.66    31  [      0.26]
erlang:integer_to_list/2                                        144     0.68    32  [      0.22]
binary:split/3                                                   32     0.68    32  [      1.00]
idna_unicode:lookup/1                                           144     0.70    33  [      0.23]
lists:reverse/1                                                 121     0.74    35  [      0.29]
hackney_bstr:to_binary/1                                        123     0.81    38  [      0.31]
idna_unicode:lowercase/1                                        144     0.85    40  [      0.28]
ets:lookup/2                                                     48     0.89    42  [      0.88]
string:chars/3                                                  432     0.93    44  [      0.10]
erlang:integer_to_list/3                                        288     0.98    46  [      0.16]
'Elixir.Poison.Parser':skip_whitespace/1                        122     1.17    55  [      0.45]
hackney_http:execute/2                                           72     1.34    63  [      0.88]
'Elixir.Poison.Parser':string_chunk_size/2                      507     1.34    63  [      0.12]
erlang:iolist_to_binary/1                                       192     1.34    63  [      0.33]
erlang:send/3                                                    36     1.40    66  [      1.83]
hackney_bstr:to_lower/1                                         141     1.47    69  [      0.49]
proplists:get_value/3                                           408     1.53    72  [      0.18]
erts_internal:port_control/3                                     32     1.68    79  [      2.47]
hackney_url:partial_pathencode/2                                496     2.04    96  [      0.19]
'Elixir.Poison.Encoder.BitString':chunk_size/3                  692     2.06    97  [      0.14]
binary:split/2                                                   87     2.31   109  [      1.25]
erts_internal:port_command/3                                      8     3.06   144  [     18.00]
hackney_bstr:'-to_lower/1-lbc$^0/2-0-'/2                       1567     3.44   162  [      0.10]
re:run/3                                                         80     3.67   173  [      2.16]
erlang:setelement/3                                             489     5.35   252  [      0.52]
hackney_bstr:char_to_lower/1                                   1426     5.84   275  [      0.19]
------------------------------------------------------------  -----  -------  ----  [----------]
Total:                                                        16645  100.00%  4709  [      0.28]

Waiting for async code without narrowing find scope

The advice for async code is to find something on the page that will be visible once the async action has completed (find will block for up to 3 secs by default). This works great but there's a problem in that find is chainable and narrows the scope of any finds further on in the chain.

    session
    |> visit("http://localhost:28080/?authAdapter=test&apiBasePath=%2F%2Flocalhost%3A4001%2F")
    |> fill_in("Add new feed", with: "Lobby")
    |> send_keys([:enter])
    |> find(".side-nav__list-item a", text: "Lobby") # wait for async action to complete
    |> fill_in("What's got you thinking?", with: "hello")

The last line fails because in this scenario the textarea that it's attempting to fill in is not inside the scope specified by the previous find, ".side-nav__list-item a", text: "Lobby".

There's a few options here:

1) Introduce a command that waits for something to appear

|> waitFor(".side-nav__list-item a", text: "Lobby") # wait for async action to complete

2) Allow the find scope to be reset

    session
    |> visit("http://localhost:28080/?authAdapter=test&apiBasePath=%2F%2Flocalhost%3A4001%2F")
    |> fill_in("Add new feed", with: "Lobby")
    |> send_keys([:enter])
    |> find(".side-nav__list-item a", text: "Lobby") # wait for async action to complete
    |> resetScope
    |> fill_in("What's got you thinking?", with: "hello")

3) Don't make find chainable
...seeing as you can always express chained finds with a single find

4) Introduce something like tap

session
|> visit("/page.html")
|> tap(fn session -> 
  session
  |> users
  |> find(".user", count: 3)
  |> List.first
  |> find(".user-name")
end)
|> continue with original scope

Ability to set user agent.

I have a frontend which depends on various options, like screen resolution or user agent.

I haven't found ability to mock user agent unfortunately.

Better names for screenshots

I have configured wallaby to take screenshots when something went wrong.

This was fine when only a single test failed, but when there are multiple ones failing I do have problems to assign the correct screenshot to the test.

So it would be nice if either the testsname or some info from conn ("#{method}-#{path}") could be part of the name of the screenshot.

Automatically convert css selectors into xpath queries

Using css selectors is a convenient and familiar construct for web developers. However, css has limitations that make it hard for wallaby to generate efficient queries. In fact most queries require multiple round trips through the webdriver before they can be resolved. Multiple queries means a larger opportunity for race conditions or stale dom nodes. These are edge cases that we have to handle explicitly because if we don't they creep into the users experience.

I propose this solution. We continue to allow people to use css selectors. But under the hood we convert those css selectors into a proper xpath query. Xpath would allow us to run all of our filters as a single query. Its well supported by webdriver; we already use it for all of the actions.

A side benefit of xpath would be that the query logic could be greatly simplified. Currently its a highly stateful and error prone process.

The largest downsides to generating xpath for users is that it could be surprising if they discover any bugs in our implementation. Its also impossible to use pseudo selectors like :hover in xpath. We will need to call this out in our documentation and make sure users have a good escape hatch from xpath if need be.

In the future I want to encourage users to create page modules; re-usable functions that can encapsulate complex interactions on the page. Having a robust query generator is a good first step towards that goal.

fill_in doesn't find elements by ID or label

Hello, I have a signup form:

<form accept-charset="UTF-8" action="/signup" method="post">
  <input name="_csrf_token" type="hidden" value="...">
  <input name="_utf8" type="hidden" value="โœ“">

  <div class="form-group">
    <label>Name</label>
    <input class="form-control" id="user_name" name="user[name]" type="text">
  </div>

  <div class="form-group">
    <label>Email</label>
    <input class="form-control" id="user_email" name="user[email]" type="text">
  </div>

  <div class="form-group">
    <label>Password</label>
    <input class="form-control" id="user_password" name="user[password]" type="password">
  </div>

  <div class="form-group">
    <input class="btn" type="submit" value="Submit">
  </div>
</form>

Then, on the Wallaby test, I try to fill the inputs (Name, Email, Password). I've tried this:

fill_in(session, "Name", with: "Jaime")

and also this:

fill_in(session, "#user_name", with: "Jaime")

But both will fail with:

  1) test signs up a user (Rocket.SignupTest)
     test/acceptance/signup_test.exs:4
     ** (Wallaby.ElementNotFound) Could not find element
     stacktrace:
       (wallaby) lib/wallaby/node.ex:342: Wallaby.Node.retry/2
       (wallaby) lib/wallaby/node.ex:81: Wallaby.Node.fill_in/3
       test/acceptance/signup_test.exs:8

I could make it work with the name attribute:

fill_in(session, "user[name]", with: "Jaime")

I'm on Elixir 1.2.5, Phoenix 1.1.4, Ecto 1.1.7, Phantomjs 2.1.1.

Accessing the "head title" element

I'm trying to access the <title> element in a HTML document, so that I can assert its contents, but I'm not having any luck. Is this possible with Wallaby at the moment?

I've tried the following:

Given the following html snippet from a "home-page":

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>My Title</title>
  </head>
  <body>
    This is the home-page
  </body>
</html>

And the following tests:

defmodule MyApp.HomeFeatureTest do
  use MyApp.FeatureCase

  test "home-page body is present", %{session: session} do
    text =
      session
      |> visit("/")
      |> find("body")
      |> text

    assert text == "This is the home-page"
  end

  test "home-page head title is present", %{session: session} do
    text =
      session
      |> visit("/")
      |> find("title", visible: false)
      |> text

    assert text == "My Title"
  end

  test "home-page head title is present, part 2", %{session: session} do
    text =
      session
      |> visit("/")
      |> find("head title", visible: false)
      |> text

    assert text == "My Title"
  end
end

2 out of 3 tests fail:

$ mix test test/features/homepage_feature_test.exs                                                           

  1) test home-page head title is present (MyApp.HomeFeatureTest)
     test/features/homepage_feature_test.exs:27
     Assertion with == failed
     code: text == "My Title"
     lhs:  ""
     rhs:  "My Title"
     stacktrace:
       test/features/homepage_feature_test.exs:34



  2) test home-page head title is present, part 2 (MyApp.HomeFeatureTest)
     test/features/homepage_feature_test.exs:37
     Assertion with == failed
     code: text == "My Title"
     lhs:  ""
     rhs:  "My Title"
     stacktrace:
       test/features/homepage_feature_test.exs:44



Finished in 1.1 seconds (0.1s on load, 0.9s on tests)
3 tests, 2 failures

`Wallaby.DSL.Navigation` does not exist

Mentioned in README:

Wallaby.DSL.Navigation.visit(session, Phoenix.Ecto.SQL.Sandbox.path_for(YourApp.Repo, self()))

Should be either Wallaby.Driver.visit or Wallaby.Session.visit? (they're the only two visit methods present)

Include what failed in failure messages

So if you call click("Submit") and it fails:

Could not click "Submit" because it was not found on the page

Would be extra cool if it found all the link text on the page and used String.jaro_distance to find potential mispellings.

Could not click "Submit" because it was not found on the page

Did you mean "submit"?

It could potentiall work the same for CSS

Could not find ".my-css"

If you spelled it wrong

Could not find ".my-css"

Did you mean ".my_css"?

These problems come up a lot so these error messages would be insanely useful!

Unable to click on nodes outside of session window size

Setup

We have a page where clicking on a button will cause other buttons to appear further down the page.

Problem

Wallaby.Node.Find would be unable to find the buttons that appeared further down the page. Originally I thought it was a problem with the nodes not rendering in time, but I could see >part< of buttons inside the failure screenshots.

Workaround Solution

Increasing the window size for the session fixed the problem

This behavior seems odd though - one would think that phantom would be able to click anything on the page regardless of if it is scrolled off.

fill_in appends content instead of replacing it

When interacting with a form and filling in a form field which already contains pre-existing text, fill_in appends to the content.

Given a form field with an input containing a value "Foo"

session |> fill_in("Name", with: "Bar")

The input field will have "FooBar" as its value

File upload?

Has file uploading been implemented in Wallaby? I looked but didn't see anything that would match a file input in xpath.ex nor did I see anything in the docs to indicate support.

Wallaby.Node.find can return invisible elements

This test will fail based on existing elements in page_1.html

test "not finding an invisible element", %{session: session, server: server} do
  session
  |> visit(server.base_url <> "page_1.html")

  assert_raise Wallaby.ElementNotFound, fn ->
    find(session, "#invisible", count: :any)
  end

  assert find(session, "#visible", count: :any) |> length == 1
end

[BUG] Session does not load

When using boilerplate instructions & trying to find an element on the page, the page was never fully rendering (in Allocations, we captured screenshots of the "Loading" page):

session
  |> sign_in
  |> visit("/")

# at this point, the page is stuck in the loading screen and never finds the project, even after:
:timer.sleep(5000)

session
  |> find(".project", count: 1)

It seems like a setup issue, and the bug starts via this commit: f1bcc46

Unable to chain `fill_in`?

Slightly related to a previous issue, I'm trying to create a helper that steps through user sign in's.

Esteem.UserHelper.sign_in/3 is only ever invoked from another module which is using AcceptanceCase

defmodule Esteem.UserHelper do
  use Wallaby.DSL

  def sign_in(session, email, password) do
    session
    |> visit("/sessions/new")
    |> fill_in("Your email", with: email)
    |> fill_in("Password", with: password)
    |> click_button("Submit")
  end
end

When it runs, I get the following error

  1) test user signs out and is redirected to login page (Esteem.UserSessionsTest)
     test/acceptance/user_sessions_test.exs:16
     ** (FunctionClauseError) no function clause matching in Wallaby.DSL.Actions.fill_in/3
     stacktrace:
       (wallaby) lib/wallaby/dsl/actions.ex:59: Wallaby.DSL.Actions.fill_in(%Wallaby.Session{base_url: "http://localhost:65372/", id: "195cd7d0-3f74-11e6-b0d4-d76992d84dcf", screenshots: [], server: #PID<0.467.0>}, "Password", [with: 'test'])
       (esteem) test/support/user_helper.ex:8: Esteem.UserHelper.sign_in/3
       test/acceptance/user_sessions_test.exs:18

It seems that the second fill_in (in this case, "Password") is getting a clause error.. and I honestly have no idea why.

Here is another test in the suite that works just fine, so I don't know why chaining fill_in's would be an issue

defmodule Esteem.UserSignsUpTest do
  use Esteem.AcceptanceCase, async: true

  test "user signs up", %{session: session} do
    session
    |> visit("/")
    |> fill_in("First name", with: "Luke")
    |> fill_in("Last name", with: "Rollans")
    |> fill_in("Email", with: "[email protected]")
    |> fill_in("Password", with: "123456")
    |> fill_in("Organisation name", with: "Marvellous Mutants")
    |> click_button("Submit")

    notice =
      session
      |> find(".alert-info")
      |> text

    assert notice == "Signed up successfully!"
  end
end

I am really sorry to post again, but I just don't know how to proceed.. and hopefully this might help someone else in future :)

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.