crabfarm 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/assets/live-tools/tools.js +0 -1
  3. data/lib/crabfarm/adapters/browser/abstract_webdriver.rb +13 -28
  4. data/lib/crabfarm/adapters/browser/base.rb +43 -0
  5. data/lib/crabfarm/adapters/browser/chrome.rb +5 -1
  6. data/lib/crabfarm/adapters/browser/firefox.rb +4 -0
  7. data/lib/crabfarm/adapters/browser/noop.rb +3 -10
  8. data/lib/crabfarm/adapters/browser/phantom_js.rb +8 -8
  9. data/lib/crabfarm/adapters/driver_wrapper/pincers.rb +6 -0
  10. data/lib/crabfarm/cli.rb +1 -7
  11. data/lib/crabfarm/context.rb +17 -21
  12. data/lib/crabfarm/driver_pool.rb +3 -2
  13. data/lib/crabfarm/errors.rb +2 -0
  14. data/lib/crabfarm/http_client.rb +1 -1
  15. data/lib/crabfarm/live/context.rb +32 -2
  16. data/lib/crabfarm/live/controller.rb +19 -16
  17. data/lib/crabfarm/live/interactable.rb +5 -14
  18. data/lib/crabfarm/live/manager.rb +85 -95
  19. data/lib/crabfarm/live/navigator_runner.rb +43 -40
  20. data/lib/crabfarm/live/navigator_runner_direct.rb +1 -2
  21. data/lib/crabfarm/live/navigator_runner_rspec.rb +34 -55
  22. data/lib/crabfarm/live/reducer_runner.rb +43 -22
  23. data/lib/crabfarm/live/reducer_runner_direct.rb +1 -2
  24. data/lib/crabfarm/live/reducer_runner_rspec.rb +0 -5
  25. data/lib/crabfarm/live/viewer.rb +92 -0
  26. data/lib/crabfarm/live/watcher.rb +6 -1
  27. data/lib/crabfarm/modes/live.rb +1 -1
  28. data/lib/crabfarm/modes/recorder/snapshot.rb +9 -25
  29. data/lib/crabfarm/support/webdriver_factory.rb +1 -1
  30. data/lib/crabfarm/templates/Gemfile.erb +1 -1
  31. data/lib/crabfarm/utils/rspec_runner.rb +54 -22
  32. data/lib/crabfarm/version.rb +1 -1
  33. metadata +4 -2
@@ -1,5 +1,3 @@
1
- require 'crabfarm/utils/webdriver'
2
-
3
1
  module Crabfarm
4
2
  module Live
5
3
  module Interactable
@@ -29,19 +27,12 @@ module Crabfarm
29
27
 
30
28
  end
31
29
 
32
- # Tooling
33
-
34
- def highlight(_elements)
30
+ def examine(_tools=true)
35
31
  if Crabfarm.live?
36
- if _elements.respond_to? :webdriver_elements
37
- _elements = _elements.webdriver_elements
38
- end
39
-
40
- if _elements.is_a? String
41
- _elements = Crabfarm.live.primary_driver.find_elements(css: _elements)
42
- end
43
-
44
- Utils::Webdriver.set_style _elements, "border: 3px solid yellow;"
32
+ Crabfarm.live.show_primary_contents if self.is_a? BaseNavigator
33
+ Crabfarm.live.show_content raw_document if self.is_a? BaseReducer
34
+ Crabfarm.live.show_selector_gadget if _tools
35
+ raise LiveInterrupted.new
45
36
  end
46
37
  end
47
38
 
@@ -1,49 +1,37 @@
1
1
  require 'timeout'
2
- require 'crabfarm/utils/console'
3
- require 'crabfarm/utils/webdriver'
2
+ require 'crabfarm/live/viewer'
4
3
  require 'crabfarm/support/webdriver_factory'
5
4
  require 'crabfarm/crabtrap_runner'
6
5
 
7
6
  module Crabfarm
8
7
  module Live
9
8
  class Manager
9
+ extend Forwardable
10
10
 
11
- INJECTION_TM = 5 # seconds
11
+ attr_reader :primary_driver, :browser_adapter, :proxy_port
12
12
 
13
- def initialize
14
- @port = Utils::PortDiscovery.find_available_port
15
- @driver_name = Crabfarm.config.recorder_driver
16
- end
13
+ def_delegators :@viewer, :show_message, :show_selector_gadget
17
14
 
18
- def proxy_port
19
- @port
15
+ def initialize
16
+ reserve_port
20
17
  end
21
18
 
22
19
  def start
23
- set_memento
24
- load_primary_driver
25
- primary_driver.get('https://www.crabtrap.io/welcome.html')
20
+ restart_crabtrap
21
+ load_browser_adapter
22
+ load_primary_driver_and_viewer
23
+ @viewer.welcome
26
24
  end
27
25
 
28
26
  def stop
29
- stop_crabtrap
30
27
  release_primary_driver
28
+ release_viewer_driver
29
+ stop_crabtrap
31
30
  end
32
31
 
33
- def primary_driver
34
- @driver
35
- end
36
-
37
- def reset_driver_status
38
- if Crabfarm.config.live_full_reload
39
- # recreate driver if configured to do so
40
- release_primary_driver
41
- load_primary_driver
42
- else
43
- primary_driver.manage.delete_all_cookies
44
- end
45
-
46
- primary_driver.get('https://www.crabtrap.io/instructions.html')
32
+ def reset
33
+ reset_primary_driver
34
+ @viewer.reset
47
35
  end
48
36
 
49
37
  def block_requests
@@ -51,12 +39,25 @@ module Crabfarm
51
39
  stop_crabtrap
52
40
  return yield
53
41
  ensure
54
- set_memento nil
42
+ restart_crabtrap nil
55
43
  end
56
44
  end
57
45
 
58
- def set_memento(_memento=nil)
46
+ def show_file(_path)
47
+ block_requests { @viewer.show_file(_path) }
48
+ end
49
+
50
+ def show_content(_content)
51
+ block_requests { @viewer.show_content(_content) }
52
+ end
53
+
54
+ def show_primary_contents
55
+ unless @viewer_driver.nil?
56
+ @viewer.show_content(primary_driver.to_html)
57
+ end
58
+ end
59
59
 
60
+ def restart_crabtrap(_memento=nil)
60
61
  options = if _memento
61
62
  path = Utils::Resolve.memento_path _memento
62
63
  raise ConfigurationError.new "No memento found at #{path}" unless File.exists? path
@@ -65,103 +66,92 @@ module Crabfarm
65
66
  { mode: :pass }
66
67
  end
67
68
 
68
- options.merge!({
69
- port: @port,
70
- virtual: File.expand_path('./assets/live-tools', Crabfarm.root)
71
- })
72
-
73
69
  stop_crabtrap
74
- @crabtrap = CrabtrapRunner.new config.crabtrap_config.merge(options)
75
- @crabtrap.start
76
-
70
+ start_crabtrap options
77
71
  end
78
72
 
79
- def stop_crabtrap
80
- unless @crabtrap.nil?
81
- @crabtrap.kill
82
- @crabtrap = nil
83
- else nil end
73
+ private
74
+
75
+ def reserve_port
76
+ @proxy_port = Utils::PortDiscovery.find_available_port
84
77
  end
85
78
 
86
- def inject_web_tools
87
- Utils::Console.trap_errors 'injecting web tools' do
88
- Utils::Webdriver.inject_style primary_driver, 'https://www.crabtrap.io/selectorgadget_combined.css'
89
- Utils::Webdriver.inject_style primary_driver, 'https://www.crabtrap.io/tools.css'
90
- Utils::Webdriver.inject_script primary_driver, 'https://www.crabtrap.io/selectorgadget_combined.js'
91
- Utils::Webdriver.inject_script primary_driver, 'https://www.crabtrap.io/tools.js'
92
- Timeout::timeout(INJECTION_TM) { wait_for_injection }
93
- end
79
+ def load_browser_adapter
80
+ @browser_adapter = Strategies.load(:browser, config.browser).new crabtrap_address
81
+ @browser_adapter.prepare_driver_services
94
82
  end
95
83
 
96
- def show_dialog(_status, _title, _subtitle, _content=nil, _content_type=:text)
97
- Utils::Console.trap_errors 'loading web dialog' do
98
- primary_driver.execute_script(
99
- "window.crabfarm.showDialog.apply(null, arguments);",
100
- _status.to_s,
101
- _title,
102
- _subtitle,
103
- _content,
104
- _content_type.to_s
105
- );
84
+ def load_primary_driver_and_viewer
85
+ @primary_driver = browser_adapter.build_driver :default_driver
86
+
87
+ # IDEA: improve this to allow different viewer modes
88
+ unless browser_adapter.headless?
89
+ primary_webdriver = browser_adapter.extract_webdriver @primary_driver
90
+ @viewer = Viewer.new primary_webdriver unless primary_webdriver.nil?
106
91
  end
107
- end
108
92
 
109
- def show_selector_gadget()
110
- Utils::Console.trap_errors 'loading selector gadget' do
111
- primary_driver.execute_script(
112
- 'window.crabfarm.showSelectorGadget();'
113
- )
93
+ if @viewer.nil?
94
+ @viewer_driver = build_support_driver
95
+ @viewer = Viewer.new @viewer_driver
114
96
  end
115
97
  end
116
98
 
117
- # Viewer implementation
118
-
119
- def attach(_primary=true)
120
- if _primary then primary_driver else build_driver end
99
+ def build_support_driver
100
+ case config.recorder_driver
101
+ when :firefox
102
+ Crabfarm::Support::WebdriverFactory.build_firefox_driver driver_config
103
+ when :chrome
104
+ Crabfarm::Support::WebdriverFactory.build_chrome_driver driver_config
105
+ else return nil end
121
106
  end
122
107
 
123
- def detach(_driver)
124
- if _driver != primary_driver
125
- _driver.quit rescue nil
126
- end
108
+ def reset_primary_driver
109
+ @browser_adapter.reset_driver @primary_driver
127
110
  end
128
111
 
129
- private
112
+ def start_crabtrap(_options)
113
+ _options = _options.merge({
114
+ port: @proxy_port,
115
+ virtual: File.expand_path('./assets/live-tools', Crabfarm.root)
116
+ })
130
117
 
131
- def load_primary_driver
132
- @driver = build_driver
118
+ @crabtrap = CrabtrapRunner.new config.crabtrap_config.merge(_options)
119
+ @crabtrap.start
120
+ end
121
+
122
+ def stop_crabtrap
123
+ unless @crabtrap.nil?
124
+ @crabtrap.kill
125
+ @crabtrap = nil
126
+ else nil end
133
127
  end
134
128
 
135
129
  def release_primary_driver
136
- unless @driver.nil?
137
- @driver.quit rescue nil
138
- @driver = nil
139
- end
130
+ @browser_adapter.release_driver @primary_driver
131
+ @browser_adapter.cleanup_driver_services
132
+ @primary_driver = nil
140
133
  end
141
134
 
142
- def build_driver
143
- case @driver_name
144
- when :firefox
145
- Crabfarm::Support::WebdriverFactory.build_firefox_driver driver_config
146
- when :chrome
147
- Crabfarm::Support::WebdriverFactory.build_chrome_driver driver_config
148
- else return nil end
135
+ def release_viewer_driver
136
+ unless @viewer_driver.nil?
137
+ @viewer_driver.quit rescue nil
138
+ @viewer_driver = nil
139
+ @viewer = nil
140
+ end
149
141
  end
150
142
 
151
143
  def driver_config
152
144
  {
153
- proxy: "127.0.0.1:#{@port}"
145
+ proxy: crabtrap_address
154
146
  }
155
147
  end
156
148
 
157
- def config
158
- Crabfarm.config
149
+ def crabtrap_address
150
+ "127.0.0.1:#{@proxy_port}"
159
151
  end
160
152
 
161
- def wait_for_injection
162
- while primary_driver.execute_script "return (typeof window.crabfarm === 'undefined');"
163
- sleep 1.0
164
- end
153
+ def config
154
+ Crabfarm.config
165
155
  end
166
156
 
167
157
  end
@@ -6,16 +6,6 @@ module Crabfarm
6
6
  module Live
7
7
  class NavigatorRunner
8
8
 
9
- class Dsl
10
- extend Forwardable
11
-
12
- def initialize(_runner)
13
- @runner = _runner
14
- end
15
-
16
- def_delegators :@runner, :use_memento, :use_params, :clear_params, :use_rspec, :navigate_to
17
- end
18
-
19
9
  def initialize(_manager, _target)
20
10
  @manager = _manager
21
11
  @target = _target
@@ -27,10 +17,6 @@ module Crabfarm
27
17
  @dsl ||= Dsl.new self
28
18
  end
29
19
 
30
- def memento
31
- if @memento.nil? then memento_for(@target) else @memento end
32
- end
33
-
34
20
  def use_memento(_memento)
35
21
  @memento = _memento
36
22
  @rspec = false
@@ -50,15 +36,6 @@ module Crabfarm
50
36
  @rspec = true
51
37
  end
52
38
 
53
- def navigate_to(_navigator, _params={})
54
- # TODO.
55
- end
56
-
57
- def prepare(_memento) # decorator
58
- @manager.set_memento _memento
59
- Context.new @manager
60
- end
61
-
62
39
  def execute
63
40
  strategy = if @rspec
64
41
  NavigatorRunnerRSpec.new @manager, @target
@@ -66,31 +43,57 @@ module Crabfarm
66
43
  NavigatorRunnerDirect.new @manager, memento, @target, @params
67
44
  end
68
45
 
69
- Factories::Context.with_decorator self do
70
- strategy.execute
71
- end
46
+ begin
47
+ Factories::Context.with_decorator navigator_decorator do
48
+ strategy.execute
49
+ end
72
50
 
73
- strategy.show_results
51
+ @manager.show_primary_contents
52
+ strategy.show_results
53
+ rescue Crabfarm::LiveInterrupted
54
+ Utils::Console.info "Execution interrupted"
55
+ end
74
56
  end
75
57
 
76
58
  private
77
59
 
60
+ def memento
61
+ if @memento.nil? then memento_for(@target) else @memento end
62
+ end
63
+
78
64
  def memento_for(_class)
79
- Utils::Naming.route_from_constant(_class.to_s).join(File::SEPARATOR)
65
+ Utils::Naming.route_from_constant(_class.to_s).join File::SEPARATOR
66
+ end
67
+
68
+ def navigator_decorator
69
+ @decorator ||= InterceptContextDecorator.new @manager
80
70
  end
81
71
 
82
- def show_result
83
- @manager.inject_web_tools
84
- @manager.show_dialog(
85
- :neutral,
86
- 'Navigation completed!',
87
- "The page was scrapped in #{@elapsed.real} seconds",
88
- @transition.document.to_json,
89
- :json
90
- )
91
-
92
- Utils::Console.json_result @transition.document
93
- Utils::Console.info "Completed in #{@elapsed.real} s"
72
+ class InterceptContextDecorator
73
+
74
+ def initialize(_manager)
75
+ @manager = _manager
76
+ end
77
+
78
+ def prepare(_memento)
79
+ @manager.restart_crabtrap _memento
80
+ inject_managed_context
81
+ end
82
+
83
+ def inject_managed_context
84
+ Context.new @manager
85
+ end
86
+
87
+ end
88
+
89
+ class Dsl
90
+ extend Forwardable
91
+
92
+ def initialize(_runner)
93
+ @runner = _runner
94
+ end
95
+
96
+ def_delegators :@runner, :use_memento, :use_params, :clear_params, :use_rspec, :navigate_to
94
97
  end
95
98
 
96
99
  end
@@ -21,8 +21,7 @@ module Crabfarm
21
21
  end
22
22
 
23
23
  def show_results
24
- @manager.inject_web_tools
25
- @manager.show_dialog(
24
+ @manager.show_message(
26
25
  :neutral,
27
26
  'Navigation completed!',
28
27
  "The page was scrapped in #{@elapsed.real} seconds",
@@ -5,25 +5,23 @@ module Crabfarm
5
5
  module Live
6
6
  class NavigatorRunnerRSpec
7
7
 
8
+ attr_reader :example
9
+
8
10
  def initialize(_manager, _target)
9
11
  @manager = _manager
10
12
  @target = _target
11
13
  end
12
14
 
13
15
  def execute
14
- @examples = Factories::Context.with_decorator self do
15
- Utils::RSpecRunner.run_spec_for spec_for(@target), live: true
16
- end
16
+ @example = Utils::RSpecRunner.run_single_spec_for spec_for(@target), :live
17
+ bubble_standard_errors
17
18
  end
18
19
 
19
20
  def show_results
20
- @manager.inject_web_tools
21
- if @examples.count == 0
21
+ if example.nil?
22
22
  show_empty_warning
23
- elsif @examples.count == 1
24
- show_example_output @examples.first
25
23
  else
26
- show_example_summary @examples
24
+ show_example_output
27
25
  end
28
26
  end
29
27
 
@@ -37,75 +35,56 @@ module Crabfarm
37
35
  end
38
36
 
39
37
  def show_empty_warning
40
- @manager.show_dialog(
38
+ @manager.show_message(
41
39
  :warning,
42
- 'No examples were found!',
43
- 'Make sure you have tagged some specs with live: true'
40
+ "No examples were found!",
41
+ "You will need to write at least one spec for #{@target.to_s}"
44
42
  )
45
43
 
46
- Utils::Console.warning 'No examples were found!'
44
+ console.warning 'No examples were found!'
47
45
  end
48
46
 
49
- def show_example_summary(_examples)
50
- total = _examples.count
51
- error = _examples.select { |e| !e.exception.nil? }.count
52
- errored = (error > 0)
53
-
54
- if error > 0
55
- @manager.show_dialog(
47
+ def show_example_output
48
+ if example.exception
49
+ @manager.show_message(
56
50
  :error,
57
51
  'FAILED',
58
- "#{error} of #{total} tests failed"
59
- )
60
-
61
- Utils::Console.error "#{total} examples, #{error} failures"
62
- else
63
- @manager.show_dialog(
64
- :success,
65
- 'SUCCESS',
66
- "All #{total} tests passed!"
67
- )
68
-
69
- Utils::Console.result "#{total} examples, 0 failures"
70
- end
71
- end
72
-
73
- def show_example_output(_example)
74
-
75
- handle_standard_errors _example
76
-
77
- if _example.exception
78
- @manager.show_dialog(
79
- :error,
80
- 'FAILED',
81
- _example.exception.to_s,
82
- _example.metadata[:result].to_json,
52
+ example.exception.to_s,
53
+ example.metadata[:result].to_json,
83
54
  :json
84
55
  )
85
56
 
86
- Utils::Console.error "1 example, 1 failure"
87
- Utils::Console.error _example.exception.to_s
88
- Utils::Console.json_result _example.metadata[:result]
57
+ console.error "Example \"#{example.full_description}\" failed (line: #{example.metadata[:line_number]})"
58
+ console.error example.exception.to_s
59
+ console.json_result example.metadata[:result]
89
60
  else
90
- @manager.show_dialog(
61
+ @manager.show_message(
91
62
  :success,
92
63
  'SUCCESS',
93
- "\"#{_example.full_description}\"",
94
- _example.metadata[:result].to_json,
64
+ "\"#{example.full_description}\"",
65
+ example.metadata[:result].to_json,
95
66
  :json
96
67
  )
97
68
 
98
- Utils::Console.result "1 example, 0 failures"
99
- Utils::Console.json_result _example.metadata[:result]
69
+ console.result "Example \"#{example.full_description}\" passed (line: #{example.metadata[:line_number]})"
70
+ console.json_result example.metadata[:result]
100
71
  end
101
72
  end
102
73
 
103
- def handle_standard_errors(_example)
104
- if _example.exception and not _example.exception.is_a? ::RSpec::Expectations::ExpectationNotMetError
105
- raise _example.exception
74
+ def bubble_standard_errors
75
+ if example and example.exception and not example.exception.is_a? expectation_error
76
+ raise example.exception
106
77
  end
107
78
  end
108
79
 
80
+ def expectation_error
81
+ ::RSpec::Expectations::ExpectationNotMetError
82
+ end
83
+
84
+ def console
85
+ Utils::Console
86
+ end
87
+
109
88
  end
110
89
  end
111
90
  end