rwebspec-mechanize 0.2.1
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/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
|