mitchellh-rubyuw 0.7.2 → 0.99.0
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/.gitignore +3 -1
- data/{README.markdown → README.md} +6 -11
- data/Rakefile +12 -2
- data/VERSION +1 -1
- data/lib/rubyuw.rb +8 -0
- data/lib/rubyuw/base.rb +122 -0
- data/lib/rubyuw/connection.rb +145 -0
- data/lib/rubyuw/curriculum_enrollment.rb +75 -0
- data/lib/rubyuw/errors.rb +16 -0
- data/lib/rubyuw/sln.rb +108 -0
- data/test/live/curriculum_enrollment_test.rb +47 -0
- data/test/live/sln_test.rb +16 -26
- data/test/live/test_helper.rb +15 -2
- data/test/mocked/base_test.rb +171 -0
- data/test/mocked/connection_test.rb +178 -0
- data/test/mocked/curriculum_enrollment_test.rb +132 -61
- data/test/mocked/sln_test.rb +106 -142
- data/test/mocked/test_helper.rb +57 -1
- metadata +20 -29
- data/lib/myuw.rb +0 -67
- data/lib/myuw/curriculum_enrollment.rb +0 -110
- data/lib/myuw/errors.rb +0 -18
- data/lib/myuw/registration.rb +0 -98
- data/lib/myuw/schedule.rb +0 -74
- data/lib/myuw/session.rb +0 -91
- data/lib/myuw/sln.rb +0 -131
- data/rubyuw.gemspec +0 -102
- data/test/live/registration_test.rb +0 -46
- data/test/live/schedule_test.rb +0 -28
- data/test/live/session_test.rb +0 -34
- data/test/mocked/myuw_test.rb +0 -39
- data/test/mocked/registration_test.rb +0 -105
- data/test/mocked/schedule_test.rb +0 -132
- data/test/mocked/session_test.rb +0 -96
data/lib/rubyuw/sln.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module RubyUW
|
2
|
+
# RubyUW::SLN is used to find and extract information about
|
3
|
+
# specific SLNs. It grabs SLN information via the MyUW time
|
4
|
+
# schedule.
|
5
|
+
#
|
6
|
+
# <b>Requires authentication with RubyUW::Base prior to use!</b>
|
7
|
+
#
|
8
|
+
# Additionally, this class should typically never be instantiated
|
9
|
+
# by any developer. Instead, the class methods should be used
|
10
|
+
# which will return an instance of the SLN object.
|
11
|
+
#
|
12
|
+
# == Usage Examples
|
13
|
+
#
|
14
|
+
# require 'rubyuw'
|
15
|
+
# RubyUW::Base.authenticate("netid", "password")
|
16
|
+
# sln_info = RubyUW::SLN.find("12345", "AUT+2009")
|
17
|
+
class SLN
|
18
|
+
attr_reader :sln
|
19
|
+
attr_reader :data
|
20
|
+
|
21
|
+
# Initialize a new SLN object. This should never be called on its
|
22
|
+
# own, but instead you should use the find method to setup a
|
23
|
+
# sln.
|
24
|
+
#
|
25
|
+
# @param [String] SLN number in string format.
|
26
|
+
# @param [String] Term that the SLN corresponds to.
|
27
|
+
# @param [Hash] Data of key to value.
|
28
|
+
def initialize(sln, term, data)
|
29
|
+
@sln = sln
|
30
|
+
@term = term
|
31
|
+
@data = data
|
32
|
+
end
|
33
|
+
|
34
|
+
# Grab the data of the SLN based on a key. Returns the value of
|
35
|
+
# a field for the SLN, or nil otherwise. Supported fields coming
|
36
|
+
# soon.
|
37
|
+
def data(key)
|
38
|
+
@data[key.to_sym]
|
39
|
+
end
|
40
|
+
|
41
|
+
class <<self
|
42
|
+
# Finds information about a specific SLN. The SLN information
|
43
|
+
# is grabbed from the MyUW time schedule page. Authentication is
|
44
|
+
# required prior to use.
|
45
|
+
#
|
46
|
+
# @param [#to_s] The SLN, which must respond to #to_s
|
47
|
+
# @param [String] The term, as represented in the time schedule URL.
|
48
|
+
# @return [RubyUW::SLN]
|
49
|
+
def find(sln_number, term)
|
50
|
+
raise Errors::NotLoggedInError.new unless Base.authenticated?
|
51
|
+
|
52
|
+
# Grab the SLN page and check for various failure scenarios
|
53
|
+
page = Base.connection.get("https://sdb.admin.washington.edu/timeschd/uwnetid/sln.asp?QTRYR=#{term}&SLN=#{sln_number}")
|
54
|
+
raise Errors::SLNRequestedTooSoonError.new if requested_too_soon?(page)
|
55
|
+
raise Errors::SLNDoesNotExistError.new if !sln_exists?(page)
|
56
|
+
raise Errors::SLNServiceClosedError.new if time_schedule_closed?(page)
|
57
|
+
|
58
|
+
# Now that the page is probably valid, we extract the field data
|
59
|
+
# based on various xpaths.
|
60
|
+
new(sln_number, term, extract_data_from_page(page))
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def requested_too_soon?(page)
|
66
|
+
page.uri.to_s == "http://www.washington.edu/students/timeschd/badrequest.html"
|
67
|
+
end
|
68
|
+
|
69
|
+
def sln_exists?(page)
|
70
|
+
page.body.to_s.match(/SLN: (.{5,6}) does not exist./).nil?
|
71
|
+
end
|
72
|
+
|
73
|
+
def time_schedule_closed?(page)
|
74
|
+
page.uri.to_s == "http://www.washington.edu/students/timeschd/nots.html"
|
75
|
+
end
|
76
|
+
|
77
|
+
def extract_data_from_page(page)
|
78
|
+
extract_data = [
|
79
|
+
[[nil, :course, :section, :type, :credits, :title], "//table[@border=1 and @cellpadding=3]//tr[@rowspan=1]//td"],
|
80
|
+
[[:current_enrollment, :limit_enrollment, :room_capacity, :space_available, :status], "//table[@border=1 and @cellpadding=3]//tr[count(td)=5]//td"],
|
81
|
+
[[:notes], "//table[@border=1 and @cellpadding=3]//tr[count(td)=1]//preceding-sibling::tr[count(th)=1]//following-sibling::tr//td"]
|
82
|
+
]
|
83
|
+
|
84
|
+
data = {}
|
85
|
+
extract_data.each do |keys, xpath|
|
86
|
+
data.merge!(Base.extract(page, xpath, keys))
|
87
|
+
end
|
88
|
+
|
89
|
+
data
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module Errors
|
95
|
+
# An error indicating that an SLN was requested back-to-back too
|
96
|
+
# quickly. MyUW enforces a timeout between requests for SLN information,
|
97
|
+
# and when this is not obeyed, this error will be thrown by RubyUW.
|
98
|
+
class SLNRequestedTooSoonError < Exception; end
|
99
|
+
|
100
|
+
# An error indicating that an SLN requested is invalid (does not
|
101
|
+
# exist).
|
102
|
+
class SLNDoesNotExistError < Exception; end
|
103
|
+
|
104
|
+
# An error indicating that the time scheduling service of MyUW
|
105
|
+
# is currently closed.
|
106
|
+
class SLNServiceClosedError < Exception; end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class LiveCurriculumEnrollmentTest < Test::Unit::TestCase
|
4
|
+
context "live curriculum info grabbing" do
|
5
|
+
setup do
|
6
|
+
@curriculum = "CHEM"
|
7
|
+
@term = "AUT+2009"
|
8
|
+
|
9
|
+
@curriculum_info = {
|
10
|
+
"11633" => {
|
11
|
+
:course => "CHEM 110",
|
12
|
+
:section => "A",
|
13
|
+
:type => "LC"
|
14
|
+
},
|
15
|
+
"11635" => {
|
16
|
+
:course => "CHEM 110",
|
17
|
+
:section => "AB",
|
18
|
+
:type => "QZ"
|
19
|
+
},
|
20
|
+
"11826" => {
|
21
|
+
:course => "CHEM 475",
|
22
|
+
:section => "A",
|
23
|
+
:type => "LC"
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
should "raise an error for an invalid SLN/quarter" do
|
29
|
+
authenticate
|
30
|
+
assert_raise(RubyUW::Errors::CurriculumDoesNotExistError) { RubyUW::CurriculumEnrollment.find("NOTCHEM", @term) }
|
31
|
+
end
|
32
|
+
|
33
|
+
should "grab all SLNs properly" do
|
34
|
+
authenticate
|
35
|
+
results = RubyUW::CurriculumEnrollment.find(@curriculum, @term)
|
36
|
+
|
37
|
+
@curriculum_info.each do |sln, info|
|
38
|
+
course = results[sln]
|
39
|
+
assert !course.nil?
|
40
|
+
|
41
|
+
info.each do |k,v|
|
42
|
+
assert_equal v, course.data(k)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/live/sln_test.rb
CHANGED
@@ -3,13 +3,6 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
3
3
|
class LiveSLNTest < Test::Unit::TestCase
|
4
4
|
context "live SLN info grabbing" do
|
5
5
|
setup do
|
6
|
-
@myuw = MyUW.new
|
7
|
-
@session = @myuw.session
|
8
|
-
@session.email = MYUW_ID
|
9
|
-
@session.password = MYUW_PASSWORD
|
10
|
-
@session.login
|
11
|
-
assert @session.logged_in? # Sanity
|
12
|
-
|
13
6
|
@sln_info = {
|
14
7
|
:sln => "17237",
|
15
8
|
:quarter => "AUT+2009",
|
@@ -26,39 +19,36 @@ class LiveSLNTest < Test::Unit::TestCase
|
|
26
19
|
:notes => "Quiz Section"
|
27
20
|
}
|
28
21
|
}
|
29
|
-
|
30
|
-
@sln = @myuw.sln(@sln_info[:sln], @sln_info[:quarter])
|
31
|
-
assert @sln # Sanity
|
32
22
|
end
|
33
23
|
|
34
24
|
teardown do
|
35
|
-
sleep(5)
|
25
|
+
sleep(5)
|
36
26
|
end
|
37
27
|
|
38
|
-
|
28
|
+
def get_sln_obj
|
29
|
+
RubyUW::SLN.find(@sln_info[:sln], @sln_info[:quarter])
|
30
|
+
end
|
31
|
+
|
32
|
+
should "grab course info for a valid SLN" do
|
33
|
+
authenticate
|
34
|
+
@sln = get_sln_obj
|
35
|
+
|
39
36
|
@sln_info[:info].each do |k,v|
|
40
|
-
assert_equal v, @sln.
|
37
|
+
assert_equal v, @sln.data(k), "#{k} should've been #{v}"
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|
44
41
|
should "raise an error if requests are back to back too fast" do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@sln.sln = @sln.sln # Force reload
|
50
|
-
|
51
|
-
assert_raise MyUW::RequestSLNTooSoonError do
|
52
|
-
@sln.course
|
53
|
-
end
|
42
|
+
authenticate
|
43
|
+
assert_nothing_raised() { get_sln_obj }
|
44
|
+
assert_raise(RubyUW::Errors::SLNRequestedTooSoonError) { get_sln_obj }
|
54
45
|
end
|
55
46
|
|
56
47
|
should "raise an error for an invalid SLN/quarter" do
|
57
|
-
@sln
|
48
|
+
@sln_info[:sln] = 91919 # Tested to not exist
|
58
49
|
|
59
|
-
|
60
|
-
|
61
|
-
end
|
50
|
+
authenticate
|
51
|
+
assert_raise(RubyUW::Errors::SLNDoesNotExistError) { get_sln_obj }
|
62
52
|
end
|
63
53
|
end
|
64
54
|
end
|
data/test/live/test_helper.rb
CHANGED
@@ -4,8 +4,21 @@ rescue LoadError => e
|
|
4
4
|
abort("Running live tests requires a password.rb file in the test folder with your MyUW credentials.")
|
5
5
|
end
|
6
6
|
|
7
|
-
require
|
7
|
+
require 'rubygems'
|
8
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
9
|
+
require 'rubyuw'
|
8
10
|
require 'test/unit'
|
9
11
|
require "contest"
|
10
12
|
require "stories"
|
11
|
-
require "mocha"
|
13
|
+
require "mocha"
|
14
|
+
|
15
|
+
class Test::Unit::TestCase
|
16
|
+
def setup
|
17
|
+
RubyUW::Base.reset_connection!
|
18
|
+
end
|
19
|
+
|
20
|
+
def authenticate
|
21
|
+
assert RubyUW::Base.authenticate(MYUW_ID, MYUW_PASSWORD)
|
22
|
+
assert RubyUW::Base.authenticated? # sanity
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class BaseTest < Test::Unit::TestCase
|
4
|
+
context "with connection" do
|
5
|
+
setup do
|
6
|
+
RubyUW::Base.reset_connection!
|
7
|
+
end
|
8
|
+
|
9
|
+
should "initialize a WWW::Mechanize object on the first call" do
|
10
|
+
RubyUW::Connection.expects(:new).once
|
11
|
+
RubyUW::Base.connection
|
12
|
+
end
|
13
|
+
|
14
|
+
should "not initialize WWW::Mechanize objects on subsequent calls" do
|
15
|
+
RubyUW::Connection.expects(:new).once.returns(true)
|
16
|
+
50.times { RubyUW::Base.connection }
|
17
|
+
end
|
18
|
+
|
19
|
+
should "clear out the connection to force recreation of object on reset_connection!" do
|
20
|
+
assert !RubyUW::Base.connection.nil?
|
21
|
+
RubyUW::Base.reset_connection!
|
22
|
+
RubyUW::Connection.expects(:new).once.returns(true)
|
23
|
+
50.times { RubyUW::Base.connection }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with authentication" do
|
28
|
+
setup do
|
29
|
+
# initialize the base connection
|
30
|
+
@conn = RubyUW::Base.reset_connection!.connection
|
31
|
+
@conn.follow_meta_refresh = false
|
32
|
+
|
33
|
+
@good_id = "foo"
|
34
|
+
@good_password = "bar"
|
35
|
+
@bad_password = @good_password + "wrong"
|
36
|
+
end
|
37
|
+
|
38
|
+
should "clear the cookie jar of the connection" do
|
39
|
+
RubyUW::Base.expects(:logout).once
|
40
|
+
|
41
|
+
result_page = mock('page')
|
42
|
+
result_page.stubs(:form_with).returns(true)
|
43
|
+
@conn.stubs(:execute!).returns(result_page)
|
44
|
+
|
45
|
+
RubyUW::Base.authenticate(@good_id, @good_password)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "succeed login with good ID and password and valid pages" do
|
49
|
+
mock_flow([
|
50
|
+
[:goto, ["http://myuw.washington.edu"], "welcome"],
|
51
|
+
[:submit_form, ["f", anything], "not_logged_in_relay"],
|
52
|
+
[:submit_form, ["relay", anything], "login"],
|
53
|
+
[:submit_form, ["query", anything], "not_logged_in_relay"]
|
54
|
+
])
|
55
|
+
|
56
|
+
assert RubyUW::Base.authenticate(@good_id, @good_password)
|
57
|
+
end
|
58
|
+
|
59
|
+
should "fail login with bad ID and password" do
|
60
|
+
mock_flow([
|
61
|
+
[:goto, ["http://myuw.washington.edu"], "welcome"],
|
62
|
+
[:submit_form, ["f", anything], "not_logged_in_relay"],
|
63
|
+
[:submit_form, ["relay", anything], "login"],
|
64
|
+
[:submit_form, ["query", anything], "login"]
|
65
|
+
])
|
66
|
+
|
67
|
+
assert !RubyUW::Base.authenticate(@good_id, @bad_password)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "with authentication check" do
|
72
|
+
should "return true if it can find the correct xpath" do
|
73
|
+
mock_flow([
|
74
|
+
[:goto, ["http://myuw.washington.edu"], "welcome"],
|
75
|
+
[:submit_form, ["f", anything], "logged_in_relay"]
|
76
|
+
])
|
77
|
+
|
78
|
+
assert RubyUW::Base.authenticated?
|
79
|
+
end
|
80
|
+
|
81
|
+
should "not return true if it can't find the greeting" do
|
82
|
+
mock_flow([
|
83
|
+
[:goto, ["http://myuw.washington.edu"], "welcome"],
|
84
|
+
[:submit_form, ["f", anything], "login"]
|
85
|
+
])
|
86
|
+
|
87
|
+
assert !RubyUW::Base.authenticated?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "with logging out" do
|
92
|
+
should "clear the cookie jar on logout" do
|
93
|
+
cookie_jar = mock('cookie_jar')
|
94
|
+
cookie_jar.expects(:clear!).once
|
95
|
+
|
96
|
+
conn = RubyUW::Base.connection
|
97
|
+
conn.expects(:cookie_jar).returns(cookie_jar)
|
98
|
+
|
99
|
+
RubyUW::Base.logout
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "with extracting data from page" do
|
104
|
+
setup do
|
105
|
+
@page = mock('page')
|
106
|
+
@xpath = "foo"
|
107
|
+
end
|
108
|
+
|
109
|
+
def setup_nodes(inner_texts)
|
110
|
+
nodes = []
|
111
|
+
inner_texts.each do |text|
|
112
|
+
node = mock('node')
|
113
|
+
node.stubs(:inner_text).returns(text)
|
114
|
+
|
115
|
+
nodes << node
|
116
|
+
end
|
117
|
+
|
118
|
+
nodes
|
119
|
+
end
|
120
|
+
|
121
|
+
should "run the xpath on the specified page" do
|
122
|
+
@page.expects(:search).with(@xpath).returns([])
|
123
|
+
RubyUW::Base.extract(@page, @xpath, [])
|
124
|
+
end
|
125
|
+
|
126
|
+
should "return nil if the xpath returns an empty array" do
|
127
|
+
@page.expects(:search).with(@xpath).returns([])
|
128
|
+
assert_nil RubyUW::Base.extract(@page, @xpath, [])
|
129
|
+
end
|
130
|
+
|
131
|
+
should "map keys to node results if xpath returns valid nodes" do
|
132
|
+
expected = { :one => "1", :two => "2", :three => "3" }
|
133
|
+
nodes = setup_nodes(expected.values)
|
134
|
+
keys = expected.keys
|
135
|
+
|
136
|
+
@page.expects(:search).with(@xpath).returns(nodes)
|
137
|
+
result = RubyUW::Base.extract(@page, @xpath, keys)
|
138
|
+
assert expected == result
|
139
|
+
end
|
140
|
+
|
141
|
+
should "skip the nil keys (while continuing to go through the node list)" do
|
142
|
+
nodes = setup_nodes(["1","2","3"])
|
143
|
+
keys = [:one, nil, :three]
|
144
|
+
|
145
|
+
@page.expects(:search).with(@xpath).returns(nodes)
|
146
|
+
result = RubyUW::Base.extract(@page, @xpath, keys)
|
147
|
+
assert_equal 2, result.length
|
148
|
+
assert !result.value?("2")
|
149
|
+
end
|
150
|
+
|
151
|
+
should "return what it has so far if it runs out of keys" do
|
152
|
+
nodes = setup_nodes((1..50).to_a.map(&:to_s))
|
153
|
+
keys = [:one]
|
154
|
+
|
155
|
+
@page.expects(:search).with(@xpath).returns(nodes)
|
156
|
+
result = RubyUW::Base.extract(@page, @xpath, keys)
|
157
|
+
assert_equal keys.length, result.length
|
158
|
+
assert_equal "1", result[keys[0]]
|
159
|
+
end
|
160
|
+
|
161
|
+
should "get rid of odd characters that MyUW has in text" do
|
162
|
+
nodes = setup_nodes(["foo\302\240"])
|
163
|
+
keys = [:one]
|
164
|
+
|
165
|
+
@page.expects(:search).with(@xpath).returns(nodes)
|
166
|
+
result = RubyUW::Base.extract(@page, @xpath, keys)
|
167
|
+
assert_equal keys.length, result.length
|
168
|
+
assert_equal "foo", result[keys[0]]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class ConnectionTest < Test::Unit::TestCase
|
4
|
+
should "be a kind of WWW::Mechanize" do
|
5
|
+
assert RubyUW::Connection.new.kind_of?(WWW::Mechanize)
|
6
|
+
end
|
7
|
+
|
8
|
+
context "web flows" do
|
9
|
+
setup do
|
10
|
+
@conn = RubyUW::Connection.new
|
11
|
+
end
|
12
|
+
|
13
|
+
should "be empty to begin with" do
|
14
|
+
assert @conn.current_flow.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with goto" do
|
18
|
+
should "add new item to flow and return self when calling goto" do
|
19
|
+
url = "http://foo.com"
|
20
|
+
assert_equal @conn, @conn.goto(url)
|
21
|
+
assert_equal 1, @conn.current_flow.length
|
22
|
+
assert_equal :goto, @conn.current_flow[0][0]
|
23
|
+
end
|
24
|
+
|
25
|
+
should "get the page when executing" do
|
26
|
+
@url = "http://foo.com"
|
27
|
+
@conn.goto(@url)
|
28
|
+
@conn.expects(:get).with(@url).once
|
29
|
+
@conn.execute!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with verify" do
|
34
|
+
setup do
|
35
|
+
@xpath = "//foo"
|
36
|
+
@url = "fake"
|
37
|
+
end
|
38
|
+
|
39
|
+
def mock_context(return_value=nil)
|
40
|
+
context = mock('context')
|
41
|
+
context.expects(:search).with(@xpath).once.returns(return_value)
|
42
|
+
@conn.expects(:execute_goto!).returns(context)
|
43
|
+
@conn.goto(@url)
|
44
|
+
|
45
|
+
context
|
46
|
+
end
|
47
|
+
|
48
|
+
should "add new item to flow and return self when calling verify" do
|
49
|
+
xpath = "//foo"
|
50
|
+
assert_equal @conn, @conn.verify(xpath)
|
51
|
+
assert_equal 1, @conn.current_flow.length
|
52
|
+
assert_equal :verify, @conn.current_flow[0][0]
|
53
|
+
end
|
54
|
+
|
55
|
+
should "verify the previous page result when executing" do
|
56
|
+
mock_context([1])
|
57
|
+
@conn.verify(@xpath)
|
58
|
+
|
59
|
+
assert_nothing_raised { @conn.execute! }
|
60
|
+
end
|
61
|
+
|
62
|
+
should "return back the context given" do
|
63
|
+
context = mock_context([1])
|
64
|
+
@conn.verify(@xpath)
|
65
|
+
|
66
|
+
assert_equal context, @conn.execute!
|
67
|
+
end
|
68
|
+
|
69
|
+
should "raise an InvalidPageError if no elements found" do
|
70
|
+
mock_context([])
|
71
|
+
@conn.verify(@xpath)
|
72
|
+
|
73
|
+
assert_raises(RubyUW::Errors::InvalidPageError) { @conn.execute! }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "with submitting form" do
|
78
|
+
setup do
|
79
|
+
@url = "fake"
|
80
|
+
@form = "form"
|
81
|
+
@params = { :key => :value, :key2 => :value2 }
|
82
|
+
end
|
83
|
+
|
84
|
+
def mock_context
|
85
|
+
context = mock('context')
|
86
|
+
@conn.expects(:execute_goto!).returns(context)
|
87
|
+
@conn.goto(@url)
|
88
|
+
|
89
|
+
context
|
90
|
+
end
|
91
|
+
|
92
|
+
def mock_form_object(context)
|
93
|
+
form_obj = mock('form_obj')
|
94
|
+
form_obj.stubs(:[]=)
|
95
|
+
form_obj.expects(:submit).returns(:submit)
|
96
|
+
context.expects(:form_with).with(:name => @form).once.returns(form_obj)
|
97
|
+
form_obj
|
98
|
+
end
|
99
|
+
|
100
|
+
should "add new item to flow and return self when calling submit_form" do
|
101
|
+
assert_equal @conn, @conn.submit_form(@form, @params)
|
102
|
+
assert_equal 1, @conn.current_flow.length
|
103
|
+
assert_equal :submit_form, @conn.current_flow[0][0]
|
104
|
+
end
|
105
|
+
|
106
|
+
should "raise InvalidPageError if the form is not found on the page" do
|
107
|
+
context = mock_context
|
108
|
+
context.expects(:form_with).with(:name => @form).once.returns(nil)
|
109
|
+
@conn.submit_form(@form, @params)
|
110
|
+
|
111
|
+
assert_raises(RubyUW::Errors::InvalidPageError) { @conn.execute! }
|
112
|
+
end
|
113
|
+
|
114
|
+
should "assign the parameters to the form object" do
|
115
|
+
context = mock_context
|
116
|
+
form_obj = mock_form_object(context)
|
117
|
+
form_obj.expects(:[]=).times(@params.length)
|
118
|
+
|
119
|
+
@conn.submit_form(@form, @params)
|
120
|
+
@conn.execute!
|
121
|
+
end
|
122
|
+
|
123
|
+
should "send the parameters after #to_s'ing them" do
|
124
|
+
key = mock('para_key')
|
125
|
+
key.expects(:to_s).once
|
126
|
+
|
127
|
+
param = mock('param')
|
128
|
+
param.expects(:to_s).once
|
129
|
+
|
130
|
+
params = { key => param }
|
131
|
+
|
132
|
+
context = mock_context
|
133
|
+
form_obj = mock_form_object(context)
|
134
|
+
form_obj.expects(:[]=).times(params.length)
|
135
|
+
|
136
|
+
@conn.submit_form(@form, params)
|
137
|
+
@conn.execute!
|
138
|
+
end
|
139
|
+
|
140
|
+
should "submit and return the form result" do
|
141
|
+
context = mock_context
|
142
|
+
mock_form_object(context)
|
143
|
+
@conn.submit_form(@form, @params)
|
144
|
+
|
145
|
+
assert_equal :submit, @conn.execute!
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "with executing" do
|
150
|
+
setup do
|
151
|
+
@url = "foo"
|
152
|
+
@form_name = "form"
|
153
|
+
@form_params = {}
|
154
|
+
|
155
|
+
@conn.goto(@url).submit_form(@form_name, @form_params)
|
156
|
+
@conn.stubs(:execute_goto!).returns(:goto)
|
157
|
+
@conn.stubs(:execute_submit_form!).returns(:submit_form)
|
158
|
+
end
|
159
|
+
|
160
|
+
should "execute in the order given" do
|
161
|
+
execution_sequence = sequence('execution')
|
162
|
+
@conn.expects(:execute_goto!).in_sequence(execution_sequence)
|
163
|
+
@conn.expects(:execute_submit_form!).in_sequence(execution_sequence)
|
164
|
+
@conn.execute!
|
165
|
+
end
|
166
|
+
|
167
|
+
should "reset the current flow to empty" do
|
168
|
+
assert !@conn.current_flow.empty?
|
169
|
+
@conn.execute!
|
170
|
+
assert @conn.current_flow.empty?
|
171
|
+
end
|
172
|
+
|
173
|
+
should "return the last task's return value" do
|
174
|
+
assert_equal :submit_form, @conn.execute!
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|