2
votes

I'm running to issues attempting to set cookies using the Poltergeist gem, and from reading through the closed issues at the Poltergeist gem, it appears this is a user error issue on my part, but I've spent a full day now on attempting to get the cookies set properly, and I can't seem to set things up properly.

Note: This test works fine in selenium, but I'd like to use poltergeist due to run time issues with selenium.

The application I'm working on is using "_location" cookie to determine some overall settings, and I need to have the cookie accessible on my first visit of any page in the application. Otherwise I get a javascript error looking for a value that is not set due to the location not being set.

The README for the Poltergeist gem shows the following usage for cookies

Manipulating cookies

The following methods are used to inspect and manipulate cookies:

page.driver.cookies - a hash of cookies accessible to the current page. The keys are cookie names. The values are Cookie objects, with the following methods: name, value, domain, path, secure?, httponly?, expires.

page.driver.set_cookie(name, value, options = {}) - set a cookie. The options hash can take the following keys: :domain, :path, :secure, :httponly, :expires. :expires should be a Time object.

page.driver.remove_cookie(name) - remove a cookie

-- specs/spec_helper.rb

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, :debug => true)
end

Capybara.javascript_driver = :poltergeist

-- views/admin/article/new.html.haml

= link_to_function "test js", '$(this).html("js works")'

-- specs/requests/article_products_spec.rb

require 'spec_helper'

describe "Associating Articles with Products and Product Categories" do

  before (:all) do
    @user = create(:user, role: "admin")
    5.times { create(:product_category) }
    @product_categories = ProductCategory.all
    @product_categories.each do |pc|
      4.times { create(:product, product_category: pc) }
    end
  end

  before (:each) do
    visit new_user_session_path
    page.driver.set_cookie("_location", "US")
    page.driver.cookies
    fill_in "Username Or Email", with: @user.email
    fill_in "Password", with: @user.password
    click_button "Sign In"
    visit new_admin_article_path
  end

  it "supports js", :js => true do
    click_link "test js"
    page.should have_content("js works")
  end

end

test response

{"name"=>"visit", "args"=>["http://127.0.0.1:64554/users/sign_in"]}
{"error"=>{"name"=>"Poltergeist.JavascriptError", "args"=>[[{"message"=>"TypeError: 'null' is not an object (evaluating 'response.custentitydefault_shipping_location')", "stack"=>"TypeError: 'null' is not an object (evaluating 'response.custentitydefault_shipping_location')\n    at http://127.0.0.1:64554/assets/non_deferred.js:12338\n    at http://127.0.0.1:64554/assets/non_deferred.js:1076\n    at http://127.0.0.1:64554/assets/non_deferred.js:1194\n    at http://127.0.0.1:64554/assets/non_deferred.js:7539 in done\n    at http://127.0.0.1:64554/assets/non_deferred.js:8325"}]]}}
{"name"=>"reset", "args"=>[]}
{"response"=>true}
F

Failures:

  1) Associating Articles with Products and Product Categories supports js
     Failure/Error: visit new_user_session_path
     Capybara::Poltergeist::JavascriptError:
       One or more errors were raised in the Javascript code on the page:

       TypeError: 'null' is not an object (evaluating 'response.custentitydefault_shipping_location')
           at http://127.0.0.1:64554/assets/non_deferred.js:12338
           at http://127.0.0.1:64554/assets/non_deferred.js:1076
           at http://127.0.0.1:64554/assets/non_deferred.js:1194
           at http://127.0.0.1:64554/assets/non_deferred.js:7539 in done
           at http://127.0.0.1:64554/assets/non_deferred.js:8325
     # ./spec/requests/article_products_spec.rb:15:in `block (2 levels) in <top (required)>'
     # ./spec/support/vcr.rb:14:in `block (2 levels) in <top (required)>'

With this failure, I thought perhaps I should be setting the cookies before visiting the page, however it appears that when I use the page.driver.set_cookie command before I use "visit" in my Capybara scripts, it doesn't actually set anything. As seen from this modified code block and this result set.

-- specs/requests/article_products_spec.rb

describe "Associating Articles with Products and Product Categories" do

  before (:all) do
    @user = create(:user, role: "admin")
    5.times { create(:product_category) }
    @product_categories = ProductCategory.all
    @product_categories.each do |pc|
      4.times { create(:product, product_category: pc) }
    end
  end

  before (:each) do
    page.driver.set_cookie("_location", "US")
    page.driver.cookies
    visit new_user_session_path
    fill_in "Username Or Email", with: @user.email
    fill_in "Password", with: @user.password
    click_button "Sign In"
    visit new_admin_article_path
  end

  it "supports js", :js => true do
    click_link "test js"
    page.should have_content("js works")
  end
end

test response

{"name"=>"set_cookie", "args"=>[{:name=>"_location", :value=>"US", :domain=>"127.0.0.1"}]}
{"response"=>true}
{"name"=>"cookies", "args"=>[]}
{"response"=>[]}
{"name"=>"visit", "args"=>["http://127.0.0.1:64090/users/sign_in"]}
{"error"=>{"name"=>"Poltergeist.JavascriptError", "args"=>[[{"message"=>"TypeError: 'null' is not an object (evaluating 'response.custentitydefault_shipping_location')", "stack"=>"TypeError: 'null' is not an object (evaluating 'response.custentitydefault_shipping_location')\n    at http://127.0.0.1:64090/assets/non_deferred.js:12338\n    at http://127.0.0.1:64090/assets/non_deferred.js:1076\n    at http://127.0.0.1:64090/assets/non_deferred.js:1194\n    at http://127.0.0.1:64090/assets/non_deferred.js:7539 in done\n    at http://127.0.0.1:64090/assets/non_deferred.js:8325"}]]}}
{"name"=>"reset", "args"=>[]}
{"response"=>true}
F

Failures:

  1) Associating Articles with Products and Product Categories supports js
     Failure/Error: visit new_user_session_path
     Capybara::Poltergeist::JavascriptError:
       One or more errors were raised in the Javascript code on the page:

       TypeError: 'null' is not an object (evaluating 'response.custentitydefault_shipping_location')
           at http://127.0.0.1:64554/assets/non_deferred.js:12338
           at http://127.0.0.1:64554/assets/non_deferred.js:1076
           at http://127.0.0.1:64554/assets/non_deferred.js:1194
           at http://127.0.0.1:64554/assets/non_deferred.js:7539 in done
           at http://127.0.0.1:64554/assets/non_deferred.js:8325
     # ./spec/requests/article_products_spec.rb:15:in `block (2 levels) in <top (required)>'
     # ./spec/support/vcr.rb:14:in `block (2 levels) in <top (required)>'

I've also attempted to pass in a phantomjs_options block to the poltergeist driver, with an external cookies file. That actually appeared to get me a bit farther, but I ended up with a null cookie_jar. You can see this attempt below:

--spec/spec_helper.rb

  Capybara.register_driver :poltergeist do |app|
    Capybara::Poltergeist::Driver.new(app, [phantomjs_options: [--cookies-file="#{::Rails.root}/spec/requests/cookies.txt"]] )
  end

  Capybara.javascript_driver = :poltergeist

-- cookies.txt

phantom.addCookie({
    'name':     '_location',
    'value':    'US',
    'domain':   'localhost',
    'expires':  (new Date()).getTime() + 3600
});

test response F

Failures:

  1) Associating Articles with Products and Product Categories supports js
     Failure/Error: visit new_user_session_path
     NoMethodError:
       undefined method `cookie_jar' for nil:NilClass
     # ./spec/requests/article_products_spec.rb:15:in `block (2 levels) in <top (required)>'
     # ./spec/support/vcr.rb:14:in `block (2 levels) in <top (required)>'

Finished in 2.42 seconds
1 example, 1 failure
1

1 Answers

3
votes

I believe your attempt to specify options to Poltergeist got confused with options to PhantomJS. Your registration block should look like this:

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, :phantomjs_options => ["--cookies-file=#{::Rails.root}/spec/requests/cookies.txt"])
end

Hope that helps.