capybara-webkit 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CONTRIBUTING.md +38 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +28 -28
- data/README.md +39 -4
- data/capybara-webkit.gemspec +2 -2
- data/lib/capybara-webkit.rb +4 -0
- data/lib/capybara/driver/webkit.rb +23 -3
- data/lib/capybara/driver/webkit/browser.rb +44 -6
- data/lib/capybara/driver/webkit/node.rb +15 -4
- data/lib/capybara/driver/webkit/socket_debugger.rb +43 -0
- data/lib/capybara_webkit_builder.rb +9 -2
- data/spec/browser_spec.rb +26 -0
- data/spec/driver_rendering_spec.rb +80 -0
- data/spec/driver_spec.rb +186 -15
- data/spec/integration/driver_spec.rb +4 -0
- data/spec/integration/session_spec.rb +2 -2
- data/src/Body.h +12 -0
- data/src/Connection.cpp +5 -2
- data/src/Header.cpp +18 -0
- data/src/Header.h +11 -0
- data/src/NetworkAccessManager.cpp +22 -0
- data/src/NetworkAccessManager.h +18 -0
- data/src/Render.cpp +19 -0
- data/src/Render.h +12 -0
- data/src/Reset.cpp +3 -0
- data/src/Server.cpp +5 -2
- data/src/Server.h +1 -0
- data/src/Source.cpp +9 -2
- data/src/Source.h +7 -0
- data/src/WebPage.cpp +79 -5
- data/src/WebPage.h +9 -0
- data/src/body.cpp +11 -0
- data/src/capybara.js +19 -4
- data/src/find_command.h +3 -0
- data/src/main.cpp +2 -1
- data/src/webkit_server.pro +2 -2
- metadata +34 -9
- data/spec/support/socket_debugger.rb +0 -42
@@ -3,23 +3,30 @@ require "fileutils"
|
|
3
3
|
module CapybaraWebkitBuilder
|
4
4
|
extend self
|
5
5
|
|
6
|
+
def make_bin
|
7
|
+
make_binaries = ['gmake', 'make']
|
8
|
+
make_binaries.detect { |make| system("which #{make}") }
|
9
|
+
end
|
10
|
+
|
6
11
|
def makefile
|
7
12
|
qmake_binaries = ['qmake', 'qmake-qt4']
|
8
13
|
qmake = qmake_binaries.detect { |qmake| system("which #{qmake}") }
|
9
14
|
case RUBY_PLATFORM
|
10
15
|
when /linux/
|
11
16
|
system("#{qmake} -spec linux-g++")
|
17
|
+
when /freebsd/
|
18
|
+
system("#{qmake} -spec freebsd-g++")
|
12
19
|
else
|
13
20
|
system("#{qmake} -spec macx-g++")
|
14
21
|
end
|
15
22
|
end
|
16
23
|
|
17
24
|
def qmake
|
18
|
-
system("
|
25
|
+
system("#{make_bin} qmake")
|
19
26
|
end
|
20
27
|
|
21
28
|
def build
|
22
|
-
system(
|
29
|
+
system(make_bin) or return false
|
23
30
|
|
24
31
|
FileUtils.mkdir("bin") unless File.directory?("bin")
|
25
32
|
FileUtils.cp("src/webkit_server", "bin", :preserve => true)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'capybara/driver/webkit/browser'
|
3
|
+
|
4
|
+
describe Capybara::Driver::Webkit::Browser do
|
5
|
+
|
6
|
+
let(:browser) { Capybara::Driver::Webkit::Browser.new }
|
7
|
+
|
8
|
+
describe '#server_port' do
|
9
|
+
subject { browser.server_port }
|
10
|
+
it 'returns a valid port number' do
|
11
|
+
should be_a(Integer)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns a port in the allowed range' do
|
15
|
+
should be_between 0x400, 0xffff
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'random port' do
|
20
|
+
it 'chooses a new port number for a new browser instance' do
|
21
|
+
new_browser = Capybara::Driver::Webkit::Browser.new
|
22
|
+
new_browser.server_port.should_not == browser.server_port
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'capybara/driver/webkit'
|
3
|
+
require 'mini_magick'
|
4
|
+
|
5
|
+
describe Capybara::Driver::Webkit, "rendering an image" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
# Set up the tmp directory and file name
|
9
|
+
tmp_dir = File.join(PROJECT_ROOT, 'tmp')
|
10
|
+
FileUtils.mkdir_p tmp_dir
|
11
|
+
@file_name = File.join(tmp_dir, 'render-test.png')
|
12
|
+
|
13
|
+
app = lambda do |env|
|
14
|
+
body = <<-HTML
|
15
|
+
<html>
|
16
|
+
<body>
|
17
|
+
<h1>Hello World</h1>
|
18
|
+
</body>
|
19
|
+
</html>
|
20
|
+
HTML
|
21
|
+
[200,
|
22
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
23
|
+
[body]]
|
24
|
+
end
|
25
|
+
|
26
|
+
@driver = Capybara::Driver::Webkit.new(app, :browser => $webkit_browser)
|
27
|
+
@driver.visit("/hello/world?success=true")
|
28
|
+
end
|
29
|
+
|
30
|
+
after(:all) { @driver.reset! }
|
31
|
+
|
32
|
+
def render(options)
|
33
|
+
FileUtils.rm_f @file_name
|
34
|
+
@driver.render @file_name, options
|
35
|
+
|
36
|
+
@image = MiniMagick::Image.open @file_name
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with default options" do
|
40
|
+
before(:all){ render({}) }
|
41
|
+
|
42
|
+
it "should be a PNG" do
|
43
|
+
@image[:format].should == "PNG"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "width default to 1000px (with 15px less for the scrollbar)" do
|
47
|
+
@image[:width].should be < 1001
|
48
|
+
@image[:width].should be > 1000-17
|
49
|
+
end
|
50
|
+
|
51
|
+
it "height should be at least 10px" do
|
52
|
+
@image[:height].should >= 10
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with dimensions set larger than necessary" do
|
57
|
+
before(:all){ render(:width => 500, :height => 400) }
|
58
|
+
|
59
|
+
it "width should match the width given" do
|
60
|
+
@image[:width].should == 500
|
61
|
+
end
|
62
|
+
|
63
|
+
it "height should match the height given" do
|
64
|
+
@image[:height].should > 10
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with dimensions set smaller than the document's default" do
|
69
|
+
before(:all){ render(:width => 50, :height => 10) }
|
70
|
+
|
71
|
+
it "width should be greater than the width given" do
|
72
|
+
@image[:width].should > 50
|
73
|
+
end
|
74
|
+
|
75
|
+
it "height should be greater than the height given" do
|
76
|
+
@image[:height].should > 10
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/spec/driver_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe Capybara::Driver::Webkit do
|
|
20
20
|
p_id = "greeting"
|
21
21
|
msg = "hello"
|
22
22
|
iframe = "<iframe id=\"f\" src=\"/?iframe=true\"></iframe>"
|
23
|
-
end
|
23
|
+
end
|
24
24
|
body = <<-HTML
|
25
25
|
<html>
|
26
26
|
<head>
|
@@ -56,12 +56,12 @@ describe Capybara::Driver::Webkit do
|
|
56
56
|
|
57
57
|
it "raises error for missing frame by index" do
|
58
58
|
expect { subject.within_frame(1) { } }.
|
59
|
-
to raise_error(Capybara::Driver::Webkit::
|
59
|
+
to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
|
60
60
|
end
|
61
61
|
|
62
62
|
it "raise_error for missing frame by id" do
|
63
63
|
expect { subject.within_frame("foo") { } }.
|
64
|
-
to raise_error(Capybara::Driver::Webkit::
|
64
|
+
to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
|
65
65
|
end
|
66
66
|
|
67
67
|
it "returns an attribute's value" do
|
@@ -119,6 +119,7 @@ describe Capybara::Driver::Webkit do
|
|
119
119
|
<div id="invisible">Can't see me</div>
|
120
120
|
</div>
|
121
121
|
<input type="text" disabled="disabled"/>
|
122
|
+
<input id="checktest" type="checkbox" checked="checked"/>
|
122
123
|
<script type="text/javascript">
|
123
124
|
document.write("<p id='greeting'>he" + "llo</p>");
|
124
125
|
</script>
|
@@ -142,7 +143,7 @@ describe Capybara::Driver::Webkit do
|
|
142
143
|
|
143
144
|
it "raises an error for an invalid xpath query" do
|
144
145
|
expect { subject.find("totally invalid salad") }.
|
145
|
-
to raise_error(Capybara::Driver::Webkit::
|
146
|
+
to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError, /xpath/i)
|
146
147
|
end
|
147
148
|
|
148
149
|
it "returns an attribute's value" do
|
@@ -176,10 +177,6 @@ describe Capybara::Driver::Webkit do
|
|
176
177
|
subject.source.should =~ %r{<html>.*greeting.*}m
|
177
178
|
end
|
178
179
|
|
179
|
-
it "aliases body as source" do
|
180
|
-
subject.body.should == subject.source
|
181
|
-
end
|
182
|
-
|
183
180
|
it "evaluates Javascript and returns a string" do
|
184
181
|
result = subject.evaluate_script(%<document.getElementById('greeting').innerText>)
|
185
182
|
result.should == "hello"
|
@@ -237,7 +234,7 @@ describe Capybara::Driver::Webkit do
|
|
237
234
|
|
238
235
|
it "raises an error for failing Javascript" do
|
239
236
|
expect { subject.execute_script(%<invalid salad>) }.
|
240
|
-
to raise_error(Capybara::Driver::Webkit::
|
237
|
+
to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
|
241
238
|
end
|
242
239
|
|
243
240
|
it "doesn't raise an error for Javascript that doesn't return anything" do
|
@@ -253,6 +250,10 @@ describe Capybara::Driver::Webkit do
|
|
253
250
|
subject.find("//input").first.should be_disabled
|
254
251
|
end
|
255
252
|
|
253
|
+
it "reads checked property" do
|
254
|
+
subject.find("//input[@id='checktest']").first.should be_checked
|
255
|
+
end
|
256
|
+
|
256
257
|
it "finds visible elements" do
|
257
258
|
subject.find("//p").first.should be_visible
|
258
259
|
subject.find("//*[@id='invisible']").first.should_not be_visible
|
@@ -311,6 +312,12 @@ describe Capybara::Driver::Webkit do
|
|
311
312
|
input.value.should == "newvalue"
|
312
313
|
end
|
313
314
|
|
315
|
+
it "sets an input's nil value" do
|
316
|
+
input = subject.find("//input").first
|
317
|
+
input.set(nil)
|
318
|
+
input.value.should == ""
|
319
|
+
end
|
320
|
+
|
314
321
|
it "sets a select's value" do
|
315
322
|
select = subject.find("//select").first
|
316
323
|
select.set("Monkey")
|
@@ -365,28 +372,36 @@ describe Capybara::Driver::Webkit do
|
|
365
372
|
checked_box['checked'].should be_true
|
366
373
|
end
|
367
374
|
|
375
|
+
it "knows a checked box is checked using checked?" do
|
376
|
+
checked_box.should be_checked
|
377
|
+
end
|
378
|
+
|
368
379
|
it "knows an unchecked box is unchecked" do
|
369
380
|
unchecked_box['checked'].should_not be_true
|
370
381
|
end
|
371
382
|
|
383
|
+
it "knows an unchecked box is unchecked using checked?" do
|
384
|
+
unchecked_box.should_not be_checked
|
385
|
+
end
|
386
|
+
|
372
387
|
it "checks an unchecked box" do
|
373
388
|
unchecked_box.set(true)
|
374
|
-
unchecked_box
|
389
|
+
unchecked_box.should be_checked
|
375
390
|
end
|
376
391
|
|
377
392
|
it "unchecks a checked box" do
|
378
393
|
checked_box.set(false)
|
379
|
-
checked_box
|
394
|
+
checked_box.should_not be_checked
|
380
395
|
end
|
381
396
|
|
382
397
|
it "leaves a checked box checked" do
|
383
398
|
checked_box.set(true)
|
384
|
-
checked_box
|
399
|
+
checked_box.should be_checked
|
385
400
|
end
|
386
401
|
|
387
402
|
it "leaves an unchecked box unchecked" do
|
388
403
|
unchecked_box.set(false)
|
389
|
-
unchecked_box
|
404
|
+
unchecked_box.should_not be_checked
|
390
405
|
end
|
391
406
|
|
392
407
|
let(:enabled_input) { subject.find("//input[@name='foo']").first }
|
@@ -620,7 +635,7 @@ describe Capybara::Driver::Webkit do
|
|
620
635
|
wait_for_error_to_complete
|
621
636
|
subject.find("//body")
|
622
637
|
}.
|
623
|
-
to raise_error(Capybara::Driver::Webkit::
|
638
|
+
to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError, %r{/error})
|
624
639
|
end
|
625
640
|
|
626
641
|
def wait_for_error_to_complete
|
@@ -651,7 +666,7 @@ describe Capybara::Driver::Webkit do
|
|
651
666
|
|
652
667
|
it "raises a webkit error and then continues" do
|
653
668
|
subject.find("//input").first.click
|
654
|
-
expect { subject.find("//p") }.to raise_error(Capybara::Driver::Webkit::
|
669
|
+
expect { subject.find("//p") }.to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
|
655
670
|
subject.visit("/")
|
656
671
|
subject.find("//p").first.text.should == "hello"
|
657
672
|
end
|
@@ -681,4 +696,160 @@ describe Capybara::Driver::Webkit do
|
|
681
696
|
subject.find("//p").first.text.should == "success"
|
682
697
|
end
|
683
698
|
end
|
699
|
+
|
700
|
+
context "custom header" do
|
701
|
+
before(:all) do
|
702
|
+
@app = lambda do |env|
|
703
|
+
body = <<-HTML
|
704
|
+
<html><body>
|
705
|
+
<p id="user-agent">#{env['HTTP_USER_AGENT']}</p>
|
706
|
+
<p id="x-capybara-webkit-header">#{env['HTTP_X_CAPYBARA_WEBKIT_HEADER']}</p>
|
707
|
+
<p id="accept">#{env['HTTP_ACCEPT']}</p>
|
708
|
+
<a href="/">/</a>
|
709
|
+
</body></html>
|
710
|
+
HTML
|
711
|
+
[200,
|
712
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
713
|
+
[body]]
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
before do
|
718
|
+
subject.header('user-agent', 'capybara-webkit/custom-user-agent')
|
719
|
+
subject.header('x-capybara-webkit-header', 'x-capybara-webkit-header')
|
720
|
+
subject.header('accept', 'text/html')
|
721
|
+
subject.visit('/')
|
722
|
+
end
|
723
|
+
|
724
|
+
it "can set user_agent" do
|
725
|
+
subject.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent'
|
726
|
+
subject.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent'
|
727
|
+
end
|
728
|
+
|
729
|
+
it "keep user_agent in next page" do
|
730
|
+
subject.find("//a").first.click
|
731
|
+
subject.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent'
|
732
|
+
subject.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent'
|
733
|
+
end
|
734
|
+
|
735
|
+
it "can set custom header" do
|
736
|
+
subject.find('id("x-capybara-webkit-header")').first.text.should == 'x-capybara-webkit-header'
|
737
|
+
end
|
738
|
+
|
739
|
+
it "can set Accept header" do
|
740
|
+
subject.find('id("accept")').first.text.should == 'text/html'
|
741
|
+
end
|
742
|
+
|
743
|
+
it "can reset all custom header" do
|
744
|
+
subject.reset!
|
745
|
+
subject.visit('/')
|
746
|
+
subject.find('id("user-agent")').first.text.should_not == 'capybara-webkit/custom-user-agent'
|
747
|
+
subject.evaluate_script('navigator.userAgent').should_not == 'capybara-webkit/custom-user-agent'
|
748
|
+
subject.find('id("x-capybara-webkit-header")').first.text.should be_empty
|
749
|
+
subject.find('id("accept")').first.text.should_not == 'text/html'
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
753
|
+
context "no response app" do
|
754
|
+
before(:all) do
|
755
|
+
@app = lambda do |env|
|
756
|
+
body = <<-HTML
|
757
|
+
<html><body>
|
758
|
+
<form action="/error"><input type="submit"/></form>
|
759
|
+
</body></html>
|
760
|
+
HTML
|
761
|
+
[200,
|
762
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
763
|
+
[body]]
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
it "raises a webkit error for the requested url" do
|
768
|
+
make_the_server_go_away
|
769
|
+
expect {
|
770
|
+
subject.find("//body")
|
771
|
+
}.
|
772
|
+
to raise_error(Capybara::Driver::Webkit::WebkitNoResponseError, %r{response})
|
773
|
+
make_the_server_come_back
|
774
|
+
end
|
775
|
+
|
776
|
+
def make_the_server_come_back
|
777
|
+
subject.browser.instance_variable_get(:@socket).unstub!(:gets)
|
778
|
+
subject.browser.instance_variable_get(:@socket).unstub!(:puts)
|
779
|
+
subject.browser.instance_variable_get(:@socket).unstub!(:print)
|
780
|
+
end
|
781
|
+
|
782
|
+
def make_the_server_go_away
|
783
|
+
subject.browser.instance_variable_get(:@socket).stub!(:gets).and_return(nil)
|
784
|
+
subject.browser.instance_variable_get(:@socket).stub!(:puts)
|
785
|
+
subject.browser.instance_variable_get(:@socket).stub!(:print)
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
789
|
+
context "custom font app" do
|
790
|
+
before(:all) do
|
791
|
+
@app = lambda do |env|
|
792
|
+
body = <<-HTML
|
793
|
+
<html>
|
794
|
+
<head>
|
795
|
+
<style type="text/css">
|
796
|
+
p { font-family: "Verdana"; }
|
797
|
+
</style>
|
798
|
+
</head>
|
799
|
+
<body>
|
800
|
+
<p id="text">Hello</p>
|
801
|
+
</body>
|
802
|
+
</html>
|
803
|
+
HTML
|
804
|
+
[200,
|
805
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
806
|
+
[body]]
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
it "ignores custom fonts" do
|
811
|
+
font_family = subject.evaluate_script(<<-SCRIPT)
|
812
|
+
var element = document.getElementById("text");
|
813
|
+
element.ownerDocument.defaultView.getComputedStyle(element, null).getPropertyValue("font-family");
|
814
|
+
SCRIPT
|
815
|
+
font_family.should == "Arial"
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
context "with socket debugger" do
|
820
|
+
let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger }
|
821
|
+
let(:browser_with_debugger){
|
822
|
+
Capybara::Driver::Webkit::Browser.new(:socket_class => socket_debugger_class)
|
823
|
+
}
|
824
|
+
let(:driver_with_debugger){ Capybara::Driver::Webkit.new(@app, :browser => browser_with_debugger) }
|
825
|
+
|
826
|
+
before(:all) do
|
827
|
+
@app = lambda do |env|
|
828
|
+
body = <<-HTML
|
829
|
+
<html><body>
|
830
|
+
<div id="parent">
|
831
|
+
<div class="find">Expected</div>
|
832
|
+
</div>
|
833
|
+
<div class="find">Unexpected</div>
|
834
|
+
</body></html>
|
835
|
+
HTML
|
836
|
+
[200,
|
837
|
+
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
838
|
+
[body]]
|
839
|
+
end
|
840
|
+
end
|
841
|
+
|
842
|
+
it "prints out sent content" do
|
843
|
+
socket_debugger_class.any_instance.stub(:received){|content| content }
|
844
|
+
sent_content = ['Find', 1, 17, "//*[@id='parent']"]
|
845
|
+
socket_debugger_class.any_instance.should_receive(:sent).exactly(sent_content.size).times
|
846
|
+
driver_with_debugger.find("//*[@id='parent']")
|
847
|
+
end
|
848
|
+
|
849
|
+
it "prints out received content" do
|
850
|
+
socket_debugger_class.any_instance.stub(:sent)
|
851
|
+
socket_debugger_class.any_instance.should_receive(:received).at_least(:once).and_return("ok")
|
852
|
+
driver_with_debugger.find("//*[@id='parent']")
|
853
|
+
end
|
854
|
+
end
|
684
855
|
end
|
@@ -11,6 +11,10 @@ describe Capybara::Driver::Webkit do
|
|
11
11
|
|
12
12
|
it_should_behave_like "driver with javascript support"
|
13
13
|
it_should_behave_like "driver with cookies support"
|
14
|
+
|
15
|
+
it "returns the rack server port" do
|
16
|
+
@driver.server_port.should eq(@driver.instance_variable_get(:@rack_server).port)
|
17
|
+
end
|
14
18
|
|
15
19
|
# Can't support:
|
16
20
|
# it_should_behave_like "driver with header support"
|