webkit_remote 0.1.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/.document +5 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +114 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/lib/webkit_remote/browser.rb +150 -0
- data/lib/webkit_remote/client/page.rb +59 -0
- data/lib/webkit_remote/client/page_events.rb +45 -0
- data/lib/webkit_remote/client/runtime.rb +406 -0
- data/lib/webkit_remote/client.rb +114 -0
- data/lib/webkit_remote/event.rb +138 -0
- data/lib/webkit_remote/process.rb +160 -0
- data/lib/webkit_remote/rpc.rb +205 -0
- data/lib/webkit_remote/top_level.rb +31 -0
- data/lib/webkit_remote.rb +12 -0
- data/test/fixtures/config.ru +12 -0
- data/test/fixtures/html/load.html +7 -0
- data/test/fixtures/html/runtime.html +31 -0
- data/test/helper.rb +44 -0
- data/test/webkit_remote/browser_test.rb +80 -0
- data/test/webkit_remote/client/page_test.rb +31 -0
- data/test/webkit_remote/client/remote_object_group_test.rb +81 -0
- data/test/webkit_remote/client/remote_object_test.rb +133 -0
- data/test/webkit_remote/client/runtime_test.rb +109 -0
- data/test/webkit_remote/client_test.rb +99 -0
- data/test/webkit_remote/event_test.rb +83 -0
- data/test/webkit_remote/process_test.rb +52 -0
- data/test/webkit_remote/rpc_test.rb +55 -0
- data/test/webkit_remote_test.rb +63 -0
- metadata +274 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# Top-level namespace.
|
2
|
+
module WebkitRemote
|
3
|
+
# Launches a WebKit process locally, and sets up a debugger client for it.
|
4
|
+
#
|
5
|
+
# @param (see WebkitRemote::Process#initialize)
|
6
|
+
# @return [WebkitRemote::Client] a debugging client connected to a local
|
7
|
+
# WebKit process; the client will automatically stop the process when
|
8
|
+
# closed
|
9
|
+
def self.local(opts = {})
|
10
|
+
process = WebkitRemote::Process.new opts
|
11
|
+
browser = process.start
|
12
|
+
browser.stop_process = true
|
13
|
+
client = WebkitRemote::Client.new tab: browser.tabs.first,
|
14
|
+
close_browser: true
|
15
|
+
client
|
16
|
+
end
|
17
|
+
|
18
|
+
# Connects to a Webkit process, and sets up a debugger client for it.
|
19
|
+
#
|
20
|
+
# @param (see WebkitRemote::Browser#initialize)
|
21
|
+
# @return [WebkitRemote::Client] a debugging client connected to the remote
|
22
|
+
# WebKit process; the connection will be automatically terminated when
|
23
|
+
# the debugging client is closed
|
24
|
+
def self.remote(opts = {})
|
25
|
+
browser = WebkitRemote::Browser.new opts
|
26
|
+
# NOTE: connecting to the last tab to avoid internal tabs and whatnot
|
27
|
+
client = WebkitRemote::Client.new tab: browser.tabs.last,
|
28
|
+
close_browser: true
|
29
|
+
client
|
30
|
+
end
|
31
|
+
end # namespace WebkitRemote
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module WebkitRemote; end
|
2
|
+
require 'webkit_remote/top_level.rb'
|
3
|
+
|
4
|
+
require 'webkit_remote/browser.rb'
|
5
|
+
require 'webkit_remote/process.rb'
|
6
|
+
require 'webkit_remote/rpc.rb'
|
7
|
+
|
8
|
+
require 'webkit_remote/client.rb'
|
9
|
+
require 'webkit_remote/event.rb'
|
10
|
+
require 'webkit_remote/client/page.rb'
|
11
|
+
require 'webkit_remote/client/page_events.rb'
|
12
|
+
require 'webkit_remote/client/runtime.rb'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup :default, :development
|
3
|
+
|
4
|
+
use Rack::Static, urls: ['/html'], root: 'test/fixtures'
|
5
|
+
app = lambda do |env|
|
6
|
+
[
|
7
|
+
200,
|
8
|
+
{'Content-Type' => 'text/plain'},
|
9
|
+
['Fixture app catch-all page. Invalid test URL.']
|
10
|
+
]
|
11
|
+
end
|
12
|
+
run app
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>WebkitRemote Runtime test</title>
|
5
|
+
<script type="text/javascript">
|
6
|
+
(function() {
|
7
|
+
window.test_fn = function(hello, ruby) {
|
8
|
+
return hello + ruby;
|
9
|
+
};
|
10
|
+
var TestClass = function (hello) {
|
11
|
+
this.hello = hello;
|
12
|
+
};
|
13
|
+
TestClass.prototype.number = 42;
|
14
|
+
TestClass.prototype.add3 = function(hello, again, ruby) {
|
15
|
+
return this.hello + hello + again + ruby;
|
16
|
+
};
|
17
|
+
TestClass.prototype.greetings = function(arg1, arg2) {
|
18
|
+
return new TestClass(this.hello + ', ' + arg1.hello + ' and ' +
|
19
|
+
arg2.hello);
|
20
|
+
};
|
21
|
+
TestClass.prototype.toString = function() {
|
22
|
+
return this.hello;
|
23
|
+
};
|
24
|
+
window.TestClass = TestClass;
|
25
|
+
})();
|
26
|
+
</script>
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
<p>tbd</p>
|
30
|
+
</body>
|
31
|
+
</html>
|
data/test/helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'minitest/unit'
|
11
|
+
require 'minitest/spec'
|
12
|
+
|
13
|
+
require 'simplecov'
|
14
|
+
SimpleCov.start
|
15
|
+
|
16
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
18
|
+
require 'webkit_remote'
|
19
|
+
|
20
|
+
require 'thread'
|
21
|
+
Thread.abort_on_exception = true
|
22
|
+
|
23
|
+
# Launch a dev server and wait until it starts.
|
24
|
+
pid = Process.spawn 'bundle exec puma --port 9969 --quiet test/fixtures/config.ru',
|
25
|
+
:in => '/dev/null', :out => '/dev/null'
|
26
|
+
Process.detach pid
|
27
|
+
at_exit { Process.kill 'TERM', pid }
|
28
|
+
loop do
|
29
|
+
begin
|
30
|
+
response = Net::HTTP.get_response URI.parse('http://localhost:9969')
|
31
|
+
break if response.kind_of?(Net::HTTPSuccess)
|
32
|
+
rescue SystemCallError
|
33
|
+
sleep 0.1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class MiniTest::Unit::TestCase
|
38
|
+
# URL for a file in the test/fixtures directory.
|
39
|
+
def fixture_url(name)
|
40
|
+
"http://localhost:9969/html/#{name}.html"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
MiniTest::Unit.autorun
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.expand_path('../helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe WebkitRemote::Browser do
|
4
|
+
before :each do
|
5
|
+
@process = WebkitRemote::Process.new port: 9669
|
6
|
+
@process.start
|
7
|
+
end
|
8
|
+
after :each do
|
9
|
+
@process.stop if @process
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'with process' do
|
13
|
+
before :each do
|
14
|
+
@browser = WebkitRemote::Browser.new process: @process
|
15
|
+
end
|
16
|
+
after :each do
|
17
|
+
@browser.close if @browser
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'sets the host and port correctly' do
|
21
|
+
@browser.host.must_equal 'localhost'
|
22
|
+
@browser.port.must_equal 9669
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'enumerates the browser tabs correctly' do
|
26
|
+
tabs = @browser.tabs
|
27
|
+
tabs.length.must_equal 1
|
28
|
+
tabs.first.must_be_kind_of WebkitRemote::Browser::Tab
|
29
|
+
tabs.first.browser.must_equal @browser
|
30
|
+
tabs.first.debug_url.must_match(/^ws:\/\/localhost:9669\//)
|
31
|
+
tabs.first.url.must_equal 'about:blank'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'does not auto-stop the process by default' do
|
35
|
+
@browser.stop_process?.must_equal false
|
36
|
+
@browser.close
|
37
|
+
@browser.closed?.must_equal true
|
38
|
+
@process.running?.must_equal true
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'with process auto-stopping' do
|
42
|
+
before do
|
43
|
+
@browser.stop_process = true
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'stops the process when closed' do
|
47
|
+
@browser.stop_process?.must_equal true
|
48
|
+
@browser.close
|
49
|
+
@browser.closed?.must_equal true
|
50
|
+
@process.running?.must_equal false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'with host/port' do
|
56
|
+
before :each do
|
57
|
+
@browser = WebkitRemote::Browser.new host: 'localhost', port: 9669
|
58
|
+
end
|
59
|
+
after :each do
|
60
|
+
@browser.close if @browser
|
61
|
+
end
|
62
|
+
|
63
|
+
it "does not support process auto-stopping" do
|
64
|
+
@browser.stop_process.must_equal false
|
65
|
+
lambda {
|
66
|
+
@browser.stop_process = true
|
67
|
+
}.must_raise ArgumentError
|
68
|
+
@browser.stop_process.must_equal false
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'enumerates the browser tabs correctly' do
|
72
|
+
tabs = @browser.tabs
|
73
|
+
tabs.length.must_equal 1
|
74
|
+
tabs.first.must_be_kind_of WebkitRemote::Browser::Tab
|
75
|
+
tabs.first.browser.must_equal @browser
|
76
|
+
tabs.first.debug_url.must_match(/^ws:\/\/localhost:9669\//)
|
77
|
+
tabs.first.url.must_equal 'about:blank'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path('../../helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe WebkitRemote::Client::Page do
|
4
|
+
before do
|
5
|
+
@client = WebkitRemote.local port: 9669
|
6
|
+
end
|
7
|
+
after do
|
8
|
+
@client.close
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'navigate' do
|
12
|
+
before do
|
13
|
+
@url = fixture_url(:load)
|
14
|
+
@client.page_events = true
|
15
|
+
@client.navigate_to @url
|
16
|
+
@events = []
|
17
|
+
@client.each_event do |event|
|
18
|
+
@events << event
|
19
|
+
break if event.kind_of?(WebkitRemote::Event::PageLoaded)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'changes the tab URL' do
|
24
|
+
@client.browser.tabs.map(&:url).must_include @url
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'fires a PageLoaded event' do
|
28
|
+
@events.map(&:class).must_include WebkitRemote::Event::PageLoaded
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.expand_path('../../helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe WebkitRemote::Client::RemoteObjectGroup do
|
4
|
+
before :each do
|
5
|
+
@client = WebkitRemote.local port: 9669
|
6
|
+
@client.page_events = true
|
7
|
+
@client.navigate_to fixture_url(:runtime)
|
8
|
+
@client.wait_for type: WebkitRemote::Event::PageLoaded
|
9
|
+
|
10
|
+
@object1 = @client.remote_eval '({})', group: 'g1'
|
11
|
+
@object2 = @client.remote_eval '({})', group: 'g1'
|
12
|
+
@object3 = @client.remote_eval '({})', group: 'g2'
|
13
|
+
@group1 = @client.object_group 'g1'
|
14
|
+
@group2 = @client.object_group 'g2'
|
15
|
+
end
|
16
|
+
after :each do
|
17
|
+
@group1.release_all if @group1
|
18
|
+
@group2.release_all if @group2
|
19
|
+
@client.close
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'include?' do
|
23
|
+
it 'is true for objects in the group' do
|
24
|
+
@group1.include?(@object1).must_equal true
|
25
|
+
@group1.include?(@object2).must_equal true
|
26
|
+
@group2.include?(@object3).must_equal true
|
27
|
+
end
|
28
|
+
it 'is false for objects in different groups' do
|
29
|
+
@group2.include?(@object2).must_equal false
|
30
|
+
@group1.include?(@object3).must_equal false
|
31
|
+
@group2.include?(@object1).must_equal false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'after an object release' do
|
36
|
+
before :each do
|
37
|
+
@object1.release
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not include the released object' do
|
41
|
+
@group1.include?(@object1).must_equal false
|
42
|
+
end
|
43
|
+
it 'includes unreleased objects' do
|
44
|
+
@group1.include?(@object2).must_equal true
|
45
|
+
end
|
46
|
+
it 'does not release the whole group' do
|
47
|
+
@group1.released?.must_equal false
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'after releasing the only other object in the group' do
|
51
|
+
before :each do
|
52
|
+
@object2.release
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'released the whole group' do
|
56
|
+
@group1.released?.must_equal true
|
57
|
+
end
|
58
|
+
it 'removes the group from the client' do
|
59
|
+
@client.object_group('g1').must_equal nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#release_all' do
|
65
|
+
before :each do
|
66
|
+
@group1.release_all
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'releases all the objects in the group' do
|
70
|
+
@object1.released?.must_equal true
|
71
|
+
@object2.released?.must_equal true
|
72
|
+
end
|
73
|
+
it 'does not release objects in other groups' do
|
74
|
+
@object3.released?.must_equal false
|
75
|
+
end
|
76
|
+
it 'releases the group and removes the group from the client' do
|
77
|
+
@group1.released?.must_equal true
|
78
|
+
@client.object_group('g1').must_equal nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.expand_path('../../helper.rb', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe WebkitRemote::Client::RemoteObject do
|
4
|
+
before :each do
|
5
|
+
@client = WebkitRemote.local port: 9669
|
6
|
+
@client.page_events = true
|
7
|
+
@client.navigate_to fixture_url(:runtime)
|
8
|
+
@client.wait_for type: WebkitRemote::Event::PageLoaded
|
9
|
+
end
|
10
|
+
after :each do
|
11
|
+
@client.close
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'properties' do
|
15
|
+
describe 'with simple JSON' do
|
16
|
+
before :each do
|
17
|
+
@object = @client.remote_eval 'window.t = ({answer: 42, test: true})'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'enumerates the properties correctly' do
|
21
|
+
@object.properties[:answer].name.must_equal :answer
|
22
|
+
@object.properties[:test].name.must_equal :test
|
23
|
+
@object.properties[:other].must_equal nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'gets the correct values' do
|
27
|
+
@object.properties[:answer].value.must_equal 42
|
28
|
+
@object.properties[:test].value.must_equal true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'sets owner correctly' do
|
32
|
+
@object.properties[:answer].owner.must_equal @object
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'does not have extra properties' do
|
36
|
+
@object.properties.select { |name, property| property.enumerable? }.
|
37
|
+
keys.sort.must_equal [:answer, :test]
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'recognizes writable properties' do
|
41
|
+
@object.properties[:answer].writable?.must_equal true
|
42
|
+
@object.properties[:constructor].writable?.must_equal false
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'recognizes configurable properties' do
|
46
|
+
@object.properties[:answer].configurable?.must_equal true
|
47
|
+
@object.properties[:constructor].configurable?.must_equal false
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'recognizes enumerable properties' do
|
51
|
+
@object.properties[:answer].enumerable?.must_equal true
|
52
|
+
@object.properties[:constructor].enumerable?.must_equal false
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'after property update' do
|
56
|
+
before do
|
57
|
+
@object.properties[:DONE]
|
58
|
+
@client.remote_eval 'window.t.test = "updated"'
|
59
|
+
end
|
60
|
+
it 'does not automatically refresh' do
|
61
|
+
@object.properties[:test].value.must_equal true
|
62
|
+
end
|
63
|
+
it 'refreshes when properties! is called' do
|
64
|
+
@object.properties![:test].value.must_equal 'updated'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'with the XMHttpRequest built-in' do
|
70
|
+
before :each do
|
71
|
+
@object = @client.remote_eval 'XMLHttpRequest'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'recognizes configurable, non-writable, enumerable properties' do
|
75
|
+
@object.properties[:DONE].configurable?.must_equal true
|
76
|
+
@object.properties[:DONE].writable?.must_equal false
|
77
|
+
@object.properties[:DONE].enumerable?.must_equal true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'bound_call' do
|
83
|
+
before :each do
|
84
|
+
@object = @client.remote_eval 'new TestClass("hello ruby")', group: 'g1'
|
85
|
+
end
|
86
|
+
after :each do
|
87
|
+
group = @client.object_group 'g1'
|
88
|
+
group.release_all if group
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'with a function that operates on primitives' do
|
92
|
+
before :each do
|
93
|
+
@result = @object.bound_call 'TestClass.prototype.add3',
|
94
|
+
' answer:', 4, 2
|
95
|
+
end
|
96
|
+
it 'returns a native primitive type' do
|
97
|
+
@result.must_equal 'hello ruby answer:42'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'with a function that returns a primitive' do
|
102
|
+
before :each do
|
103
|
+
@arg1 = @client.remote_eval 'new TestClass(" again")', group: 'g1'
|
104
|
+
@arg2 = @client.remote_eval 'new TestClass(" ruby")', group: 'g2'
|
105
|
+
@result = @object.bound_call 'TestClass.prototype.add3', ' hello',
|
106
|
+
@arg1, @arg2
|
107
|
+
end
|
108
|
+
it 'returns a native primitive type' do
|
109
|
+
@result.must_equal 'hello ruby hello again ruby'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'with objects' do
|
114
|
+
before :each do
|
115
|
+
@arg1 = @client.remote_eval '({hello: "rbx", goodbye: "java"})',
|
116
|
+
group: 'g1'
|
117
|
+
@arg2 = @client.remote_eval '({hello: "jruby", goodbye: "java2"})',
|
118
|
+
group: 'g2'
|
119
|
+
@result = @object.bound_call 'TestClass.prototype.greetings',
|
120
|
+
@arg1, @arg2
|
121
|
+
end
|
122
|
+
it 'passes the objects and returns an object correctly' do
|
123
|
+
@result.must_be_kind_of WebkitRemote::Client::RemoteObject
|
124
|
+
@result.js_class_name.must_equal 'TestClass'
|
125
|
+
@result.bound_call('TestClass.prototype.toString').
|
126
|
+
must_equal 'hello ruby, rbx and jruby'
|
127
|
+
end
|
128
|
+
it 'adds the result to the target group' do
|
129
|
+
@result.group.must_equal @object.group
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|