1

I am trying to take a screenshot using take_screenshot() (Hound). I just need to capture the screenshot on failure.

I have tried try/rescue however rescue block always executed even though assertion fails.

try do
   // some page elements action
   assert visible_page_text(), "Hello World"
rescue
  _ -> take_screenshot()
end

I also tried,

try do
   // some page elements action
   assert visible_page_text(), "Hello World"
catch
  _ -> take_screenshot()
end

I want, if assertion fails, only then it should take screenshot.

1 Answers1

0

With a small modification your code works:

try do
   // some page elements action
   assert visible_page_text() =~ "Hello World"
catch
  error ->
    take_screenshot()
    raise error
end

Or turn it into a macro:

  # assert screenshot on failure
  defmacro assert_sof(assertion) do
    quote do
      try do
        assert unquote(assertion)
      rescue
        error ->
          take_screenshot()
          raise error
      end
    end
  end

And call it like this:

assert_sof visible_page_text() =~ "Hello World"

Update: As you mentioned, this will only take screenshots when doing an assertion. That can be fixed though.

Here is a macro that will wrap the contents of a whole test in a try/rescue block and save a screenshot on any error. As a bonus, it prefixes the screenshot with the name of the test. The big drawback is that you lose the stracktrace, so it's harder to pinpoint the failing line of test code. (solved with catch instead of rescue) Put the macro in support/conn_case.ex or somewhere else if you prefer:

def MyAppWeb.ConnCase
  # ...

  # Test and take screenshot on failure. Only works for hound tests.
  defmacro test_sof(message, var \\ quote do _ end, contents) do
    prefix = String.replace(message, ~r/\W+/, "-")
    filename = Hound.Utils.temp_file_path(prefix, "png")

    quote do
      test unquote(message), unquote(var) do
        try do
          unquote(contents)
        catch
          error ->
            take_screenshot(unquote(filename))
            raise error
        end
      end
    end
  end

  using do
    quote do
      # Import conveniences for testing with connections
      use Phoenix.ConnTest
      import MyAppWeb.ConnCase, only: [test_sof: 2, test_sof: 3] # <- Add this line
      # ...
    end
  end

  # ...
end

And call it like a normal test:

test_sof "form with valid data" do
  navigate_to "/form"
  click({:id, "test"})
  assert visible_page_text() =~ "test successful"
end

Now it should work for all kinds of errors.

zwippie
  • 15,050
  • 3
  • 39
  • 54
  • Great that worked as intended. However if Test fails (other steps than assert, su as element not found), it wont capture snapshot. – LearningNewTech372923 Sep 27 '19 at 20:49
  • Ok, that's a pity. Although it works as intended if I test something like `assert_sof element_displayed?({:class, "foobar"})` when it's not there. It takes a screenshot. – zwippie Sep 27 '19 at 23:41
  • I've updated the answer and added a new macro that works for a whole test, not only for assertions. – zwippie Sep 28 '19 at 16:15