opal-browser 0.2.0.beta1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/build.yml +95 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +17 -3
- data/LICENSE +2 -1
- data/README.md +183 -52
- data/Rakefile +29 -1
- data/config.ru +20 -3
- data/docs/polyfills.md +24 -0
- data/examples/2048/Gemfile +6 -0
- data/examples/2048/README.md +13 -0
- data/examples/2048/app/application.rb +169 -0
- data/examples/2048/config.ru +9 -0
- data/examples/canvas/Gemfile +6 -0
- data/examples/canvas/README.md +9 -0
- data/examples/canvas/app/application.rb +55 -0
- data/examples/canvas/config.ru +9 -0
- data/examples/component/Gemfile +6 -0
- data/examples/component/README.md +10 -0
- data/examples/component/app/application.rb +66 -0
- data/examples/component/config.ru +9 -0
- data/examples/integrations/README.md +24 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/Gemfile +6 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/README.md +16 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/app/application.rb +6 -0
- data/examples/integrations/dynamic-rack-opal-sprockets-server/config.ru +9 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/.gitignore +1 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/Gemfile +7 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/README.md +22 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/Rakefile +4 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/app/application.rb +6 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/app.rb +32 -0
- data/examples/integrations/dynamic-roda-roda-sprockets/config.ru +3 -0
- data/examples/integrations/dynamic-roda-tilt/.gitignore +1 -0
- data/examples/integrations/dynamic-roda-tilt/Gemfile +8 -0
- data/examples/integrations/dynamic-roda-tilt/README.md +17 -0
- data/examples/integrations/dynamic-roda-tilt/Rakefile +6 -0
- data/examples/integrations/dynamic-roda-tilt/app/application.rb +6 -0
- data/examples/integrations/dynamic-roda-tilt/app.rb +50 -0
- data/examples/integrations/dynamic-roda-tilt/config.ru +3 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/Gemfile +7 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/README.md +16 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/app/application.rb +6 -0
- data/examples/integrations/dynamic-sinatra-opal-sprockets-server/config.ru +29 -0
- data/examples/integrations/static-bash/.gitignore +2 -0
- data/examples/integrations/static-bash/Gemfile +3 -0
- data/examples/integrations/static-bash/README.md +8 -0
- data/examples/integrations/static-bash/app/application.rb +6 -0
- data/examples/integrations/static-bash/build.sh +4 -0
- data/examples/integrations/static-bash/index.html +10 -0
- data/examples/integrations/static-bash-opal-parser/.gitignore +3 -0
- data/examples/integrations/static-bash-opal-parser/Gemfile +3 -0
- data/examples/integrations/static-bash-opal-parser/README.md +10 -0
- data/examples/integrations/static-bash-opal-parser/build.sh +4 -0
- data/examples/integrations/static-bash-opal-parser/index.html +19 -0
- data/examples/integrations/static-rake/.gitignore +1 -0
- data/examples/integrations/static-rake/Gemfile +4 -0
- data/examples/integrations/static-rake/README.md +7 -0
- data/examples/integrations/static-rake/Rakefile +10 -0
- data/examples/integrations/static-rake/app/application.rb +6 -0
- data/examples/integrations/static-rake/index.html +9 -0
- data/examples/integrations/static-rake-guard/.gitignore +1 -0
- data/examples/integrations/static-rake-guard/Gemfile +6 -0
- data/examples/integrations/static-rake-guard/Guardfile +3 -0
- data/examples/integrations/static-rake-guard/README.md +10 -0
- data/examples/integrations/static-rake-guard/Rakefile +10 -0
- data/examples/integrations/static-rake-guard/app/application.rb +6 -0
- data/examples/integrations/static-rake-guard/index.html +9 -0
- data/examples/svg/.gitignore +1 -0
- data/examples/svg/Gemfile +4 -0
- data/examples/svg/README.md +7 -0
- data/examples/svg/Rakefile +10 -0
- data/examples/svg/app/application.rb +11 -0
- data/examples/svg/index.html +17 -0
- data/examples/svg/index.svg +6 -0
- data/index.html.erb +8 -6
- data/lib/opal-browser.rb +1 -0
- data/opal/browser/animation_frame.rb +26 -1
- data/opal/browser/audio/node.rb +121 -0
- data/opal/browser/audio/param_schedule.rb +43 -0
- data/opal/browser/audio.rb +66 -0
- data/opal/browser/blob.rb +94 -0
- data/opal/browser/canvas/data.rb +1 -11
- data/opal/browser/canvas/gradient.rb +1 -11
- data/opal/browser/canvas/style.rb +3 -11
- data/opal/browser/canvas/text.rb +1 -11
- data/opal/browser/canvas.rb +17 -13
- data/opal/browser/console.rb +3 -1
- data/opal/browser/cookies.rb +78 -42
- data/opal/browser/crypto.rb +79 -0
- data/opal/browser/css/declaration.rb +1 -1
- data/opal/browser/css/rule.rb +1 -1
- data/opal/browser/css/style_sheet.rb +2 -2
- data/opal/browser/css.rb +23 -7
- data/opal/browser/database/sql.rb +193 -0
- data/opal/browser/delay.rb +41 -7
- data/opal/browser/dom/attribute.rb +13 -12
- data/opal/browser/dom/builder.rb +31 -17
- data/opal/browser/dom/document.rb +174 -42
- data/opal/browser/dom/document_fragment.rb +18 -0
- data/opal/browser/dom/document_or_shadow_root.rb +19 -0
- data/opal/browser/dom/element/attributes.rb +111 -0
- data/opal/browser/dom/element/button.rb +31 -0
- data/opal/browser/dom/element/custom.rb +177 -0
- data/opal/browser/dom/element/data.rb +82 -0
- data/opal/browser/dom/element/editable.rb +47 -0
- data/opal/browser/dom/element/form.rb +38 -0
- data/opal/browser/dom/element/iframe.rb +37 -0
- data/opal/browser/dom/element/image.rb +2 -0
- data/opal/browser/dom/element/input.rb +48 -1
- data/opal/browser/dom/element/media.rb +17 -0
- data/opal/browser/dom/element/offset.rb +5 -0
- data/opal/browser/dom/element/position.rb +11 -2
- data/opal/browser/dom/element/scroll.rb +123 -24
- data/opal/browser/dom/element/select.rb +42 -0
- data/opal/browser/dom/element/size.rb +17 -0
- data/opal/browser/dom/element/template.rb +11 -0
- data/opal/browser/dom/element/textarea.rb +26 -0
- data/opal/browser/dom/element.rb +468 -238
- data/opal/browser/dom/mutation_observer.rb +4 -4
- data/opal/browser/dom/node.rb +142 -60
- data/opal/browser/dom/node_set.rb +73 -44
- data/opal/browser/dom/shadow_root.rb +12 -0
- data/opal/browser/dom/text.rb +2 -2
- data/opal/browser/dom.rb +40 -16
- data/opal/browser/effects.rb +180 -3
- data/opal/browser/event/all.rb +26 -0
- data/opal/browser/{dom/event → event}/animation.rb +4 -2
- data/opal/browser/{dom/event → event}/audio_processing.rb +4 -2
- data/opal/browser/{dom/event → event}/base.rb +98 -9
- data/opal/browser/{dom/event → event}/before_unload.rb +4 -2
- data/opal/browser/{dom/event → event}/clipboard.rb +11 -2
- data/opal/browser/{dom/event → event}/close.rb +4 -2
- data/opal/browser/{dom/event → event}/composition.rb +4 -2
- data/opal/browser/{dom/event → event}/custom.rb +3 -3
- data/opal/browser/event/data_transfer.rb +95 -0
- data/opal/browser/{dom/event → event}/device_light.rb +4 -2
- data/opal/browser/{dom/event → event}/device_motion.rb +4 -2
- data/opal/browser/{dom/event → event}/device_orientation.rb +4 -2
- data/opal/browser/{dom/event → event}/device_proximity.rb +4 -2
- data/opal/browser/{dom/event → event}/drag.rb +11 -7
- data/opal/browser/{dom/event → event}/focus.rb +4 -2
- data/opal/browser/{dom/event → event}/gamepad.rb +5 -3
- data/opal/browser/{dom/event → event}/hash_change.rb +4 -2
- data/opal/browser/{dom/event → event}/keyboard.rb +16 -3
- data/opal/browser/{dom/event → event}/message.rb +4 -2
- data/opal/browser/{dom/event → event}/mouse.rb +12 -8
- data/opal/browser/{dom/event → event}/page_transition.rb +4 -2
- data/opal/browser/{dom/event → event}/pop_state.rb +4 -2
- data/opal/browser/{dom/event → event}/progress.rb +4 -2
- data/opal/browser/{dom/event → event}/sensor.rb +4 -2
- data/opal/browser/{dom/event → event}/storage.rb +4 -2
- data/opal/browser/{dom/event → event}/touch.rb +4 -2
- data/opal/browser/{dom/event → event}/ui.rb +2 -2
- data/opal/browser/{dom/event → event}/wheel.rb +4 -2
- data/opal/browser/event.rb +163 -0
- data/opal/browser/event_source.rb +2 -2
- data/opal/browser/form_data.rb +225 -0
- data/opal/browser/history.rb +4 -8
- data/opal/browser/http/binary.rb +1 -0
- data/opal/browser/http/headers.rb +16 -2
- data/opal/browser/http/request.rb +46 -48
- data/opal/browser/http/response.rb +5 -1
- data/opal/browser/http.rb +25 -2
- data/opal/browser/immediate.rb +9 -5
- data/opal/browser/interval.rb +34 -11
- data/opal/browser/location.rb +7 -1
- data/opal/browser/navigator.rb +127 -7
- data/opal/browser/polyfill/visual_viewport.rb +216 -0
- data/opal/browser/screen.rb +3 -3
- data/opal/browser/setup/base.rb +6 -0
- data/opal/browser/setup/full.rb +13 -0
- data/opal/browser/setup/large.rb +17 -0
- data/opal/browser/setup/mini.rb +8 -0
- data/opal/browser/setup/traditional.rb +10 -0
- data/opal/browser/socket.rb +8 -4
- data/opal/browser/storage.rb +53 -35
- data/opal/browser/support.rb +72 -5
- data/opal/browser/utils.rb +94 -14
- data/opal/browser/version.rb +1 -1
- data/opal/browser/visual_viewport.rb +39 -0
- data/opal/browser/window/size.rb +31 -3
- data/opal/browser/window/view.rb +15 -0
- data/opal/browser/window.rb +46 -25
- data/opal/browser.rb +1 -10
- data/opal/opal-browser.rb +1 -0
- data/opal-browser.gemspec +3 -3
- data/spec/database/sql_spec.rb +139 -0
- data/spec/delay_spec.rb +41 -0
- data/spec/dom/attribute_spec.rb +49 -0
- data/spec/dom/builder_spec.rb +25 -8
- data/spec/dom/document_spec.rb +22 -0
- data/spec/dom/element/attributes_spec.rb +52 -0
- data/spec/dom/element/custom_spec.rb +106 -0
- data/spec/dom/element/subclass_spec.rb +144 -0
- data/spec/dom/element_spec.rb +181 -4
- data/spec/dom/mutation_observer_spec.rb +12 -8
- data/spec/dom/node_set_spec.rb +44 -0
- data/spec/dom/node_spec.rb +48 -0
- data/spec/dom_spec.rb +8 -0
- data/spec/event_source_spec.rb +15 -12
- data/spec/{dom/event_spec.rb → event_spec.rb} +44 -15
- data/spec/history_spec.rb +23 -19
- data/spec/http_spec.rb +19 -31
- data/spec/immediate_spec.rb +5 -4
- data/spec/interval_spec.rb +59 -0
- data/spec/native_cached_wrapper_spec.rb +46 -0
- data/spec/runner.rb +62 -69
- data/spec/socket_spec.rb +16 -12
- data/spec/spec_helper.rb +2 -5
- data/spec/spec_helper_promise.rb.erb +25 -0
- data/spec/storage_spec.rb +1 -1
- metadata +172 -50
- data/.travis.yml +0 -60
- data/opal/browser/dom/event.rb +0 -253
- data/opal/browser/http/parameters.rb +0 -8
- data/opal/browser/window/scroll.rb +0 -59
data/spec/history_spec.rb
CHANGED
@@ -19,39 +19,43 @@ describe Browser::History do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
describe '#back' do
|
22
|
-
|
22
|
+
it 'should go back once' do
|
23
23
|
expect($window.history.current).to eq('/')
|
24
24
|
$window.history.push('/wut')
|
25
25
|
expect($window.history.current).to eq('/wut')
|
26
26
|
|
27
|
-
|
28
|
-
e.off
|
27
|
+
promise = Browser::Promise.new
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
$window.one 'pop:state' do |e|
|
30
|
+
expect($window.history.current).to eq('/')
|
31
|
+
promise.resolve
|
33
32
|
end
|
34
33
|
|
35
34
|
$window.history.back
|
35
|
+
promise.for_rspec
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
describe '#state' do
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
40
|
+
it 'gets the right state' do
|
41
|
+
# XX: The previous test creates a race condition with this one.
|
42
|
+
# Adding a delay fixes it.
|
43
|
+
promise = Browser::Promise.new
|
44
|
+
|
45
|
+
after 0.05 do
|
46
|
+
$window.history.push('/wut', 42)
|
47
|
+
$window.history.state.should eq(42)
|
48
|
+
$window.history.push('/omg', 23)
|
49
|
+
$window.history.state.should eq(23)
|
50
|
+
|
51
|
+
$window.one 'pop:state' do |e|
|
50
52
|
expect(true).to eq(true)
|
51
|
-
|
52
|
-
|
53
|
+
promise.resolve
|
54
|
+
end
|
53
55
|
|
54
|
-
|
56
|
+
$window.history.back(2)
|
57
|
+
end
|
58
|
+
promise.for_rspec
|
55
59
|
end
|
56
60
|
end if Browser.supports? 'History.state'
|
57
61
|
end if Browser::History.supported?
|
data/spec/http_spec.rb
CHANGED
@@ -2,20 +2,15 @@ require 'spec_helper'
|
|
2
2
|
require 'browser/http'
|
3
3
|
|
4
4
|
describe Browser::HTTP do
|
5
|
-
let
|
6
|
-
|
7
|
-
end
|
5
|
+
let(:path) { '/http' }
|
6
|
+
let(:path_file) { '/http-file' }
|
8
7
|
|
9
8
|
describe '.get' do
|
10
|
-
|
9
|
+
it 'fetches a path' do
|
11
10
|
Browser::HTTP.get(path).then {|res|
|
12
|
-
|
13
|
-
expect(res.text).to eq('lol')
|
14
|
-
}
|
11
|
+
expect(res.text).to eq('lol')
|
15
12
|
}.rescue {
|
16
|
-
|
17
|
-
fail
|
18
|
-
}
|
13
|
+
fail
|
19
14
|
}
|
20
15
|
end
|
21
16
|
end
|
@@ -27,15 +22,11 @@ describe Browser::HTTP do
|
|
27
22
|
end
|
28
23
|
|
29
24
|
describe '.post' do
|
30
|
-
|
25
|
+
it 'sends parameters properly' do
|
31
26
|
Browser::HTTP.post(path, lol: 'wut').then {|res|
|
32
|
-
|
33
|
-
expect(res.text).to eq('ok')
|
34
|
-
}
|
27
|
+
expect(res.text).to eq('ok')
|
35
28
|
}.rescue {
|
36
|
-
|
37
|
-
fail
|
38
|
-
}
|
29
|
+
fail
|
39
30
|
}
|
40
31
|
end
|
41
32
|
end
|
@@ -44,18 +35,19 @@ describe Browser::HTTP do
|
|
44
35
|
it 'sends parameters properly' do
|
45
36
|
expect(Browser::HTTP.post!(path, lol: 'wut').text).to eq('ok')
|
46
37
|
end
|
38
|
+
|
39
|
+
it 'sends files properly' do
|
40
|
+
file = Browser::File.create(["content"], "yay.txt", type: "text/plain")
|
41
|
+
expect(Browser::HTTP.post!(path_file, lol: 'wut', file: file).text).to eq('ok')
|
42
|
+
end
|
47
43
|
end
|
48
44
|
|
49
45
|
describe '.put' do
|
50
|
-
|
46
|
+
it 'sends parameters properly' do
|
51
47
|
Browser::HTTP.put(path, lol: 'wut').then {|res|
|
52
|
-
|
53
|
-
expect(res.text).to eq('ok')
|
54
|
-
}
|
48
|
+
expect(res.text).to eq('ok')
|
55
49
|
}.rescue {
|
56
|
-
|
57
|
-
fail
|
58
|
-
}
|
50
|
+
fail
|
59
51
|
}
|
60
52
|
end
|
61
53
|
end
|
@@ -67,15 +59,11 @@ describe Browser::HTTP do
|
|
67
59
|
end
|
68
60
|
|
69
61
|
describe '.delete' do
|
70
|
-
|
62
|
+
it 'fetches a path' do
|
71
63
|
Browser::HTTP.delete(path).then {|res|
|
72
|
-
|
73
|
-
expect(res.text).to eq('lol')
|
74
|
-
}
|
64
|
+
expect(res.text).to eq('lol')
|
75
65
|
}.rescue {
|
76
|
-
|
77
|
-
fail
|
78
|
-
}
|
66
|
+
fail
|
79
67
|
}
|
80
68
|
end
|
81
69
|
end
|
data/spec/immediate_spec.rb
CHANGED
@@ -3,12 +3,13 @@ require 'browser/immediate'
|
|
3
3
|
|
4
4
|
describe Proc do
|
5
5
|
describe '#defer' do
|
6
|
-
|
6
|
+
it 'defers the parameters' do
|
7
|
+
promise = Browser::Promise.new
|
7
8
|
proc {|a|
|
8
|
-
|
9
|
-
|
10
|
-
}
|
9
|
+
expect(a).to eq(42)
|
10
|
+
promise.resolve
|
11
11
|
}.defer(42)
|
12
|
+
promise.for_rspec
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'browser/interval'
|
3
|
+
|
4
|
+
describe Browser::Window do
|
5
|
+
describe '#every' do
|
6
|
+
it 'calls the block multiple times' do
|
7
|
+
x = 0
|
8
|
+
|
9
|
+
promise = Browser::Promise.new
|
10
|
+
$window.every 0.3 do
|
11
|
+
x += 1
|
12
|
+
|
13
|
+
if x == 3
|
14
|
+
expect(true).to be_truthy
|
15
|
+
promise.resolve
|
16
|
+
end
|
17
|
+
end
|
18
|
+
promise.for_rspec
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Kernel do
|
24
|
+
describe '#every' do
|
25
|
+
it 'calls the block multiple times' do
|
26
|
+
x = 0
|
27
|
+
|
28
|
+
promise = Browser::Promise.new
|
29
|
+
every 0.3 do
|
30
|
+
x += 1
|
31
|
+
|
32
|
+
if x == 3
|
33
|
+
expect(true).to be_truthy
|
34
|
+
promise.resolve
|
35
|
+
end
|
36
|
+
end
|
37
|
+
promise.for_rspec
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe Proc do
|
43
|
+
describe '#every' do
|
44
|
+
it 'calls the block multiple times' do
|
45
|
+
x = 0
|
46
|
+
|
47
|
+
promise = Browser::Promise.new
|
48
|
+
-> {
|
49
|
+
x += 1
|
50
|
+
|
51
|
+
if x == 3
|
52
|
+
expect(true).to be_truthy
|
53
|
+
promise.resolve
|
54
|
+
end
|
55
|
+
}.every 0.3
|
56
|
+
promise.for_rspec
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Browser::NativeCachedWrapper do
|
4
|
+
it 'deduplicates DOM objects' do
|
5
|
+
expect($document.at_css("body").hash).to eq($document.body.hash)
|
6
|
+
expect($document.body.hash).not_to eq($document.body.dup.hash) # Should dup/clone have different semantics?
|
7
|
+
expect($document.body.hash).not_to eq($document.head.hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'accurately intercepts the last new call' do
|
11
|
+
class Demo
|
12
|
+
include Browser::NativeCachedWrapper
|
13
|
+
|
14
|
+
def self.new(arg1, arg2)
|
15
|
+
super(`{arg1: #{arg1}, arg2: #{arg2}}`)
|
16
|
+
end
|
17
|
+
|
18
|
+
def data
|
19
|
+
[:data, `#@native.arg1`, `#@native.arg2`]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class SuperDemo < Demo
|
24
|
+
def self.new(arg1, arg2, arg3)
|
25
|
+
super("superdemo", "#{arg1} - #{arg2} - #{arg3}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
expect(Demo.new("a", "b").data).to eq([:data, "a", "b"])
|
30
|
+
expect(SuperDemo.new("1", "2", "3").data).to eq([:data, "superdemo", "1 - 2 - 3"])
|
31
|
+
end
|
32
|
+
|
33
|
+
html <<-HTML
|
34
|
+
<iframe id='ifr' src='about:blank' sandbox=''></iframe>
|
35
|
+
HTML
|
36
|
+
|
37
|
+
it 'supports restricted objects' do
|
38
|
+
# Window won't be restricted
|
39
|
+
expect($window.restricted?).to eq(false)
|
40
|
+
# Iframe itself won't be restricted
|
41
|
+
expect($document['ifr'].restricted?).to eq(false)
|
42
|
+
# But its content_window will be (due to CORS)
|
43
|
+
expect($document['ifr'].content_window.restricted?).to eq(true)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/spec/runner.rb
CHANGED
@@ -1,67 +1,45 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
|
+
require 'webdrivers'
|
2
3
|
require 'selenium/webdriver'
|
3
4
|
require 'rest_client'
|
4
5
|
require 'json'
|
5
6
|
|
6
|
-
# setup tunnel
|
7
|
-
begin
|
8
|
-
File.open('tunnel.jar', 'w') {|f|
|
9
|
-
f.write RestClient.get('http://www.browserstack.com/BrowserStackTunnel.jar').to_str
|
10
|
-
}
|
11
|
-
|
12
|
-
tunnel = IO.popen 'java -jar tunnel.jar $BS_AUTHKEY localhost,9292,0 -tunnelIdentifier $TRAVIS_JOB_ID'
|
13
|
-
|
14
|
-
loop do
|
15
|
-
break if tunnel.gets.start_with? 'You can now access'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# configure based on environment variables
|
20
|
-
hub = "http://#{ENV['BS_USERNAME']}:#{ENV['BS_AUTHKEY']}@hub.browserstack.com/wd/hub"
|
21
|
-
plan = "https://#{ENV['BS_USERNAME']}:#{ENV['BS_AUTHKEY']}@www.browserstack.com/automate/plan.json"
|
22
|
-
cap = Selenium::WebDriver::Remote::Capabilities.new
|
23
|
-
|
24
|
-
cap['platform'] = ENV['SELENIUM_PLATFORM'] || 'ANY'
|
25
|
-
cap['browser'] = ENV['SELENIUM_BROWSER'] || 'chrome'
|
26
|
-
cap['browser_version'] = ENV['SELENIUM_VERSION'] if ENV['SELENIUM_VERSION']
|
27
|
-
|
28
|
-
cap['browserstack.tunnelIdentifier'] = ENV['TRAVIS_JOB_ID']
|
29
|
-
cap['browserstack.tunnel'] = 'true'
|
30
|
-
cap['browserstack.debug'] = 'false'
|
31
|
-
|
32
7
|
print 'Loading...'
|
33
8
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
browser.
|
49
|
-
rescue Selenium::WebDriver::Error::UnknownError
|
50
|
-
retry
|
9
|
+
browser, options = case ENV['BROWSER']
|
10
|
+
when "chrome"
|
11
|
+
opts = Selenium::WebDriver::Chrome::Options.new(args: ['--headless', '--no-sandbox'])
|
12
|
+
[:chrome, opts]
|
13
|
+
when "gecko"
|
14
|
+
opts = Selenium::WebDriver::Firefox::Options.new(args: ['--headless'])
|
15
|
+
[:firefox, opts]
|
16
|
+
when "safari"
|
17
|
+
opts = Selenium::WebDriver::Safari::Options.new()
|
18
|
+
[:safari, opts]
|
19
|
+
when "edge"
|
20
|
+
opts = Selenium::WebDriver::Edge::Options.new(args: ['--headless'])
|
21
|
+
[:edge, opts]
|
22
|
+
else
|
23
|
+
raise "Wrong web browser provided in BROWSER. Acceptable values: chrome, gecko, safari, edge"
|
51
24
|
end
|
52
25
|
|
26
|
+
browser = Selenium::WebDriver.for(browser, capabilities: options)
|
27
|
+
browser.navigate.to('http://localhost:9292')
|
28
|
+
|
53
29
|
# if we don't quit the browser it will stall
|
54
30
|
at_exit {
|
55
31
|
browser.quit
|
56
32
|
}
|
57
33
|
|
34
|
+
puts "Browser: " + browser.execute_script("return window.navigator.userAgent")
|
35
|
+
|
58
36
|
# the title is a good way to know if anything went wrong while fetching the
|
59
37
|
# page
|
60
38
|
Selenium::WebDriver::Wait.new(timeout: 30, interval: 5).until {
|
61
39
|
not browser.title.strip.empty?
|
62
40
|
}
|
63
41
|
|
64
|
-
unless browser.title =~ /Opal Browser/
|
42
|
+
unless browser.title =~ /Opal Browser|RSpec results/
|
65
43
|
puts "\rThe page failed loading."
|
66
44
|
exit 1
|
67
45
|
end
|
@@ -78,37 +56,52 @@ begin
|
|
78
56
|
puts "\r#{element.text}"
|
79
57
|
exit 1
|
80
58
|
end
|
81
|
-
rescue Selenium::WebDriver::Error::
|
59
|
+
rescue Selenium::WebDriver::Error::TimeoutError; end
|
82
60
|
|
83
61
|
print "\rRunning specs..."
|
84
62
|
|
85
|
-
|
86
|
-
|
87
|
-
|
63
|
+
begin
|
64
|
+
# wait until the specs have finished, thus changing the content of #totals
|
65
|
+
Selenium::WebDriver::Wait.new(timeout: 3000, interval: 30).until {
|
66
|
+
print '.'
|
88
67
|
|
89
|
-
|
90
|
-
}
|
68
|
+
not browser['totals'].text.strip.empty?
|
69
|
+
}
|
91
70
|
|
92
|
-
totals = browser['totals'].text
|
93
|
-
duration = browser[css: '#duration strong'].text
|
71
|
+
totals = browser['totals'].text
|
72
|
+
duration = browser[css: '#duration strong'].text
|
94
73
|
|
95
|
-
print "\r#{totals} in #{duration}"
|
74
|
+
print "\r#{totals} in #{duration}"
|
96
75
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
76
|
+
# no failures, happy times
|
77
|
+
if totals =~ / 0 failures/
|
78
|
+
exit 0
|
79
|
+
end
|
80
|
+
rescue Selenium::WebDriver::Error::TimeoutError
|
81
|
+
if element = browser['rspec-error'] rescue nil
|
82
|
+
print "\r#{element.text}"
|
83
|
+
else
|
84
|
+
print "\rThe specs have timed out."
|
85
|
+
end
|
86
|
+
ensure
|
87
|
+
# take a screenshot and upload it to imgur
|
88
|
+
begin
|
89
|
+
upload = lambda do |filepath|
|
90
|
+
response = RestClient.post('https://api.imgur.com/3/upload',
|
91
|
+
{ image: File.open(filepath) },
|
92
|
+
{ 'Authorization' => 'Client-ID 1979876fe2a097e' })
|
93
|
+
|
94
|
+
JSON.parse(response.to_str)['data']['link']
|
95
|
+
end
|
110
96
|
|
111
|
-
|
112
|
-
|
113
|
-
|
97
|
+
w, h = browser.execute_script("return [document.body.clientWidth, document.body.clientHeight];")
|
98
|
+
browser.manage.window.resize_to(w, h)
|
99
|
+
browser.save_screenshot('screenshot.png')
|
100
|
+
screenshot_url = upload.('screenshot.png')
|
101
|
+
puts " (#{screenshot_url})"
|
102
|
+
rescue Exception
|
103
|
+
puts
|
104
|
+
end
|
114
105
|
end
|
106
|
+
|
107
|
+
exit 1
|
data/spec/socket_spec.rb
CHANGED
@@ -1,31 +1,35 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'browser/location'
|
2
3
|
require 'browser/socket'
|
3
4
|
|
4
5
|
describe Browser::Socket do
|
5
6
|
# FIXME: find out why it doesn't work inline
|
6
7
|
ws = "ws://#{$window.location.host}/socket"
|
7
8
|
|
8
|
-
|
9
|
+
it 'creates a socket' do
|
10
|
+
promise = Browser::Promise.new
|
9
11
|
Browser::Socket.new ws do |s|
|
10
12
|
s.on :open do |e|
|
11
|
-
|
12
|
-
|
13
|
-
}
|
13
|
+
expect(e.target).to be_a(Browser::Socket)
|
14
|
+
promise.resolve
|
14
15
|
end
|
15
16
|
end
|
17
|
+
promise.for_rspec
|
16
18
|
end
|
17
19
|
|
18
|
-
|
20
|
+
it 'receives messages' do
|
21
|
+
promise = Browser::Promise.new
|
19
22
|
Browser::Socket.new ws do |s|
|
20
23
|
s.on :message do |e|
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
+
expect(e.data).to eq('lol')
|
25
|
+
promise.resolve
|
24
26
|
end
|
25
27
|
end
|
28
|
+
promise.for_rspec
|
26
29
|
end
|
27
30
|
|
28
|
-
|
31
|
+
it 'sends messages' do
|
32
|
+
promise = Browser::Promise.new
|
29
33
|
Browser::Socket.new ws do |s|
|
30
34
|
s.on :message do |e|
|
31
35
|
e.off
|
@@ -33,11 +37,11 @@ describe Browser::Socket do
|
|
33
37
|
s.print 'omg'
|
34
38
|
|
35
39
|
s.on :message do |e|
|
36
|
-
|
37
|
-
|
38
|
-
}
|
40
|
+
expect(e.data).to eq('omg')
|
41
|
+
promise.resolve
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
45
|
+
promise.for_rspec
|
42
46
|
end
|
43
47
|
end if Browser::Socket.supported?
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
<% if ENV['OPAL_BROWSER_PROMISE'] == 'v2' %>
|
2
|
+
require 'promise'
|
3
|
+
require 'promise/v2'
|
4
|
+
<% else %>
|
5
|
+
require 'promise'
|
6
|
+
|
7
|
+
# Polyfill #to_v1, which isn't present before Opal v1.3.0
|
8
|
+
class Promise
|
9
|
+
unless Promise.method_defined? :to_v1
|
10
|
+
alias to_v1 itself
|
11
|
+
end
|
12
|
+
end
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
require 'browser/utils'
|
16
|
+
|
17
|
+
module Browser
|
18
|
+
class Promise
|
19
|
+
# Return a correct promise for opal-rspec, which for now is
|
20
|
+
# PromiseV1 until opal-rspec is ported.
|
21
|
+
def for_rspec
|
22
|
+
to_v1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/storage_spec.rb
CHANGED