0

We use Capybara along with Chrome Headless for integration testing. I'd like to write a linter, that checks some metrics on the HTML structure everytime chrome navigates to another page. Then I'd raise an error when something is against our linter.

We have some tests without javascript, and monkey patching rack-test works so far:

Capybara::RackTest::Browser.class_eval do
  alias_method :process_orig, :process
  def process *args
    response = process_orig *args
    # do some linting
    response
  end
end

But I haven't found a way inside Capybara and/or Chrome Headless where I could intercept a response, and check the body of the page.

Is it possible to trigger a hook, when a page changes? Or is there some kind of API Chrome provides where I could get the body of every request? Or would a proxy be a feasible solution?

23tux
  • 14,104
  • 15
  • 88
  • 187

2 Answers2

1

This isn't possible directly with Capybara, since it doesn't actually know about page transitions/requests that happen in the browser unless they are specifically user initiated with visit.

A potential way to do what you want would be using a programmable proxy like puffing-billy to handle every request to the app under test. If you use puffing-billy you'll want to look at the pass_request feature - https://github.com/oesmith/puffing-billy#in-your-tests-capybarawatir - to forward on the initial request and then do whatever you want with the response.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
0

I'd not tangle capybara tests with HTML linting. It may seem smart at this moment, as you get a list of URL's to check for free with each test, but:

  • You'd probably lint each URL few times because some tests go through it
  • You might get failures because HTML is not perfect, even though the feature you're testing is actually ok.

You probably have something like sitemap.xml or other sources of all available URLs. I'd use it to make a separate check, which will be simple: request the URL, lint the response. Rinse and repeat.

If still not convinced, try using page.html and do sth like

expect(page.html).to pass_linter

https://github.com/teamcapybara/capybara#debugging

You can then add it as an around hook for every type: :feature spec if you want.

EDIT: here's another workaround to have every visited path. Just parse the server log file (like this cat log/devlopment.log | grep path) to get a full list if visited paths:

method=POST path=/users/login format=html controller=SessionsController action=create
status=302 duration=256.82 view=0.00 db=52.29 location=http://0.0.0.0:3000/platform/admin/dashboard params={"utf8"=>"✓", "authenticity_token"=>"ubGnWKOq8gbUE5C/aK375QQn5DpjHarUYxHtBLglGe6Lr9Ie3O5XPq90k5gr/SZbIPoDiiasvY0mGlwhzD/MsQ==", "user"=>{"email"=>"alex-3d51048235c9d1a8@toptal.io", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"} uid=983 remote_ip=127.0.0.1 x_forwarded_for= x_request_id=                
method=GET path=/admin/dashboard format=html controller=XXX action=show status=200 duration=3285.54 view=1051.32 db=2016.87 params={} uid=983 remote_ip=127.0.0.1 x_forwarded_for= x_request_id=   

and use it for linting.

Greg
  • 5,862
  • 1
  • 25
  • 52
  • Thanks for your answer. The linting itself is fast, so doing it multiple times is not a problem. However, maintaining a list of URLs that have to be checked everytime someone introduces a new URL leads to a lot of manual work. Of course HTML is not perfect, but I'm not validating to a perfect HTML document, just some bigger metrics like "only one h1 tag per page" and stuff like that. – 23tux Jul 13 '18 at 14:35
  • You're right. I've added a way which may work for you. Instead of looking for a hook in capybara - set up expectations on your specs and user `page.html` (see my updated answer) – Greg Jul 13 '18 at 14:42
  • thanks for your update. I already tried an around hook, but when a single tests navigates through multiple pages, I'd like to lint every one of them, and not only the last one. So IMHO some kind of hook into google chrome is mandatory – 23tux Jul 13 '18 at 14:44
  • Ok, then maybe you can use log file to get every visited path when running the capybara tests? – Greg Jul 13 '18 at 15:27
  • I'm inside a test, so when the test is over, the resources are cleaned and the route would not be accessible any more – 23tux Jul 13 '18 at 16:34