Rails page JS works in real browser / manual testing but not in PhantomJS & Selenium specs

我是研究僧i 提交于 2019-12-11 04:27:33

问题


In one of my Rails projects, I'm working on an interface to do CRUD operations on a resource (Commands) fully via AJAX (ie. no page reload needed). So there's a link to add a Command to the list, the user can click on any Command to edit its data then click Save to update via AJAX, and so forth. This last operation (clicking the Update button) is causing me trouble: it works perfectly in any browser I've tried, but when I follow the exact same steps in my Capybara specs (using either PhantomJS or Poltergeist driver) the specs fail right around that step.

I'm posting to ask for guidance re: how to move forward with this. I can get away with incomplete test coverage in this case, but it worries me to think that PhantomJS isn't executing all page javascript properly. (This app relies heavily on PhantomJS for unrelated reasons, so it's important for me to know how faithful its JS execution is.)

Does anyone know of any cases where PhantomJS executes Jquery AJAXy JS less-than-faithfully, and if so, what can be done about it?

Thanks in advance. Specifics and code snippets are below. Any ideas are appreciated.

Specifics

The offending JS

This is vanilla Jquery. Nothing too complicated.

// User clicks "Save" in a URL edit form to update that URL
$('.command .update_url').click(function(){
  var command = $(this).parents('.command');
  var command_path = command.attr('command_path');
  var new_url = command.find('.url_field').val();

  $.ajax({
    type: 'PATCH',
    url: command_path,
    data: { command: { url: new_url }}, // <-- (Defines required param)
    success: function(data){
      if (data.success) {
        // ... Close edit window & display cues that save is complete
      } else {
        alert("Unable to save changes. Please refresh the page.");
      }
    }
  })
});

The spec

The following is a plain Rspec integration test that uses Capybara, FactoryGirl, and not much else.

@user = create :user
@site = create :site, user: @user
@command = create :command, site: @site, url: "http://example.com/123"

stub_login(@user) # a helper I wrote that stubs Devise #current_user etc.
visit site_path(@site)
first('.command .edit_link').click

within '.editing' do
  fill_in 'url', with: "http://example.com/456"
  click_button "Save" # <-- (This triggers the above listener)
  # <-- (PhantomJS: Controller hits an error here) 
end

# <-- (The spec fails before this point)
page.should have_css '.command .edit_link', text: "http://example.com/456"
page.should_not have_css '.url_field'
@command.reload.url.should eq  "http://example.com/456"

The expected behavior

Again, this works perfectly in a real live browser. Which it should, because the above sort of ajax is extremely common and not particularly complicated.

When the button is clicked, the above JS listener is triggered. The listener gathers a couple variables, then sends a request to the Rails app to update that Command record with the URL provided.

When I open up my browser and follow the exact same steps as defined in the above Capybara spec, the controller sees the following parameters as expected:

Parameters: {
  "command" => {"url"=>"http://example.com/456"},
  "action" => "update",
  "controller" => "commands",
  "id" => "578"}

But the "command" param is absent when I execute the Capybara spec, which triggers the exact same JS code. That's the crux of the problem; see below.

The actual behavior

When I run the above example using the Poltergeist (PhantomJS) driver, the CommandsController raises an error because a required parameter (:command) wasn't present. But that parameter should be included in the PATCH request; see "Defines required param" in the JS above. Instead, the Rails controller receives the following params:

Parameters: {
  "action" => "update",
  "controller" => "commands",
  "id" => "934"}

...which understandably triggers a ParameterMissing error:

1) Command pages user updates command URL
   Failure/Error: Unable to find matching line from backtrace
   ActionController::ParameterMissing:
     param not found: command
   # /Users/topher/.rvm/gems/ruby-2.0.0-p598/gems/actionpack-4.0.3/lib/action_controller/metal/strong_parameters.rb:173:in `require'
   # ./app/controllers/commands_controller.rb:46:in `command_params'
   # ./app/controllers/commands_controller.rb:14:in `update'

Note that, when I run the exact same steps manually in a browser, the controller receives additional parameters (see above) and therefore no error occurs.

Out of curiosity I installed selenium-webdriver and tried running the spec using that driver. When I ran the spec under Selenium, it hit an error even sooner, seemingly unrelated but equally confusing. I haven't dug into this one because I don't have much interest in Selenium, and the error makes my head hurt. Will post more if requested.

What's going on?

Any ideas as to what's happening here would be greatly appreciated. As I said above, I can skip test coverage on this AJAX update feature; I'm very confident in my Jquery (or at least I was...) and it won't be a dealbreaker if I can't figure this out. But I do care to get a feel for whether or not PhantomJS can be trusted with Javascript like this; if it can't, that would really reduce my confidence in the project.

Thanks in advance!


回答1:


Update: as @Artjom B suggested, I upgraded to PhantomJS 2.0.0. It appears that this partially fixed the problem: running the specs now properly sends the AJAX request to the server, but it appears that the success function still doesn't execute (ie. the page HTML doesn't change). So at least this gets me to the point where I can do 80% tests of these features... good enough to set aside for now.



来源:https://stackoverflow.com/questions/28389135/rails-page-js-works-in-real-browser-manual-testing-but-not-in-phantomjs-sele

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!