rwebspec-mechanize 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/MIT-LICENSE +21 -0
- data/README +41 -0
- data/Rakefile +102 -0
- data/lib/rwebspec-mechanize/assert.rb +388 -0
- data/lib/rwebspec-mechanize/context.rb +25 -0
- data/lib/rwebspec-mechanize/extensions/firewatir_extensions.rb +74 -0
- data/lib/rwebspec-mechanize/extensions/rspec_extensions.rb +51 -0
- data/lib/rwebspec-mechanize/extensions/watir_extensions.rb +85 -0
- data/lib/rwebspec-mechanize/extensions/window_script_extensions.rb +19 -0
- data/lib/rwebspec-mechanize/load_test_helper.rb +359 -0
- data/lib/rwebspec-mechanize/plugins/loadwise_plugin.rb +93 -0
- data/lib/rwebspec-mechanize/rspec_helper.rb +96 -0
- data/lib/rwebspec-mechanize/test_utils.rb +393 -0
- data/lib/rwebspec-mechanize/web_browser.rb +650 -0
- data/lib/rwebspec-mechanize/web_page.rb +108 -0
- data/lib/rwebspec-mechanize.rb +8 -0
- metadata +110 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Spec
|
2
|
+
module Extensions
|
3
|
+
module Main
|
4
|
+
|
5
|
+
alias :spec :describe
|
6
|
+
alias :specification :describe
|
7
|
+
alias :test_suite :describe
|
8
|
+
alias :suite :describe
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# For RSpec 1.1.12
|
15
|
+
module Spec
|
16
|
+
module DSL
|
17
|
+
module Main
|
18
|
+
|
19
|
+
alias :spec :describe
|
20
|
+
alias :specification :describe
|
21
|
+
alias :test_suite :describe
|
22
|
+
alias :suite :describe
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# ZZ patches to RSpec 1.1.4
|
29
|
+
# - add to_s method to example_group
|
30
|
+
module Spec
|
31
|
+
module Example
|
32
|
+
class ExampleGroup
|
33
|
+
def to_s
|
34
|
+
@_defined_description
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module Spec
|
41
|
+
module Example
|
42
|
+
module ExampleGroupMethods
|
43
|
+
|
44
|
+
alias_method :scenario, :it
|
45
|
+
alias_method :story, :it
|
46
|
+
alias_method :test_case, :it
|
47
|
+
alias_method :use_case, :it
|
48
|
+
alias_method :test, :it
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
gem 'watir'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'watir/container'
|
4
|
+
require 'watir/element_collections'
|
5
|
+
require 'watir/element'
|
6
|
+
|
7
|
+
module Watir
|
8
|
+
# Base class for html elements.
|
9
|
+
# This is not a class that users would normally access.
|
10
|
+
class Element
|
11
|
+
|
12
|
+
def method_missing(method_name, *args, &block)
|
13
|
+
|
14
|
+
if ($TESTWISE_DIR || $TESTWISE_BROWSER) && method_name.to_s =~ /(.*)_no_wait/ && self.respond_to?($1)
|
15
|
+
ruby_code = testwise_generate_ruby_code(self, $1, *args)
|
16
|
+
testwise_click_no_wait(ruby_code)
|
17
|
+
|
18
|
+
elsif method_name.to_s =~ /(.*)_no_wait/ && self.respond_to?($1)
|
19
|
+
puts "[Watir] handle it"
|
20
|
+
assert_exists
|
21
|
+
assert_enabled
|
22
|
+
highlight(:set)
|
23
|
+
ruby_code = generate_ruby_code(self, $1, *args)
|
24
|
+
system(spawned_no_wait_command(ruby_code))
|
25
|
+
highlight(:clear)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def testwise_generate_ruby_code(element, method_name, *args)
|
34
|
+
element = "#{self.class}.new(#{@page_container.attach_command}, :unique_number, #{self.unique_number})"
|
35
|
+
method = build_method(method_name, *args)
|
36
|
+
watir_load_path = []
|
37
|
+
watir_lib_path = nil
|
38
|
+
$LOAD_PATH.each do |x|
|
39
|
+
if x =~ /rautomation/ || x =~ /watir/
|
40
|
+
watir_load_path << x
|
41
|
+
if x =~ /\/gems\/watir-/
|
42
|
+
watir_lib_path = x
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
watir_load_path = $LOAD_PATH
|
47
|
+
ruby_code = "$:.unshift(#{watir_load_path.map {|p| "'#{p}'" }.join(").unshift(")});" <<
|
48
|
+
"require '#{watir_lib_path}/watir/core';#{element}.#{method};"
|
49
|
+
return ruby_code
|
50
|
+
end
|
51
|
+
|
52
|
+
# customiiation here
|
53
|
+
#
|
54
|
+
def testwise_click_no_wait(ruby_code)
|
55
|
+
begin
|
56
|
+
puts "[TestWise] I am handling it"
|
57
|
+
assert_exists
|
58
|
+
assert_enabled
|
59
|
+
highlight(:set)
|
60
|
+
current_path = File.expand_path(".")
|
61
|
+
|
62
|
+
# not necessary
|
63
|
+
# ruby_code.gsub("C:/Program Files/TestWise/vendor/bundle/ruby/1.8", "C:/rubyshell/ruby/lib/ruby/gems/1.8")
|
64
|
+
|
65
|
+
# Trick 1: need to set RUBYOPT, otherwise might get -F error
|
66
|
+
ENV["RUBYOPT"] = "-rubygems"
|
67
|
+
|
68
|
+
# Trick 2: need to wrap no-wait click operation in a thread
|
69
|
+
Thread.new do
|
70
|
+
# this will pop up Windows Command window
|
71
|
+
# system("ruby", "-e", ruby_code)
|
72
|
+
system("rubyw", "-e", ruby_code)
|
73
|
+
end
|
74
|
+
highlight(:clear)
|
75
|
+
rescue RuntimeError => re
|
76
|
+
puts re.backtrace
|
77
|
+
|
78
|
+
rescue => e
|
79
|
+
puts "Failed to click_no_wait: #{e.backtrace}"
|
80
|
+
raise e
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'watir'
|
3
|
+
|
4
|
+
# Used for calling javacript of VBScript
|
5
|
+
# Applies to IE only
|
6
|
+
#
|
7
|
+
# Ref: http://msdn.microsoft.com/en-us/library/aa741364%28VS.85%29.aspx
|
8
|
+
#
|
9
|
+
module Watir
|
10
|
+
class IE
|
11
|
+
def execute_script(scriptCode)
|
12
|
+
window.execScript(scriptCode)
|
13
|
+
end
|
14
|
+
|
15
|
+
def window
|
16
|
+
ie.Document.parentWindow
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,359 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "plugins", "loadwise_plugin.rb")
|
2
|
+
require "timeout"
|
3
|
+
|
4
|
+
module RWebSpec
|
5
|
+
module Mechanize
|
6
|
+
|
7
|
+
module LoadTestHelper
|
8
|
+
|
9
|
+
include RWebSpec::Mechanize::Utils
|
10
|
+
include RWebSpec::Mechanize::Assert
|
11
|
+
include RWebSpec::Mechanize::LoadWisePlugin
|
12
|
+
|
13
|
+
MAX_VU = 1000
|
14
|
+
|
15
|
+
# only support firefox or Celerity
|
16
|
+
def open_browser(base_url = nil, options = {})
|
17
|
+
default_options = {:resynchronize => false, :firefox => false, :go => false }
|
18
|
+
options = default_options.merge(options)
|
19
|
+
|
20
|
+
base_url ||= $LOADWISE_PROJECT_BASE_URL
|
21
|
+
if RUBY_PLATFORM =~ /java/
|
22
|
+
base_url ||= ENV["LOADWISE_PROJECT_BASE_URL"] # pass to java
|
23
|
+
end
|
24
|
+
base_url ||= $BASE_URL
|
25
|
+
puts "[DEBUG] open |#{base_url}|#{$BASE_URL}| in browser"
|
26
|
+
|
27
|
+
mode_preview = ($LOADWISE_PREVIEW || ENV['LOADWISE_PREVIEW'])
|
28
|
+
|
29
|
+
unless mode_preview
|
30
|
+
RWebSpec::Mechanize::WebBrowser.new(base_url, nil, options)
|
31
|
+
else
|
32
|
+
if RUBY_PLATFORM =~ /mingw/
|
33
|
+
puts "loading RWEBSPEC..."
|
34
|
+
require 'rwebspec'
|
35
|
+
RWebSpec.framework = "Watir"
|
36
|
+
RWebSpec::WebBrowser.new(base_url, nil, options)
|
37
|
+
else
|
38
|
+
require 'rwebspec'
|
39
|
+
RWebSpec.framework = "Selenium-WebDriver"
|
40
|
+
if RUBY_PLATFORM =~ /darwin/
|
41
|
+
if File.exists?("/usr/bin/chromedriver") && File.exists?("/usr/local/bin/chromedriver")
|
42
|
+
options[:browser] = "chrome"
|
43
|
+
else
|
44
|
+
options[:browser] = "firefox"
|
45
|
+
end
|
46
|
+
else
|
47
|
+
options[:browser] = "firefox"
|
48
|
+
end
|
49
|
+
RWebSpec::WebBrowser.new(base_url, nil, options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# maybe attach_browser
|
55
|
+
|
56
|
+
# Does not provide real function, other than make enhancing test syntax
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
# allow { click_button('Register') }
|
60
|
+
def allow(&block)
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
alias shall_allow allow
|
64
|
+
alias allowing allow
|
65
|
+
|
66
|
+
# try operation, ignore if errors occur
|
67
|
+
#
|
68
|
+
# Example:
|
69
|
+
# failsafe { click_link("Logout") } # try logout, but it still OK if not being able to (already logout))
|
70
|
+
def failsafe(&block)
|
71
|
+
begin
|
72
|
+
yield
|
73
|
+
rescue =>e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
alias fail_safe failsafe
|
77
|
+
|
78
|
+
# Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds).
|
79
|
+
# Error will be ignored until timeout
|
80
|
+
# Example
|
81
|
+
# try_for { click_link('waiting')}
|
82
|
+
# try_for(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
|
83
|
+
# try_for { click_button('Search' }
|
84
|
+
def try_for(timeout = $testwise_polling_timeout, polling_interval = $testwise_polling_interval || 1, &block)
|
85
|
+
start_time = Time.now
|
86
|
+
|
87
|
+
last_error = nil
|
88
|
+
until (duration = Time.now - start_time) > timeout
|
89
|
+
begin
|
90
|
+
return if yield
|
91
|
+
last_error = nil
|
92
|
+
rescue => e
|
93
|
+
last_error = e
|
94
|
+
end
|
95
|
+
sleep polling_interval
|
96
|
+
end
|
97
|
+
|
98
|
+
raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
|
99
|
+
raise "Timeout after #{duration.to_i} seconds."
|
100
|
+
end
|
101
|
+
alias try_upto try_for
|
102
|
+
alias try_until try_for
|
103
|
+
|
104
|
+
##
|
105
|
+
# Convert :first to 1, :second to 2, and so on...
|
106
|
+
def symbol_to_sequence(symb)
|
107
|
+
value = { :zero => 0,
|
108
|
+
:first => 1,
|
109
|
+
:second => 2,
|
110
|
+
:third => 3,
|
111
|
+
:fourth => 4,
|
112
|
+
:fifth => 5,
|
113
|
+
:sixth => 6,
|
114
|
+
:seventh => 7,
|
115
|
+
:eighth => 8,
|
116
|
+
:ninth => 9,
|
117
|
+
:tenth => 10 }[symb]
|
118
|
+
return value || symb.to_i
|
119
|
+
end
|
120
|
+
|
121
|
+
# monitor current execution using
|
122
|
+
#
|
123
|
+
# Usage
|
124
|
+
# log_time { browser.click_button('Confirm') }
|
125
|
+
def log_time(msg, &block)
|
126
|
+
start_time = Time.now
|
127
|
+
begin;
|
128
|
+
dump_caller_stack;
|
129
|
+
rescue;
|
130
|
+
end;
|
131
|
+
|
132
|
+
Thread.current[:log] ||= []
|
133
|
+
begin
|
134
|
+
yield
|
135
|
+
|
136
|
+
Thread.current[:log] << {:file => File.basename(__FILE__),
|
137
|
+
:message => msg,
|
138
|
+
:start_time => Time.now,
|
139
|
+
:duration => Time.now - start_time}
|
140
|
+
|
141
|
+
rescue => e
|
142
|
+
|
143
|
+
Thread.current[:log] << {:file => File.basename(__FILE__),
|
144
|
+
:message => msg + " => Failed",
|
145
|
+
:start_time => Time.now,
|
146
|
+
:duration => Time.now - start_time}
|
147
|
+
ensure
|
148
|
+
end_time = Time.now
|
149
|
+
format_date_time = start_time.strftime("%Y-%m-%d %H:%M:%S")
|
150
|
+
connect_to_loadwise(" LOAD", "#{Thread.current[:id]}|#{msg}|#{format_date_time}|#{Time.now - start_time}")
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
def init_memory_database(force = true)
|
156
|
+
# Open a database
|
157
|
+
require 'sqlite3'
|
158
|
+
if $memory_db.nil? || force
|
159
|
+
$memory_db = SQLite3::Database.new ":memory:"
|
160
|
+
|
161
|
+
|
162
|
+
# Create a database
|
163
|
+
rows = $memory_db.execute "
|
164
|
+
create table load_test_stats (
|
165
|
+
id integer PRIMARY KEY,
|
166
|
+
virtual_user varchar(64),
|
167
|
+
test_file varchar(256),
|
168
|
+
description varchar(256),
|
169
|
+
started_at integer,
|
170
|
+
duration decimal(6, 2),
|
171
|
+
ended_at integer
|
172
|
+
);"
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# @started_at : Unix timestamp to get back: Time.at()
|
179
|
+
#
|
180
|
+
def append_test_result(vu, test_file, description, started_at, duration)
|
181
|
+
return if RUBY_PLATFORM =~ /java/
|
182
|
+
init_memory_database if $memory_db.nil?
|
183
|
+
begin
|
184
|
+
$memory_db.execute("insert into load_test_stats (virtual_user, test_file, description, started_at, duration, ended_at) values (?, ?, ?, ?, ?, ?)", vu, "", description, started_at, duration, Time.now.to_i)
|
185
|
+
rescue => e
|
186
|
+
puts "[WARN] Failed to append test results: #{vu}|#{test_file}|#{description}|#{started_at}|#{duration}\n#{e} => #{e.backtrace}"
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
#
|
193
|
+
# How many virtual users should be running immedately
|
194
|
+
# :start_virtual_user_count
|
195
|
+
#
|
196
|
+
# How many threads should be running at peak load.
|
197
|
+
# :peak_virtual_user_count
|
198
|
+
#
|
199
|
+
# How many seconds to wait between starting threads.
|
200
|
+
# :delay_between_thread_start
|
201
|
+
#
|
202
|
+
#
|
203
|
+
# How many minutes the test should run with all threads active.
|
204
|
+
# TIME_AT_PEAK_QPS = 10 # minutes
|
205
|
+
#
|
206
|
+
# Defaults:
|
207
|
+
# :start_virtual_user_count => 1, :peak_virtual_user_count => 3, :delay_between_thread_start => 10
|
208
|
+
def run_with_virtual_users(opts = {}, &block)
|
209
|
+
|
210
|
+
init_memory_database unless RUBY_PLATFORM =~ /java/
|
211
|
+
$vu_error_printed = false
|
212
|
+
|
213
|
+
if $load_runtime_options
|
214
|
+
default_opts = $load_runtime_options
|
215
|
+
else
|
216
|
+
if RUBY_PLATFORM =~ /java/
|
217
|
+
default_opts = {}
|
218
|
+
default_opts[:start_virtual_user_count] = ENV["LOADWISE_START_VIRTUAL_USER_COUNT"].to_i if ENV["LOADWISE_START_VIRTUAL_USER_COUNT"]
|
219
|
+
default_opts[:peak_virtual_user_count] = ENV["LOADWISE_PEAK_VIRTUAL_USER_COUNT"].to_i if ENV["LOADWISE_PEAK_VIRTUAL_USER_COUNT"]
|
220
|
+
default_opts[:delay_between_thread_start] = ENV["LOADWISE_DELAY_BETWEEN_THREAD_START"].to_i if ENV["LOADWISE_DELAY_BETWEEN_THREAD_START"]
|
221
|
+
default_opts[:for_how_long] = ENV["LOADWISE_FOR_HOW_LONG"].to_i if ENV["LOADWISE_FOR_HOW_LONG"]
|
222
|
+
else
|
223
|
+
# default to performance testing
|
224
|
+
default_opts = {:start_virtual_user_count => 1,
|
225
|
+
:peak_virtual_user_count => 1,
|
226
|
+
:delay_between_thread_start => 0 }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
opts = default_opts.merge(opts)
|
231
|
+
puts "[INFO] {LoadTestHelper} opts => #{opts.inspect}"
|
232
|
+
start_virtual_user_count = opts[:start_virtual_user_count] || 2
|
233
|
+
peak_virtual_user_count = opts[:peak_virtual_user_count] || 2
|
234
|
+
delay_between_thread_start = opts[:delay_between_thread_start] || 0
|
235
|
+
for_how_long = opts[:for_how_long]
|
236
|
+
|
237
|
+
# puts "DEBUG for_how_long => #{for_how_long}"
|
238
|
+
if opts[:virtual_user_count] then
|
239
|
+
start_virtual_user_count ||= opts[:virtual_user_count]
|
240
|
+
peak_virtual_user_count ||= opts[:virtual_user_count]
|
241
|
+
end
|
242
|
+
|
243
|
+
raise "too many virtual users" if peak_virtual_user_count > MAX_VU
|
244
|
+
|
245
|
+
if $LOADWISE_PREVIEW
|
246
|
+
start_virtual_user_count = peak_virtual_user_count = 1
|
247
|
+
end
|
248
|
+
|
249
|
+
connect_to_loadwise("VU_START", "")
|
250
|
+
|
251
|
+
if (peak_virtual_user_count <= 1)
|
252
|
+
yield
|
253
|
+
else
|
254
|
+
threads = []
|
255
|
+
vu_reports = {}
|
256
|
+
|
257
|
+
start_virtual_user_count.times do |idx|
|
258
|
+
threads[idx] = Thread.new do
|
259
|
+
Thread.current[:id] = idx
|
260
|
+
start_time = Time.now
|
261
|
+
vu_reports[idx] ||= []
|
262
|
+
begin
|
263
|
+
if for_how_long
|
264
|
+
Timeout::timeout(for_how_long) do
|
265
|
+
while(true)
|
266
|
+
yield
|
267
|
+
end
|
268
|
+
end
|
269
|
+
else
|
270
|
+
yield
|
271
|
+
end
|
272
|
+
|
273
|
+
vu_reports[idx] = Thread.current[:log]
|
274
|
+
rescue Timeout::Error
|
275
|
+
vu_reports[idx] = Thread.current[:log]
|
276
|
+
puts "Too Slow 2"
|
277
|
+
rescue => e
|
278
|
+
vu_reports[idx] = Thread.current[:log]
|
279
|
+
vu_reports[idx] ||= []
|
280
|
+
vu_reports[idx] << { :error => e }
|
281
|
+
# TODO
|
282
|
+
connect_to_loadwise("VU_ERROR", Thread.current[:id].to_s + "|" + e.to_s)
|
283
|
+
unless $vu_error_printed
|
284
|
+
puts "VU[#{idx}] Failed: " + e.backtrace.to_s
|
285
|
+
$vu_error_printed = true
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
vu_reports[idx] ||= []
|
290
|
+
vu_reports[idx] << { :message => "Total Duration (Initial)", :start_time => start_time, :duration => Time.now - start_time }
|
291
|
+
connect_to_loadwise("VU_END", Thread.current[:id].to_s)
|
292
|
+
puts "VU[#{idx+1}] #{Time.now - start_time}s"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
(peak_virtual_user_count - start_virtual_user_count).times do |nidx|
|
297
|
+
sleep delay_between_thread_start
|
298
|
+
idx = nidx + start_virtual_user_count
|
299
|
+
threads[idx] = Thread.new do
|
300
|
+
start_time = Time.now
|
301
|
+
vu_reports[idx] ||= []
|
302
|
+
begin
|
303
|
+
if for_how_long
|
304
|
+
Timeout::timeout(for_how_long) do
|
305
|
+
while(true)
|
306
|
+
yield
|
307
|
+
end
|
308
|
+
end
|
309
|
+
else
|
310
|
+
yield
|
311
|
+
end
|
312
|
+
vu_reports[idx] = Thread.current[:log]
|
313
|
+
rescue Timeout::Error
|
314
|
+
vu_reports[idx] = Thread.current[:log]
|
315
|
+
puts "!!!Too Slow 2"
|
316
|
+
rescue => e
|
317
|
+
vu_reports[idx] = Thread.current[:log]
|
318
|
+
vu_reports[idx] ||= []
|
319
|
+
vu_reports[idx] << { :error => e }
|
320
|
+
connect_to_loadwise("VU_ERROR", Thread.current[:id].to_s + "|" + e.to_s)
|
321
|
+
unless $vu_error_printed
|
322
|
+
puts "VU[#{idx}] Failed: " + e.backtrace.to_s
|
323
|
+
$vu_error_printed = true
|
324
|
+
end
|
325
|
+
end
|
326
|
+
vu_reports[idx] ||= []
|
327
|
+
vu_reports[idx] << { :message => "Total Duration (Peak)", :start_time => start_time, :duration => Time.now - start_time }
|
328
|
+
puts "VU[#{idx+1}] #{Time.now - start_time}s"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
threads.each {|t| t.join; }
|
333
|
+
|
334
|
+
=begin
|
335
|
+
# after test finishing, don't try to parse the data, LoadWise can see $memory database
|
336
|
+
|
337
|
+
vu_reports.each do |key, value|
|
338
|
+
value.each do |entry|
|
339
|
+
append_test_result(key.to_s, entry[:file], entry[:message], entry[:start_time].to_i, entry[:duration])
|
340
|
+
if entry[:error] then
|
341
|
+
puts "{load_test_helper.rb} Execution Error: #{entry[:error]}"
|
342
|
+
append_test_result(key.to_s, entry[:file], entry[:error], entry[:start_time].to_i, entry[:duration])
|
343
|
+
else
|
344
|
+
puts "[#{key}] #{entry[:message]}, #{entry[:duration]}"
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
=end
|
349
|
+
return vu_reports
|
350
|
+
|
351
|
+
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
end
|
359
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module RWebSpec
|
4
|
+
module Mechanize
|
5
|
+
|
6
|
+
module LoadWisePlugin
|
7
|
+
|
8
|
+
def debug(message)
|
9
|
+
Thread.pass
|
10
|
+
connect_to_loadwise(" DEBUG", message.to_s + "\r\n") if $RUN_IN_TESTWISE && message
|
11
|
+
end
|
12
|
+
|
13
|
+
def connect_to_loadwise(message_type, body)
|
14
|
+
return if RUBY_PLATFORM !~ /java/i && $LOADWISE_TRACE_PORT.nil?
|
15
|
+
# Thread.pass
|
16
|
+
loadwise_port = ($LOADWISE_TRACE_PORT || 7125) + rand(5)
|
17
|
+
the_message = message_type + "|" + body
|
18
|
+
|
19
|
+
begin
|
20
|
+
# $log.info("[MESSAGE] " + the_message)
|
21
|
+
loadwise_socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
22
|
+
loadwise_socket.connect(Socket.pack_sockaddr_in(loadwise_port, '127.0.0.1'))
|
23
|
+
loadwise_socket.puts(the_message)
|
24
|
+
@last_message = the_message
|
25
|
+
loadwise_socket.close
|
26
|
+
rescue => e
|
27
|
+
puts("Failed to contact LoadWise '#{message_type}|#{body}' at #{loadwise_port}: #{e}")
|
28
|
+
retry
|
29
|
+
# $log.warn("Failed to contact TestWise: #{e}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Support of iTest to ajust the intervals between keystroke/mouse operations
|
34
|
+
def operation_delay
|
35
|
+
begin
|
36
|
+
|
37
|
+
if $TESTWISE_OPERATION_DELAY && $TESTWISE_OPERATION_DELAY > 0 &&
|
38
|
+
$TESTWISE_OPERATION_DELAY < 30000 then # max 30 seconds
|
39
|
+
Thread.pass
|
40
|
+
sleep($TESTWISE_OPERATION_DELAY / 1000)
|
41
|
+
end
|
42
|
+
|
43
|
+
while $TESTWISE_PAUSE || $LOADWISE_PAUSE
|
44
|
+
Thread.pass
|
45
|
+
debug("Paused, waiting ...")
|
46
|
+
sleep 1
|
47
|
+
end
|
48
|
+
rescue => e
|
49
|
+
puts "Error on delaying: #{e}"
|
50
|
+
# ignore
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def notify_screenshot_location(image_file_path)
|
55
|
+
connect_to_loadwise(" SHOT", image_file_path)
|
56
|
+
end
|
57
|
+
|
58
|
+
# find out the line (and file) the execution is on, and notify iTest via Socket
|
59
|
+
def dump_caller_stack
|
60
|
+
# puts "CAlling dump_caller_stack"
|
61
|
+
return unless ($TESTWISE_TRACE_EXECUTION || $LOADWISE_TRACE_EXECUTION)
|
62
|
+
begin
|
63
|
+
trace_lines = []
|
64
|
+
trace_file = nil
|
65
|
+
found_first_spec_reference = false
|
66
|
+
caller.each_with_index do |position, idx|
|
67
|
+
next unless position =~ /\A(.*?):(\d+)/
|
68
|
+
trace_file = $1
|
69
|
+
if trace_file =~ /(_spec|_test|_rwebspec)\.rb\s*$/ || trace_file =~ /\.feature$/
|
70
|
+
found_first_spec_reference = true
|
71
|
+
trace_lines << position
|
72
|
+
break
|
73
|
+
end
|
74
|
+
trace_lines << position
|
75
|
+
break if trace_file =~ /example\/example_methods\.rb$/ or trace_file =~ /example\/example_group_methods\.rb$/
|
76
|
+
break if trace_lines.size > 10
|
77
|
+
# TODO: send multiple trace to be parse with pages.rb
|
78
|
+
# break if trace_file =~ /example\/example_methods\.rb$/ or trace_file =~ /example\/example_group_methods\.rb$/ or trace_file =~ /driver\.rb$/ or trace_file =~ /timeout\.rb$/ # don't include rspec or ruby trace
|
79
|
+
end
|
80
|
+
|
81
|
+
# (trace_file.include?("_spec.rb") || trace_file.include?("_rwebspec.rb") || trace_file.include?("_test.rb") || trace_file.include?("_cmd.rb"))
|
82
|
+
if !trace_lines.empty?
|
83
|
+
connect_to_loadwise(" TRACE", trace_lines.reverse.join("|"))
|
84
|
+
end
|
85
|
+
|
86
|
+
rescue => e
|
87
|
+
puts "failed to capture log: #{e}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
# ZZ patches to RSpec 1.1.2 - 1.1.4
|
4
|
+
# - add to_s method to example_group
|
5
|
+
module Spec
|
6
|
+
module Example
|
7
|
+
class ExampleGroup
|
8
|
+
def to_s
|
9
|
+
@_defined_description
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# example
|
16
|
+
# should link_by_text(text, options).size > 0
|
17
|
+
|
18
|
+
module RWebSpec
|
19
|
+
module RSpecHelper
|
20
|
+
include RWebSpec::Driver
|
21
|
+
include RWebSpec::Utils
|
22
|
+
include RWebSpec::Assert
|
23
|
+
|
24
|
+
# --
|
25
|
+
# Content
|
26
|
+
# --
|
27
|
+
|
28
|
+
def table_source(table_id)
|
29
|
+
table(:id, table_id).innerHTML
|
30
|
+
# elem = @web_browser.document.getElementById(table_id)
|
31
|
+
# raise "The element '#{table_id}' is not a table or there are multple elements with same id" unless elem.name.uppercase == "TABLE"
|
32
|
+
# elem.innerHTML
|
33
|
+
end
|
34
|
+
alias table_source_by_id table_source
|
35
|
+
|
36
|
+
def element_text(elem_id)
|
37
|
+
@web_browser.element_value(elem_id)
|
38
|
+
end
|
39
|
+
alias element_text_by_id element_text
|
40
|
+
|
41
|
+
#TODO: is it working?
|
42
|
+
def element_source(elem_id)
|
43
|
+
@web_browser.get_html_in_element(elem_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def button_by_id(button_id)
|
48
|
+
button(:id, button_id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def buttons_by_caption(text)
|
52
|
+
button(:text, text)
|
53
|
+
end
|
54
|
+
alias buttons_by_text buttons_by_caption
|
55
|
+
|
56
|
+
def link_by_id(link_id)
|
57
|
+
link(:id, link_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# default options: exact => true
|
61
|
+
def links_by_text(link_text, options = {})
|
62
|
+
options.merge!({:exact=> true})
|
63
|
+
matching_links = []
|
64
|
+
links.each { |link|
|
65
|
+
matching_links << link if (options[:exact] ? link.text == link_text : link.text.include?(link_text))
|
66
|
+
}
|
67
|
+
return matching_links
|
68
|
+
end
|
69
|
+
alias links_with_text links_by_text
|
70
|
+
|
71
|
+
def save_page(file_name = nil)
|
72
|
+
@web_browser.save_page(file_name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def save_content_to_file(content, file_name = nil)
|
76
|
+
file_name ||= Time.now.strftime("%Y%m%d%H%M%S") + ".html"
|
77
|
+
puts "about to save page: #{File.expand_path(file_name)}"
|
78
|
+
File.open(file_name, "w").puts content
|
79
|
+
end
|
80
|
+
|
81
|
+
# When running
|
82
|
+
def debugging?
|
83
|
+
($TESTWISE_DEBUGGING && $TESTWISE_RUNNING_AS == "test_case")
|
84
|
+
end
|
85
|
+
|
86
|
+
# RSpec Matchers
|
87
|
+
#
|
88
|
+
# Example,
|
89
|
+
# a_number.should be_odd_number
|
90
|
+
def be_odd_number
|
91
|
+
simple_matcher("must be odd number") { |actual| actual && actual.to_id % 2 == 1}
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|