capybara-webkit 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|