Skip to content

Commit

Permalink
Mock xhr early
Browse files Browse the repository at this point in the history
Needed for window.onload-type ajax requests
  • Loading branch information
mynyml committed Mar 13, 2010
1 parent de579bc commit 6c814d5
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 47 deletions.
37 changes: 15 additions & 22 deletions lib/holygrail.rb
@@ -1,15 +1,14 @@
require 'harmony' require 'harmony'


module HolyGrail module HolyGrail
class XhrProxy module XhrProxy
class << self extend self
attr_accessor :context attr_accessor :context


def request(info, data="") def request(info, data="")
context.instance_eval do context.instance_eval do
xhr(info["method"].downcase, info["url"]) xhr(info["method"].downcase, info["url"])
@response.body.to_s @response.body.to_s
end
end end
end end
end end
Expand All @@ -33,7 +32,6 @@ module HolyGrail
# #
# @private # @private
def process(*args) #:nodoc: def process(*args) #:nodoc:
#::HolyGrail::XhrProxy.context = self
@__page = nil @__page = nil
super super
end end
Expand All @@ -57,21 +55,14 @@ def process(*args) #:nodoc:
# javascript code exception # javascript code exception
# #
def js(code) def js(code)
@__page ||= ::HolyGrail::XhrProxy.context = self
begin @__page ||= Harmony::Page.new(XHR_MOCK_SCRIPT + rewrite_script_paths(@response.body.to_s))
::HolyGrail::XhrProxy.context = self
page = Harmony::Page.new(rewrite_script_paths(@response.body.to_s))
page.execute_js(mock_xhr)
page
end
@__page.execute_js(code) @__page.execute_js(code)
end end
alias :execute_javascript :js alias :execute_javascript :js


private XHR_MOCK_SCRIPT = <<-JS

<script>
def mock_xhr
<<-JS
XMLHttpRequest.prototype.open = function(method, url, async, username, password) { XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
this.info = { method: method, url: url } this.info = { method: method, url: url }
} }
Expand All @@ -80,8 +71,10 @@ def mock_xhr
this.readyState = 4 this.readyState = 4
this.onreadystatechange() this.onreadystatechange()
} }
JS </script>
end JS

private


# Rewrite relative src paths in <script> tags # Rewrite relative src paths in <script> tags
# #
Expand Down
66 changes: 45 additions & 21 deletions test/integration_test.rb
Expand Up @@ -2,30 +2,48 @@


class IntegrationController < ActionController::Base class IntegrationController < ActionController::Base


def perform_xhr_function
<<-JS
function perform_xhr(method, url) {
var xhr = new XMLHttpRequest()
xhr.open(method, url, false) //false == synchronous
xhr.onreadystatechange = function() {
if (this.readyState != 4) { return }
document.body.innerHTML = this.responseText
}
xhr.send(null) // POST request sends data here
}
JS
end

def baz def baz
render :text => <<-HTML render :text => <<-HTML
<html> <html>
<head> <head>
<script>#{perform_xhr_function}</script>
</head>
<body></body>
</html>
HTML
end

def boo
render :text => <<-HTML
<html>
<head>
<script>#{perform_xhr_function}</script>
<script> <script>
function perform_xhr(method, url) { window.onload = function() {
var xhr = new XMLHttpRequest() perform_xhr("GET", "xhr")
xhr.open(method, url, false) //false == synchronous
xhr.onreadystatechange = function() {
if (this.readyState != 4) { return }
document.getElementById("xhr_result").innerHTML = this.responseText
}
xhr.send(null) // POST request sends data here
} }
</script> </script>
</head> </head>
<body> <body></body>
<div id="xhr_result">orig</div>
</body>
</html> </html>
HTML HTML
end end


def baz_xhr def xhr
render :text => "xhr response" render :text => "xhr response"
end end
end end
Expand All @@ -34,7 +52,6 @@ class IntegrationControllerTest < ActionController::IntegrationTest


# TODO test xhr POST # TODO test xhr POST
# TODO test xhr uris with initial "/" # TODO test xhr uris with initial "/"
# TODO test xhr is mocked early, e.g. requests triggered on page load


test "api" do test "api" do
assert_respond_to self, :execute_javascript assert_respond_to self, :execute_javascript
Expand All @@ -44,25 +61,32 @@ class IntegrationControllerTest < ActionController::IntegrationTest
## xhr ## xhr


test "xhr calls controller" do test "xhr calls controller" do
get "baz" get 'baz'


assert_equal "orig", js(<<-JS) assert_equal "", js(<<-JS).gsub("\n",'').strip
document.getElementById("xhr_result").innerHTML document.body.innerHTML
JS JS
assert_equal "xhr response", js(<<-JS) assert_equal "xhr response", js(<<-JS)
perform_xhr("GET", "baz_xhr") perform_xhr("GET", "xhr")
document.getElementById("xhr_result").innerHTML document.body.innerHTML
JS JS
end end


test "xhr identifes properly" do test "xhr identifes properly" do
get "baz" get 'baz'
assert_nil request.headers['X-Requested-With'] assert_nil request.headers['X-Requested-With']


js(<<-JS) js(<<-JS)
perform_xhr("GET", "baz_xhr") perform_xhr("GET", "xhr")
JS
assert_equal 'XMLHttpRequest', request.headers['X-Requested-With']
end

test "xhr is mocked early" do
get 'boo'
assert_equal "xhr response", js(<<-JS)
document.body.innerHTML
JS JS
assert_equal "XMLHttpRequest", request.headers['X-Requested-With']
end end
end end


9 changes: 5 additions & 4 deletions test/test_helper.rb
Expand Up @@ -15,10 +15,11 @@ def self.root
end end


ActionController::Routing::Routes.draw do |map| ActionController::Routing::Routes.draw do |map|
map.connect '/foo', :controller => 'functionals', :action => 'foo' map.connect '/foo', :controller => 'functionals', :action => 'foo'
map.connect '/bar', :controller => 'functionals', :action => 'bar' map.connect '/bar', :controller => 'functionals', :action => 'bar'
map.connect '/baz', :controller => 'integration', :action => 'baz' map.connect '/baz', :controller => 'integration', :action => 'baz'
map.connect '/baz_xhr', :controller => 'integration', :action => 'baz_xhr' map.connect '/xhr', :controller => 'integration', :action => 'xhr'
map.connect '/boo', :controller => 'integration', :action => 'boo'
end end


ActionController::Base.session = { ActionController::Base.session = {
Expand Down

0 comments on commit 6c814d5

Please sign in to comment.