capybara-webkit 0.11.0 → 0.12.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.
Files changed (86) hide show
  1. data/.gitignore +3 -1
  2. data/Gemfile.lock +5 -4
  3. data/NEWS.md +11 -0
  4. data/README.md +42 -0
  5. data/lib/capybara/driver/webkit.rb +7 -2
  6. data/lib/capybara/driver/webkit/browser.rb +22 -96
  7. data/lib/capybara/driver/webkit/connection.rb +120 -0
  8. data/lib/capybara/driver/webkit/version.rb +1 -1
  9. data/lib/capybara/webkit/matchers.rb +2 -4
  10. data/lib/capybara_webkit_builder.rb +22 -4
  11. data/spec/browser_spec.rb +19 -29
  12. data/spec/connection_spec.rb +54 -0
  13. data/spec/driver_resize_window_spec.rb +59 -0
  14. data/spec/driver_spec.rb +175 -27
  15. data/spec/spec_helper.rb +9 -2
  16. data/src/Body.h +2 -2
  17. data/src/ClearCookies.cpp +2 -5
  18. data/src/ClearCookies.h +2 -2
  19. data/src/Command.cpp +7 -3
  20. data/src/Command.h +4 -2
  21. data/src/CommandFactory.cpp +7 -2
  22. data/src/CommandFactory.h +1 -1
  23. data/src/CommandParser.cpp +13 -5
  24. data/src/CommandParser.h +6 -2
  25. data/src/Connection.cpp +18 -47
  26. data/src/Connection.h +5 -7
  27. data/src/ConsoleMessages.cpp +2 -3
  28. data/src/ConsoleMessages.h +2 -2
  29. data/src/CurrentUrl.cpp +3 -6
  30. data/src/CurrentUrl.h +2 -2
  31. data/src/Evaluate.cpp +3 -3
  32. data/src/Evaluate.h +2 -2
  33. data/src/Execute.cpp +4 -4
  34. data/src/Execute.h +2 -2
  35. data/src/Find.cpp +4 -4
  36. data/src/Find.h +2 -2
  37. data/src/FrameFocus.cpp +7 -7
  38. data/src/FrameFocus.h +2 -2
  39. data/src/GetCookies.cpp +2 -4
  40. data/src/GetCookies.h +2 -2
  41. data/src/Header.cpp +4 -4
  42. data/src/Header.h +2 -2
  43. data/src/Headers.cpp +2 -3
  44. data/src/Headers.h +2 -2
  45. data/src/IgnoreSslErrors.cpp +12 -0
  46. data/src/IgnoreSslErrors.h +12 -0
  47. data/src/NetworkAccessManager.cpp +4 -0
  48. data/src/NetworkAccessManager.h +2 -1
  49. data/src/Node.cpp +3 -3
  50. data/src/Node.h +2 -2
  51. data/src/NullCommand.cpp +10 -0
  52. data/src/NullCommand.h +11 -0
  53. data/src/PageLoadingCommand.cpp +46 -0
  54. data/src/PageLoadingCommand.h +40 -0
  55. data/src/Render.cpp +5 -6
  56. data/src/Render.h +2 -2
  57. data/src/RequestedUrl.cpp +3 -6
  58. data/src/RequestedUrl.h +2 -2
  59. data/src/Reset.cpp +8 -7
  60. data/src/Reset.h +2 -2
  61. data/src/ResizeWindow.cpp +16 -0
  62. data/src/ResizeWindow.h +12 -0
  63. data/src/Response.cpp +6 -1
  64. data/src/Response.h +4 -2
  65. data/src/Server.cpp +2 -3
  66. data/src/Server.h +1 -1
  67. data/src/SetCookie.cpp +3 -5
  68. data/src/SetCookie.h +2 -2
  69. data/src/SetProxy.cpp +7 -9
  70. data/src/SetProxy.h +2 -2
  71. data/src/Source.cpp +2 -4
  72. data/src/Source.h +2 -2
  73. data/src/Status.cpp +2 -3
  74. data/src/Status.h +2 -2
  75. data/src/Url.cpp +3 -6
  76. data/src/Url.h +2 -2
  77. data/src/Visit.cpp +4 -13
  78. data/src/Visit.h +2 -5
  79. data/src/WebPage.cpp +11 -9
  80. data/src/WebPage.h +3 -3
  81. data/src/body.cpp +2 -3
  82. data/src/capybara.js +58 -3
  83. data/src/find_command.h +3 -1
  84. data/src/main.cpp +1 -2
  85. data/src/webkit_server.pro +8 -0
  86. metadata +29 -16
@@ -22,29 +22,47 @@ module CapybaraWebkitBuilder
22
22
  "linux-g++"
23
23
  when /freebsd/
24
24
  "freebsd-g++"
25
+ when /mingw32/
26
+ "win32-g++"
25
27
  else
26
28
  "macx-g++"
27
29
  end
28
30
  end
29
31
 
30
32
  def makefile
31
- system("LANG='en_US.UTF-8' #{qmake_bin} -spec #{spec}")
33
+ system("#{qmake_bin} -spec #{spec}")
32
34
  end
33
35
 
34
36
  def qmake
35
- system("LANG='en_US.UTF-8' #{make_bin} qmake")
37
+ system("#{make_bin} qmake")
38
+ end
39
+
40
+ def path_to_binary
41
+ case RUBY_PLATFORM
42
+ when /mingw32/
43
+ "src/debug/webkit_server.exe"
44
+ else
45
+ "src/webkit_server"
46
+ end
36
47
  end
37
48
 
38
49
  def build
39
50
  system(make_bin) or return false
40
51
 
41
52
  FileUtils.mkdir("bin") unless File.directory?("bin")
42
- FileUtils.cp("src/webkit_server", "bin", :preserve => true)
53
+ FileUtils.cp(path_to_binary, "bin", :preserve => true)
54
+ end
55
+
56
+ def clean
57
+ File.open("Makefile", "w") do |file|
58
+ file.print "all:\n\t@echo ok\ninstall:\n\t@echo ok"
59
+ end
43
60
  end
44
61
 
45
62
  def build_all
46
63
  makefile &&
47
64
  qmake &&
48
- build
65
+ build &&
66
+ clean
49
67
  end
50
68
  end
data/spec/browser_spec.rb CHANGED
@@ -2,42 +2,19 @@ require 'spec_helper'
2
2
  require 'self_signed_ssl_cert'
3
3
  require 'stringio'
4
4
  require 'capybara/driver/webkit/browser'
5
+ require 'capybara/driver/webkit/connection'
5
6
  require 'socket'
6
7
  require 'base64'
7
8
 
8
9
  describe Capybara::Driver::Webkit::Browser do
9
10
 
10
- let(:browser) { Capybara::Driver::Webkit::Browser.new }
11
- let(:browser_ignore_ssl_err) {
12
- Capybara::Driver::Webkit::Browser.new(:ignore_ssl_errors => true)
13
- }
14
-
15
- describe '#server_port' do
16
- subject { browser.server_port }
17
- it 'returns a valid port number' do
18
- should be_a(Integer)
19
- end
20
-
21
- it 'returns a port in the allowed range' do
22
- should be_between 0x400, 0xffff
11
+ let(:browser) { Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new) }
12
+ let(:browser_ignore_ssl_err) do
13
+ Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
14
+ browser.ignore_ssl_errors
23
15
  end
24
16
  end
25
17
 
26
- context 'random port' do
27
- it 'chooses a new port number for a new browser instance' do
28
- new_browser = Capybara::Driver::Webkit::Browser.new
29
- new_browser.server_port.should_not == browser.server_port
30
- end
31
- end
32
-
33
- it 'forwards stdout to the given IO object' do
34
- io = StringIO.new
35
- new_browser = Capybara::Driver::Webkit::Browser.new(:stdout => io)
36
- new_browser.execute_script('console.log("hello world")')
37
- sleep(0.5)
38
- io.string.should include "hello world\n"
39
- end
40
-
41
18
  context 'handling of SSL validation errors' do
42
19
  before do
43
20
  # set up minimal HTTPS server
@@ -81,7 +58,8 @@ describe Capybara::Driver::Webkit::Browser do
81
58
  browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
82
59
  end
83
60
  end
84
- describe "forking" do
61
+
62
+ describe "forking", :skip_on_windows => true do
85
63
  it "only shuts down the server from the main process" do
86
64
  browser.reset!
87
65
  pid = fork {}
@@ -180,4 +158,16 @@ describe Capybara::Driver::Webkit::Browser do
180
158
  @proxy_requests.size.should == 0
181
159
  end
182
160
  end
161
+
162
+ it "doesn't try to read an empty response" do
163
+ connection = stub("connection")
164
+ connection.stub(:puts)
165
+ connection.stub(:print)
166
+ connection.stub(:gets).and_return("ok\n", "0\n")
167
+ connection.stub(:read).and_raise(StandardError.new("tried to read empty response"))
168
+
169
+ browser = Capybara::Driver::Webkit::Browser.new(connection)
170
+
171
+ expect { browser.visit("/") }.not_to raise_error(/empty response/)
172
+ end
183
173
  end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'capybara/driver/webkit/connection'
3
+
4
+ describe Capybara::Driver::Webkit::Connection do
5
+ it "boots a server to talk to" do
6
+ url = @rack_server.url("/")
7
+ connection.puts "Visit"
8
+ connection.puts 1
9
+ connection.puts url.to_s.bytesize
10
+ connection.print url
11
+ connection.gets.should == "ok\n"
12
+ connection.gets.should == "0\n"
13
+ connection.puts "Body"
14
+ connection.puts 0
15
+ connection.gets.should == "ok\n"
16
+ response_length = connection.gets.to_i
17
+ response = connection.read(response_length)
18
+ response.should include("Hey there")
19
+ end
20
+
21
+ it 'forwards stdout to the given IO object' do
22
+ io = StringIO.new
23
+ redirected_connection = Capybara::Driver::Webkit::Connection.new(:stdout => io)
24
+ script = 'console.log("hello world")'
25
+ redirected_connection.puts "Execute"
26
+ redirected_connection.puts 1
27
+ redirected_connection.puts script.to_s.bytesize
28
+ redirected_connection.print script
29
+ sleep(0.5)
30
+ io.string.should include "hello world\n"
31
+ end
32
+
33
+ it "returns the server port" do
34
+ connection.port.should be_between 0x400, 0xffff
35
+ end
36
+
37
+ it "chooses a new port number for a new connection" do
38
+ new_connection = Capybara::Driver::Webkit::Connection.new
39
+ new_connection.port.should_not == connection.port
40
+ end
41
+
42
+ let(:connection) { Capybara::Driver::Webkit::Connection.new }
43
+
44
+ before(:all) do
45
+ @app = lambda do |env|
46
+ body = "<html><body>Hey there</body></html>"
47
+ [200,
48
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s },
49
+ [body]]
50
+ end
51
+ @rack_server = Capybara::Server.new(@app)
52
+ @rack_server.boot
53
+ end
54
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+ require 'capybara/driver/webkit'
3
+
4
+ describe Capybara::Driver::Webkit, "#resize_window(width, height)" do
5
+
6
+ before(:all) do
7
+ app = lambda do |env|
8
+ body = <<-HTML
9
+ <html>
10
+ <body>
11
+ <h1 id="dimentions">UNKNOWN</h1>
12
+
13
+ <script>
14
+ window.onload = window.onresize = function(){
15
+ document.getElementById("dimentions").innerHTML = "[" + window.innerWidth + "x" + window.innerHeight + "]";
16
+ };
17
+ </script>
18
+
19
+ </body>
20
+ </html>
21
+ HTML
22
+
23
+ [
24
+ 200,
25
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
26
+ [body]
27
+ ]
28
+ end
29
+
30
+ @driver = Capybara::Driver::Webkit.new(app, :browser => $webkit_browser)
31
+ end
32
+
33
+ DEFAULT_DIMENTIONS = "[1680x1050]"
34
+
35
+ it "resizes the window to the specified size" do
36
+ @driver.visit("/")
37
+
38
+ @driver.resize_window(800, 600)
39
+ @driver.body.should include("[800x600]")
40
+
41
+ @driver.resize_window(300, 100)
42
+ @driver.body.should include("[300x100]")
43
+ end
44
+
45
+ it "resizes the window to the specified size even before the document has loaded" do
46
+ @driver.resize_window(800, 600)
47
+ @driver.visit("/")
48
+ @driver.body.should include("[800x600]")
49
+ end
50
+
51
+ it "resets the window to the default size when the driver is reset" do
52
+ @driver.resize_window(800, 600)
53
+ @driver.reset!
54
+ @driver.visit("/")
55
+ @driver.body.should include(DEFAULT_DIMENTIONS)
56
+ end
57
+
58
+ after(:all) { @driver.reset! }
59
+ end
data/spec/driver_spec.rb CHANGED
@@ -659,6 +659,7 @@ describe Capybara::Driver::Webkit do
659
659
  element.addEventListener("keydown", recordEvent);
660
660
  element.addEventListener("keypress", recordEvent);
661
661
  element.addEventListener("keyup", recordEvent);
662
+ element.addEventListener("input", recordEvent);
662
663
  element.addEventListener("change", recordEvent);
663
664
  element.addEventListener("blur", recordEvent);
664
665
  element.addEventListener("mousedown", recordEvent);
@@ -678,7 +679,7 @@ describe Capybara::Driver::Webkit do
678
679
 
679
680
  let(:keyevents) do
680
681
  (%w{focus} +
681
- newtext.length.times.collect { %w{keydown keypress keyup} } +
682
+ newtext.length.times.collect { %w{keydown keypress keyup input} } +
682
683
  %w{change blur}).flatten
683
684
  end
684
685
 
@@ -987,15 +988,15 @@ describe Capybara::Driver::Webkit do
987
988
  end
988
989
 
989
990
  def make_the_server_come_back
990
- subject.browser.instance_variable_get(:@socket).unstub!(:gets)
991
- subject.browser.instance_variable_get(:@socket).unstub!(:puts)
992
- subject.browser.instance_variable_get(:@socket).unstub!(:print)
991
+ subject.browser.instance_variable_get(:@connection).unstub!(:gets)
992
+ subject.browser.instance_variable_get(:@connection).unstub!(:puts)
993
+ subject.browser.instance_variable_get(:@connection).unstub!(:print)
993
994
  end
994
995
 
995
996
  def make_the_server_go_away
996
- subject.browser.instance_variable_get(:@socket).stub!(:gets).and_return(nil)
997
- subject.browser.instance_variable_get(:@socket).stub!(:puts)
998
- subject.browser.instance_variable_get(:@socket).stub!(:print)
997
+ subject.browser.instance_variable_get(:@connection).stub!(:gets).and_return(nil)
998
+ subject.browser.instance_variable_get(:@connection).stub!(:puts)
999
+ subject.browser.instance_variable_get(:@connection).stub!(:print)
999
1000
  end
1000
1001
  end
1001
1002
 
@@ -1090,7 +1091,8 @@ describe Capybara::Driver::Webkit do
1090
1091
  context "with socket debugger" do
1091
1092
  let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger }
1092
1093
  let(:browser_with_debugger){
1093
- Capybara::Driver::Webkit::Browser.new(:socket_class => socket_debugger_class)
1094
+ connection = Capybara::Driver::Webkit::Connection.new(:socket_class => socket_debugger_class)
1095
+ Capybara::Driver::Webkit::Browser.new(connection)
1094
1096
  }
1095
1097
  let(:driver_with_debugger){ Capybara::Driver::Webkit.new(@app, :browser => browser_with_debugger) }
1096
1098
 
@@ -1276,6 +1278,39 @@ describe Capybara::Driver::Webkit do
1276
1278
  end
1277
1279
  end
1278
1280
 
1281
+ context "localStorage works" do
1282
+ before(:all) do
1283
+ @app = lambda do |env|
1284
+ body = <<-HTML
1285
+ <html>
1286
+ <body>
1287
+ <span id='output'></span>
1288
+ <script type="text/javascript">
1289
+ if (typeof localStorage !== "undefined") {
1290
+ if (!localStorage.refreshCounter) {
1291
+ localStorage.refreshCounter = 0;
1292
+ }
1293
+ if (localStorage.refreshCounter++ > 0) {
1294
+ document.getElementById("output").innerHTML = "localStorage is enabled";
1295
+ }
1296
+ }
1297
+ </script>
1298
+ </body>
1299
+ </html>
1300
+ HTML
1301
+ [200,
1302
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
1303
+ [body]]
1304
+ end
1305
+ end
1306
+
1307
+ it "displays the message on subsequent page loads" do
1308
+ subject.find("//span[contains(.,'localStorage is enabled')]").should be_empty
1309
+ subject.visit "/"
1310
+ subject.find("//span[contains(.,'localStorage is enabled')]").should_not be_empty
1311
+ end
1312
+ end
1313
+
1279
1314
  context "app with a lot of HTML tags" do
1280
1315
  before(:all) do
1281
1316
  @app = lambda do |env|
@@ -1372,33 +1407,146 @@ describe Capybara::Driver::Webkit do
1372
1407
  end
1373
1408
  end
1374
1409
 
1410
+ def key_app_body(event)
1411
+ body = <<-HTML
1412
+ <html>
1413
+ <head><title>Form</title></head>
1414
+ <body>
1415
+ <div id="charcode_value"></div>
1416
+ <div id="keycode_value"></div>
1417
+ <div id="which_value"></div>
1418
+ <input type="text" id="charcode" name="charcode" on#{event}="setcharcode" />
1419
+ <script type="text/javascript">
1420
+ var element = document.getElementById("charcode")
1421
+ element.addEventListener("#{event}", setcharcode);
1422
+ function setcharcode(event) {
1423
+ var element = document.getElementById("charcode_value");
1424
+ element.innerHTML = event.charCode;
1425
+ element = document.getElementById("keycode_value");
1426
+ element.innerHTML = event.keyCode;
1427
+ element = document.getElementById("which_value");
1428
+ element.innerHTML = event.which;
1429
+ }
1430
+ </script>
1431
+ </body>
1432
+ </html>
1433
+ HTML
1434
+ body
1435
+ end
1436
+
1437
+ def charCode_for(character)
1438
+ subject.find("//input")[0].set(character)
1439
+ subject.find("//div[@id='charcode_value']")[0].text
1440
+ end
1441
+
1442
+ def keyCode_for(character)
1443
+ subject.find("//input")[0].set(character)
1444
+ subject.find("//div[@id='keycode_value']")[0].text
1445
+ end
1446
+
1447
+ def which_for(character)
1448
+ subject.find("//input")[0].set(character)
1449
+ subject.find("//div[@id='which_value']")[0].text
1450
+ end
1451
+
1375
1452
  context "keypress app" do
1376
1453
  before(:all) do
1377
1454
  @app = lambda do |env|
1378
- body = <<-HTML
1379
- <html>
1380
- <head><title>Form</title></head>
1381
- <body>
1382
- <div id="charcode_value"></div>
1383
- <input type="text" id="charcode" name="charcode" onkeypress="setcharcode" />
1384
- <script type="text/javascript">
1385
- var element = document.getElementById("charcode")
1386
- element.addEventListener("keypress", setcharcode);
1387
- function setcharcode(event) {
1388
- var element = document.getElementById("charcode_value");
1389
- element.innerHTML = event.charCode;
1390
- }
1391
- </script>
1392
- </body>
1393
- </html>
1394
- HTML
1455
+ body = key_app_body("keypress")
1395
1456
  [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]]
1396
1457
  end
1397
1458
  end
1398
1459
 
1399
1460
  it "returns the charCode for the keypressed" do
1400
- subject.find("//input")[0].set("a")
1401
- subject.find("//div")[0].text.should == "97"
1461
+ charCode_for("a").should == "97"
1462
+ charCode_for("A").should == "65"
1463
+ charCode_for("\r").should == "13"
1464
+ charCode_for(",").should == "44"
1465
+ charCode_for("<").should == "60"
1466
+ charCode_for("0").should == "48"
1467
+ end
1468
+
1469
+ it "returns the keyCode for the keypressed" do
1470
+ keyCode_for("a").should == "97"
1471
+ keyCode_for("A").should == "65"
1472
+ keyCode_for("\r").should == "13"
1473
+ keyCode_for(",").should == "44"
1474
+ keyCode_for("<").should == "60"
1475
+ keyCode_for("0").should == "48"
1476
+ end
1477
+
1478
+ it "returns the which for the keypressed" do
1479
+ which_for("a").should == "97"
1480
+ which_for("A").should == "65"
1481
+ which_for("\r").should == "13"
1482
+ which_for(",").should == "44"
1483
+ which_for("<").should == "60"
1484
+ which_for("0").should == "48"
1485
+ end
1486
+ end
1487
+
1488
+ shared_examples "a keyupdown app" do
1489
+ it "returns a 0 charCode for the event" do
1490
+ charCode_for("a").should == "0"
1491
+ charCode_for("A").should == "0"
1492
+ charCode_for("\r").should == "0"
1493
+ charCode_for(",").should == "0"
1494
+ charCode_for("<").should == "0"
1495
+ charCode_for("0").should == "0"
1496
+ end
1497
+
1498
+ it "returns the keyCode for the event" do
1499
+ keyCode_for("a").should == "65"
1500
+ keyCode_for("A").should == "65"
1501
+ keyCode_for("\r").should == "13"
1502
+ keyCode_for(",").should == "188"
1503
+ keyCode_for("<").should == "188"
1504
+ keyCode_for("0").should == "48"
1505
+ end
1506
+
1507
+ it "returns the which for the event" do
1508
+ which_for("a").should == "65"
1509
+ which_for("A").should == "65"
1510
+ which_for("\r").should == "13"
1511
+ which_for(",").should == "188"
1512
+ which_for("<").should == "188"
1513
+ which_for("0").should == "48"
1514
+ end
1515
+ end
1516
+
1517
+ context "keydown app" do
1518
+ before(:all) do
1519
+ @app = lambda do |env|
1520
+ body = key_app_body("keydown")
1521
+ [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]]
1522
+ end
1523
+ end
1524
+ it_behaves_like "a keyupdown app"
1525
+ end
1526
+
1527
+ context "keyup app" do
1528
+ before(:all) do
1529
+ @app = lambda do |env|
1530
+ body = key_app_body("keyup")
1531
+ [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]]
1532
+ end
1533
+ end
1534
+
1535
+ it_behaves_like "a keyupdown app"
1536
+ end
1537
+
1538
+ context "null byte app" do
1539
+ before(:all) do
1540
+ @app = lambda do |env|
1541
+ body = "Hello\0World"
1542
+ [200,
1543
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
1544
+ [body]]
1545
+ end
1546
+ end
1547
+
1548
+ it "should include all the bytes in the source" do
1549
+ subject.source.should == "Hello\0World"
1402
1550
  end
1403
1551
  end
1404
1552
  end