rwebspec-webdriver 0.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 +99 -0
- data/lib/rspec_extensions.rb +51 -0
- data/lib/rwebspec-webdriver.rb +52 -0
- data/lib/rwebspec/assert.rb +443 -0
- data/lib/rwebspec/clickJSDialog.rb +15 -0
- data/lib/rwebspec/context.rb +24 -0
- data/lib/rwebspec/database_checker.rb +74 -0
- data/lib/rwebspec/driver.rb +1009 -0
- data/lib/rwebspec/element_locator.rb +87 -0
- data/lib/rwebspec/load_test_helper.rb +172 -0
- data/lib/rwebspec/matchers/contains_text.rb +37 -0
- data/lib/rwebspec/popup.rb +147 -0
- data/lib/rwebspec/rspec_helper.rb +99 -0
- data/lib/rwebspec/test_script.rb +8 -0
- data/lib/rwebspec/test_utils.rb +217 -0
- data/lib/rwebspec/testwise_plugin.rb +83 -0
- data/lib/rwebspec/using_pages.rb +49 -0
- data/lib/rwebspec/web_browser.rb +742 -0
- data/lib/rwebspec/web_page.rb +108 -0
- data/lib/rwebspec/web_testcase.rb +38 -0
- data/lib/webdriver_extensions.rb +9 -0
- data/lib/window_script_extensions.rb +19 -0
- metadata +121 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module RWebSpec
|
2
|
+
|
3
|
+
module ElementLocator
|
4
|
+
|
5
|
+
BUTTON_VALID_TYPES = %w[button reset submit image]
|
6
|
+
def button_elements
|
7
|
+
find_elements(:xpath, ".//button | .//input[#{attribute_expression :type => BUTTON_VALID_TYPES}]")
|
8
|
+
end
|
9
|
+
|
10
|
+
CHECK_BOX_TYPES = %w(checkbox)
|
11
|
+
def check_box_elements(how, what, opts = [])
|
12
|
+
find_elements(:xpath, ".//input[#{attribute_expression :type => CHECK_BOX_TYPES}]")
|
13
|
+
end
|
14
|
+
|
15
|
+
RADIO_TYPES = %w(radio)
|
16
|
+
def radio_elements(how, what, opts = [])
|
17
|
+
find_elements(:xpath, ".//input[#{attribute_expression :type => RADIO_TYPES}]")
|
18
|
+
end
|
19
|
+
|
20
|
+
def select_elements(how, what, opts = [])
|
21
|
+
find_elements(:xpath, ".//input[#{attribute_expression :type => RADIO_TYPES}]")
|
22
|
+
end
|
23
|
+
|
24
|
+
# TextField, TextArea
|
25
|
+
TEXT_FILED_TYPES = %w(text)
|
26
|
+
def text_field_elements
|
27
|
+
find_elements(:xpath, ".//input[#{attribute_expression :type => TEXT_FILED_TYPES}]")
|
28
|
+
end
|
29
|
+
|
30
|
+
def text_area_elements
|
31
|
+
find_elements(:xpath, ".//textarea")
|
32
|
+
end
|
33
|
+
|
34
|
+
FILE_FIELD_TYPES = %w(file)
|
35
|
+
def file_field_elements
|
36
|
+
find_elements(:xpath, ".//input[#{attribute_expression :type => FILE_FIELD_TYPES}]")
|
37
|
+
end
|
38
|
+
|
39
|
+
HIDDEN_TYPES = %w(hidden)
|
40
|
+
def hidden_elements
|
41
|
+
find_elements(:xpath, ".//input[#{attribute_expression :type => HIDDEN_TYPES}]")
|
42
|
+
end
|
43
|
+
|
44
|
+
#---
|
45
|
+
def find_by_tag(tag)
|
46
|
+
find_elements(:tag_name, tag)
|
47
|
+
end
|
48
|
+
|
49
|
+
def should_use_label_element?
|
50
|
+
@selector[:tag_name] != "option" rescue false
|
51
|
+
end
|
52
|
+
|
53
|
+
def equal_pair(key, value)
|
54
|
+
# we assume :label means a corresponding label element, not the attribute
|
55
|
+
if key == :label && should_use_label_element?
|
56
|
+
"@id=//label[normalize-space()='#{value}']/@for"
|
57
|
+
else
|
58
|
+
"#{lhs_for(key)}='#{value}'"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def lhs_for(key)
|
63
|
+
case key
|
64
|
+
when :text, 'text'
|
65
|
+
'normalize-space()'
|
66
|
+
when :href
|
67
|
+
# TODO: change this behaviour?
|
68
|
+
'normalize-space(@href)'
|
69
|
+
else
|
70
|
+
"@#{key.to_s.gsub("_", "-")}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def attribute_expression(selectors)
|
76
|
+
selectors.map do |key, val|
|
77
|
+
if val.kind_of?(Array)
|
78
|
+
"(" + val.map { |v| equal_pair(key, v) }.join(" or ") + ")"
|
79
|
+
else
|
80
|
+
equal_pair(key, val)
|
81
|
+
end
|
82
|
+
end.join(" and ")
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
|
2
|
+
module RWebSpec
|
3
|
+
module LoadTestHelper
|
4
|
+
|
5
|
+
include RWebSpec::Utils
|
6
|
+
include RWebSpec::Assert
|
7
|
+
|
8
|
+
MAX_VU = 1000
|
9
|
+
|
10
|
+
# only support firefox or Celerity
|
11
|
+
def open_browser(base_url, options = {})
|
12
|
+
default_options = {:resynchronize => false, :firefox => false }
|
13
|
+
options = default_options.merge(options)
|
14
|
+
options[:firefox] ||= (ENV['LOADWISE_PREVIEW'] || $LOADWISE_PREVIEW)
|
15
|
+
RWebSpec::WebBrowser.new(base_url, nil, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# maybe attach_browser
|
19
|
+
|
20
|
+
# Does not provide real function, other than make enhancing test syntax
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
# allow { click_button('Register') }
|
24
|
+
def allow(&block)
|
25
|
+
yield
|
26
|
+
end
|
27
|
+
alias shall_allow allow
|
28
|
+
alias allowing allow
|
29
|
+
|
30
|
+
# try operation, ignore if errors occur
|
31
|
+
#
|
32
|
+
# Example:
|
33
|
+
# failsafe { click_link("Logout") } # try logout, but it still OK if not being able to (already logout))
|
34
|
+
def failsafe(&block)
|
35
|
+
begin
|
36
|
+
yield
|
37
|
+
rescue =>e
|
38
|
+
end
|
39
|
+
end
|
40
|
+
alias fail_safe failsafe
|
41
|
+
|
42
|
+
# Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds).
|
43
|
+
# Error will be ignored until timeout
|
44
|
+
# Example
|
45
|
+
# try { click_link('waiting')}
|
46
|
+
# try(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
|
47
|
+
# try { click_button('Search' }
|
48
|
+
def try(timeout = @@default_timeout, polling_interval = @@default_polling_interval || 1, &block)
|
49
|
+
start_time = Time.now
|
50
|
+
|
51
|
+
last_error = nil
|
52
|
+
until (duration = Time.now - start_time) > timeout
|
53
|
+
begin
|
54
|
+
return if yield
|
55
|
+
last_error = nil
|
56
|
+
rescue => e
|
57
|
+
last_error = e
|
58
|
+
end
|
59
|
+
sleep polling_interval
|
60
|
+
end
|
61
|
+
|
62
|
+
raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
|
63
|
+
raise "Timeout after #{duration.to_i} seconds."
|
64
|
+
end
|
65
|
+
alias try_upto try
|
66
|
+
|
67
|
+
##
|
68
|
+
# Convert :first to 1, :second to 2, and so on...
|
69
|
+
def symbol_to_sequence(symb)
|
70
|
+
value = { :zero => 0,
|
71
|
+
:first => 1,
|
72
|
+
:second => 2,
|
73
|
+
:third => 3,
|
74
|
+
:fourth => 4,
|
75
|
+
:fifth => 5,
|
76
|
+
:sixth => 6,
|
77
|
+
:seventh => 7,
|
78
|
+
:eighth => 8,
|
79
|
+
:ninth => 9,
|
80
|
+
:tenth => 10 }[symb]
|
81
|
+
return value || symb.to_i
|
82
|
+
end
|
83
|
+
|
84
|
+
# monitor current execution using
|
85
|
+
#
|
86
|
+
# Usage
|
87
|
+
# log_time { browser.click_button('Confirm') }
|
88
|
+
def log_time(msg, &block)
|
89
|
+
start_time = Time.now
|
90
|
+
yield
|
91
|
+
end_time = Time.now
|
92
|
+
|
93
|
+
Thread.current[:log] ||= []
|
94
|
+
Thread.current[:log] << {:file => File.basename(__FILE__),
|
95
|
+
:message => msg,
|
96
|
+
:start_time => Time.now,
|
97
|
+
:duration => Time.now - start_time}
|
98
|
+
|
99
|
+
if $LOADWISE_MONITOR
|
100
|
+
begin
|
101
|
+
require 'java'
|
102
|
+
puts "Calling Java 1"
|
103
|
+
java_import com.loadwise.db.MemoryDatabase
|
104
|
+
#puts "Calling Java 2: #{MemoryDatabase.count}"
|
105
|
+
MemoryDatabase.addEntry(1, "zdfa01", "a_spec.rb", msg, start_time, end_time);
|
106
|
+
puts "Calling Java Ok: #{MemoryDatabase.count}"
|
107
|
+
rescue NameError => ne
|
108
|
+
puts "Name Error: #{ne}"
|
109
|
+
# failed to load Java class
|
110
|
+
rescue => e
|
111
|
+
puts "Failed to calling Java: #{e.class.name}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
# How to notify LoadWise at real time
|
115
|
+
# LoadWise to collect CPU
|
116
|
+
end
|
117
|
+
|
118
|
+
def run_with_virtual_users(virtual_user_count = 2, preview = false, &block)
|
119
|
+
raise "too many virtual users" if virtual_user_count > MAX_VU
|
120
|
+
|
121
|
+
begin
|
122
|
+
if defined?(LOADWISE_PREVIEW)
|
123
|
+
preview = LOADWISE_PREVIEW
|
124
|
+
end
|
125
|
+
rescue => e1
|
126
|
+
end
|
127
|
+
|
128
|
+
if preview
|
129
|
+
virtual_user_count = 1
|
130
|
+
$LOADWISE_PREVIEW = true
|
131
|
+
end
|
132
|
+
|
133
|
+
if (virtual_user_count <= 1)
|
134
|
+
yield
|
135
|
+
else
|
136
|
+
threads = []
|
137
|
+
vu_reports = {}
|
138
|
+
virtual_user_count.times do |idx|
|
139
|
+
threads[idx] = Thread.new do
|
140
|
+
start_time = Time.now
|
141
|
+
vu_reports[idx] ||= []
|
142
|
+
begin
|
143
|
+
yield
|
144
|
+
vu_reports[idx] = Thread.current[:log]
|
145
|
+
rescue => e
|
146
|
+
vu_reports[idx] = Thread.current[:log]
|
147
|
+
vu_reports[idx] ||= []
|
148
|
+
vu_reports[idx] << { :error => e }
|
149
|
+
end
|
150
|
+
vu_reports[idx] ||= []
|
151
|
+
vu_reports[idx] << { :message => "Total Duration", :duration => Time.now - start_time }
|
152
|
+
puts "VU[#{idx+1}] #{Time.now - start_time}s"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
threads.each {|t| t.join; }
|
157
|
+
vu_reports.each do |key, value|
|
158
|
+
value.each do |entry|
|
159
|
+
if entry[:error] then
|
160
|
+
puts "Error: #{entry[:error]}"
|
161
|
+
else
|
162
|
+
puts "[#{key}] #{entry[:message]}, #{entry[:duration]}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
return vu_reports
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class ContainsText
|
2
|
+
|
3
|
+
# this is what the matcher is called on.
|
4
|
+
# In this case:
|
5
|
+
# foo.should contains(:bars)
|
6
|
+
# foo would be passed to the +initialize+
|
7
|
+
def initialize(expected)
|
8
|
+
@expected = expected
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(actual)
|
12
|
+
@actual = actual
|
13
|
+
return actual && actual.include?(@expected)
|
14
|
+
end
|
15
|
+
|
16
|
+
def actual_text
|
17
|
+
@actual.to_s.length > 256 ? @actual[0, 255] : @actual
|
18
|
+
end
|
19
|
+
|
20
|
+
# error message for should
|
21
|
+
def failure_message
|
22
|
+
"expected '#{actual_text}' to contain '#{@expected}', but it didn't"
|
23
|
+
end
|
24
|
+
|
25
|
+
# error message for should_not
|
26
|
+
def negative_failure_message
|
27
|
+
"expected '#{actual_text}' not to contain '#{@expected}', but it did"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# This method is the one you use with should/should_not
|
34
|
+
def contains_text?(expected)
|
35
|
+
ContainsText.new(expected)
|
36
|
+
end
|
37
|
+
alias contains? contains_text?
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module RWebSpec
|
2
|
+
module Popup
|
3
|
+
|
4
|
+
#= Popup
|
5
|
+
#
|
6
|
+
|
7
|
+
# Start background thread to click popup windows
|
8
|
+
# Warning:
|
9
|
+
# Make browser window active
|
10
|
+
# Don't mouse your mouse to focus other window during test execution
|
11
|
+
def check_for_popups
|
12
|
+
autoit = WIN32OLE.new('AutoItX3.Control')
|
13
|
+
#
|
14
|
+
# Do forever - assumes popups could occur anywhere/anytime in your
|
15
|
+
# application.
|
16
|
+
loop do
|
17
|
+
# Look for window with given title. Give up after 1 second.
|
18
|
+
ret = autoit.WinWait('Windows Internet Explorer', '', 1)
|
19
|
+
#
|
20
|
+
# If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
|
21
|
+
if (ret==1) then
|
22
|
+
autoit.Send('{enter}')
|
23
|
+
end
|
24
|
+
#
|
25
|
+
# Take a rest to avoid chewing up cycles and give another thread a go.
|
26
|
+
# Then resume the loop.
|
27
|
+
sleep(3)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Check for "Security Information" and "Security Alert" alert popup, click 'Yes'
|
33
|
+
#
|
34
|
+
# Usage: For individual test suite
|
35
|
+
#
|
36
|
+
# before(:all) do
|
37
|
+
# $popup = Thread.new { check_for_alerts }
|
38
|
+
# open_in_browser
|
39
|
+
# ...
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# after(:all) do
|
43
|
+
# close_browser
|
44
|
+
# Thread.kill($popup)
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# or for all tests,
|
48
|
+
# $popup = Thread.new { check_for_alerts }
|
49
|
+
# at_exit{ Thread.kill($popup) }
|
50
|
+
def check_for_security_alerts
|
51
|
+
autoit = WIN32OLE.new('AutoItX3.Control')
|
52
|
+
loop do
|
53
|
+
["Security Alert", "Security Information"].each do |win_title|
|
54
|
+
ret = autoit.WinWait(win_title, '', 1)
|
55
|
+
if (ret==1) then
|
56
|
+
autoit.Send('{Y}')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
sleep(3)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def verify_alert(title = "Microsoft Internet Explorer", button = "OK")
|
64
|
+
if is_windows? && !is_firefox?
|
65
|
+
WIN32OLE.new('AutoItX3.Control').ControlClick(title, '', button)
|
66
|
+
else
|
67
|
+
raise "This function only supports IE"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def click_button_in_security_information_popup(button = "&Yes")
|
72
|
+
verify_alert("Security Information", "", button)
|
73
|
+
end
|
74
|
+
alias click_security_information_popup click_button_in_security_information_popup
|
75
|
+
|
76
|
+
def click_button_in_security_alert_popup(button = "&Yes")
|
77
|
+
verify_alert("Security Alert", "", button)
|
78
|
+
end
|
79
|
+
alias click_security_alert_popup click_button_in_security_alert_popup
|
80
|
+
|
81
|
+
def click_button_in_javascript_popup(button = "OK")
|
82
|
+
verify_alert()
|
83
|
+
end
|
84
|
+
alias click_javascript_popup click_button_in_javascript_popup
|
85
|
+
|
86
|
+
##
|
87
|
+
# This only works for IEs
|
88
|
+
# Cons:
|
89
|
+
# - Slow
|
90
|
+
# - only works in IE
|
91
|
+
# - does not work for security alert ?
|
92
|
+
def ie_popup_clicker(button_name = "OK", max_wait = 15)
|
93
|
+
require 'watir/contrib/enabled_popup'
|
94
|
+
require 'win32ole'
|
95
|
+
hwnd = ie.enabled_popup(15)
|
96
|
+
if (hwnd) #yeah! a popup
|
97
|
+
popup = WinClicker.new
|
98
|
+
popup.makeWindowActive(hwnd) #Activate the window.
|
99
|
+
popup.clickWindowsButton_hwnd(hwnd, button_name) #Click the button
|
100
|
+
#popup.clickWindowsButton(/Internet/,button_name,30)
|
101
|
+
popup = nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def click_popup_window(button, wait_time= 9, user_input=nil )
|
106
|
+
@web_browser.start_clicker(button, wait_time, user_input)
|
107
|
+
sleep 0.5
|
108
|
+
end
|
109
|
+
# run a separate process waiting for the popup window to click
|
110
|
+
#
|
111
|
+
#
|
112
|
+
def prepare_to_click_button_in_popup(button = "OK", wait_time = 3)
|
113
|
+
# !@web_browser.is_firefox?
|
114
|
+
# TODO: firefox is OK
|
115
|
+
if RUBY_PLATFORM =~ /mswin/ || RUBY_PLATFORM =~ /mingw/ then
|
116
|
+
start_checking_js_dialog(button, wait_time)
|
117
|
+
else
|
118
|
+
raise "this only support on Windows and on IE"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Start a background process to click the button on a javascript popup window
|
123
|
+
def start_checking_js_dialog(button = "OK", wait_time = 3)
|
124
|
+
w = WinClicker.new
|
125
|
+
longName = File.expand_path(File.dirname(__FILE__)).gsub("/", "\\" )
|
126
|
+
shortName = w.getShortFileName(longName)
|
127
|
+
c = "start ruby #{shortName}\\clickJSDialog.rb #{button} #{wait_time} "
|
128
|
+
w.winsystem(c)
|
129
|
+
w = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# Click the button in javascript popup dialog
|
133
|
+
# Usage:
|
134
|
+
# click_button_in_popup_after { click_link('Cancel')}
|
135
|
+
# click_button_in_popup_after("OK") { click_link('Cancel')}
|
136
|
+
#
|
137
|
+
def click_button_in_popup_after(options = {:button => "OK", :wait_time => 3}, &block)
|
138
|
+
if is_windows? then
|
139
|
+
start_checking_js_dialog(options[:button], options[:wait_time])
|
140
|
+
yield
|
141
|
+
else
|
142
|
+
raise "this only support on Windows and on IE"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require File.dirname(__FILE__) + "/driver"
|
3
|
+
require File.dirname(__FILE__) + "/web_page"
|
4
|
+
require File.dirname(__FILE__) + "/assert"
|
5
|
+
|
6
|
+
# ZZ patches to RSpec 1.1.2 - 1.1.4
|
7
|
+
# - add to_s method to example_group
|
8
|
+
module Spec
|
9
|
+
module Example
|
10
|
+
class ExampleGroup
|
11
|
+
def to_s
|
12
|
+
@_defined_description
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# example
|
19
|
+
# should link_by_text(text, options).size > 0
|
20
|
+
|
21
|
+
module RWebSpec
|
22
|
+
module RSpecHelper
|
23
|
+
include RWebSpec::Driver
|
24
|
+
include RWebSpec::Assert
|
25
|
+
include RWebSpec::Utils
|
26
|
+
|
27
|
+
# --
|
28
|
+
# Content
|
29
|
+
# --
|
30
|
+
|
31
|
+
def table_source(table_id)
|
32
|
+
table(:id, table_id).innerHTML
|
33
|
+
# elem = @web_browser.document.getElementById(table_id)
|
34
|
+
# raise "The element '#{table_id}' is not a table or there are multple elements with same id" unless elem.name.uppercase == "TABLE"
|
35
|
+
# elem.innerHTML
|
36
|
+
end
|
37
|
+
alias table_source_by_id table_source
|
38
|
+
|
39
|
+
def element_text(elem_id)
|
40
|
+
@web_browser.element_value(elem_id)
|
41
|
+
end
|
42
|
+
alias element_text_by_id element_text
|
43
|
+
|
44
|
+
#TODO: is it working?
|
45
|
+
def element_source(elem_id)
|
46
|
+
@web_browser.get_html_in_element(elem_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def button_by_id(button_id)
|
51
|
+
button(:id, button_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def buttons_by_caption(text)
|
55
|
+
button(:text, text)
|
56
|
+
end
|
57
|
+
alias buttons_by_text buttons_by_caption
|
58
|
+
|
59
|
+
def link_by_id(link_id)
|
60
|
+
link(:id, link_id)
|
61
|
+
end
|
62
|
+
|
63
|
+
# default options: exact => true
|
64
|
+
def links_by_text(link_text, options = {})
|
65
|
+
options.merge!({:exact=> true})
|
66
|
+
matching_links = []
|
67
|
+
links.each { |link|
|
68
|
+
matching_links << link if (options[:exact] ? link.text == link_text : link.text.include?(link_text))
|
69
|
+
}
|
70
|
+
return matching_links
|
71
|
+
end
|
72
|
+
alias links_with_text links_by_text
|
73
|
+
|
74
|
+
def save_page(file_name = nil)
|
75
|
+
@web_browser.save_page(file_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
def save_content_to_file(content, file_name = nil)
|
79
|
+
file_name ||= Time.now.strftime("%Y%m%d%H%M%S") + ".html"
|
80
|
+
puts "about to save page: #{File.expand_path(file_name)}"
|
81
|
+
File.open(file_name, "w").puts content
|
82
|
+
end
|
83
|
+
|
84
|
+
# When running
|
85
|
+
def debugging?
|
86
|
+
$ITEST2_DEBUGGING && $ITEST2_RUNNING_AS == "test_case"
|
87
|
+
end
|
88
|
+
|
89
|
+
# RSpec Matchers
|
90
|
+
#
|
91
|
+
# Example,
|
92
|
+
# a_number.should be_odd_number
|
93
|
+
def be_odd_number
|
94
|
+
simple_matcher("must be odd number") { |actual| actual && actual.to_id % 2 == 1}
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|