sakai-oae-test-api 0.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.
@@ -0,0 +1,168 @@
1
+ # This file contains custom Utility methods used throughout the Sakai-OAE test scripts,
2
+ # as well as Monkey patches to the Page Object and Watir-webdriver gems.
3
+ #
4
+
5
+ # Contains methods that extend the PageObject module to include
6
+ # methods that are custom to OAE.
7
+ module PageObject
8
+
9
+ # Monkey patch helper method for links to named objects...
10
+ def name_link(name)
11
+ self.link(:text=>/#{Regexp.escape(name)}/i)
12
+ end
13
+
14
+ # Monkey patch helper method for li elements referring to
15
+ # named items...
16
+ def name_li(name)
17
+ self.li(:text=>/#{Regexp.escape(name)}/i)
18
+ end
19
+
20
+ def method_missing(sym, *args, &block)
21
+ @browser.send sym, *args, &block
22
+ end
23
+
24
+ module Accessors
25
+
26
+ # Use this for menus that require floating the mouse
27
+ # over the first link, before you click on the second
28
+ # link...
29
+ def float_menu(name, menu_text, link_text, target_class)
30
+ define_method(name) {
31
+ self.back_to_top
32
+ self.link(:text=>menu_text).fire_event("onmouseover")
33
+ self.link(:text=>/#{link_text}/).click
34
+ self.linger_for_ajax(10)
35
+ eval(target_class).new @browser
36
+ }
37
+ end
38
+
39
+ def open_link(name, klass)
40
+ define_method("open_#{name}") do |value|
41
+ self.back_to_top
42
+ self.link(:text=>/#{value}/).click
43
+ sleep 2
44
+ self.linger_for_ajax(6)
45
+ # This code is necessary because of a null style tag
46
+ # that confuses Watir into thinking the buttons aren't really there.
47
+ if self.div(:id=>"joinrequestbuttons_widget").exist?
48
+ @browser.execute_script("$('#joinrequestbuttons_widget').css({display: 'block'})")
49
+ end
50
+ eval(klass).new @browser
51
+ end
52
+ end
53
+
54
+ # Use this for menu items that are accessed via clicking
55
+ # the div to get to the target menu item.
56
+ def permissions_menu(name, text) #, target_class)
57
+ define_method(name) {
58
+ self.link(:text=>text).fire_event("onmouseover")
59
+ self.link(:text=>text).parent.div(:class=>"lhnavigation_selected_submenu_image").fire_event("onclick")
60
+ self.link(:id=>"lhnavigation_submenu_user_permissions").click
61
+ self.class.class_eval { include ProfilePermissionsPopUp }
62
+ }
63
+ end
64
+
65
+ # Use this for button objects that cause page navigations and thus
66
+ # require a new Page Object.
67
+ def navigating_button(name, id, class_name=nil)
68
+ define_method(name) {
69
+ self.button(:id=>id).click
70
+ sleep 0.2
71
+ browser.wait_for_ajax(2)
72
+ sleep 0.2
73
+ unless class_name==nil
74
+ eval(class_name).new @browser
75
+ end
76
+ }
77
+ end
78
+
79
+ # Use this for links on the page that cause page navigations and
80
+ # thus require a new Page Object.
81
+ def navigating_link(name, link_text, class_name=nil)
82
+ define_method(name) {
83
+ self.link(:text=>/#{Regexp.escape(link_text)}/).click
84
+ sleep 2 # wait_for_ajax keeps throwing unknown JS errors in Selenium-webdriver
85
+ unless class_name==nil
86
+ eval(class_name).new @browser
87
+ end
88
+ }
89
+ end
90
+
91
+ # This method is specifically for defining the contents of
92
+ # the Insert button, found on the Document Edit page. See the module
93
+ # DocumentWidget
94
+ def insert_button(name, id, module_name=nil)
95
+ define_method("insert_#{name}") {
96
+ self.button(:id=>"sakaidocs_insert_dropdown_button").click
97
+ sleep 0.1
98
+ self.button(:id=>id).click
99
+ unless module_name==nil
100
+ self.class.class_eval { include eval(module_name) }
101
+ sleep 0.4
102
+ end
103
+ self.wait_for_ajax(2)
104
+ }
105
+ end
106
+
107
+ end
108
+ end
109
+
110
+ # Extension of the Utilities module.
111
+ # This is included here because it contains methods
112
+ # specific to OAE testing only.
113
+ module Utilities
114
+
115
+ # Returns an array containing a randomized list of the specified
116
+ # number of OAE Category strings (The array returned is one string long if no
117
+ # number is specified).
118
+ def random_categories(number=1)
119
+ categories = ["Agriculture", "Animal Sciences", "Food Sciences", "Plant Sciences", "Soil Sciences", "Architecture & Planning", "City, Urban, Community & Regional Planning", "Environmental Design", "Interior Architecture", "Landscape Architecture", "Real Estate Development", "Arts & Music", "Acting", "Art History, Criticism & Conservation", "Arts Management", "Arts, Entertainment, & Media Management", "Ballet", "Brass Instruments", "Ceramic Arts & Ceramics", "Cinematography & Film/Video Production", "Commercial & Advertising Art", "Commercial Photography", "Conducting", "Costume Design", "Crafts/Craft Design, Folk Art & Artisanry", "Dance", "Design & Applied Arts", "Digital Arts", "Directing & Theatrical Production", "Documentary Production", "Drama/Theatre Arts & Stagecraft", "Drawing", "Fashion/Apparel Design", "Fiber, Textile & Weaving Arts", "Film/Cinema/Video Studies", "Fine & Studio Arts Management", "Game & Interactive Media Design", "Graphic Design", "Illustration", "Industrial & Product Design", "Interior Design", "Intermedia/Multimedia", "Jazz/Jazz Studies", "Keyboard Instruments", "Metal & Jewelry Arts", "Music", "Music History, Literature, & Theory", "Music Management & Merchandising", "Music Pedagogy", "Music Performance", "Music Technology", "Music Theory & Composition", "Musical Theatre", "Musicology & Ethnomusicology", "Painting", "Percussion Instruments", "Photography", "Playwriting & Screenwriting", "Printmaking", "Sculpture", "Stringed Instruments", "Technical Theatre/Theatre Design & Technology", "Theatre Literature, History & Criticism", "Theatre/Theatre Arts Management", "Voice & Opera", "Woodwind Instruments", "Business", "Accounting & Related Services", "Business Administration, Management & Operations", "Business Operations Support & Assistant Services", "Busines & Corporate Communications", "Business & Managerial Economics", "Construction Management", "Entrepreneurial & Small Business Operations", "Finance & Financial Management Services", "Hospitality Administration & Management", "Human Resources Management & Services", "Insurance", "International Business", "Management Information Systems & Services", "Management Sciences & Quantitative Methods", "Marketing", "Real Estate", "Sales & Merchandising", "Taxation", "Telecommunications Management", "Communications", "Animation, Interactive Technology, Video Graphics & Special Effects", "Graphic Communications", "Journalism", "Photographic & Film/Video Technology", "Public Relations & Advertising", "Publishing", "Radio & Television Broadcasting Technology", "Recording Arts Technology", "Computers & Information", "Archives/Archival Administration", "Artificial Intelligence", "Children & Youth Library Services", "Computer Programming", "Computer Science", "Human Computer Interaction", "Informatics", "Information Science/Studies", "Information Technology", "Library & Information Science", "Library Science & Administration", "Education", "Adult & Continuing Education", "Bilingual, Multilingual, & Multicultural Education", "Curriculum & Instruction", "Developmental & Remedial English", "Developmental & Remedial Mathematics", "Early Childhood Education", "Educational Administration & Supervision", "Educational Assessment, Evaluation, & Research", "Educational & Instructional Media Design", "Elementary Education", "High School & Secondary Diploma Programs", "International & Comparative Education", "Outdoor Education", "Second Language Learning", "Secondary Education", "Special Education", "Student Counseling & Personnel Services", "Vocational Education", "Engineering & Technology", "Aerospace, Aeronautical & Astronautical Engineering", "Agricultural Engineering", "Architectural Engineering", "Biomedical & Medical Engineering", "Ceramic Sciences & Engineering", "Chemical Engineering", "Civil Engineering", "Computer Engineering", "Electrical, Electronics & Communications Engineering", "Environmental & Environmental Health Engineering", "Geological & Geophysical Engineering", "Industrial Engineering", "Materials Science", "Mechanical Engineering", "Mining & Mineral Engineering", "Nanotechnology", "Naval Architecture & Marine Engineering", "Nuclear Engineering", "Systems Engineering", "History", "American History", "Asian History", "Canadian History", "European History", "Military History", "Science & Technology History", "Languages & Literatures", "African Languages & Literatures", "Albanian Language & Literature", "American Literature", "American Sign Language", "Ancient Near Eastern & Biblical Languages & Literatures", "Ancient/Classical Greek Language & Literature", "Arabic Language & Literature", "Australian, Oceanic, & Pacific Languages & Literatures", "Baltic Languages & Literatures", "Bengali Language & Literature", "Bosnian, Serbian, & Croatian Languages & Literatures", "Bulgarian Language & Literature", "Burmese Language & Literature", "Catalan Language & Literature", "Celtic Languages & Literatures", "Children's & Adolescent Literature", "Chinese Language & Literature", "Classics & Classical Languages & Literatures", "Comparative Literature", "Creative Writing", "Czech Language & Literature", "Danish Language & Literature", "Dutch/Flemish Language & Literature", "East Asian Languages & Literatures", "English Composition", "English Literature", "Filipino/Tagalog Language & Literature", "French Language & Literature", "Germanic Languages & Literatures", "Hebrew Language & Literature", "Hindi Language & Literature", "Hungarian & Magyar Language & Literature", "Indonesian & Malay Languages & Literatures", "Iranian & Persian Languages & Literatures", "Italian Language & Literature", "Japanese Language & Literature", "Khmer & Cambodian Language & Literature", "Korean Language & Literature", "Lao Language & Literature", "Latin Language & Literature", "Linguistics", "Literature", "Middle & Near Eastern & Semitic Languages & Literatures", "Modern Greek Language & Literature", "Mongolian Language & Literature", "Native American Languages & Literatures", "Norwegian Language & Literature", "Polish Language & Literature", "Portuguese Language & Literature", "Punjabi Language & Literature", "Romance Languages & Literatures", "Romanian Language & Literature", "Russian Language & Literature", "Sanskrit & Classical Indian Languages & Literatures", "Scandinavian Languages & Literatures", "Slavic Languages & Literatures", "Slovak Language & Literature", "South Asian Languages & Literatures", "Southeast Asian, Australasian, & Pacific Languages & Literatures", "Spanish Language & Literature", "Speech & Rhetorical Studies", "Swedish Language & Literature", "Tamil Language & Literature", "Technical & Business Writing", "Thai Language & Literature", "Tibetan Language & Literature", "Turkic, Uralic-Altaic, Caucasian, & Central Asian Languages & Literatures", "Turkish Language & Literature", "Ukrainian Language & Literature", "Uralic Languages & Literatures", "Urdu Language & Literature", "Vietnamese Language & Literature", "Law", "Banking, Corporate, Finance, & Securities Law", "Comparative Law", "Energy, Environment, & Natural Resources Law", "Health Law", "Intellectual Property Law", "International Law & Legal Studies", "Law", "Legal Support Services", "Pre-Law Studies", "Tax Law & Taxation", "Lifelong Learning", "Addiction Prevention & Treatment", "Adult & Continuing Education", "Aircraft Piloting", "Art", "Basic Computer Skills", "Birthing & Parenting", "Board, Card & Role-Playing Games", "Career Exploration", "Collecting", "Computer Games & Programming Skills", "Cooking & Other Domestic Skills", "Dancing", "Handicrafts & Model-Making", "Home Maintenance & Improvement", "Music", "Nature Appreciation", "Personal Health", "Pets", "Reading", "Sports & Exercise", "Theater", "Travel", "Workforce Development & Training", "Writing", "Math", "Algebra & Number Theory", "Applied Mathematics", "Geometry & Geometric Analysis", "Statistics", "Topology & Foundations", "Medicine & Health", "Alternative & Complementary Medicine", "Bioethics & Medical Ethics", "Chiropractic", "Clinical & Medical Laboratory Science & Research", "Communication Disorders Sciences", "Dentistry", "Dietetics & Clinical Nutrition", "Energy & Biologically Based Therapies", "Health & Medical Administration", "Health & Medical Assistance", "Health & Medical Preparatory Programs", "Health Diagnostics, Intervention & Treatment", "Health, Physical Education & Fitness", "Medical Illustration & Informatics", "Medicine", "Mental & Social Health", "Movement & Mind-Body Therapies", "Nursing", "Ophthalmics & Optometrics", "Optometry", "Osteopathic Medicine", "Pharmacy & Pharmaceutical Sciences", "Podiatric Medicine", "Public Health", "Rehabilitation & Therapeutics", "Somatic Bodywork", "Veterinary Medicine", "Military & Security", "Air Force ROTC, Air Science & Operations", "Army ROTC, Military Science & Operations", "Corrections", "Criminal Justice", "Crisis, Emergency & Disaster Management", "Critical Incident Response & Special Police Operations", "Critical Infrastructure Protection", "Cyber & Computer Forensics & Counterterrorism", "Financial Forensics & Fraud Investigation", "Fire Protection", "Fire Science & Fire-fighting", "Fire Systems Technology", "Fire & Arson Investigation & Prevention", "Forensic Science & Technology", "Homeland Security", "Intelligence, Command Control & Information Operations", "Maritime Law Enforcement", "Military Economics & Management", "Military Science & Operational Studies", "Military Technologies", "Navy & Marine ROTC, Naval Science & Operations", "Protective Services Operations", "Security Policy & Strategy", "Terrorism & Counterterrorism Operations", "Wildland & Forest Firefighting & Investigation", "Multidisciplinary Studies", "African Studies", "African-American & Black Studies", "American Studies & Civilization", "Asian Studies & Civilization", "Asian-American Studies", "Balkans Studies", "Baltic Studies", "Canadian Studies", "Caribbean Studies", "Chinese Studies", "Classical & Ancient Studies", "Commonwealth Studies", "Cultural Studies, Critical Theory & Analysis", "Deaf Studies", "Disability Studies", "East Asian Studies", "European Studies & Civilization", "Folklore Studies", "French Studies", "Gay & Lesbian Studies", "General Studies", "German Studies", "Hispanic-American, Puerto Rican, & Mexican-American/Chicano Studies", "Historic Preservation & Conservation", "Holocaust & Related Studies", "Housing & Human Environments", "Humanities & Humanistic Studies", "Intercultural, Multicultural & Diversity Studies", "International & Global Studies", "Irish Studies", "Italian Studies", "Japanese Studies", "Korean Studies", "Latin American & Caribbean Studies", "Medieval & Renaissance Studies", "Museology & Museum Studies", "Native American Studies", "Near & Middle Eastern Studies", "Pacific Area & Pacific Rim Studies", "Peace Studies & Conflict Resolution", "Polish Studies", "Russian, Central European, East European & Eurasian Studies", "Scandinavian Studies", "Slavic Studies", "South Asian Studies", "Southeast Asian Studies", "Spanish & Iberian Studies", "Sustainability Studies", "Systems Science & Theory", "Tibetan Studies", "Ukraine Studies", "Ural-Altaic & Central Asian Studies", "Western European Studies", "Women's Studies", "Work & Family Studies", "Natural & Physical Sciences", "Astronomy", "Astrophysics", "Atmospheric Sciences & Meteorology", "Atomic & Molecular Physics", "Biochemistry, Biophysics & Molecular Biology", "Biology", "Biomathematics, Bioinformatics, & Computational Biology", "Biotechnology", "Botany & Plant Biology", "Cellular Biology & Anatomical Sciences", "Chemistry", "Cognitive Science", "Ecology", "Ecology, Evolution, Systematics, & Population Biology", "Genetics", "Geochemistry & Petrology", "Geological & Earth Sciences", "Geophysics & Seismology", "Hydrology & Water Resources Science", "Marine Biology & Biological Oceanography", "Materials Sciences", "Microbiological Sciences & Immunology", "Neurobiology & Neurosciences", "Neuroscience", "Nuclear Physics", "Oceanography", "Optics", "Paleontology", "Pharmacology & Toxicology", "Physics", "Physiology, Pathology & Related Sciences", "Zoology & Animal Biology", "Philosophy & Religion", "Bible & Biblical Studies", "Buddhist Studies", "Christian Studies", "Divinity & Ministry", "Ethics", "Hindu Studies", "Islamic Studies", "Jewish & Judaic Studies", "Lay Ministry", "Logic", "Missionary Studies & Missiology", "Pastoral Counseling & Specialized Ministries", "Philosophy", "Rabbinical Studies", "Religion & Religious Studies", "Religious Education", "Religious & Sacred Music", "Talmudic Studies", "Theological & Ministerial Studies", "Urban Ministry", "Women's Ministry", "Youth Ministry", "Public Policy & Administration", "Community Organization & Advocacy", "Education Policy Analysis", "Fishing & Fisheries", "Forestry", "Health Policy Analysis", "Human Services", "International Policy Analysis", "Public Administration", "Public Policy Analysis", "Social Work", "Wildlife & Wildlands", "Youth Services", "Social Sciences", "Anthropology", "Archeology", "Criminology", "Demography & Population Studies", "Economics", "Geography & Cartography", "International Relations & National Security Studies", "Political Science & Government", "Psychology", "Sociology", "Urban Studies & Affairs", "Trades & Professions", "Air Traffic Control", "Aircraft Powerplant Technology", "Airframe Mechanics & Aircraft Maintenance & Repair", "Airline Flight Attendant", "Airline Pilot & Flight Crew", "Alternative Fuel Vehicle Technology", "Apparel & Textiles", "Automotive Mechanics", "Aviation Management & Operations", "Avionics Maintenance & Repair", "Bicycle Mechanics & Repair", "Blasting & Blaster", "Boilermaking & Boilermaker", "Building & Construction Finishing, Management, & Inspection", "Building & Construction Site Management", "Building, Home & Construction Inspection", "Building & Property Maintenance", "Cabinetmaking & Millwork", "Carpenters", "Carpet, Floor & Tile Worker", "Commercial Fishing", "Computer Numerically Controlled Machinist", "Concrete Finishing", "Construction, Heavy Equipment & Earthmoving Equipment Operation", "Cosmetology", "Culinary Arts", "Diesel Mechanics", "Diver, Professional & Instructor", "Drywall Installation", "Electrical & Electronics Maintenance & Repair", "Electrician", "Engine Machinist", "Flagging & Traffic Control", "Flight Instruction", "Foods, Nutrition & Related Services", "Funeral Service & Mortuary Science", "Furniture Design & Manufacturing", "Glazing", "Gunsmithing", "Heating, Air Conditioning, Ventilation & Refrigeration Maintenance & Repair", "Heavy & Industrial Equipment Maintenance & Repair", "High Performance & Custom Engine Mechanics", "Insulator", "Ironworking", "Locksmithing & Safe Repair", "Machine Tool Technology & Machinist", "Marine Maintenance, Fitter & Ship Repair", "Marine Science & Merchant Marine Officer", "Marine Transportation", "Masonry", "Medium & Heavy Vehicle & Truck Technology", "Metal Building Assembly", "Metal Fabricator", "Mobile Crane Operation", "Motorcycle Maintenance & Repair", "Musical Instrument Fabrication & Repair", "Painting & Wall Covering", "Pipefitting & Sprinkler Fitting", "Plumbing", "Railroad & Railway Transportation", "Recreation Vehicle (RV) Service", "Roofing", "Sheet Metal Technology & Sheetworking", "Shoe, Boot & Leather Repair", "Small Engine Mechanics", "Tool & Die Technology", "Truck/Bus Driver & Commercial Vehicle Operator & Instructor", "Upholstery", "Watchmaking & Jewelrymaking", "Welding", "Well Drilling", "Woodworking"]
120
+ list = []
121
+ number.times do
122
+ categories.shuffle!
123
+ list << categories.pop
124
+ end
125
+ return list
126
+ end
127
+
128
+ end
129
+
130
+ # Need this to extend Watir to be able to attach to Sakai's non-standard tags...
131
+ module Watir
132
+
133
+ class Browser
134
+
135
+ def linger_for_ajax(timeout=5)
136
+ end_time = ::Time.now + timeout
137
+ while self.execute_script("return jQuery.active") > 0
138
+ sleep 0.2
139
+ break if ::Time.now > end_time
140
+ end
141
+ self.wait(timeout + 10)
142
+ end
143
+
144
+ def back_to_top
145
+ self.execute_script("javascript:window.scrollTo(0,0)")
146
+ end
147
+
148
+ alias return_to_top back_to_top
149
+ alias scroll_to_top back_to_top
150
+
151
+ end
152
+
153
+ class Element
154
+ # attaches to the "headers" tags inside of the assignments table.
155
+ def headers
156
+ @how = :ole_object
157
+ return @o.headers
158
+ end
159
+
160
+ # attaches to the "for" tags in "label" tags.
161
+ def for
162
+ @how = :ole_object
163
+ return @o.for
164
+ end
165
+
166
+ end
167
+ end
168
+
@@ -0,0 +1,109 @@
1
+ # coding: UTF-8
2
+
3
+ # This module contains methods that will be almost
4
+ # universally useful, and don't pertain to any specific
5
+ # area or widget or pop up on a given page.
6
+ #
7
+ # The primary method provided in this module is of the type
8
+ # .open_<page>('target_text'). Depending on the type of <page>
9
+ # specified, the method will return the appropriate Class object.
10
+ module GlobalMethods
11
+
12
+ include PageObject
13
+
14
+ # These create methods of the form
15
+ # open_<name>('target link text')
16
+ # Example usage in a script on a page where there's a calendar link
17
+ # with the text "Moon Phases" ...
18
+ #
19
+ # calendar_page = current_page.open_calendar("Moon Phases")
20
+ #
21
+ # Once the link is clicked, the method
22
+ # returns the specified class object.
23
+ #
24
+ # It's important to note that the methods created
25
+ # assume that the target page will be opened in the
26
+ # same tab. If a new tab is opened, these methods will not work.
27
+ #
28
+ # In addition, the page classes that are instantiated for the
29
+ # target pages assume that the user has editing
30
+ # rights.
31
+ open_link(:document, "ContentDetailsPage")
32
+ open_link(:content, "ContentDetailsPage")
33
+ open_link(:remote_content, "Remote")
34
+ open_link(:library, "Library")
35
+ open_link(:participants, "Participants")
36
+ open_link(:discussions, "Discussions")
37
+ open_link(:tests_and_quizzes, "Tests")
38
+ open_link(:assessments, "Tests")
39
+ open_link(:calendar, "Calendar")
40
+ open_link(:map, "GoogleMaps")
41
+ open_link(:file, "Files")
42
+ open_link(:forum, "Forum")
43
+ open_link(:comments, "Comments")
44
+ open_link(:jisc, "JISC")
45
+ open_link(:assignments, "Assignments")
46
+ open_link(:feed, "RSS")
47
+ open_link(:rss_feed, "RSS")
48
+ open_link(:rss, "RSS")
49
+ open_link(:lti, "LTI")
50
+ open_link(:basic_lti, "LTI")
51
+ open_link(:gadget, "Gadget")
52
+ open_link(:gradebook, "Gradebook")
53
+
54
+ alias open_group open_library
55
+ alias open_course open_library
56
+ alias go_to open_library
57
+
58
+ # The "gritter" notification that appears to confirm
59
+ # when something has happened (like updating a user profile
60
+ # or sending a message).
61
+ div(:notification, :class=>"gritter-with-image")
62
+
63
+ # This method is essentially
64
+ # identical with the
65
+ # open_link methods listed above.
66
+ # It opens page/document items that are listed on the page--for example
67
+ # in the Recent activity box.
68
+ # There is an important distinction, however:
69
+ # This method should be used in cases when clicking the
70
+ # link results in a new browser tab/window being generated.
71
+ # May ultimately convert this to open_public_<object>
72
+ # if that seems the best generic way to handle things.
73
+ #
74
+ # THIS METHOD MAY SOON BE DEPRECATED (if so, it
75
+ # will be included as an alias of open_content)
76
+ def open_page(name)
77
+ name_link(name).click
78
+ self.wait_for_ajax
79
+ self.window(:title=>"rSmart | Content Profile").use
80
+ ContentDetailsPage.new @browser
81
+ end
82
+
83
+ # Clicks the link of the specified name (It will click any link on the page,
84
+ # really, but it should be used for Person links only, because it
85
+ # instantiates the ViewPerson Class)
86
+ def view_person(name)
87
+ name_link(name).click
88
+ sleep 3
89
+ self.wait_for_ajax
90
+ ViewPerson.new @browser
91
+ end
92
+ alias view_profile view_person
93
+
94
+ # Clicks the X in the Notification box, to dismiss it.
95
+ def close_notification
96
+ self.div(:class=>"gritter-item").hover
97
+ self.div(:class=>"gritter-close").fire_event "onclick"
98
+ end
99
+
100
+ # This method exposes the "draggable" menu items in the left-hand
101
+ # menus, so that you can use Watir's <X>.drag_and_drop_on <Y> method.
102
+ # Note that not all matching menu items are necessarily draggable.
103
+ # Also useful if you just want to see if the menu item is visible
104
+ # on the page
105
+ def menu_item(name)
106
+ self.div(:class=>/lhnavigation(_subnav|)_item_content/, :text=>name)
107
+ end
108
+
109
+ end # GlobalMethods
@@ -0,0 +1,1949 @@
1
+ # coding: UTF-8
2
+ require 'sakai-OAE/gem_extensions'
3
+ require 'sakai-OAE/global_methods'
4
+ require 'sakai-OAE/toolbars_and_menus'
5
+ require 'sakai-OAE/pop_up_dialogs'
6
+ require 'sakai-OAE/widgets'
7
+ require 'sakai-OAE/cle_frame_classes'
8
+
9
+ # The Login page for OAE.
10
+ class LoginPage
11
+
12
+ include PageObject
13
+ include HeaderFooterBar
14
+ include GlobalMethods
15
+
16
+ # Page Objects
17
+ div(:expand_categories, :class=>"categories_expand")
18
+
19
+ # Custom Methods...
20
+
21
+ # Returns an array containing the titles of the items
22
+ # displayed in the "Recent activity" box on the login page.
23
+ def recent_activity_list
24
+ list = []
25
+ self.div(:id=>"recentactivity_activity_container").links(:class=>"recentactivity_activity_item_title recentactivity_activity_item_text s3d-regular-links s3d-bold").each do |link|
26
+ list << link.text
27
+ end
28
+ return list.uniq!
29
+ end
30
+
31
+ # Returns an array containing the titles of the items in the
32
+ # Featured Content area of the page.
33
+ def featured_content_list
34
+ list = []
35
+ self.div(:id=>"featuredcontent_content_container").links(:class=>/featuredcontent_content_title/).each do |link|
36
+ list << link.text
37
+ end
38
+ return list
39
+ end
40
+
41
+ end
42
+
43
+ # Page Objects and Methods for the "All Categories" page.
44
+ # Note that this page is distinct from the "Search => All types"
45
+ # page.
46
+ class AllCategoriesPage
47
+
48
+ include PageObject
49
+ include HeaderFooterBar
50
+ include GlobalMethods
51
+
52
+ # Page Objects
53
+ div(:page_title, :class=>"s3d-contentpage-title")
54
+
55
+ # Custom Methods...
56
+
57
+ end
58
+
59
+ # TODO - Write a class description
60
+ class Calendar
61
+
62
+ include PageObject
63
+ include HeaderFooterBar
64
+ include LeftMenuBar
65
+ include HeaderBar
66
+ include DocButtons
67
+ include GlobalMethods
68
+
69
+ def calendar_frame
70
+ self.frame(:src=>/sakai2calendar.launch.html/)
71
+ end
72
+
73
+ end
74
+
75
+ # Methods related to the Content Details page.
76
+ class ContentDetailsPage
77
+
78
+ include PageObject
79
+ include GlobalMethods
80
+ include HeaderFooterBar
81
+ include DocButtons
82
+ include LeftMenuBar
83
+
84
+ # Page Objects
85
+ text_area(:comment_text_area, :id=>"contentcomments_txtMessage")
86
+ button(:comment_button, :text=>"Comment")
87
+ button(:see_more, :id=>"contentmetadata_show_more")
88
+ button(:see_less, :id=>"contentmetadata_show_more")
89
+ button(:permissions_menu_button, :id=>"entity_content_permissions")
90
+ button(:permissions_button, :text=>"Permissions")
91
+ button(:delete_button, :text=>"Delete")
92
+ button(:add_to_button, :id=>"entity_content_save")
93
+ button(:share_button, :id=>"entity_content_share")
94
+
95
+ span(:name, :id=>"entity_name")
96
+ span(:type, :id=>"entity_type")
97
+
98
+ # Custom Methods...
99
+
100
+ # Returns the text of the description display span.
101
+ def description
102
+ self.span(:id=>"contentmetadata_description_display").text
103
+ end
104
+
105
+ # Enters the specified text into the description text area box.
106
+ # Note that this method first fires off the edit_description method
107
+ # because the description text area is not present by default.
108
+ def description=(text)
109
+ edit_description
110
+ self.text_area(:id=>"contentmetadata_description_description").set text
111
+ end
112
+
113
+ # Header row items...
114
+ def update_name=(new_name)
115
+ name_element.click
116
+ self.text_field(:id=>"entity_name_text").set new_name + "\n"
117
+ end
118
+
119
+ # Visibility...
120
+ def change_visibility_private
121
+ # TODO - Write method
122
+ end
123
+
124
+ def change_visibility_logged_in
125
+ # TODO - Write method
126
+ end
127
+
128
+ def change_visibility_public
129
+ # TODO - Write method
130
+ end
131
+
132
+ # Collaboration...
133
+
134
+ #
135
+ def view_collaborators
136
+ # TODO - Write method
137
+ end
138
+
139
+ #
140
+ def change_collaborators
141
+ # TODO - Write method
142
+ end
143
+
144
+ # This method is currently not working TODO - Fix method
145
+ #def change_sharing
146
+ # self.div(:class=>"entity_owns_actions_share has_counts ew_permissions").hover
147
+ # self.div(:class=>"entity_owns_actions_share has_counts ew_permissions").click
148
+ # self.execute_script(%|$('.entity_owns_actions_share.has_counts.ew_permissions').trigger("mouseover");|)
149
+ # wait_for_ajax
150
+ # self.div(:class=>"entity_owns_actions_share has_counts ew_permissions").button(:class=>"s3d-link-button ew_permissions").click
151
+ # self.class.class_eval { include ContentPermissionsPopUp }
152
+ #end
153
+
154
+ def collaboration_share
155
+ self.div(:id=>"entity_actions").button(:text=>"Share").click
156
+ self.wait_until { self.text.include? "Who do you want to share with?" }
157
+ self.class.class_eval { include ShareWithPopUp }
158
+ end
159
+
160
+ # Comments count...
161
+
162
+ # Comments field...
163
+
164
+ # Clicks the Comments button
165
+ def comment
166
+ comment_button
167
+ self.wait_for_ajax(2)
168
+ end
169
+
170
+ # Enters the specified text string into the Comment box.
171
+ def comment_text(text)
172
+ comment_text_area_element.click
173
+ comment_text_area_element.send_keys text
174
+ end
175
+ alias comment_text= comment_text
176
+
177
+ # Clicks the "Add to..." button
178
+ def add_to
179
+ add_to_button
180
+ self.wait_for_ajax(2)
181
+ end
182
+
183
+ # Clicks "Permissions" in the menu...
184
+ def permissions
185
+ permissions_menu_button
186
+ self.wait_for_ajax(2)
187
+ permissions_button
188
+ self.wait_for_ajax(2)
189
+ self.class.class_eval { include ContentPermissionsPopUp }
190
+ end
191
+
192
+ # Returns an array object containing the items displayed in
193
+ # "Related Content" on the page.
194
+ def related_content
195
+ list = []
196
+ self.div(:class=>"relatedcontent_list").links.each do |link|
197
+ list << link.title
198
+ end
199
+ return list
200
+ end
201
+
202
+ # Clicks on the "Share Content" button.
203
+ def share_content
204
+ self.div(:id=>"entity_actions").span(:class=>"entity_share_content").click
205
+ self.wait_until { @browser.text.include? "Who do you want to share with?" }
206
+ self.class.class_eval { include ShareWithPopUp }
207
+ end
208
+
209
+ # Clicks on the "Add to library" button.
210
+ def add_to_library
211
+ self.button(:text=>"Add to library").click
212
+ self.wait_until { self.text.include? "Save to" }
213
+ self.class.class_eval { include SaveContentPopUp }
214
+ end
215
+
216
+ # Opens the description text field for editing.
217
+ def edit_description
218
+ self.div(:id=>"contentmetadata_description_container").fire_event "onmouseover"
219
+ self.div(:id=>"contentmetadata_description_container").fire_event "onclick"
220
+ end
221
+
222
+ # Opens the tag field for editing.
223
+ def edit_tags
224
+ self.div(:id=>"contentmetadata_tags_container").fire_event "onclick"
225
+ end
226
+
227
+ # Opens the Copyright field for editing.
228
+ def edit_copyright
229
+ self.div(:id=>"contentmetadata_copyright_container").fire_event "onclick"
230
+ end
231
+
232
+ # Opens the Categories field for editing.
233
+ def edit_categories
234
+ self.div(:id=>"contentmetadata_locations_container").fire_event "onclick"
235
+ self.class.class_eval { include AddRemoveCategories }
236
+ end
237
+
238
+ # Returns an array containing the tags and categories listed on the page.
239
+ def tags_and_categories_list
240
+ list =[]
241
+ self.div(:id=>"contentmetadata_tags_container").links.each do |link|
242
+ list << link.text
243
+ end
244
+ return list
245
+ end
246
+
247
+ # The "share" button next to the Download button.
248
+ def share_with_others
249
+ self.share_button
250
+ self.wait_for_ajax
251
+ self.class.class_eval { include ShareWithPopUp }
252
+ end
253
+
254
+ # Comments List Stuff
255
+
256
+ # This method grabs all of the information about the last listed comment and
257
+ # returns it in a hash object. Relevant strings are put into the following
258
+ # keys: :poster, :date, :message. The delete button element is defined in the
259
+ # :delete_button key. Note that you'll have to use Watir's .click method to click
260
+ # the button.
261
+ def last_comment
262
+ hash = {}
263
+ comments_table = self.div(:class=>"contentcommentsTable")
264
+ last_message = comments_table.div(:class=>"contentcomments_comment last")
265
+ hash.store(:poster, last_message.span(:class=>"contentcomments_posterDataName s3d-regular-links").link.text)
266
+ hash.store(:date, last_message.span(:class=>"contentcomments_dateComment").text)
267
+ hash.store(:message, last_message.div(:class=>"contentcomments_message").text)
268
+ hash.store(:delete_button, last_message.button(:id=>/contentcomments_delete_\d+/))
269
+ return hash
270
+ end
271
+
272
+ # This method grabs all of the information about the first listed comment and
273
+ # returns it in a hash object. Relevant strings are put into the following
274
+ # keys: :poster, :date, :message. The delete button element is defined in the
275
+ # :delete_button key. Note that you'll have to use Watir's .click method to click
276
+ # the button.
277
+ def first_comment
278
+ hash = {}
279
+ comments_table = self.div(:class=>"contentcommentsTable")
280
+ last_message = comments_table.div(:class=>"contentcomments_comment last")
281
+ hash.store(:poster, last_message.span(:class=>"contentcomments_posterDataName s3d-regular-links").link.text)
282
+ hash.store(:date, last_message.span(:class=>"contentcomments_dateComment").text)
283
+ hash.store(:message, last_message.div(:class=>"contentcomments_message").text)
284
+ hash.store(:delete_button, last_message.button(:id=>/contentcomments_delete_\d+/))
285
+ return hash
286
+ end
287
+
288
+ end
289
+
290
+ # Methods related to the page for creating a new user account
291
+ class CreateNewAccount
292
+
293
+ include PageObject
294
+ include HeaderFooterBar
295
+
296
+ text_field(:user_name, :id=>"username")
297
+ text_field(:institution, :id=>"institution")
298
+ # The password field's method name needs to be
299
+ # "new_password" so that it doesn't conflict with
300
+ # the "password" field in the Sign In menu...
301
+ text_field(:new_password, :id=>"password")
302
+ text_field(:retype_password, :id=>"password_repeat")
303
+ select_list(:role, :id=>"role")
304
+ select_list(:title, :id=>"title")
305
+ text_field(:first_name,:id=>"firstName")
306
+ text_field(:last_name,:id=>"lastName")
307
+ text_field(:email,:id=>"email")
308
+ text_field(:email_confirm, :id=>"emailConfirm")
309
+ text_field(:phone_number,:id=>"phone")
310
+ checkbox(:receive_tips, :id=>"emailContact")
311
+ checkbox(:contact_me_directly, :id=>"contactMe")
312
+ button(:create_account_button, :id=>"save_account")
313
+
314
+ span(:username_error, :id=>"username_error")
315
+ span(:password_error, :id=>"password_error")
316
+ span(:password_repeat_error, :id=>"password_repeat_error")
317
+ span(:title_error, :id=>"title_error")
318
+ span(:firstname_error, :id=>"firstName_error")
319
+ span(:lastname_error, :id=>"lastName_error")
320
+ span(:email_error, :id=>"email_error")
321
+ span(:email_confirm_error, :id=>"emailConfirm_error")
322
+ span(:institution_error, :id=>"institution_error")
323
+ span(:role_error, :id=>"role_error")
324
+ span(:password_strength, :class=>/strength (zero|one|two|three|four)/)
325
+
326
+ # Clicks the 'create account' button, waits for the dashboard,
327
+ # then returns the MyDashboard class object.
328
+ def create_account
329
+ self.back_to_top
330
+ self.create_account_button
331
+ sleep 4
332
+ self.wait_until { self.text.include? "My dashboard" }
333
+ MyDashboard.new @browser
334
+ #self.class.class_eval { include OurAgreementPopUp }
335
+ end
336
+
337
+ end
338
+
339
+ # Methods related to the page that appears when you are
340
+ # creating a new Course.
341
+ class CreateCourses
342
+
343
+ include PageObject
344
+ include HeaderFooterBar
345
+ include LeftMenuBarCreateWorlds
346
+
347
+ # Clicks the button for using the math template,
348
+ # then returns the MathTemplate class object.
349
+ def use_math_template
350
+ self.div(:class=>"selecttemplate_template_large").button(:text=>"Use this template").click
351
+ # TODO - Class goes here
352
+ end
353
+
354
+ # Clicks the button to use the basic template,
355
+ # waits for the new page to load, then returns
356
+ # the CreateGroups class object.
357
+ def use_basic_template
358
+ self.div(:class=>"selecttemplate_template_small selecttemplate_template_right").button(:text=>"Use this template").click
359
+ self.wait_until { self.text.include? "Suggested URL:" }
360
+ CreateGroups.new @browser
361
+ end
362
+
363
+ end
364
+
365
+ # Methods related to the page where a new Course/Group/Project
366
+ # is set up.
367
+ class CreateGroups
368
+
369
+ include PageObject
370
+ include HeaderFooterBar
371
+ include LeftMenuBarCreateWorlds
372
+
373
+ text_field(:title, :id=>"newcreategroup_title")
374
+ text_field(:suggested_url, :id=>"newcreategroup_suggested_url")
375
+ text_area(:description, :id=>"newcreategroup_description")
376
+ text_area(:tags, :name=>"newcreategroup_tags")
377
+ select_list(:can_be_discovered_by, :id=>"newcreategroup_can_be_found_in")
378
+ select_list(:membership, :id=>"newcreategroup_membership")
379
+
380
+ # Clicks the 'Add people' button and waits for the
381
+ # Manage Participants dialog to appear.
382
+ # Includes the ManageParticipants module in the class.
383
+ def add_people
384
+ self.button(:text, "Add people").click
385
+ self.wait_for_ajax(2)
386
+ self.class.class_eval { include ManageParticipants }
387
+ end
388
+
389
+ # Clicks the 'Add more people' button and waits for
390
+ # the Manage Participants dialog to appear.
391
+ # Includes the ManageParticipants module in the class.
392
+ def add_more_people
393
+ self.button(:text, "Add more people").click
394
+ self.wait_for_ajax(2)
395
+ self.class.class_eval { include ManageParticipants }
396
+ end
397
+
398
+ # Clicks the 'List categories' button, waits for
399
+ # the Categories dialog to appear, and then
400
+ # includes the AddRemoveCategories module in the class.
401
+ def list_categories
402
+ self.button(:text=>"List categories").click
403
+ self.wait_for_ajax(2)
404
+ self.class.class_eval { include AddRemoveCategories }
405
+ end
406
+
407
+ # Clicks the 'Create' button for the Course or Group, etc.,
408
+ # then waits until the Course Library page loads. Once that
409
+ # happens, returns the Library class object.
410
+ def create_basic_course
411
+ create_thing
412
+ unless url_error_element.visible?
413
+ self.wait_until(45) { self.text.include? "Add content" }
414
+ self.button(:id=>"group_create_new_area", :class=>"s3d-button s3d-header-button s3d-popout-button").wait_until_present
415
+ Library.new @browser
416
+ end
417
+ end
418
+ alias create_simple_group create_basic_course
419
+ alias create_group create_basic_course
420
+ alias create_research_support_group create_basic_course
421
+
422
+ # Clicks the 'Create' button then waits until the Research Intro page loads. Once that
423
+ # happens, returns the ResearchIntro class object.
424
+ def create_research_project
425
+ create_thing
426
+ unless url_error_element.visible?
427
+ self.button(:id=>"group_create_new_area", :class=>"s3d-button s3d-header-button s3d-popout-button").wait_until_present
428
+ ResearchIntro.new @browser
429
+ end
430
+ end
431
+
432
+
433
+ span(:url_error, :id=>"newcreategroup_suggested_url_error")
434
+
435
+ private
436
+
437
+ # Do not use. This method is used by the public 'create' methods in this class.
438
+ def create_thing
439
+ self.button(:class=>"s3d-button s3d-overlay-button newcreategroup_create_simple_group").click
440
+ sleep 0.3
441
+ self.div(:id=>"sakai_progressindicator").wait_while_present
442
+ sleep 2 # The poor man's wait_for_ajax, since that was failing.
443
+ end
444
+
445
+ end
446
+
447
+ # Methods related to the page for Creating a Research Project
448
+ class CreateResearch
449
+
450
+ include PageObject
451
+ include HeaderFooterBar
452
+ include LeftMenuBarCreateWorlds
453
+
454
+ # Clicks the button for using the Research Project template, waits for the
455
+ # page to load, then returns the CreateGroups class object.
456
+ def use_research_project_template
457
+ self.div(:class=>"selecttemplate_template_large").button(:text=>"Use this template").click
458
+ self.wait_until { self.text.include? "Suggested URL:" }
459
+ CreateGroups.new @browser
460
+ end
461
+
462
+ # Clicks the button for using the Research Support Group template,
463
+ # waits for the page to load, then returns the CreateGroups class object.
464
+ def use_research_support_group_template
465
+ self.div(:class=>"selecttemplate_template_small selecttemplate_template_right").button(:text=>"Use this template").click
466
+ self.wait_until { self.text.include? "Suggested URL:" }
467
+ CreateGroups.new @browser
468
+ end
469
+
470
+ end
471
+
472
+ # Page Object and methods for the SEARCH ALL TYPES page
473
+ # NOT the "Browse All Categories" page!
474
+ class ExploreAll
475
+
476
+ include PageObject
477
+ include GlobalMethods
478
+ include HeaderFooterBar
479
+ include LeftMenuBarSearch
480
+ include ListWidget
481
+ include ListCollections
482
+ include ListContent
483
+ include ListGroups
484
+ include ListPeople
485
+ include ListProjects
486
+ include SearchBar
487
+
488
+ # Returns the results header title (the text prior to the count of the results returned)
489
+ def results_header
490
+ top = self.div(:class=>"searchall_content_main")
491
+ top.div(:id=>"results_header").span.text =~ /^.+(?=.\()/
492
+ $~.to_s
493
+ end
494
+
495
+ end
496
+
497
+ # Methods related to the page for searching Content.
498
+ class ExploreContent
499
+
500
+ include PageObject
501
+ include GlobalMethods
502
+ include HeaderFooterBar
503
+ include LeftMenuBarSearch
504
+ include ListWidget
505
+ include ListContent
506
+ include SearchBar
507
+
508
+ # Returns the results header title (the text prior to the count of the results returned)
509
+ def results_header
510
+ top = self.div(:class=>"searchcontent_content_main")
511
+ top.div(:id=>"results_header").span.text =~ /^.+(?=.\()/
512
+ $~.to_s
513
+ end
514
+
515
+ end
516
+
517
+ # Methods related to the People/Users search page
518
+ class ExplorePeople
519
+
520
+ include PageObject
521
+ include GlobalMethods
522
+ include HeaderFooterBar
523
+ include LeftMenuBarSearch
524
+ include ListWidget
525
+ include ListPeople
526
+ include SearchBar
527
+
528
+ # Returns the results header title (the text prior to the count of the results returned)
529
+ def results_header
530
+ top = self.div(:class=>"searchpeople_content_main")
531
+ top.div(:id=>"results_header").span.text =~ /^.+(?=.\()/
532
+ $~.to_s
533
+ end
534
+
535
+ end
536
+
537
+ # Methods related to the Groups search page.
538
+ class ExploreGroups
539
+
540
+ include PageObject
541
+ include GlobalMethods
542
+ include HeaderFooterBar
543
+ include LeftMenuBarSearch
544
+ include ListWidget
545
+ include ListGroups
546
+ include SearchBar
547
+
548
+ # Returns the results header title (the text prior to the count of the results returned)
549
+ def results_header
550
+ top = self.div(:id=>"searchgroups_widget", :index=>0)
551
+ top.div(:id=>"results_header").span(:id=>"searchgroups_type_title").text
552
+ end
553
+
554
+ end
555
+
556
+ # Methods related to the page for searching Courses.
557
+ class ExploreCourses
558
+
559
+ include PageObject
560
+ include GlobalMethods
561
+ include HeaderFooterBar
562
+ include LeftMenuBarSearch
563
+ include ListWidget
564
+ include ListGroups
565
+ include SearchBar
566
+
567
+ # Returns the results header title (the text prior to the count of the results returned)
568
+ def results_header
569
+ top = self.div(:id=>"searchgroups_widget", :index=>1)
570
+ top.div(:id=>"results_header").span(:id=>"searchgroups_type_title").text
571
+ end
572
+
573
+ # TODO - Describe method
574
+ def courses_count
575
+ #TODO - Write method
576
+ end
577
+
578
+ # Selects the specified item in the 'Filter by' field. Waits for
579
+ # Ajax calls to drop to zero.
580
+ def filter_by=(selection)
581
+ self.select(:id=>"facted_select").select(selection)
582
+ self.wait_for_ajax(2)
583
+ end
584
+
585
+ # Selects the specified item in the 'Sort by' field. Waits for
586
+ # any Ajax calls to finish.
587
+ def sort_by=(selection)
588
+ self.div(:class=>"s3d-search-sort").select().select(selection)
589
+ self.wait_for_ajax(2)
590
+ end
591
+
592
+ end
593
+
594
+ # Methods related to the page for searching for Research Projects.
595
+ class ExploreResearch
596
+
597
+ include PageObject
598
+ include GlobalMethods
599
+ include HeaderFooterBar
600
+ include LeftMenuBarSearch
601
+ include ListWidget
602
+ include ListProjects
603
+ include SearchBar
604
+
605
+ # Returns the results header title (the text prior to the count of the results returned)
606
+ def results_header
607
+ top = self.div(:id=>"searchgroups_widget", :index=>2)
608
+ top.div(:id=>"results_header").span(:id=>"searchgroups_type_title").text
609
+ end
610
+
611
+ end
612
+
613
+ # Methods related to objects found on the Dashboard
614
+ class MyDashboard
615
+
616
+ include PageObject
617
+ include GlobalMethods
618
+ include HeaderFooterBar
619
+ include LeftMenuBarYou
620
+ include ChangePicturePopUp # TODO ... Rethink including this by default
621
+
622
+ # Page Objects
623
+ button(:edit_layout, :text=>"Edit layout")
624
+ radio_button(:one_column, :id=>"layout-picker-onecolumn")
625
+ radio_button(:two_column, :id=>"layout-picker-dev")
626
+ radio_button(:three_column, :id=>"layout-picker-threecolumn")
627
+ button(:save_layout, :id=>"select-layout-finished")
628
+ button(:add_widgets_button, :class=>/dashboard_global_add_widget/) # Do not use for clicking the button. See custom methods
629
+ image(:profile_pic, :id=>"entity_profile_picture")
630
+ div(:my_name, :class=>"s3d-bold entity_name_me")
631
+
632
+ #div(:page_title, :class=>"s3d-contentpage-title")
633
+
634
+ # Custom Methods...
635
+
636
+ # Returns the text contents of the page title div
637
+ def page_title
638
+ self.div(:id=>"s3d-page-container").div(:class=>"s3d-contentpage-title").text
639
+ end
640
+
641
+ # Clicks the 'Add widget' button, waits for the page to load,
642
+ # then includes the AddRemoveWidgets module in the class.
643
+ # Note that this method is specifically "add_widgets" because
644
+ # otherwise there would be a method collision with the "add widget"
645
+ # method in the AddRemoveWidgets module.
646
+ def add_widgets
647
+ self.add_widgets_button
648
+ self.wait_until { self.text.include? "Add widgets" }
649
+ self.class.class_eval { include AddRemoveWidgets }
650
+ end
651
+
652
+ # Returns an array object containing a list of all selected widgets.
653
+ def displayed_widgets
654
+ list = []
655
+ self.div(:class=>"fl-container-flex widget-content").divs(:class=>"s3d-contentpage-title").each do |div|
656
+ list << div.text
657
+ end
658
+ return list
659
+ end
660
+
661
+ # Returns the name of the recent membership item displayed.
662
+ def recent_membership_item
663
+ self.div(:class=>"recentmemberships_widget").link(:class=>/recentmemberships_item_link/).text
664
+ end
665
+
666
+ # Clicks on the membership item displayed in the Recent Memberships widget.
667
+ # Then returns the Library class object.
668
+ def go_to_most_recent_membership
669
+ self.link(:class=>"recentmemberships_item_link s3d-widget-links s3d-bold").click
670
+ sleep 2 # The next line sometimes throws an "unknown javascript error" without this line.
671
+ self.wait_for_ajax(2)
672
+ Library.new @browser
673
+ end
674
+
675
+ # Returns an array containing all the items listed in the "My memberships" dashboard widget.
676
+ def my_memberships_list
677
+ list = []
678
+ self.ul(:class=>"mygroup_items_list").spans(:class=>"mygroups_ellipsis_text").each { |span| list << span.text }
679
+ return list
680
+ end
681
+
682
+ end
683
+
684
+ # Methods related to the My Messages pages.
685
+ class MyMessages
686
+
687
+ include PageObject
688
+ include GlobalMethods
689
+ include HeaderFooterBar
690
+ include LeftMenuBarYou
691
+
692
+ # Page Objects
693
+ button(:accept_invitation, :text=>"Accept invitation")
694
+ button(:ignore_invitation, :text=>"Ignore invitation")
695
+
696
+ # Custom Methods...
697
+
698
+ # Returns the text of the displayed page title
699
+ def page_title
700
+ active_div.span(:id=>"inbox_box_title").text
701
+ end
702
+
703
+ # Clicks the "Compose message" button on any of the
704
+ # My messages pages.
705
+ def compose_message
706
+ active_div.link(:id=>"inbox_create_new_message").click
707
+ self.wait_for_ajax(2)
708
+ self.class.class_eval { include SendMessagePopUp }
709
+ end
710
+
711
+ # Returns an Array containing the list of Email subjects.
712
+ def message_subjects
713
+ list = []
714
+ active_div.divs(:class=>"inbox_subject").each do |div|
715
+ list << div.text
716
+ end
717
+ return list
718
+ end
719
+
720
+ # Clicks on the specified email to open it for reading
721
+ def open_message(subject)
722
+ active_div.div(:class=>"inbox_subject").link(:text=>subject).click
723
+ self.wait_for_ajax(2)
724
+ self.class.class_eval { include SendMessagePopUp }
725
+ end
726
+
727
+ # Clicks the Delete button for the specified message (specified by Subject), then
728
+ # waits for Ajax calls to complete.
729
+ def delete_message(subject)
730
+ subject_div = active_div.div(:class=>"inbox_subject", :text=>subject)
731
+ subject_div.parent.parent.parent.button(:title=>"Delete message").click
732
+ self.wait_for_ajax
733
+ end
734
+
735
+ # Clicks the Reply button for the specified (by Subject) message
736
+ # then waits for the Ajax calls to complete
737
+ def reply_to_message(subject)
738
+ subject_div = active_div.div(:class=>"inbox_subject", :text=>subject)
739
+ subject_div.parent.parent.parent.link(:title=>"Reply").click
740
+ self.wait_for_ajax
741
+ self.class.class_eval { include SendMessagePopUp }
742
+ end
743
+ alias read_message open_message
744
+
745
+ # Message Preview methods...
746
+
747
+ # Returns the Sender text for the specified message (by Subject)
748
+ def preview_sender(subject)
749
+ message_div(subject).div(:class=>"inbox_name").button.text
750
+ end
751
+
752
+ # Returns the message recipient name for the specified message (by Subject)
753
+ def preview_recipient(subject)
754
+ message_div(subject).div(:class=>"inbox_name").span.text
755
+ end
756
+
757
+ # Returns the date/time string for the specified message.
758
+ def preview_date(subject)
759
+ message_div(subject).div(:class=>"inbox_date").span.text
760
+ end
761
+
762
+ # Returns the file path and name of the displayed profile pic of the
763
+ # specified message.
764
+ def preview_profile_pic(subject)
765
+ message_div(subject).parent.image(:class=>"person_icon").src
766
+ end
767
+
768
+ # Returns the text of the Body of the specified message.
769
+ def preview_body(subject)
770
+ message_div(subject).div(:class=>"inbox_excerpt").text
771
+ end
772
+
773
+ # The New Message page is controlled by the SendMessagePopUp module
774
+
775
+ # Read/Reply Page Objects (defined with Watir)
776
+
777
+ # Returns the text of the name of the sender of the message being viewed
778
+ def message_sender
779
+ active_div.div(:id=>"inbox_show_message").div(:class=>"inbox_name").button(:class=>"s3d-regular-links s3d-link-button s3d-bold personinfo_trigger_click personinfo_trigger").text
780
+ end
781
+
782
+ # Returns the recipient name text. The method assumes you're currently
783
+ # viewing a message--that you're not looking at a list of messages.
784
+ def message_recipient
785
+ active_div.div(:class, "inbox_name").span(:class=>"inbox_to_list").text
786
+ end
787
+
788
+ # Returns the date of the message being viewed (as a String object)
789
+ def message_date
790
+ active_div.div(:id=>"inbox_show_message").div(:class=>"inbox_date").span.text
791
+ end
792
+
793
+ # Returns the text of the message subject. The method assumes you're currently
794
+ # viewing a message--that you're not looking at a list of messages.
795
+ def message_subject
796
+ active_div.div(:id=>"inbox_show_message").div(:class=>"inbox_subject").link.text
797
+ end
798
+
799
+ # Returns the text of the message body.The method assumes you're currently
800
+ # viewing a message--that you're not looking at a list of messages.
801
+ def message_body
802
+ active_div.div(:id=>"inbox_show_message").div(:class=>"inbox_excerpt").text
803
+ end
804
+
805
+ # The page element for the "Delete selected" button.
806
+ def delete_selected_element
807
+ active_div.button(:id=>"inbox_delete_selected")
808
+ end
809
+
810
+ # Clicks the "Delete selected" buton and waits for Ajax calls to complete
811
+ def delete_selected
812
+ delete_selected_element.click
813
+ self.wait_for_ajax
814
+ end
815
+
816
+ # The page element for the "Mark as read" button
817
+ def mark_as_read_element
818
+ active_div.button(:id=>"inbox_mark_as_read")
819
+ end
820
+
821
+ # Clicks the "Mark as read" button, then waits for Ajax calls to complete
822
+ def mark_as_read
823
+ mark_as_read_element.click
824
+ sleep 0.3
825
+ self.wait_for_ajax
826
+ end
827
+
828
+ # Checks the checkbox for the specified message in the list.
829
+ def select_message(subject)
830
+ subject_div = active_div.div(:class=>"inbox_subject", :text=>subject)
831
+ subject_div.parent.parent.parent.checkbox.set
832
+ end
833
+
834
+ # Returns "read" or "unread", based on the relevant div's class setting.
835
+ def message_status(subject)
836
+ classname = self.div(:class=>/^inbox_item fl-container fl-fix/, :text=>/#{Regexp.escape(subject)}/).class_name
837
+ if classname =~ /unread/
838
+ return "unread"
839
+ else
840
+ return "read"
841
+ end
842
+ end
843
+
844
+ # Counts the number of displayed messages on the current page.
845
+ # Returns a hash containing counts for read and unread messages on the page.
846
+ # Keys in the hash are :all, :read, and :unread.
847
+ def message_counts
848
+ hash = {}
849
+ total = active_div.divs(:class=>"inbox_items_inner").length
850
+ unread = active_div.divs(:class=>/unread/).length
851
+ read = total - unread
852
+ hash.store(:total, total)
853
+ hash.store(:unread, unread)
854
+ hash.store(:read, read)
855
+ return hash
856
+ end
857
+
858
+ # Search
859
+
860
+ # The page element for the Search text field.
861
+ def search_field_element
862
+ active_div.text_field(:id=>"inbox_search_messages")
863
+ end
864
+
865
+ # Enters the specified text in the Search text box.
866
+ # Note that it appends a line feed on the end of the text
867
+ # so that the search happens immediately. Thus there is
868
+ # no need for a second line in the test script to
869
+ # specify clicking the Search button.
870
+ def search_messages=(text)
871
+ search_field_element.set(text+"\n")
872
+ begin
873
+ active_div.p(:id=>"inbox_search_term").wait_until_present(3)
874
+ rescue
875
+ # do nothing because the result set might be empty
876
+ end
877
+ end
878
+
879
+ # The page element for the Search button
880
+ def search_button_element
881
+ active_div.button(:class=>"s3d-button s3d-overlay-button s3d-search-button")
882
+ end
883
+
884
+ # Clicks the Search button and waits for Ajax calls to complete
885
+ def search_messages
886
+ search_button_element.click
887
+ self.wait_for_ajax
888
+ end
889
+
890
+ # Private Methods in this class
891
+ private
892
+
893
+ # Determines which sub page is currently active,
894
+ # so that all the other methods in the class will work
895
+ # properly.
896
+ def active_div
897
+ container_div = self.div(:id=>"s3d-page-container")
898
+ id = "x"
899
+ mail_divs = container_div.divs(:id=>"inbox_widget")
900
+ if mail_divs.length == 1
901
+ id = mail_divs[0].id
902
+ else
903
+ mail_divs.each do |div|
904
+ if div.visible?
905
+ id = div.parent.parent.parent.id
906
+ break
907
+ end
908
+ end
909
+ end
910
+ if id == "x"
911
+ puts "==========================="
912
+ puts "Couldn't find the visible inbox widget div, so didn't get a valid ID"
913
+ puts "==========================="
914
+ end
915
+ return self.div(:id=>id)
916
+ end
917
+
918
+ # Uses the specified subject text to determine which message div to
919
+ # use.
920
+ def message_div(subject)
921
+ active_div.div(:class=>"inbox_subject",:text=>subject).parent.parent
922
+ end
923
+
924
+ end
925
+
926
+ # Methods related to the Basic Info page in My Profile
927
+ class MyProfileBasicInfo
928
+
929
+ include PageObject
930
+ include GlobalMethods
931
+ include HeaderFooterBar
932
+ include LeftMenuBarYou
933
+
934
+ # Basic Information
935
+ text_field(:given_name, :name=>"firstName")
936
+ text_field(:family_name, :id=>"lastName")
937
+ text_field(:preferred_name, :id=>"preferredName")
938
+ text_area(:tags, :name=>"tags")
939
+ span(:first_name_error, :id=>"firstName_error")
940
+ span(:last_name_error, :id=>"lastName_error")
941
+
942
+ # Clicks the "List categories" button and waits for the
943
+ # pop-up dialog to load. Includes the AddRemoveCategories
944
+ # module in the class object.
945
+ def list_categories
946
+ self.form(:id=>"displayprofilesection_form_basic").button(:text=>"List categories").click
947
+ self.wait_for_ajax(3)
948
+ self.class.class_eval { include AddRemoveCategories }
949
+ end
950
+
951
+ # Returns an array consisting of the contents of the Tags and Categories
952
+ # field. Returns the categories split up among children and parents.
953
+ # In other words, for example, "Engineering & Technology » Computer Engineering"
954
+ # becomes "Engineering & Technology", "Computer Engineering"
955
+ def categories
956
+ list = []
957
+ self.form(:id=>"displayprofilesection_form_basic").ul(:class=>"as-selections").lis.each do |li|
958
+ next if li.text == ""
959
+ string = li.text[/(?<=\n).+/]
960
+ split = string.split(" » ")
961
+ list << split
962
+ end
963
+ list.flatten!
964
+ list.uniq!
965
+ return list
966
+ end
967
+
968
+ # Removes the specified category from the list
969
+ def remove_category(name)
970
+ self.form(:id=>"displayprofilesection_form_basic").li(:text=>/#{Regexp.escape(name)}/).link(:class=>"as-close").click
971
+ self.wait_for_ajax
972
+ end
973
+
974
+ # Clicks the "Update" button and waits for any Ajax calls
975
+ # to complete.
976
+ def update
977
+ self.form(:id=>"displayprofilesection_form_basic").button(:text=>"Update").click
978
+ self.wait_for_ajax(2)
979
+ end
980
+
981
+ end
982
+
983
+ # Methods related to the About Me page in My Profile
984
+ class MyProfileAboutMe
985
+
986
+ include PageObject
987
+ include GlobalMethods
988
+ include HeaderFooterBar
989
+ include LeftMenuBarYou
990
+
991
+ text_area(:about_Me, :id=>"aboutme")
992
+ text_area(:academic_interests, :id=>"academicinterests")
993
+ text_area(:personal_interests, :id=>"personalinterests")
994
+
995
+ # Clicks the "Update" button and waits for any Ajax calls
996
+ # to complete.
997
+ def update
998
+ self.form(:id=>"displayprofilesection_form_aboutme").button(:text=>"Update").click
999
+ self.wait_for_ajax(2)
1000
+ end
1001
+
1002
+ end
1003
+
1004
+ # Methods related to the 'Online' page in My Profile.
1005
+ class MyProfileOnline
1006
+
1007
+ include PageObject
1008
+ include GlobalMethods
1009
+ include HeaderFooterBar
1010
+ include LeftMenuBarYou
1011
+
1012
+ button(:add_another_online, :text=>"Add another Online", :id=>"displayprofilesection_add_online")
1013
+
1014
+ text_field(:site, :id=>/siteOnline_\d+/, :index=>-1)
1015
+ text_field(:url, :id=>/urlOnline_\d+/, :index=>-1)
1016
+
1017
+ # Clicks the "Update" button and waits for any Ajax calls
1018
+ # to complete.
1019
+ def update
1020
+ self.form(:id=>"displayprofilesection_form_online").button(:text=>"Update").click
1021
+ self.wait_for_ajax
1022
+ end
1023
+
1024
+ # Returns a hash object, where the keys are the site names and the
1025
+ # values are the urls.
1026
+ def sites_list
1027
+ hash = {}
1028
+ self.div(:id=>"displayprofilesection_sections_online").divs(:class=>"s3d-form-field-wrapper").each do |div|
1029
+ hash.store(div.text_field(:id=>/siteOnline_/).value, div.text_field(:id=>/urlOnline_/).value)
1030
+ end
1031
+ return hash
1032
+ end
1033
+
1034
+ # Removes the specified Online record from the list by clicking its
1035
+ # "Remove this Online" button.
1036
+ def remove_this_online(text)
1037
+ #find the div...
1038
+ div = self.div(:class=>"online").text_field(:value=>text).parent.parent.parent
1039
+ #click the button
1040
+ div.button(:id=>/displayprofilesection_remove_link_/).click
1041
+ self.wait_for_ajax
1042
+ end
1043
+ end
1044
+
1045
+ # Methods related to the My Profile: Contact Information page
1046
+ class MyProfileContactInfo
1047
+
1048
+ include PageObject
1049
+ include GlobalMethods
1050
+ include HeaderFooterBar
1051
+ include LeftMenuBarYou
1052
+
1053
+ # Page Objects
1054
+ #button(:add_another, :text=>"Add another", :id=>/profilesection_add_link_\d/)
1055
+ text_field(:institution, :id=>"college", :name=>"college")
1056
+ text_field(:department, :id=>"department", :name=>"department")
1057
+ text_field(:title_role, :name=>"role")
1058
+ text_field(:role, :name=>"role")
1059
+ text_field(:email, :name=>"emailContact")
1060
+ text_field(:instant_messaging, :name=>"imContact")
1061
+ text_field(:phone, :name=>"phoneContact")
1062
+ text_field(:mobile, :name=>"mobileContact")
1063
+ text_field(:fax, :name=>"faxContact")
1064
+ text_field(:address, :name=>"addressContact")
1065
+ text_field(:city, :id=>"cityContact")
1066
+ text_field(:state, :name=>"stateContact")
1067
+ text_field(:postal_code, :name=>"postalContact")
1068
+ text_field(:country, :name=>"countryContact")
1069
+
1070
+ # Custom Methods
1071
+
1072
+ # Clicks the "Update" button and waits for any Ajax calls
1073
+ # to complete.
1074
+ def update
1075
+ self.form(:id=>"displayprofilesection_form_contact").button(:text=>"Update").click
1076
+ self.wait_for_ajax(2)
1077
+ end
1078
+
1079
+ # Takes a hash object and uses it to fill out
1080
+ # the fields on the form. The necessary key values in the
1081
+ # hash argument are as follows:
1082
+ # :institution, :department, :title, :email, :im, :phone,
1083
+ # :mobile, :fax, :address, :city, :state, :zip, and :country.
1084
+ # Any keys that are different or missing will be ignored.
1085
+ def fill_out_form(hash)
1086
+ self.email=hash[:email]
1087
+ self.fax=hash[:fax]
1088
+ self.institution=hash[:institution]
1089
+ self.department=hash[:department]
1090
+ self.title_role=hash[:title]
1091
+ self.instant_messaging=hash[:im]
1092
+ self.phone=hash[:phone]
1093
+ self.mobile=hash[:mobile]
1094
+ self.address=hash[:address]
1095
+ self.city=hash[:city]
1096
+ self.state=hash[:state]
1097
+ self.postal_code=hash[:zip]
1098
+ self.country=hash[:country]
1099
+ end
1100
+
1101
+ end
1102
+
1103
+ # Publications
1104
+ class MyProfilePublications
1105
+
1106
+ include PageObject
1107
+ include GlobalMethods
1108
+ include HeaderFooterBar
1109
+ include LeftMenuBarYou
1110
+
1111
+ # Page Objects
1112
+
1113
+ button(:add_another_publication, :text=>"Add another publication", :id=>"displayprofilesection_add_publications")
1114
+ text_field(:main_title, :id=>/maintitle_\d+/, :index=>-1)
1115
+ text_field(:main_author, :name=>/mainauthor_\d+/, :index=>-1)
1116
+ text_field(:co_authors, :id=>/coauthor_\d+/, :index=>-1)
1117
+ text_field(:publisher, :id=>/publisher_\d+/, :index=>-1)
1118
+ text_field(:place_of_publication, :id=>/placeofpublication_\d+/, :index=>-1)
1119
+ text_field(:volume_title, :id=>/volumetitle_\d+/, :index=>-1)
1120
+ text_field(:volume_information, :id=>/volumeinformation_\d+/, :index=>-1)
1121
+ text_field(:year, :id=>/year_\d+/, :index=>-1)
1122
+ text_field(:number, :id=>/number_\d+/, :index=>-1)
1123
+ text_field(:series_title, :id=>/series.title_\d+/, :index=>-1)
1124
+ text_field(:url, :id=>/url_\d+/, :index=>-1)
1125
+ span(:title_error, :id=>/maintitle_\d+_error/)
1126
+ span(:author_error, :id=>/mainauthor_\d+_error/)
1127
+ span(:publisher_error, :id=>/publisher_\d+_error/)
1128
+ span(:place_error, :id=>/placeofpublication_\d+_error/)
1129
+ span(:year_error, :id=>/year_\d+_error/)
1130
+ span(:url_error, :id=>/url_\d+_error/)
1131
+
1132
+ # Custom Methods...
1133
+
1134
+ # Clicks the "Update" button and waits for any Ajax calls
1135
+ # to complete.
1136
+ def update
1137
+ self.form(:id=>"displayprofilesection_form_publications").button(:text=>"Update").click
1138
+ self.wait_for_ajax(2)
1139
+ end
1140
+
1141
+ # Takes a hash object and uses it to fill
1142
+ # in all the publication fields. The key values
1143
+ # that the has must contain are as follows:
1144
+ # :main_title, :main_author, :co_authors, :publisher,
1145
+ # :place, :volume_title, :volume_info, :year, :number,
1146
+ # :series, :url.
1147
+ # Any missing or misspelled key values will be ignored.
1148
+ def fill_out_form(hash)
1149
+ self.main_title=hash[:main_title]
1150
+ self.main_author=hash[:main_author]
1151
+ self.co_authors=hash[:co_authors]
1152
+ self.publisher=hash[:publisher]
1153
+ self.place_of_publication=hash[:place]
1154
+ self.volume_title=hash[:volume_title]
1155
+ self.volume_information=hash[:volume_info]
1156
+ self.year=hash[:year]
1157
+ self.number=hash[:number]
1158
+ self.series_title=hash[:series]
1159
+ self.url=hash[:url]
1160
+ end
1161
+
1162
+ # Clicks the "Remove this publication" link for the publication specified (by
1163
+ # the Main title of the record in question).
1164
+ def remove_this_publication(main_title)
1165
+ target_div_id = self.text_field(:value=>main_title).parent.parent.parent.id
1166
+ self.div(:id=>target_div_id).button(:id=>/displayprofilesection_remove_link_/).click
1167
+ self.wait_for_ajax
1168
+ end
1169
+
1170
+ # Returns an array containing all of the titles of the publications that exist
1171
+ # on the page.
1172
+ def publication_titles
1173
+ array = []
1174
+ self.div(:id=>"displayprofilesection_sections_publications").text_fields(:id=>/maintitle_/).each { |field| array << field.value }
1175
+ return array
1176
+ end
1177
+ alias titles publication_titles
1178
+
1179
+ # Returns an array of hashes. Each hash in the array refers to one of
1180
+ # the listed publications.
1181
+ #
1182
+ # Each hash's key=>value pairs are determined by the field title and field values for the publications.
1183
+ #
1184
+ # Example: "Main title:"=>"War and Peace","Main author:"=>"Tolstoy", etc....
1185
+ def publications_data
1186
+ list = []
1187
+ self.div(:id=>"displayprofilesection_sections_publications").divs(:class=>"displayprofilesection_multiple_section").each do |div|
1188
+ hash = {}
1189
+ div.divs(:class=>"displayprofilesection_field").each { |subdiv| hash.store(subdiv.label(:class=>"s3d-input-label").text, subdiv.text_field.value) }
1190
+ list << hash
1191
+ end
1192
+ return list
1193
+ end
1194
+ alias publication_data publications_data
1195
+ alias publications_list publications_data
1196
+
1197
+ end
1198
+
1199
+ # Methods related to the User's My Library page.
1200
+ class MyLibrary
1201
+
1202
+ include PageObject
1203
+ include GlobalMethods
1204
+ include HeaderFooterBar
1205
+ include ListWidget
1206
+ include ListContent
1207
+ include LeftMenuBarYou
1208
+ include LibraryWidget
1209
+
1210
+ # Page Objects
1211
+ button(:empty_library_add_content_button, :id=>"mylibrary_addcontent")
1212
+
1213
+ # Custom Methods and Page Objects...
1214
+
1215
+ # Defines the div that displays when the library has no contents.
1216
+ # Useful for testing whether the library is empty or not.
1217
+ def empty_library
1218
+ active_div.div(:id=>"mylibrary_empty")
1219
+ end
1220
+
1221
+ # Returns the text of the Page Title.
1222
+ def page_title
1223
+ active_div.div(:class=>"s3d-contentpage-title").text
1224
+ end
1225
+
1226
+ # Private methods...
1227
+ private
1228
+
1229
+ def active_div
1230
+ id = self.div(:id=>/mylibrarycontainer/).parent.id
1231
+ return self.div(:id=>id)
1232
+ end
1233
+
1234
+ end
1235
+
1236
+ # Methods related to the User's My Memberships page.
1237
+ class MyMemberships
1238
+
1239
+ include PageObject
1240
+ include GlobalMethods
1241
+ include HeaderFooterBar
1242
+ include ListWidget
1243
+ include ListGroups
1244
+ include LeftMenuBarYou
1245
+
1246
+ # Page Objects
1247
+ text_field(:search_memberships_field, :id=>"mymemberships_livefilter")
1248
+ select_list(:sort_by_list, :id=>"mymemberships_sortby")
1249
+ div(:gridview_button, :class=>/search-results-gridview/)
1250
+ div(:listview_button, :class=>/search-results-listview/)
1251
+ checkbox(:select_all, :id=>"mymemberships_select_checkbox")
1252
+ button(:add_selected_button, :id=>"mymemberships_addpeople_button") # Don't use this method. Use the custom one defined below
1253
+ button(:message_selected_button, :id=>"mymemberships_message_button") # Don't use this method. Use the custom one defined below
1254
+ link(:create_a_new_group_button, :text=>"Create a new group") # Don't use this method. Use the custom one defined below
1255
+
1256
+ # Custom methods...
1257
+
1258
+ # Returns the text of the Page Title.
1259
+ def page_title
1260
+ active_div.div(:class=>"s3d-contentpage-title").text
1261
+ end
1262
+
1263
+ # Returns the div object for the blue quote bubble that
1264
+ # appears when the page is empty of memberships.
1265
+ def quote_bubble
1266
+ active_div.div(:class=>"s3d-no-results-container")
1267
+ end
1268
+
1269
+ # Clicks the "Create one" link in the quote_bubble
1270
+ # div and then returns the CreateGroups class object.
1271
+ def create_one
1272
+ quote_bubble.link(:text=>"Create one").click
1273
+ self.wait_until { self.button(:class=>/create_simple_group/).present? }
1274
+ CreateGroups.new @browser
1275
+ end
1276
+
1277
+ # Sorts the list of memberships according to the specified value
1278
+ def sort_by=(type)
1279
+ self.sort_by_list=type
1280
+ self.wait_for_ajax
1281
+ end
1282
+
1283
+ # Private methods...
1284
+ private
1285
+
1286
+ def active_div
1287
+ id = self.div(:id=>/mymembershipscontainer/).parent.id
1288
+ return self.div(:id=>id)
1289
+ end
1290
+
1291
+ end
1292
+
1293
+ # Page Objects and Custom Methods for the My Contacts page.
1294
+ class MyContacts
1295
+
1296
+ include PageObject
1297
+ include GlobalMethods
1298
+ include HeaderFooterBar
1299
+ include ListWidget
1300
+ include ListPeople
1301
+ include LeftMenuBarYou
1302
+
1303
+ # Page Objects
1304
+ navigating_link(:find_and_add_people, "Find and add people", "ExplorePeople")
1305
+
1306
+ # Page Objects defined with Watir-webdriver...
1307
+
1308
+ # The text of the Page Title. It should usually return "My contacts".
1309
+ def page_title
1310
+ active_div.div(:class=>"s3d-contentpage-title").text
1311
+ end
1312
+
1313
+ # This returns the the "contacts_invited" page div
1314
+ # (as a Watir page object). This can be used to validate
1315
+ # that there are pending invites on the page. Primarily, however, it's used
1316
+ # by other methods in this class--to differentiate the pending list
1317
+ # from the contacts list.
1318
+ def pending_contacts
1319
+ active_div.div(:id=>"contacts_invited")
1320
+ end
1321
+
1322
+ # Custom Methods...
1323
+
1324
+ # Returns the list of names of people requesting
1325
+ # contact
1326
+ def pending_invites
1327
+ list = []
1328
+ pending_contacts.links(:class=>"s3d-bold s3d-regular-light-links", :title=>/View/).each { |link| list << link.text }
1329
+ return list
1330
+ end
1331
+
1332
+ # Clicks the "accept connection" plus sign for the specified
1333
+ # person in the Pending contacts list
1334
+ def accept_connection(name)
1335
+ self.li(:text=>/#{Regexp.escape(name)}/).button(:title=>"Accept connection").click
1336
+ sleep 0.8
1337
+ self.wait_for_ajax(2)
1338
+ end
1339
+
1340
+ # Clicks the "Find more people" link, then returns
1341
+ # the ExplorePeople class object.
1342
+ def find_more_people
1343
+ active_div.link(:text=>"Find more people").click
1344
+ self.wait_for_ajax
1345
+ ExplorePeople.new @browser
1346
+ end
1347
+
1348
+ # Private methods...
1349
+ private
1350
+
1351
+ # The top div for the contents of the page.
1352
+ # This method is a helper method for other objects
1353
+ # defined on the page.
1354
+ def active_div
1355
+ self.div(:id=>/^contactscontainer\d+/)
1356
+ end
1357
+
1358
+ end
1359
+
1360
+ # Methods related to the page for viewing a User's profile
1361
+ class ViewPerson
1362
+
1363
+ include PageObject
1364
+ include GlobalMethods
1365
+ include HeaderFooterBar
1366
+ include LeftMenuBarYou
1367
+
1368
+ # Page Objects
1369
+ navigating_link(:basic_information, "Basic Information", "ViewPerson")
1370
+ navigating_link(:categories, "Categories", "ViewPerson")
1371
+ navigating_link(:about_me, "About Me", "ViewPerson")
1372
+ navigating_link(:online, "Online", "ViewPerson")
1373
+ navigating_link(:contact_information, "Contact Information", "ViewPerson")
1374
+ navigating_link(:publications, "Publications", "ViewPerson")
1375
+ div(:contact_name, :id=>"entity_name")
1376
+ button(:message_button, :id=>"entity_user_message")
1377
+ button(:add_to_contacts_button, :id=>"entity_user_add_to_contacts")
1378
+ button(:invitation_sent_button, :text=>"Contact invitation sent")
1379
+ button(:accept_invitation_button, :id=>"entity_user_accept_invitation")
1380
+
1381
+ # Custom Methods...
1382
+
1383
+ # Clicks the "Accept invitation" button and waits for any Ajax calls
1384
+ # to complete
1385
+ def accept_invitation
1386
+ self.accept_invitation_button
1387
+ self.wait_for_ajax(2)
1388
+ end
1389
+
1390
+ # Clicks the message button and waits for the Pop-up dialog to appear.
1391
+ def message
1392
+ self.message_button
1393
+ self.wait_until { self.text.include? "Send this message to:" }
1394
+ self.class.class_eval { include SendMessagePopUp }
1395
+ end
1396
+
1397
+ # Clicks the "Add to contacts" button and waits for the Pop-up dialog
1398
+ # to appear.
1399
+ def add_to_contacts
1400
+ self.add_to_contacts_button
1401
+ self.wait_until { @browser.text.include? "Add a personal note to the invitation:" }
1402
+ self.class.class_eval { include AddToContactsPopUp }
1403
+ end
1404
+
1405
+ # Clicks the link to open the user's library profile page.
1406
+ def users_library
1407
+ self.link(:class=>/s3d-bold lhnavigation_toplevel lhnavigation_page_title_value/, :text=>/Library/).click
1408
+ sleep 2
1409
+ self.wait_for_ajax(2)
1410
+ self.class.class_eval { include ListWidget
1411
+ include LibraryWidget }
1412
+ end
1413
+
1414
+ # I believe this is not supported by rSmart's OAE preview
1415
+ #def users_memberships
1416
+ # @browser.link(:class=>/s3d-bold lhnavigation_toplevel lhnavigation_page_title_value/, :text=>/Memberships/).click
1417
+ # self.class.class_eval { include ListWidget }
1418
+ #end
1419
+
1420
+ # Opens the user's Contacts page to display their contacts
1421
+ def users_contacts
1422
+ self.link(:class=>/s3d-bold lhnavigation_toplevel lhnavigation_page_title_value/, :text=>/Contacts/).click
1423
+ self.class.class_eval { include ListWidget }
1424
+ end
1425
+
1426
+ # This method assumes the current page is the Basic Info page.
1427
+ # It returns a hash object where the key => value pair is:
1428
+ # "Field Title" => "Field Value" --e.g.: "Given name:"=>"Billy"
1429
+ def basic_info_data
1430
+ hash = {}
1431
+ target_div = self.div(:class=>"s3d-contentpage-title", :text=>"Basic Information").parent.parent.div(:id=>"displayprofilesection_body")
1432
+ target_div.divs(:class=>"displayprofilesection_field").each { |div| hash.store(div.span(:class=>"s3d-input-label").text, div.span(:class=>"field_value").text) }
1433
+ return hash
1434
+ end
1435
+
1436
+ # Returns an array containing the text of all of the tags and categories
1437
+ # listed on the Basic Information page. Note that it splits them up into
1438
+ # parent and child categories.
1439
+ def tags_and_categories_list
1440
+ list = []
1441
+ target_div = self.div(:class=>"s3d-contentpage-title", :text=>"Basic Information").parent.parent.div(:id=>"displayprofilesection_body")
1442
+ target_div.links.each { |link| list << link.text.split(" » ") }
1443
+ return list.flatten.uniq
1444
+ end
1445
+
1446
+ # This method assumes it will be run on the About Me page.
1447
+ # It returns a hash object where the key => value pair is:
1448
+ # "Field Title" => "Field Value" --e.g.: "About Me:"=>"Text of field"
1449
+ def about_me_data
1450
+ hash = {}
1451
+ target_div = self.div(:class=>"s3d-contentpage-title", :text=>"About Me").parent.parent.div(:id=>"displayprofilesection_body")
1452
+ target_div.divs(:class=>"displayprofilesection_field").each { |div| hash.store(div.span(:class=>"s3d-input-label").text, div.span(:class=>"field_value").text) }
1453
+ return hash
1454
+ end
1455
+
1456
+ # Returns a hash object where the key=>value pair is determined by the
1457
+ # field title and field values shown on the "Online" page.
1458
+ #
1459
+ # Because there can be an arbitrary number of Sites listed on the page,
1460
+ # The hash keys will have a number appended on the end. Example:
1461
+ # { "Site:1"=>"Twitter", "URL:1"=>"www.twitter.com","Site:2"=>"Facebook","URL:2"=>"www.facebook.com"}
1462
+ def online_data
1463
+ hash = {}
1464
+ target_div = self.div(:class=>"s3d-contentpage-title", :text=>"Online").parent.parent.div(:id=>"displayprofilesection_body")
1465
+ x=0
1466
+ target_div.divs(:class=>"displayprofilesection_field").each do |div|
1467
+ div.span(:class=>"s3d-input-label").text == "Site:" ? x+=1 : x
1468
+ hash.store("#{div.span(:class=>"s3d-input-label").text}#{x}", div.span(:class=>"field_value").text)
1469
+ end
1470
+ return hash
1471
+ end
1472
+
1473
+ # Returns a hash object where the key=>value pair is determined by the
1474
+ # field title and field values shown on the "Contact Information" page.
1475
+ #
1476
+ # Example: "Institution:"=>"University of Hard Knocks"
1477
+ def contact_info_data
1478
+ hash = {}
1479
+ target_div = self.div(:class=>"s3d-contentpage-title", :text=>"Contact Information").parent.parent.div(:id=>"displayprofilesection_body")
1480
+ target_div.divs(:class=>"displayprofilesection_field").each { |div| hash.store(div.span(:class=>"s3d-input-label").text, div.span(:class=>"field_value").text) }
1481
+ return hash
1482
+ end
1483
+
1484
+ # Takes a hash object containing the test contact info (see required format below),
1485
+ # evaluates that data against the data returned with the contact_info_data
1486
+ # method and returns true if the data match, and false, if they do not.
1487
+ #
1488
+ # The hash object passed to the method must contain the following keys, exactly:
1489
+ # :institution, :department, :title, :email, :im, :phone, :mobile, :fax,
1490
+ # :address, :city, :state, :zip, :country
1491
+ def expected_contact_info?(hash)
1492
+ info = self.contact_info_data
1493
+ key_map = {"Institution:"=>:institution, "Department:"=>:department, "Title/Role:"=>:title,
1494
+ "Email:"=>:email, "Instant Messaging:"=>:im, "Phone:"=>:phone, "Mobile:"=>:mobile, "Fax:"=>:fax,
1495
+ "Address:"=>:address, "City:"=>:city, "State:"=>:state, "Postal Code:"=>:zip, "Country:"=>:country}
1496
+ fixed = Hash[info.map { |k, v| [key_map[k], v ] } ]
1497
+ fixed==hash ? true : false
1498
+ end
1499
+
1500
+ # Returns an array of hashes. Each hash in the array refers to one of
1501
+ # the listed publications.
1502
+ #
1503
+ # Each hash's key=>value pairs are determined by the field title and field values for the publications.
1504
+ #
1505
+ # Example: "Main title:"=>"War and Peace","Main author:"=>"Tolstoy", etc....
1506
+ def publications_data
1507
+ list = []
1508
+ hash = {}
1509
+ self.div(:class=>"publications").divs(:class=>"displayprofilesection_field").each do |div|
1510
+ if div.span(:class=>"s3d-input-label").text=="Main title:" && hash != {}
1511
+ list << hash
1512
+ hash={}
1513
+ end
1514
+ hash.store(div.span(:class=>"s3d-input-label").text, div.span(:class=>"field_value").text)
1515
+ end
1516
+ list << hash
1517
+ return list
1518
+ end
1519
+ alias publication_data publications_data
1520
+ alias publications_list publications_data
1521
+
1522
+ # Expects to be passed an array containing one or more hashes (see below for
1523
+ # how the hash should be formed). Note that it's okay to send a single hash instead
1524
+ # of an array containing one hash element. The method will do the
1525
+ # necessary cleaning of the data.
1526
+ #
1527
+ # The method returns true if the contents of the hash(es) match the data evaluated against,
1528
+ # otherwise returns false.
1529
+ # The hash(es) should contain all of the following keys...
1530
+ # :main_title, main_author, :co_authors, :publisher, :place, :volume_title,
1531
+ # :volume_info, :year, :number, :series, :url
1532
+ def expected_publications_data?(array_of_hash)
1533
+ expected_data=[]
1534
+ expected_data << array_of_hash
1535
+ expected_data.flatten!
1536
+ data_array = self.publications_data
1537
+ new_array = []
1538
+ key_map = { "Main title:"=>:main_title, "Main author:"=>:main_author,
1539
+ "Co-author(s):"=>:co_authors, "Publisher:"=>:publisher, "Place of publication:"=>:place,
1540
+ "Volume title:"=>:volume_title, "Volume information:"=>:volume_info,
1541
+ "Year:"=>:year, "Number:"=>:number, "Series title:"=>:series, "URL:"=>:url }
1542
+ data_array.each do |hash|
1543
+ fixed = Hash[hash.map { |k, v| [key_map[k], v ] } ]
1544
+ new_array << fixed
1545
+ end
1546
+ expected_data==new_array ? true : false
1547
+ end
1548
+
1549
+ end
1550
+
1551
+ # TODO - describe class
1552
+ class MyPreferences
1553
+
1554
+ include PageObject
1555
+ include GlobalMethods
1556
+
1557
+ end
1558
+
1559
+ # Library pages in Courses/Groups/Research
1560
+ class Library
1561
+
1562
+ include PageObject
1563
+ include GlobalMethods
1564
+ include HeaderFooterBar
1565
+ include HeaderBar
1566
+ include LeftMenuBar
1567
+ include LibraryWidget
1568
+ include ListWidget
1569
+ include ListContent
1570
+
1571
+ # The page element that appears when there are no contents
1572
+ # in the Library
1573
+ def empty_library_element
1574
+ self.div(:id=>data_sakai_ref).div(:id=>"mylibrary_empty")
1575
+ end
1576
+
1577
+ end
1578
+
1579
+ #
1580
+ class Participants
1581
+
1582
+ include PageObject
1583
+ include GlobalMethods
1584
+ include HeaderFooterBar
1585
+ include LeftMenuBar
1586
+ include HeaderBar
1587
+
1588
+ text_field(:search_participants, :id=>"participants_search_field")
1589
+
1590
+ end
1591
+
1592
+ # Methods related to the Discussions "Area" in a Group/Course.
1593
+ class Discussions
1594
+
1595
+ include PageObject
1596
+ include GlobalMethods
1597
+ include HeaderFooterBar
1598
+ include LeftMenuBar
1599
+ include HeaderBar
1600
+ include DocButtons
1601
+
1602
+ button(:add_new_topic, :id=>"discussion_add_new_topic")
1603
+ text_field(:topic_title, :id=>"discussion_create_new_topic_title")
1604
+ text_area(:message_text, :name=>/message.text/i)
1605
+ text_area(:reply_text, :id=>"discussion_topic_reply_text")
1606
+ button(:dont_add_topic, :id=>"discussion_dont_add_topic")
1607
+
1608
+ # Clicks the "Add topic" button.
1609
+ def add_topic
1610
+ self.button(:id=>"discussion_add_topic").click
1611
+ self.wait_for_ajax(2) #
1612
+ #@browser.wait_until { @browser.h1(:class=>"discussion_topic_subject").parent.button(:text=>"Reply").present? }
1613
+ end
1614
+
1615
+ button(:collapse_all, :text=>"Collapse all")
1616
+ button(:expand_all, :text=>"Expand all")
1617
+ button(:dont_add_reply, :id=>"discussion_dont_add_reply")
1618
+ button(:add_reply, :id=>"discussion_add_reply")
1619
+
1620
+ # Clicks the "Reply" button for the specified message.
1621
+ def reply_to(message_title)
1622
+ self.h1(:class=>"discussion_topic_subject", :text=>message_title).parent.button(:text=>"Reply").click
1623
+ self.wait_until { self.h1(:class=>"discussion_topic_subject", :text=>message_title).parent.text_field(:id=>"discussion_topic_reply_text").present? }
1624
+ end
1625
+
1626
+ # Clicks the "Quote" button for the specified message.
1627
+ def quote(message_text)
1628
+ self.span(:class=>"discussion_post_message", :text=>message_text).parent.parent.button(:text=>"Quote").fire_event "onclick"
1629
+ self.wait_for_ajax(2) #
1630
+ #self.wait_until { self.textarea(:name=>"quoted_text", :text=>message_text).present? }
1631
+ end
1632
+
1633
+ # Clicks the "Edit" button for the specified message.
1634
+ def edit(message_text)
1635
+ self.span(:class=>"discussion_post_message", :text=>message_text).parent.parent.button(:text=>"Edit").click
1636
+ self.wait_until { self.textarea(:name=>"discussion_topic_reply_text", :text=>message_text).present? }
1637
+ end
1638
+
1639
+ # Clicks the "Delete" button for a specified message.
1640
+ def delete(message_text)
1641
+ self.span(:class=>"discussion_post_message", :text=>message_text).parent.parent.button(:text=>"Delete").click
1642
+ end
1643
+
1644
+ button(:restore, :text=>"Restore")
1645
+
1646
+ # Clicks the button that expands the thread to view the replies.
1647
+ def view_replies(topic_title)
1648
+ self.h1(:class=>"discussion_topic_subject", :text=>topic_title).parent.button(:class=>"discussion_show_topic_replies s3d-button s3d-link-button").click
1649
+
1650
+ end
1651
+
1652
+ # Clicks the button that collapses an expanded message thread.
1653
+ def hide_replies(topic_title)
1654
+ self.h1(:class=>"discussion_topic_subject", :text=>topic_title).parent.button(:class=>"discussion_show_topic_replies s3d-button s3d-link-button").click
1655
+
1656
+ end
1657
+
1658
+ end
1659
+
1660
+ # Methods related to the Comments "Area" in a Course/Group.
1661
+ class Comments
1662
+
1663
+ include PageObject
1664
+ include GlobalMethods
1665
+ include HeaderFooterBar
1666
+ include LeftMenuBar
1667
+ include HeaderBar
1668
+ include DocButtons
1669
+
1670
+ button(:add_comment, :text=>"Add comment")
1671
+ button(:cancel, :id=>/comments_editComment_cancel/)
1672
+ text_area(:comment, :id=>"comments_txtMessage")
1673
+ text_area(:new_comment, :id=>/comments_editComment_txt_/)
1674
+ button(:undelete, :text=>"Undelete")
1675
+
1676
+ # Clicks the "Submit comment" button.
1677
+ def submit_comment
1678
+ self.button(:text=>"Submit comment").click
1679
+ self.wait_for_ajax(2) #wait_until { self.text.include? "about 0 seconds ago" }
1680
+ end
1681
+
1682
+ # Clicks the "Edit comment" button.
1683
+ def edit_comment
1684
+ self.button(:text=>"Edit comment").click
1685
+ self.wait_for_ajax(2) #wait_until { self.textarea(:title=>"Edit your comment").present? == false }
1686
+ end
1687
+
1688
+ # Clicks the "Edit button" for the specified comment.
1689
+ def edit(comment)
1690
+ comment.gsub!("\n", " ")
1691
+ self.p(:text=>comment).parent.parent.button(:text=>"Edit").click
1692
+ self.wait_for_ajax(2) #wait_until { self.textarea(:title=>"Edit your comment").present? }
1693
+ end
1694
+
1695
+ # Deletes the specified comment.
1696
+ def delete(comment)
1697
+ comment.gsub!("\n", " ")
1698
+ self.div(:text=>comment).parent.button(:text=>"Delete").click
1699
+ self.wait_for_ajax(2) #wait_until { self.button(:text=>"Undelete").present? }
1700
+ end
1701
+
1702
+ end
1703
+
1704
+ # TODO - describe class
1705
+ class RSS
1706
+
1707
+ include PageObject
1708
+ include GlobalMethods
1709
+ include HeaderFooterBar
1710
+ include LeftMenuBar
1711
+ include HeaderBar
1712
+ include DocButtons
1713
+
1714
+ button(:sort_by_source, :text=>"Sort by source")
1715
+ button(:sort_by_date, :text=>"Sort by date")
1716
+
1717
+
1718
+ end
1719
+
1720
+ # TODO - describe class
1721
+ class Tests
1722
+
1723
+ include PageObject
1724
+ include GlobalMethods
1725
+ include HeaderFooterBar
1726
+ include LeftMenuBar
1727
+ include HeaderBar
1728
+ include DocButtons
1729
+
1730
+ # The frame object that contains all of the CLE Tests and Quizzes objects
1731
+ def tests_frame
1732
+ self.frame(:src=>/sakai2samigo.launch.html/)
1733
+ end
1734
+
1735
+ end
1736
+
1737
+ # TODO - describe class
1738
+ class Files
1739
+
1740
+ include PageObject
1741
+ include GlobalMethods
1742
+ include HeaderFooterBar
1743
+ include LeftMenuBar
1744
+ include HeaderBar
1745
+ include DocButtons
1746
+
1747
+ # Edits the page, then opens the File Settings pop up.
1748
+ def files_settings
1749
+ widget_settings
1750
+ self.text_field(:class=>"as-input").when_present { self.class.class_eval { include FilesAndDocsPopUp } }
1751
+ end
1752
+
1753
+ # TODO - Describe method
1754
+ def remove_files_widget
1755
+ remove_widget
1756
+ end
1757
+
1758
+ # TODO - Describe method
1759
+ def files_wrapping
1760
+ widget_wrapping
1761
+ end
1762
+
1763
+ end
1764
+
1765
+ # Methods related to the Forum page in Courses/Groups
1766
+ class Forum
1767
+
1768
+ include GlobalMethods
1769
+ include LeftMenuBar
1770
+ include HeaderBar
1771
+ include HeaderFooterBar
1772
+ include DocButtons
1773
+
1774
+ # The frame that contains the CLE Forums objects
1775
+ def forum_frame
1776
+ self.frame(:src=>/sakai2forums.launch.html/)
1777
+ end
1778
+
1779
+ end
1780
+
1781
+ # TODO - describe class
1782
+ class Gadget
1783
+
1784
+ include PageObject
1785
+ include GlobalMethods
1786
+ include HeaderFooterBar
1787
+ include LeftMenuBar
1788
+ include HeaderBar
1789
+ include DocButtons
1790
+
1791
+ # TODO - Describe method
1792
+ def gadget_frame
1793
+ self.frame(:id=>"ggadget_remotecontent_settings_preview_frame")
1794
+ end
1795
+
1796
+
1797
+
1798
+ end
1799
+
1800
+ # TODO - describe class
1801
+ class Gradebook
1802
+
1803
+ include PageObject
1804
+ include GlobalMethods
1805
+ include HeaderFooterBar
1806
+ include LeftMenuBar
1807
+ include HeaderBar
1808
+ include DocButtons
1809
+
1810
+ # TODO - Describe method
1811
+ def gradebook_frame
1812
+ self.frame(:src=>/sakai2gradebook.launch.html/)
1813
+ end
1814
+
1815
+ end
1816
+
1817
+ # TODO - describe class
1818
+ class LTI
1819
+
1820
+ include PageObject
1821
+ include GlobalMethods
1822
+ include HeaderFooterBar
1823
+ include LeftMenuBar
1824
+ include HeaderBar
1825
+ include DocButtons
1826
+
1827
+ text_field(:url, :id=>"basiclti_settings_ltiurl")
1828
+ text_field(:key, :id=>"basiclti_settings_ltikey")
1829
+ text_field(:secret, :id=>"basiclti_settings_ltisecret")
1830
+ button(:advanced_settings, :id=>"basiclti_settings_advanced_toggle_settings")
1831
+ button(:save, :id=>"basiclti_settings_insert")
1832
+ button(:cancel, :id=>"basiclti_settings_cancel")
1833
+
1834
+
1835
+ end
1836
+
1837
+ # Methods related to the Maps "Area" in a Course/Group.
1838
+ class GoogleMaps
1839
+
1840
+ include PageObject
1841
+ include GlobalMethods
1842
+ include HeaderFooterBar
1843
+ include LeftMenuBar
1844
+ include HeaderBar
1845
+ include DocButtons
1846
+
1847
+ # Defines the Google Maps image as an object.
1848
+ # Use this for verifying the presence of any text it's supposed to
1849
+ # contain (like the specified address it's supposed to be showing).
1850
+ def map_frame
1851
+ self.frame(:id, "googlemaps_iframe_map")
1852
+ end
1853
+
1854
+ # Edits the page, then opens the Google Maps widget's Settings Dialog.
1855
+ def map_settings
1856
+ widget_settings
1857
+ self.text_field(:id=>"googlemaps_input_text_location").when_present { self.class.class_eval { include GoogleMapsPopUp } }
1858
+ end
1859
+
1860
+ # Edits the page, then removes the widget from it.
1861
+ def remove_map
1862
+ remove_widget
1863
+ end
1864
+
1865
+ # Edits the page, then opens the "Appearance" pop-up dialog.
1866
+ def map_wrapping
1867
+ widget_wrapping
1868
+ end
1869
+
1870
+ end
1871
+
1872
+ # TODO - describe class
1873
+ class Remote
1874
+
1875
+ include PageObject
1876
+ include GlobalMethods
1877
+ include HeaderFooterBar
1878
+ include LeftMenuBar
1879
+ include HeaderBar
1880
+ include DocButtons
1881
+
1882
+ # TODO - Describe method
1883
+ def remote_frame
1884
+ self.frame(:id=>"remotecontent_settings_preview_frame")
1885
+ end
1886
+
1887
+
1888
+
1889
+ end
1890
+
1891
+ # TODO - describe class
1892
+ class ResearchIntro
1893
+
1894
+ include PageObject
1895
+ include GlobalMethods
1896
+ include HeaderFooterBar
1897
+ include LeftMenuBar
1898
+ include HeaderBar
1899
+ include DocButtons
1900
+
1901
+ end
1902
+
1903
+
1904
+ # TODO - describe class
1905
+ class Acknowledgements
1906
+
1907
+ include PageObject
1908
+ include GlobalMethods
1909
+ include HeaderFooterBar
1910
+
1911
+ # Page Objects
1912
+ div(:page_title, :class=>"s3d-bold entity_plaintitle")
1913
+ link(:featured, :text=>"Featured")
1914
+ link(:ui_technologies, :text=>"UI Technologies")
1915
+ link(:back_end_technologies, :text=>"Back-end Technologies")
1916
+
1917
+ # Custom Methods
1918
+
1919
+ end
1920
+
1921
+ # TODO - describe class
1922
+ class FourOhFourPage
1923
+
1924
+ include PageObject
1925
+ include GlobalMethods
1926
+ include HeaderFooterBar
1927
+ include CommonErrorElements
1928
+
1929
+ end
1930
+
1931
+ # TODO - describe class
1932
+ class FourOhThreePage
1933
+
1934
+ include PageObject
1935
+ include GlobalMethods
1936
+ include HeaderFooterBar
1937
+ include CommonErrorElements
1938
+
1939
+ end
1940
+
1941
+ # TODO - describe class
1942
+ class FourOhFourPage
1943
+
1944
+ include PageObject
1945
+ include GlobalMethods
1946
+ include HeaderFooterBar
1947
+ include CommonErrorElements
1948
+
1949
+ end