rwebunit 0.9.4 → 1.0.3
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 +228 -168
- data/MIT-LICENSE +1 -1
- data/README +32 -29
- data/Rakefile +5 -4
- data/lib/rspec_extensions.rb +10 -2
- data/lib/rwebunit.rb +8 -3
- data/lib/rwebunit/assert.rb +25 -24
- data/lib/rwebunit/clickJSDialog.rb +15 -0
- data/lib/rwebunit/context.rb +24 -24
- data/lib/rwebunit/driver.rb +297 -33
- data/lib/rwebunit/itest_plugin.rb +47 -0
- data/lib/rwebunit/matchers/contains_text.rb +37 -0
- data/lib/rwebunit/rspec_helper.rb +140 -128
- data/lib/rwebunit/test_utils.rb +98 -88
- data/lib/rwebunit/{web_tester.rb → web_browser.rb} +433 -510
- data/lib/rwebunit/web_page.rb +96 -99
- data/lib/rwebunit/web_testcase.rb +36 -36
- data/lib/watir_extensions.rb +65 -0
- data/test/mock_page.rb +8 -0
- data/test/setup.rb +10 -0
- data/test/test.html +129 -0
- data/test/test_assert.rb +64 -0
- data/test/test_driver.rb +23 -5
- metadata +24 -14
- data/sample/README.txt +0 -21
- data/sample/kangxi_home_webtest.rb +0 -37
- data/sample/kangxi_httpcaller_webtest.rb +0 -33
- data/sample/kangxi_pages.rb +0 -62
- data/sample/kangxi_xml_formatter_webtest.rb +0 -44
- data/sample/rwebunit_home_testcase.rb +0 -22
- data/sample/sample_rwebunit_test.rb +0 -15
- data/sample/sample_rwebunit_testcase.rb +0 -22
- data/sample/sample_watir_test.rb +0 -17
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module RWebUnit
|
4
|
+
module ITestPlugin
|
5
|
+
|
6
|
+
def connect_to_itest(message_type, body)
|
7
|
+
begin
|
8
|
+
the_message = message_type + "|" + body
|
9
|
+
if @last_message == the_message then
|
10
|
+
return
|
11
|
+
end
|
12
|
+
itest_port = $ITEST2_TRACE_PORT || 7025
|
13
|
+
itest_socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)
|
14
|
+
itest_socket.connect(Socket.pack_sockaddr_in(itest_port, 'localhost'))
|
15
|
+
itest_socket.puts(the_message)
|
16
|
+
@last_message = the_message
|
17
|
+
itest_socket.close
|
18
|
+
rescue => e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def debug(message)
|
23
|
+
connect_to_itest(" DEBUG", message + "\r\n") if $RUN_IN_ITEST
|
24
|
+
end
|
25
|
+
|
26
|
+
# find out the line (and file) the execution is on, and notify iTest via Socket
|
27
|
+
def dump_caller_stack
|
28
|
+
return unless $ITEST2_TRACE_EXECUTION
|
29
|
+
begin
|
30
|
+
caller.each_with_index do |position, idx|
|
31
|
+
next unless position =~ /\A(.*?):(\d+)/
|
32
|
+
file = $1
|
33
|
+
# TODO: send multiple trace to be parse with pages.rb
|
34
|
+
# next if file =~ /example\/example_methods\.rb$/ or file =~ /example\/example_group_methods\.rb$/ or file =~ /driver\.rb$/ or file =~ /timeout\.rb$/ # don't include rspec or ruby trace
|
35
|
+
|
36
|
+
if file.include?("_spec.rb") || file.include?("_test.rb") || file.include?("_cmd.rb")
|
37
|
+
connect_to_itest(" TRACE", position)
|
38
|
+
end
|
39
|
+
|
40
|
+
break if idx > 4 or file =~ /"_spec\.rb$/
|
41
|
+
end
|
42
|
+
rescue => e
|
43
|
+
puts "failed to capture log: #{e}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
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 > 1000000 ? @actual[0, 1000] : @actual
|
18
|
+
end
|
19
|
+
|
20
|
+
# error message for should
|
21
|
+
def failure_message
|
22
|
+
"expected #{actual_text} not to contains #{@expected}, but it did't"
|
23
|
+
end
|
24
|
+
|
25
|
+
# error message for should_not
|
26
|
+
def negative_failure_message
|
27
|
+
"expected #{actual_text} not to contains #{@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?
|
@@ -1,128 +1,140 @@
|
|
1
|
-
require 'uri'
|
2
|
-
|
3
|
-
# ZZ patches to RSpec 1.1.2
|
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 RWebUnit
|
19
|
-
module RSpecHelper
|
20
|
-
include RWebUnit::Driver
|
21
|
-
include RWebUnit::Utils
|
22
|
-
include RWebUnit::Assert
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
@
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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 RWebUnit
|
19
|
+
module RSpecHelper
|
20
|
+
include RWebUnit::Driver
|
21
|
+
include RWebUnit::Utils
|
22
|
+
include RWebUnit::Assert
|
23
|
+
|
24
|
+
# open a browser, and set base_url via hash, but does not acually
|
25
|
+
#
|
26
|
+
# example:
|
27
|
+
# open_browser :base_url => http://localhost:8080
|
28
|
+
#
|
29
|
+
# There are 3 ways to set base url
|
30
|
+
# 1. pass as first argument
|
31
|
+
# 2. If running using iTest2, used as confiured
|
32
|
+
# 3. Use default value set
|
33
|
+
def open_browser(base_url = nil, options = {})
|
34
|
+
base_url ||= $ITEST2_PROJECT_BASE_URL
|
35
|
+
base_url ||= $BASE_URL
|
36
|
+
raise "base_url must be set" if base_url.nil?
|
37
|
+
|
38
|
+
default_options = {:speed => "fast",
|
39
|
+
:visible => true,
|
40
|
+
:highlight_colour => 'yellow',
|
41
|
+
:close_others => true,
|
42
|
+
:start_new => false, # start a new browser always
|
43
|
+
:go => true}
|
44
|
+
|
45
|
+
options = default_options.merge options
|
46
|
+
options[:firefox] = true if "Firefox" == $ITEST2_BROWSER || "Firefox" == $BROWSER
|
47
|
+
($ITEST2_HIDE_BROWSER) ? $HIDE_IE = true : $HIDE_IE = false
|
48
|
+
|
49
|
+
uri = URI.parse(base_url)
|
50
|
+
uri_base = "#{uri.scheme}://#{uri.host}:#{uri.port}"
|
51
|
+
if options[:start_new]
|
52
|
+
@web_browser = WebBrowser.new(uri_base, nil, options)
|
53
|
+
else
|
54
|
+
# Reuse existing browser
|
55
|
+
@web_browser = WebBrowser.reuse(uri_base, options)
|
56
|
+
end
|
57
|
+
|
58
|
+
if options[:go]
|
59
|
+
(uri.path.length == 0) ? begin_at("/") : begin_at(uri.path)
|
60
|
+
end
|
61
|
+
return @web_browser
|
62
|
+
end
|
63
|
+
alias open_browser_with open_browser
|
64
|
+
|
65
|
+
# --
|
66
|
+
# Content
|
67
|
+
# --
|
68
|
+
|
69
|
+
def page_title
|
70
|
+
@web_browser.page_title
|
71
|
+
end
|
72
|
+
|
73
|
+
def page_source
|
74
|
+
@web_browser.page_source
|
75
|
+
end
|
76
|
+
|
77
|
+
def table_source(table_id)
|
78
|
+
table(:id, table_id).innerHTML
|
79
|
+
# elem = @web_browser.document.getElementById(table_id)
|
80
|
+
# raise "The element '#{table_id}' is not a table or there are multple elements with same id" unless elem.name.uppercase == "TABLE"
|
81
|
+
# elem.innerHTML
|
82
|
+
end
|
83
|
+
alias table_source_by_id table_source
|
84
|
+
|
85
|
+
def element_text(elem_id)
|
86
|
+
@web_browser.element_value(elem_id)
|
87
|
+
end
|
88
|
+
alias element_text_by_id element_text
|
89
|
+
|
90
|
+
#TODO: is it working?
|
91
|
+
def element_source(elem_id)
|
92
|
+
@web_browser.get_html_in_element(elem_id)
|
93
|
+
end
|
94
|
+
|
95
|
+
def element_by_id(elem_id)
|
96
|
+
@web_browser.element_by_id(elem_id)
|
97
|
+
end
|
98
|
+
|
99
|
+
def button_by_id(button_id)
|
100
|
+
button(:id, button_id)
|
101
|
+
end
|
102
|
+
|
103
|
+
def buttons_by_caption(text)
|
104
|
+
button(:text, text)
|
105
|
+
end
|
106
|
+
alias buttons_by_text buttons_by_caption
|
107
|
+
|
108
|
+
def link_by_id(link_id)
|
109
|
+
link(:id, link_id)
|
110
|
+
end
|
111
|
+
|
112
|
+
# default options: exact => true
|
113
|
+
def links_by_text(link_text, options = {})
|
114
|
+
options.merge!({:exact=> true})
|
115
|
+
matching_links = []
|
116
|
+
links.each { |link|
|
117
|
+
matching_links << link if (options[:exact] ? link.text == link_text : link.text.include?(link_text))
|
118
|
+
}
|
119
|
+
return matching_links
|
120
|
+
end
|
121
|
+
alias links_with_text links_by_text
|
122
|
+
|
123
|
+
def save_page(file_name = nil)
|
124
|
+
@web_browser.save_page(file_name)
|
125
|
+
end
|
126
|
+
|
127
|
+
def save_content_to_file(content, file_name = nil)
|
128
|
+
file_name ||= Time.now.strftime("%Y%m%d%H%M%S") + ".html"
|
129
|
+
puts "about to save page: #{File.expand_path(file_name)}"
|
130
|
+
File.open(file_name, "w").puts content
|
131
|
+
end
|
132
|
+
|
133
|
+
# When running
|
134
|
+
def debugging?
|
135
|
+
$ITEST2_DEBUGGING && $ITEST2_RUNNING_AS == "test_case"
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
data/lib/rwebunit/test_utils.rb
CHANGED
@@ -1,88 +1,98 @@
|
|
1
|
-
#***********************************************************
|
2
|
-
#* Copyright (c) 2006, Zhimin Zhan.
|
3
|
-
#* Distributed open-source, see full license in MIT-LICENSE
|
4
|
-
#***********************************************************
|
5
|
-
|
6
|
-
# useful hekoer methods for testing
|
7
|
-
#
|
8
|
-
module RWebUnit
|
9
|
-
module Utils
|
10
|
-
|
11
|
-
# default date format returned is 29/12/2007.
|
12
|
-
# if supplied parameter is not '%m/%d/%Y' -> 12/29/2007
|
13
|
-
# Otherwise, "2007-12-29", which is most approiate date format
|
14
|
-
def today(format = '%d/%m/%y')
|
15
|
-
if format.downcase == '%d/%m/%y'
|
16
|
-
format_date(Time.now, "%02d/%02d/%04d")
|
17
|
-
elsif format.downcase == '%m/%d/%y'
|
18
|
-
sprintf("%02d/%02d/%04d", Time.now.month, Time.now.day, Time.now.year)
|
19
|
-
else
|
20
|
-
sprintf("%04d-%02d-%02d", Time.now.year, Time.now.month, Time.now.day)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
alias getToday_AU today
|
24
|
-
alias getToday_US today
|
25
|
-
alias getToday today
|
26
|
-
|
27
|
-
|
28
|
-
def days_before(days)
|
29
|
-
nil if !(days.instance_of?(Fixnum))
|
30
|
-
format_date(Time.now - days * 24 * 3600)
|
31
|
-
end
|
32
|
-
|
33
|
-
def yesterday
|
34
|
-
days_before(1)
|
35
|
-
end
|
36
|
-
|
37
|
-
def days_from_now(days)
|
38
|
-
nil if !(days.instance_of?(Fixnum))
|
39
|
-
format_date(Time.now + days * 24 * 3600)
|
40
|
-
end
|
41
|
-
alias days_after days_from_now
|
42
|
-
|
43
|
-
def tomorrow
|
44
|
-
days_from_now(1)
|
45
|
-
end
|
46
|
-
|
47
|
-
# return a random number >= min, but <= max
|
48
|
-
def random_number(min, max)
|
49
|
-
rand(max-min+1)+min
|
50
|
-
end
|
51
|
-
|
52
|
-
def random_boolean
|
53
|
-
return random_number(0, 1) == 1
|
54
|
-
end
|
55
|
-
|
56
|
-
def random_char(lowercase = true)
|
57
|
-
sprintf("%c", random_number(97, 122)) if lowercase
|
58
|
-
sprintf("%c", random_number(65, 90)) unless lowercase
|
59
|
-
end
|
60
|
-
|
61
|
-
def random_digit()
|
62
|
-
sprintf("%c", random_number(48, 57))
|
63
|
-
end
|
64
|
-
|
65
|
-
def random_str(length, lowercase = true)
|
66
|
-
randomStr = ""
|
67
|
-
length.times {
|
68
|
-
randomStr += random_char(lowercase)
|
69
|
-
}
|
70
|
-
randomStr
|
71
|
-
end
|
72
|
-
|
73
|
-
# Return a random string in a rangeof pre-defined strings
|
74
|
-
def random_string_in(arr)
|
75
|
-
return nil if arr.empty?
|
76
|
-
index = random_number(0, arr.length-1)
|
77
|
-
arr[index]
|
78
|
-
end
|
79
|
-
alias random_string_in_collection random_string_in
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
1
|
+
#***********************************************************
|
2
|
+
#* Copyright (c) 2006, Zhimin Zhan.
|
3
|
+
#* Distributed open-source, see full license in MIT-LICENSE
|
4
|
+
#***********************************************************
|
5
|
+
|
6
|
+
# useful hekoer methods for testing
|
7
|
+
#
|
8
|
+
module RWebUnit
|
9
|
+
module Utils
|
10
|
+
|
11
|
+
# default date format returned is 29/12/2007.
|
12
|
+
# if supplied parameter is not '%m/%d/%Y' -> 12/29/2007
|
13
|
+
# Otherwise, "2007-12-29", which is most approiate date format
|
14
|
+
def today(format = '%d/%m/%y')
|
15
|
+
if format.downcase == '%d/%m/%y'
|
16
|
+
format_date(Time.now, "%02d/%02d/%04d")
|
17
|
+
elsif format.downcase == '%m/%d/%y'
|
18
|
+
sprintf("%02d/%02d/%04d", Time.now.month, Time.now.day, Time.now.year)
|
19
|
+
else
|
20
|
+
sprintf("%04d-%02d-%02d", Time.now.year, Time.now.month, Time.now.day)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
alias getToday_AU today
|
24
|
+
alias getToday_US today
|
25
|
+
alias getToday today
|
26
|
+
|
27
|
+
|
28
|
+
def days_before(days)
|
29
|
+
nil if !(days.instance_of?(Fixnum))
|
30
|
+
format_date(Time.now - days * 24 * 3600)
|
31
|
+
end
|
32
|
+
|
33
|
+
def yesterday
|
34
|
+
days_before(1)
|
35
|
+
end
|
36
|
+
|
37
|
+
def days_from_now(days)
|
38
|
+
nil if !(days.instance_of?(Fixnum))
|
39
|
+
format_date(Time.now + days * 24 * 3600)
|
40
|
+
end
|
41
|
+
alias days_after days_from_now
|
42
|
+
|
43
|
+
def tomorrow
|
44
|
+
days_from_now(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
# return a random number >= min, but <= max
|
48
|
+
def random_number(min, max)
|
49
|
+
rand(max-min+1)+min
|
50
|
+
end
|
51
|
+
|
52
|
+
def random_boolean
|
53
|
+
return random_number(0, 1) == 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def random_char(lowercase = true)
|
57
|
+
sprintf("%c", random_number(97, 122)) if lowercase
|
58
|
+
sprintf("%c", random_number(65, 90)) unless lowercase
|
59
|
+
end
|
60
|
+
|
61
|
+
def random_digit()
|
62
|
+
sprintf("%c", random_number(48, 57))
|
63
|
+
end
|
64
|
+
|
65
|
+
def random_str(length, lowercase = true)
|
66
|
+
randomStr = ""
|
67
|
+
length.times {
|
68
|
+
randomStr += random_char(lowercase)
|
69
|
+
}
|
70
|
+
randomStr
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return a random string in a rangeof pre-defined strings
|
74
|
+
def random_string_in(arr)
|
75
|
+
return nil if arr.empty?
|
76
|
+
index = random_number(0, arr.length-1)
|
77
|
+
arr[index]
|
78
|
+
end
|
79
|
+
alias random_string_in_collection random_string_in
|
80
|
+
|
81
|
+
def this_file
|
82
|
+
__FILE__
|
83
|
+
end
|
84
|
+
alias current_file this_file
|
85
|
+
|
86
|
+
def this_directory
|
87
|
+
File.dirname(this_file)
|
88
|
+
end
|
89
|
+
alias current_directory this_directory
|
90
|
+
|
91
|
+
private
|
92
|
+
def format_date(date, date_format = nil)
|
93
|
+
date_format ||= "%02d/%02d/%04d"
|
94
|
+
sprintf(date_format, date.day, date.month, date.year)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|