browser_shooter 0.2.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ module BrowserShooter
2
+ class Base
3
+ attr_reader :opts
4
+
5
+ def initialize( opts )
6
+ @opts = opts
7
+ end
8
+
9
+ def run
10
+ BrowserShooter::Logger.verbose = opts[:verbose]
11
+ BrowserShooter::Logger.log( "Starting script running with version #{BrowserShooter::VERSION}..." )
12
+
13
+ config = BrowserShooter::Configurator.new( opts )
14
+ suites = config.suites
15
+
16
+ suites.each do |suite|
17
+ suite.tests.each do |test|
18
+ suite.browsers.each do |browser|
19
+ BrowserShooter::Base.run_test(
20
+ suite,
21
+ test,
22
+ browser,
23
+ config["output_path"]
24
+ )
25
+ end
26
+ end
27
+ end
28
+
29
+ BrowserShooter::Logger.log( "... script running ended." )
30
+ BrowserShooter::Logger.log( "Logs and Shots are in: #{config["output_path"]}", true )
31
+ BrowserShooter::Logger.log( "BYE!" )
32
+ end
33
+
34
+ def self.run_test( suite, test, browser, output_path )
35
+ BrowserShooter::Logger.log( "Executing #{suite.name} | #{test.name} | #{browser.name}", true )
36
+ output_path = "#{output_path}/#{suite.name}/#{test.name}/#{browser.name}"
37
+
38
+ driver = nil
39
+
40
+ begin
41
+ driver =
42
+ Selenium::WebDriver.for(
43
+ :remote,
44
+ :url => browser.url,
45
+ :desired_capabilities => browser.type.to_sym
46
+ )
47
+
48
+ logs =
49
+ BrowserShooter::Commander.script(
50
+ test.commands,
51
+ driver,
52
+ output_path
53
+ )
54
+
55
+ BrowserShooter::LogExporter.export(
56
+ logs,
57
+ "#{output_path}/logs"
58
+ )
59
+
60
+ ensure
61
+ driver.quit if driver
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,141 +1,143 @@
1
- class BrowserShooter
2
- module Commander
3
- def self.execute( command, client, shots_path )
4
- BrowserShooter::Logger.log "command: #{command}"
5
-
6
- if( command.split[0].strip == "shot" )
7
- sufix = command.split[1] ? command.split[1].strip : nil
8
-
9
- BrowserShooter::Commander.shot(
10
- client,
11
- shots_path,
12
- sufix
13
- )
1
+ module BrowserShooter::Commander
2
+
3
+ def self.script( commands, driver, output_path )
4
+ test_result =
5
+ commands.map do |command|
6
+ command_result =
7
+ BrowserShooter::Commander.wrapper_execute(
8
+ command.strip,
9
+ driver,
10
+ output_path
11
+ )
14
12
 
15
- elsif( command.split[0].strip == "shot_system" )
16
- sufix = command.split[1] ? command.split[1].strip : nil
13
+ BrowserShooter::Logger.command_result( command_result )
17
14
 
18
- BrowserShooter::Commander.shot_system(
19
- client,
20
- shots_path,
21
- sufix
22
- )
15
+ command_result
16
+ end
23
17
 
24
- elsif( command.split[0].strip == "pause" )
25
- BrowserShooter::Commander.pause( command.split[1].strip.to_i )
18
+ BrowserShooter::Logger.test_result( test_result )
26
19
 
27
- elsif( command.split[0].strip == "wait_for_element" )
28
- params = command.match /wait_for_element "(.*)"\s?,\s?(\d*)/
20
+ test_result
21
+ end
29
22
 
30
- BrowserShooter::Commander.wait_for_element(
31
- client,
32
- params[1],
33
- params[2].to_i
34
- )
23
+ def self.execute( command, driver, output_path )
24
+ BrowserShooter::Logger.log "command: #{command}"
35
25
 
36
- elsif( command.split[0].strip == "type" )
37
- params = command.match /type "(.*)"\s?,\s?"(.*)"/
26
+ if( command.split[0].strip == "shot" )
27
+ sufix = command.split[1] ? command.split[1].strip : nil
38
28
 
39
- BrowserShooter::Commander.type(
40
- client,
41
- params[1],
42
- params[2]
43
- )
29
+ BrowserShooter::Commander.shot(
30
+ driver,
31
+ output_path,
32
+ sufix
33
+ )
44
34
 
45
- elsif( command.split[0].strip == "click" )
46
- params = command.match /click "(.*)"/
47
- BrowserShooter::Commander.click(
48
- client,
49
- params[1]
50
- )
35
+ elsif( command.split[0].strip == "pause" )
36
+ BrowserShooter::Commander.pause( command.split[1].strip.to_i )
51
37
 
52
- else
53
- eval "client.#{command}"
38
+ elsif( command.split[0].strip == "wait_for_element" )
39
+ params = command.match /wait_for_element "(.*)"\s?,\s?(\d*)/
54
40
 
55
- end
56
- end
41
+ BrowserShooter::Commander.wait_for_element(
42
+ driver,
43
+ params[1],
44
+ params[2].to_i
45
+ )
57
46
 
58
- def self.wrapper_execute( command, client, shots_path )
59
- result = {
60
- :time => Time.now.to_i,
61
- :command => command
62
- }
63
-
64
- begin
65
- message =
66
- BrowserShooter::Commander.execute(
67
- command,
68
- client,
69
- shots_path
70
- )
47
+ elsif( command.split[0].strip == "type" )
48
+ params = command.match /type "(.*)"\s?,\s?"(.*)"/
71
49
 
72
- result.merge!(
73
- :success => true,
74
- :message => message
75
- )
50
+ BrowserShooter::Commander.type(
51
+ driver,
52
+ params[1],
53
+ params[2]
54
+ )
76
55
 
77
- rescue Exception => e
78
- BrowserShooter::Logger.log "ERROR: #{e.message}"
56
+ elsif( command.split[0].strip == "click" )
57
+ params = command.match /click "(.*)"/
58
+ BrowserShooter::Commander.click(
59
+ driver,
60
+ params[1]
61
+ )
62
+
63
+ else
64
+ eval "driver.#{command}"
65
+
66
+ end
67
+ end
79
68
 
80
- result.merge!(
81
- :success => false,
82
- :message => e.message
69
+ def self.wrapper_execute( command, driver, output_path )
70
+ result = {
71
+ :time => Time.now.to_i,
72
+ :command => command
73
+ }
74
+
75
+ begin
76
+ message =
77
+ BrowserShooter::Commander.execute(
78
+ command,
79
+ driver,
80
+ output_path
83
81
  )
84
82
 
85
- end
86
83
 
87
- return result
88
- end
84
+ result.merge!(
85
+ :success => true,
86
+ :message => message
87
+ )
89
88
 
90
- def self.shot( client, path, sufix = nil )
91
- sufix = timestamp unless sufix
92
- path = "#{path}_#{sufix}.png"
89
+ rescue Exception => e
90
+ BrowserShooter::Logger.log "ERROR: #{e.message}"
93
91
 
94
- BrowserShooter::Logger.log "shooting in '#{path}'"
95
- client.save_screenshot path
92
+ # puts "XXX: Exception"
93
+ # puts e.backtrace.join( "\n" )
94
+
95
+ result.merge!(
96
+ :success => false,
97
+ :message => e.message
98
+ )
96
99
 
97
- return path
98
100
  end
99
101
 
100
- # FIXME: Not supported in WebDriver
101
- # def self.shot_system( client, path, sufix = timestamp )
102
- # sufix = timestamp unless sufix
103
- # path = "#{path}_#{sufix}.system.png"
102
+ return result
103
+ end
104
104
 
105
- # BrowserShooter::Logger.log "shooting system in '#{path}'"
105
+ def self.shot( driver, output_path, sufix = nil )
106
+ sufix = timestamp unless sufix
107
+ shot_path = "#{output_path}/shots/#{sufix}.png"
106
108
 
107
- # File.open( path, "wb" ) do |f|
108
- # f.write( Base64.decode64( client.capture_screenshot_to_string ) )
109
- # end
109
+ BrowserShooter::Logger.log "shooting in '#{shot_path}'"
110
110
 
111
- # return path
112
- # end
111
+ FileUtils.mkdir_p( File.dirname( shot_path ) )
112
+ driver.save_screenshot( shot_path )
113
113
 
114
- def self.wait_for_element( client, css_selector, timeout )
115
- wait = Selenium::WebDriver::Wait.new( :timeout => timeout )
114
+ return shot_path
115
+ end
116
116
 
117
- wait.until do
118
- client.find_element( "css", css_selector )
119
- end
120
- end
117
+ def self.wait_for_element( driver, css_selector, timeout )
118
+ wait = Selenium::WebDriver::Wait.new( :timeout => timeout )
121
119
 
122
- def self.click( client, css_selector )
123
- client.find_element( "css", css_selector ).click
120
+ wait.until do
121
+ driver.find_element( "css", css_selector )
124
122
  end
123
+ end
125
124
 
126
- def self.type( client, css_selector, text )
127
- client.find_element( "css", css_selector ).send_keys( text )
128
- end
125
+ def self.click( driver, css_selector )
126
+ driver.find_element( "css", css_selector ).click
127
+ end
129
128
 
130
- def self.pause( seconds )
131
- BrowserShooter::Logger.log "pausing #{seconds} seconds"
132
- Kernel.sleep seconds
129
+ def self.type( driver, css_selector, text )
130
+ driver.find_element( "css", css_selector ).send_keys( text )
131
+ end
133
132
 
134
- return "#{seconds} seconds later..."
135
- end
133
+ def self.pause( seconds )
134
+ BrowserShooter::Logger.log "pausing #{seconds} seconds"
135
+ Kernel.sleep seconds
136
136
 
137
- def self.timestamp
138
- Time.now.to_i
139
- end
137
+ return "#{seconds} seconds later..."
138
+ end
139
+
140
+ def self.timestamp
141
+ Time.now.to_i
140
142
  end
141
- end
143
+ end
@@ -1,5 +1,80 @@
1
- class BrowserShooter
2
- module Configurator
1
+ module BrowserShooter
2
+ class Configurator
3
+ attr_reader :suites
4
+
5
+ def initialize( opts )
6
+ @config = BrowserShooter::Configurator.load_config( opts[:config_file] )
7
+ models = BrowserShooter::Configurator.build_models( @config )
8
+ @suites = BrowserShooter::Configurator.filter_suites( models, opts )
9
+ end
10
+
11
+ def [](value)
12
+ @config[value]
13
+ end
14
+
15
+ def self.filter_suites( models, opts )
16
+ suites = []
17
+
18
+ if( opts[:suite] )
19
+ suite = models[:suites].select{ |e| e.name == opts[:suite] }.first
20
+ raise ArgumentError, "Not suite found '#{opts[:suite]}'" if suite.nil?
21
+
22
+ suites = [suite]
23
+
24
+ elsif( opts[:test] && opts[:browsers] )
25
+ test = models[:tests].select{ |e| e.name == opts[:test] }.first
26
+ raise ArgumentError, "Not test found '#{opts[:test]}'" if test.nil?
27
+
28
+ browsers = models[:browsers].select{ |e| opts[:browsers].include? e.name }
29
+ raise ArgumentError, "Not browsers found '#{opts[:browsers].join( "," )}'" if browsers.empty?
30
+
31
+ suite = BrowserShooter::Models::Suite.new( "anonymous", [test], browsers )
32
+ suites = [suite]
33
+
34
+ elsif( opts[:test] )
35
+ test = models[:tests].select{ |e| e.name == opts[:test] }.first
36
+ raise ArgumentError, "Not test found '#{opts[:test]}'" if test.nil?
37
+
38
+ browsers = models[:browsers]
39
+ suite = BrowserShooter::Models::Suite.new( "anonymous", [test], browsers )
40
+ suites = [suite]
41
+
42
+ else
43
+ suites = models[:suites]
44
+
45
+ end
46
+
47
+ suites
48
+ end
49
+
50
+ def self.build_models( config )
51
+ tests =
52
+ config["tests"].map do |name, commands|
53
+ test_commands = commands.split( "\n" )
54
+
55
+ BrowserShooter::Models::Test.new( name, test_commands )
56
+ end
57
+
58
+ browsers =
59
+ config["browsers"].map do |name, opts|
60
+ BrowserShooter::Models::Browser.new( name, opts["url"], opts["type"] )
61
+ end
62
+
63
+ suites =
64
+ config["suites"].map do |name, opts|
65
+ suite_tests = tests.select{ |e| opts["tests"].include? e.name }
66
+ suite_browsers = browsers.select{ |e| opts["browsers"].include? e.name }
67
+
68
+ BrowserShooter::Models::Suite.new( name, suite_tests, suite_browsers )
69
+ end
70
+
71
+ {
72
+ :tests => tests,
73
+ :browsers => browsers,
74
+ :suites => suites
75
+ }
76
+ end
77
+
3
78
  def self.load_config( config_file_path )
4
79
  config = {
5
80
  "output_path" => "~/browser_shooter",
@@ -17,10 +92,6 @@ class BrowserShooter
17
92
  output_path = File.expand_path( "#{output_path}/#{timestamp}" )
18
93
  BrowserShooter::Logger.log( "output_path: #{output_path}" )
19
94
 
20
- FileUtils.mkdir_p( output_path )
21
- FileUtils.mkdir( "#{output_path}/shots" )
22
- FileUtils.mkdir( "#{output_path}/logs" )
23
-
24
95
  output_path
25
96
  end
26
97
 
@@ -1,26 +1,20 @@
1
- class BrowserShooter
1
+ module BrowserShooter
2
2
  module LogExporter
3
- def self.export( logs, path, format )
4
- BrowserShooter::Logger.log "Exporting '#{format}' logs to #{path}"
5
- send(:"export_to_#{format}", logs, path )
6
- end
3
+ def self.export( logs, logs_path, format = "csv" )
4
+ logs_path = File.expand_path( "#{logs_path}/log.#{format}" )
5
+ BrowserShooter::Logger.log "Exporting '#{format}' logs to #{logs_path}"
6
+ FileUtils.mkdir_p( File.dirname( logs_path ) )
7
7
 
8
- def self.export_to_json( logs, path )
9
- File.open( "#{path}/logs.json", "w" ) do |f|
10
- f.write JSON.pretty_generate( logs )
11
- end
8
+ send(:"export_to_#{format}", logs, logs_path )
12
9
  end
13
10
 
14
11
  def self.export_to_csv( logs, path )
15
- logs.each do |script_name, results|
16
- _path = File.expand_path "#{path}/#{script_name}.csv"
17
-
18
- File.open( _path, "w" ) do |f|
19
- f.puts results.first.keys.join( " | " )
12
+ File.open( path, "w" ) do |f|
13
+ f.puts "time | success | command | message"
20
14
 
21
- results.each do |result|
22
- f.puts result.values.join( " | " )
23
- end
15
+ logs.each do |result|
16
+ line = "#{result[:time]} | #{result[:success]} | #{result[:command]} | #{result[:message]}".gsub( "\n", " - " )
17
+ f.puts line
24
18
  end
25
19
  end
26
20
  end
@@ -1,7 +1,24 @@
1
- class BrowserShooter
1
+ module BrowserShooter
2
2
  module Logger
3
- def self.log( message )
4
- puts "[BrowserShooter #{Time.now.strftime( "%F %T" )}] #{message}"
3
+ extend self
4
+
5
+ attr_accessor :verbose
6
+
7
+ def log( message, force = verbose )
8
+ if force
9
+ Kernel.puts "[BrowserShooter #{Time.now.strftime( "%F %T" )}] #{message}"
10
+ end
5
11
  end
12
+
13
+ def command_result( command_result )
14
+ Kernel.print "." if command_result[:success]
15
+ Kernel.print "F" if !command_result[:success]
16
+ end
17
+
18
+ def test_result( test_result )
19
+ Kernel.puts " (success)" if test_result.all? { |e| e[:success] }
20
+ Kernel.puts " (fail)" if !test_result.all? { |e| e[:success] }
21
+ end
22
+
6
23
  end
7
24
  end