rautomation 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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +71 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/ext/AutoItX/AutoItX.chm +0 -0
- data/ext/AutoItX/AutoItX3.dll +0 -0
- data/lib/rautomation.rb +5 -0
- data/lib/rautomation/button.rb +39 -0
- data/lib/rautomation/implementations/autoit.rb +5 -0
- data/lib/rautomation/implementations/autoit/button.rb +40 -0
- data/lib/rautomation/implementations/autoit/locators.rb +18 -0
- data/lib/rautomation/implementations/autoit/text_field.rb +41 -0
- data/lib/rautomation/implementations/autoit/window.rb +126 -0
- data/lib/rautomation/implementations/helper.rb +19 -0
- data/lib/rautomation/text_field.rb +47 -0
- data/lib/rautomation/wait_helper.rb +23 -0
- data/lib/rautomation/window.rb +176 -0
- data/rautomation.gemspec +79 -0
- data/spec/button_spec.rb +35 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/test.html +13 -0
- data/spec/text_field_spec.rb +47 -0
- data/spec/window_spec.rb +109 -0
- metadata +119 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jarmo Pertman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
= RAutomation
|
2
|
+
|
3
|
+
* Web: http://www.github.com/jarmo/RAutomation
|
4
|
+
* Author: Jarmo Pertman (mailto:jarmo.p[at]gmail.com)
|
5
|
+
|
6
|
+
== DESCRIPTION
|
7
|
+
|
8
|
+
RAutomation tries to be a small and easy to use library for helping out to automate windows and their controls
|
9
|
+
for automated testing.
|
10
|
+
|
11
|
+
RAutomation aims to provide:
|
12
|
+
* Easy to use and user-friendly API (inspired by Watir http://www.watir.com).
|
13
|
+
* Cross-platform compatibility
|
14
|
+
* Easy extensibility - have some application, which uses some specialized technology, but isn't supported by RAutomation?
|
15
|
+
You can get dirty and create new implementation for RAutomation, due to the applied <em>Strategy Pattern</em>!
|
16
|
+
|
17
|
+
== USAGE
|
18
|
+
|
19
|
+
require "rautomation"
|
20
|
+
|
21
|
+
window = RAutomation::Window.new(:title => /part of the title/i)
|
22
|
+
window.exists? # => true
|
23
|
+
|
24
|
+
window.title # => "blah blah part Of the title blah"
|
25
|
+
window.text # => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies..."
|
26
|
+
|
27
|
+
window.text_field(:class_name => "Edit1").set "hello, world!"
|
28
|
+
button = window.button(:text => "&Save")
|
29
|
+
button.exists? # => true
|
30
|
+
button.click
|
31
|
+
|
32
|
+
See more examples in spec directory!
|
33
|
+
|
34
|
+
== INSTALL
|
35
|
+
|
36
|
+
=== Windows
|
37
|
+
|
38
|
+
1. gem install rautomation
|
39
|
+
2. create some script and run it
|
40
|
+
|
41
|
+
You might need administrative privileges if running for the first time and you haven't installed AutoIt before!
|
42
|
+
|
43
|
+
=== Linux
|
44
|
+
|
45
|
+
Feel yourself at home on Linux and know how to automate windows and their controls? I would be happy if you'd contact me
|
46
|
+
about that matter - or even better, send me a pull request!
|
47
|
+
|
48
|
+
=== OS X
|
49
|
+
|
50
|
+
Feel yourself at home on OS X and know how to automate windows and their controls? I would be happy if you'd contact me
|
51
|
+
about that matter - or even better, send me a pull request!
|
52
|
+
|
53
|
+
=== Others
|
54
|
+
|
55
|
+
Feel yourself at home on some operating system not listed in here and know how to automate windows and their controls?
|
56
|
+
Does Ruby also work on that operating system? I would be happy if you'd contact me
|
57
|
+
about that matter - or even better, send me a pull request!
|
58
|
+
|
59
|
+
== Note on Patches/Pull Requests
|
60
|
+
|
61
|
+
* Fork the project.
|
62
|
+
* Make your feature addition or bug fix.
|
63
|
+
* Add tests for it. This is important so I don't break it in a
|
64
|
+
future version unintentionally.
|
65
|
+
* Commit, do not mess with rakefile, version, or history.
|
66
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
67
|
+
* Send me a pull request. Bonus points for topic branches.
|
68
|
+
|
69
|
+
== Copyright
|
70
|
+
|
71
|
+
Copyright (c) 2010 Jarmo Pertman. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "rautomation"
|
8
|
+
gem.summary = %Q{Automate windows and their controls through user-friendly API with Ruby}
|
9
|
+
gem.description = %Q{RAutomation tries to be a small and easy to use library for helping out to automate windows and their controls
|
10
|
+
for automated testing.
|
11
|
+
|
12
|
+
RAutomation aims to provide:
|
13
|
+
* Easy to use and user-friendly API (inspired by Watir http://www.watir.com).
|
14
|
+
* Cross-platform compatibility
|
15
|
+
* Easy extensibility - have some application, which uses some specialized technology, but isn't supported by RAutomation?
|
16
|
+
You can get dirty and create new implementation for RAutomation, due to the applied Strategy Pattern!}
|
17
|
+
gem.email = "jarmo.p@gmail.com"
|
18
|
+
gem.homepage = "http://github.com/jarmo/RAutomation"
|
19
|
+
gem.authors = ["Jarmo Pertman"]
|
20
|
+
gem.add_development_dependency "rspec", ">= 1.3.0"
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'spec/rake/spectask'
|
28
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
34
|
+
spec.libs << 'lib' << 'spec'
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :spec => :check_dependencies
|
40
|
+
|
41
|
+
task :default => :spec
|
42
|
+
|
43
|
+
require 'rake/rdoctask'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "RAutomation #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
Binary file
|
Binary file
|
data/lib/rautomation.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module RAutomation
|
2
|
+
class Button
|
3
|
+
# This constructor is meant to be accessed only through RAutomation::Window#button method.
|
4
|
+
def initialize(window, locators) #:nodoc:
|
5
|
+
@window = window
|
6
|
+
@locators = locators
|
7
|
+
@button = @window.button(@locators)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Performs a click on the Button.
|
11
|
+
#
|
12
|
+
# Raises an UnknownButtonException if the Button itself doesn't exist.
|
13
|
+
def click
|
14
|
+
assert_exists
|
15
|
+
@button.click
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieves the value of the Button, usually the visible text.
|
19
|
+
#
|
20
|
+
# Raises an UnknownButtonException if the Button itself doesn't exist.
|
21
|
+
def value
|
22
|
+
assert_exists
|
23
|
+
@button.value
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns true if Button exists, false otherwise.
|
27
|
+
def exists?
|
28
|
+
@button.exists?
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :exist?, :exists?
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def assert_exists
|
36
|
+
raise UnknownButtonException.new("Button '#{@locators.inspect}' doesn't exist on window '#{@window.locators.inspect}'!") unless exists?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Implementations
|
3
|
+
module AutoIt
|
4
|
+
class Button
|
5
|
+
include WaitHelper
|
6
|
+
include Locators
|
7
|
+
|
8
|
+
# Special-cased locators
|
9
|
+
LOCATORS = {:class_name => :classnn}
|
10
|
+
|
11
|
+
# Possible locators are :text, :id, :class, :class_name and :instance.
|
12
|
+
def initialize(window, locators)
|
13
|
+
@window = window
|
14
|
+
extract(locators)
|
15
|
+
end
|
16
|
+
|
17
|
+
def click #:nodoc:
|
18
|
+
clicked = false
|
19
|
+
wait_until do
|
20
|
+
@window.activate
|
21
|
+
@window.active? &&
|
22
|
+
Window.autoit.ControlFocus(@window.locator_hwnd, "", @locators) == 1 &&
|
23
|
+
Window.autoit.ControlClick(@window.locator_hwnd, "", @locators) == 1 &&
|
24
|
+
clicked = true # is clicked at least once
|
25
|
+
|
26
|
+
clicked && !exists?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def value #:nodoc:
|
31
|
+
Window.autoit.ControlGetText(@window.locator_hwnd, "", @locators)
|
32
|
+
end
|
33
|
+
|
34
|
+
def exists? #:nodoc:
|
35
|
+
not Window.autoit.ControlGetHandle(@window.locator_hwnd, "", @locators).empty?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Implementations
|
3
|
+
module AutoIt
|
4
|
+
module Locators
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def extract(locators) #:nodoc:
|
9
|
+
@locators = "[#{locators.map do |locator, value|
|
10
|
+
locator_key = self.class::LOCATORS[locator] || self.class::LOCATORS[[locator, value.class]]
|
11
|
+
value = value.to_s(16) if locator == :hwnd
|
12
|
+
"#{(locator_key || locator)}:#{value}"
|
13
|
+
end.join(";")}]"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Implementations
|
3
|
+
module AutoIt
|
4
|
+
class TextField
|
5
|
+
include WaitHelper
|
6
|
+
include Locators
|
7
|
+
|
8
|
+
# Special-cased locators
|
9
|
+
LOCATORS = {:class_name => :classnn}
|
10
|
+
|
11
|
+
# Possible locators are :id, :class, :class_name and :instance.
|
12
|
+
def initialize(window, locators)
|
13
|
+
@window = window
|
14
|
+
extract(locators)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set(text) #:nodoc:
|
18
|
+
wait_until do
|
19
|
+
@window.activate
|
20
|
+
@window.active? &&
|
21
|
+
Window.autoit.ControlFocus(@window.locator_hwnd, "", @locators) == 1 &&
|
22
|
+
Window.autoit.ControlSetText(@window.locator_hwnd, "", @locators, text) == 1 &&
|
23
|
+
value == text
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear #:nodoc:
|
28
|
+
set ""
|
29
|
+
end
|
30
|
+
|
31
|
+
def value #:nodoc:
|
32
|
+
Window.autoit.ControlGetText(@window.locator_hwnd, "", @locators)
|
33
|
+
end
|
34
|
+
|
35
|
+
def exists? #:nodoc:
|
36
|
+
not Window.autoit.ControlGetHandle(@window.locator_hwnd, "", @locators).empty?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Implementations
|
3
|
+
module AutoIt
|
4
|
+
class Window
|
5
|
+
include WaitHelper
|
6
|
+
include Locators
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def autoit #:nodoc:
|
10
|
+
@@autoit
|
11
|
+
end
|
12
|
+
|
13
|
+
def load_autoit #:nodoc:
|
14
|
+
@@autoit = WIN32OLE.new('AutoItX3.Control')
|
15
|
+
rescue WIN32OLERuntimeError
|
16
|
+
dll = File.dirname(__FILE__) + "/../../../ext/AutoItX/AutoItX3.dll"
|
17
|
+
system("regsvr32.exe /s #{dll.gsub('/', '\\')}")
|
18
|
+
@@autoit = WIN32OLE.new('AutoItX3.Control')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
load_autoit
|
23
|
+
@@autoit.AutoItSetOption("WinWaitDelay", 350)
|
24
|
+
|
25
|
+
attr_reader :locators
|
26
|
+
|
27
|
+
# Special-cased locators
|
28
|
+
LOCATORS = {[:title, String] => :title,
|
29
|
+
[:title, Regexp] => :regexptitle,
|
30
|
+
:hwnd => :handle}
|
31
|
+
|
32
|
+
# Possible locators are :title, :text, :hwnd and :class.
|
33
|
+
def initialize(locators)
|
34
|
+
@hwnd = locators[:hwnd]
|
35
|
+
@locator_text = locators.delete(:text)
|
36
|
+
extract(locators)
|
37
|
+
end
|
38
|
+
|
39
|
+
def hwnd #:nodoc:
|
40
|
+
@hwnd ||= @@autoit.WinList(@locators, @locator_text).pop.compact.
|
41
|
+
find {|handle| self.class.new(:hwnd => handle.hex).visible?}.hex rescue nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def title #:nodoc:
|
45
|
+
@@autoit.WinGetTitle(locator_hwnd)
|
46
|
+
end
|
47
|
+
|
48
|
+
def activate #:nodoc:
|
49
|
+
@@autoit.WinWait(locator_hwnd, "", 1)
|
50
|
+
@@autoit.WinActivate(locator_hwnd)
|
51
|
+
sleep 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def active? #:nodoc:
|
55
|
+
@@autoit.WinActive(locator_hwnd) == 1
|
56
|
+
end
|
57
|
+
|
58
|
+
def text #:nodoc:
|
59
|
+
@@autoit.WinGetText(locator_hwnd)
|
60
|
+
end
|
61
|
+
|
62
|
+
def exists? #:nodoc:
|
63
|
+
@@autoit.WinExists(locator_hwnd) == 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def visible? #:nodoc:
|
67
|
+
@@autoit.WinGetState(locator_hwnd) & 2 == 2
|
68
|
+
end
|
69
|
+
|
70
|
+
def maximize #:nodoc:
|
71
|
+
@@autoit.WinSetState(locator_hwnd, "", @@autoit.SW_MAXIMIZE)
|
72
|
+
sleep 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def minimize #:nodoc:
|
76
|
+
@@autoit.WinSetState(locator_hwnd, "", @@autoit.SW_MINIMIZE)
|
77
|
+
sleep 1
|
78
|
+
end
|
79
|
+
|
80
|
+
def minimized?
|
81
|
+
@@autoit.WinGetState(locator_hwnd) & 16 == 16
|
82
|
+
end
|
83
|
+
|
84
|
+
def restore
|
85
|
+
@@autoit.WinSetState(locator_hwnd, "", @@autoit.SW_RESTORE)
|
86
|
+
sleep 1
|
87
|
+
end
|
88
|
+
|
89
|
+
# Activates the Window and sends keys to it.
|
90
|
+
#
|
91
|
+
# Refer to AutoIt documentation for keys syntax.
|
92
|
+
def send_keys(keys)
|
93
|
+
wait_until do
|
94
|
+
restore if minimized?
|
95
|
+
activate
|
96
|
+
active?
|
97
|
+
end
|
98
|
+
@@autoit.Send(keys)
|
99
|
+
end
|
100
|
+
|
101
|
+
def close #:nodoc:
|
102
|
+
@@autoit.WinClose(locator_hwnd)
|
103
|
+
@@autoit.WinKill(locator_hwnd)
|
104
|
+
end
|
105
|
+
|
106
|
+
def button(locator) #:nodoc:
|
107
|
+
Button.new(self, locator)
|
108
|
+
end
|
109
|
+
|
110
|
+
def text_field(locator) #:nodoc:
|
111
|
+
TextField.new(self, locator)
|
112
|
+
end
|
113
|
+
|
114
|
+
def method_missing(name, *args) #:nodoc:
|
115
|
+
@@autoit.respond_to?(name) ? @@autoit.send(name, *args) : super
|
116
|
+
end
|
117
|
+
|
118
|
+
# Used internally.
|
119
|
+
# @private
|
120
|
+
def locator_hwnd
|
121
|
+
"[HANDLE:#{hwnd.to_i.to_s(16)}]"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module Implementations
|
3
|
+
autoload :AutoIt, File.dirname(__FILE__) + "/autoit.rb"
|
4
|
+
|
5
|
+
module Helper
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# @private
|
9
|
+
def default_implementation
|
10
|
+
case RUBY_PLATFORM
|
11
|
+
when /mswin|msys|mingw32/
|
12
|
+
Implementations::AutoIt::Window
|
13
|
+
else
|
14
|
+
raise "unsupported platform for RAutomation: #{RUBY_PLATFORM}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RAutomation
|
2
|
+
class TextField
|
3
|
+
# This constructor is meant to be accessed only through RAutomation::Window#text_field method.
|
4
|
+
def initialize(window, locators) #:nodoc:
|
5
|
+
@window = window
|
6
|
+
@locators = locators
|
7
|
+
@text_field = @window.text_field(@locators)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Sets TextField's text to +text+.
|
11
|
+
#
|
12
|
+
# Raises an UnknownTextFieldException if the TextField itself doesn't exist.
|
13
|
+
def set(text)
|
14
|
+
assert_exists
|
15
|
+
@text_field.set(text)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Clears TextField's text.
|
19
|
+
#
|
20
|
+
# Raises an UnknownTextFieldException if the TextField itself doesn't exist.
|
21
|
+
def clear
|
22
|
+
assert_exists
|
23
|
+
@text_field.clear
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns TextField's text.
|
27
|
+
#
|
28
|
+
# Raises an UnknownTextFieldException if the TextField itself doesn't exist.
|
29
|
+
def value
|
30
|
+
assert_exists
|
31
|
+
@text_field.value
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true if TextField exists, false otherwise.
|
35
|
+
def exists?
|
36
|
+
@text_field.exists?
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :exist?, :exists?
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def assert_exists
|
44
|
+
raise UnknownTextFieldException.new("Text field '#{@locators.inspect}' doesn't exist on window '#{@window.locators.inspect}'!") unless exists?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RAutomation
|
2
|
+
module WaitHelper
|
3
|
+
extend self
|
4
|
+
|
5
|
+
class TimeoutError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
#
|
9
|
+
# Wait until the block evaluates to true or times out.
|
10
|
+
#
|
11
|
+
def wait_until(timeout = 60, &block)
|
12
|
+
end_time = ::Time.now + timeout
|
13
|
+
|
14
|
+
until ::Time.now > end_time
|
15
|
+
result = yield(self)
|
16
|
+
return result if result
|
17
|
+
sleep 0.5
|
18
|
+
end
|
19
|
+
|
20
|
+
raise TimeoutError, "timed out after #{timeout} seconds"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module RAutomation
|
2
|
+
class UnknownWindowException < RuntimeError
|
3
|
+
end
|
4
|
+
class UnknownButtonException < RuntimeError
|
5
|
+
end
|
6
|
+
class UnknownTextFieldException < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
class Window
|
10
|
+
include Implementations::Helper
|
11
|
+
|
12
|
+
attr_reader :implementation
|
13
|
+
|
14
|
+
# Creates a new Window object using the _locators_ Hash parameter.
|
15
|
+
#
|
16
|
+
# Possible Window _locators_ may depend of the used platform and implementation, but
|
17
|
+
# following examples will use :title, :class and :hwnd.
|
18
|
+
#
|
19
|
+
# Use window with _some title_ being part of it's title:
|
20
|
+
# RAutomation::Window.new(:title => "some title")
|
21
|
+
#
|
22
|
+
# Use window with Regexp title:
|
23
|
+
# RAutomation::Window.new(:title => /some title/i)
|
24
|
+
#
|
25
|
+
# Use window with handle _123456_:
|
26
|
+
# RAutomation::Window.new(:hwnd => 123456)
|
27
|
+
#
|
28
|
+
# It is possible to use multiple locators together where every locator will be matched (AND-ed) to the window:
|
29
|
+
# RAutomation::Window.new(:title => "some title", :class => "IEFrame")
|
30
|
+
#
|
31
|
+
# Refer to all possible locators in each implementation's documentation.
|
32
|
+
#
|
33
|
+
# _locators_ may also include a key called :implementation to change default implementation,
|
34
|
+
# which is dependent of the platform, to automate windows and their controls.
|
35
|
+
#
|
36
|
+
# It is also possible to change default implementation by using environment variable:
|
37
|
+
# <em>RAUTOMATION_IMPLEMENTATION</em>
|
38
|
+
#
|
39
|
+
# * Object creation doesn't check for window's existence.
|
40
|
+
# * Window to be searched for has to be visible!
|
41
|
+
def initialize(locators)
|
42
|
+
@implementation = locators.delete(:implementation) || ENV["RAUTOMATION_IMPLEMENTATION"] || default_implementation
|
43
|
+
@window = @implementation.new(locators)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns handle of the Window.
|
47
|
+
#
|
48
|
+
# This handle will be used internally for all operations.
|
49
|
+
def hwnd
|
50
|
+
assert_exists
|
51
|
+
@window.hwnd
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns title of the Window.
|
55
|
+
#
|
56
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
57
|
+
def title
|
58
|
+
assert_exists
|
59
|
+
@window.title
|
60
|
+
end
|
61
|
+
|
62
|
+
# Activates the Window, e.g. brings to the top.
|
63
|
+
def activate
|
64
|
+
@window.activate
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns true if the Window is active, false otherwise.
|
68
|
+
def active?
|
69
|
+
@window.active?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns visible text of the Window.
|
73
|
+
#
|
74
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
75
|
+
def text
|
76
|
+
assert_exists
|
77
|
+
@window.text
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns true if the Window exists, false otherwise.
|
81
|
+
def exists?
|
82
|
+
@window.exists?
|
83
|
+
end
|
84
|
+
|
85
|
+
alias_method :exist?, :exists?
|
86
|
+
|
87
|
+
# Returns true if the Window is visible, false otherwise.
|
88
|
+
# Window is also visible, if it is behind other windows or minimized.
|
89
|
+
#
|
90
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
91
|
+
def visible?
|
92
|
+
assert_exists
|
93
|
+
@window.visible?
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns true if the Window exists and is visible, false otherwise.
|
97
|
+
def present?
|
98
|
+
exists? && visible?
|
99
|
+
end
|
100
|
+
|
101
|
+
# Maximizes the Window.
|
102
|
+
#
|
103
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
104
|
+
def maximize
|
105
|
+
assert_exists
|
106
|
+
@window.maximize
|
107
|
+
end
|
108
|
+
|
109
|
+
# Minimizes the Window.
|
110
|
+
#
|
111
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
112
|
+
def minimize
|
113
|
+
assert_exists
|
114
|
+
@window.minimize
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns true if the Window is minimized, false otherwise.
|
118
|
+
#
|
119
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
120
|
+
def minimized?
|
121
|
+
assert_exists
|
122
|
+
@window.minimized?
|
123
|
+
end
|
124
|
+
|
125
|
+
# Restores the Window.
|
126
|
+
#
|
127
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
128
|
+
def restore
|
129
|
+
assert_exists
|
130
|
+
@window.restore
|
131
|
+
end
|
132
|
+
|
133
|
+
# Sends keys to the Window. Refer to specific implementation's documentation for possible values.
|
134
|
+
#
|
135
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
136
|
+
def send_keys(keys)
|
137
|
+
assert_exists
|
138
|
+
@window.send_keys(keys)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Closes the Window if it exists.
|
142
|
+
def close
|
143
|
+
return unless @window.exists?
|
144
|
+
@window.close
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns the Button object by the _locators_ on the Window.
|
148
|
+
# Refer to specific implementation's documentation for possible parameters.
|
149
|
+
#
|
150
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
151
|
+
def button(locators)
|
152
|
+
assert_exists
|
153
|
+
Button.new(@window, locators)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns the TextField object by the _locators_ on the Window.
|
157
|
+
# Refer to specific implementation's documentation for possible parameters.
|
158
|
+
#
|
159
|
+
# Raises an UnknownWindowException if the Window itself doesn't exist.
|
160
|
+
def text_field(locators)
|
161
|
+
assert_exists
|
162
|
+
TextField.new(@window, locators)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Allow to execute implementation's methods not part of the public API
|
166
|
+
def method_missing(name, *args)
|
167
|
+
@window.respond_to?(name) ? @window.send(name, *args) : super
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def assert_exists
|
173
|
+
raise UnknownWindowException.new("Window with locator '#{@window.locators.inspect}' doesn't exist!") unless exists?
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/rautomation.gemspec
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rautomation}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jarmo Pertman"]
|
12
|
+
s.date = %q{2010-10-13}
|
13
|
+
s.description = %q{RAutomation tries to be a small and easy to use library for helping out to automate windows and their controls
|
14
|
+
for automated testing.
|
15
|
+
|
16
|
+
RAutomation aims to provide:
|
17
|
+
* Easy to use and user-friendly API (inspired by Watir http://www.watir.com).
|
18
|
+
* Cross-platform compatibility
|
19
|
+
* Easy extensibility - have some application, which uses some specialized technology, but isn't supported by RAutomation?
|
20
|
+
You can get dirty and create new implementation for RAutomation, due to the applied Strategy Pattern!}
|
21
|
+
s.email = %q{jarmo.p@gmail.com}
|
22
|
+
s.extra_rdoc_files = [
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc"
|
25
|
+
]
|
26
|
+
s.files = [
|
27
|
+
".document",
|
28
|
+
".gitignore",
|
29
|
+
"LICENSE",
|
30
|
+
"README.rdoc",
|
31
|
+
"Rakefile",
|
32
|
+
"VERSION",
|
33
|
+
"ext/AutoItX/AutoItX.chm",
|
34
|
+
"ext/AutoItX/AutoItX3.dll",
|
35
|
+
"lib/rautomation.rb",
|
36
|
+
"lib/rautomation/button.rb",
|
37
|
+
"lib/rautomation/implementations/autoit.rb",
|
38
|
+
"lib/rautomation/implementations/autoit/button.rb",
|
39
|
+
"lib/rautomation/implementations/autoit/locators.rb",
|
40
|
+
"lib/rautomation/implementations/autoit/text_field.rb",
|
41
|
+
"lib/rautomation/implementations/autoit/window.rb",
|
42
|
+
"lib/rautomation/implementations/helper.rb",
|
43
|
+
"lib/rautomation/text_field.rb",
|
44
|
+
"lib/rautomation/wait_helper.rb",
|
45
|
+
"lib/rautomation/window.rb",
|
46
|
+
"rautomation.gemspec",
|
47
|
+
"spec/button_spec.rb",
|
48
|
+
"spec/spec.opts",
|
49
|
+
"spec/spec_helper.rb",
|
50
|
+
"spec/test.html",
|
51
|
+
"spec/text_field_spec.rb",
|
52
|
+
"spec/window_spec.rb"
|
53
|
+
]
|
54
|
+
s.homepage = %q{http://github.com/jarmo/RAutomation}
|
55
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
56
|
+
s.require_paths = ["lib"]
|
57
|
+
s.rubygems_version = %q{1.3.7}
|
58
|
+
s.summary = %q{Automate windows and their controls through user-friendly API with Ruby}
|
59
|
+
s.test_files = [
|
60
|
+
"spec/button_spec.rb",
|
61
|
+
"spec/spec_helper.rb",
|
62
|
+
"spec/text_field_spec.rb",
|
63
|
+
"spec/window_spec.rb"
|
64
|
+
]
|
65
|
+
|
66
|
+
if s.respond_to? :specification_version then
|
67
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
68
|
+
s.specification_version = 3
|
69
|
+
|
70
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
71
|
+
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
74
|
+
end
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
data/spec/button_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe RAutomation::Button do
|
4
|
+
it "#button" do
|
5
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).
|
6
|
+
button(:text => SpecHelper::DATA[:window2_button_text]).should exist
|
7
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").button(:text => "Something")}.
|
8
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "#value" do
|
12
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).
|
13
|
+
button(:text => SpecHelper::DATA[:window2_button_text]).value.should == SpecHelper::DATA[:window2_button_text]
|
14
|
+
lambda {RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).button(:text => "non-existent-button").value}.
|
15
|
+
should raise_exception(RAutomation::UnknownButtonException)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "#exists?" do
|
19
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
20
|
+
window.button(:text => SpecHelper::DATA[:window2_button_text]).should exist
|
21
|
+
window.button(:text => "non-existent-button").should_not exist
|
22
|
+
end
|
23
|
+
|
24
|
+
it "#click" do
|
25
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
26
|
+
lambda{window.button(:text => "non-existent-button").click}.
|
27
|
+
should raise_exception(RAutomation::UnknownButtonException)
|
28
|
+
|
29
|
+
button = window.button(:text => SpecHelper::DATA[:window2_button_text])
|
30
|
+
button.should exist
|
31
|
+
button.click
|
32
|
+
button.should_not exist
|
33
|
+
window.should_not exist
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'rautomation'
|
3
|
+
require 'spec'
|
4
|
+
require 'spec/autorun'
|
5
|
+
|
6
|
+
module SpecHelper
|
7
|
+
# Since implementations are different then the windows to be tested
|
8
|
+
# might be different also.
|
9
|
+
#
|
10
|
+
# This constant allows to create input data for specs which could differ between the implementations.
|
11
|
+
#
|
12
|
+
# There has to be 2 windows:
|
13
|
+
# 1) Some random window, which is maximizable, minimizable, close'able and etc.
|
14
|
+
# 2) Browser window, which opens up a test.html where JavaScript prompt with a Button and a TextField objects will be shown.
|
15
|
+
DATA = {
|
16
|
+
# This implementation needs Windows OS with Internet Explorer installed into 'c:\program files\internet explorer'.
|
17
|
+
"RAutomation::Implementations::AutoIt::Window" => {
|
18
|
+
# Path to some binary, which opens up a window, what can be
|
19
|
+
# minimized, maximized, activated, closed and etc.
|
20
|
+
:window1 => "mspaint",
|
21
|
+
# Window 1 title, has to be a Regexp.
|
22
|
+
:window1_title => /untitled - paint/i,
|
23
|
+
# Path to some browser's binary.
|
24
|
+
:window2 => '"c:\\program files\\internet explorer\\iexplore.exe"',
|
25
|
+
# Window 2 title, has to be a String.
|
26
|
+
:window2_title => "Explorer User Prompt",
|
27
|
+
# Window 2 should have this text on it.
|
28
|
+
:window2_text => "Where do you want to go today?",
|
29
|
+
# When sending ENTER on Window 2, then the window OK button should be pressed and Window 2 should be closed.
|
30
|
+
:window2_send_keys => "{ENTER}",
|
31
|
+
# Window 2 should have a button with the following text.
|
32
|
+
:window2_button_text => "OK",
|
33
|
+
# Window 2 should have a text field with the specified class name.
|
34
|
+
:window2_text_field_class_name => "Edit1"
|
35
|
+
}
|
36
|
+
}[ENV["RAUTOMATION_IMPLEMENTATION"] || RAutomation::Implementations::Helper.default_implementation.to_s]
|
37
|
+
end
|
38
|
+
|
39
|
+
Spec::Runner.configure do |config|
|
40
|
+
config.before(:all) do
|
41
|
+
@pid1 = IO.popen(SpecHelper::DATA[:window1]).pid
|
42
|
+
@pid2 = IO.popen(SpecHelper::DATA[:window2] + " " + File.dirname(__FILE__) + "/test.html").pid
|
43
|
+
window1 = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
44
|
+
RAutomation::WaitHelper.wait_until(15) {window1.present?}
|
45
|
+
window2 = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
46
|
+
RAutomation::WaitHelper.wait_until(15) {window2.present?}
|
47
|
+
end
|
48
|
+
|
49
|
+
config.after(:all) do
|
50
|
+
Process.kill(9, @pid1) rescue nil
|
51
|
+
Process.kill(9, @pid2) rescue nil
|
52
|
+
end
|
53
|
+
end
|
data/spec/test.html
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>RAutomation testing page</title>
|
4
|
+
<script type="text/javascript">
|
5
|
+
function showPrompt() {
|
6
|
+
prompt("Where do you want to go today?");
|
7
|
+
}
|
8
|
+
</script>
|
9
|
+
</head>
|
10
|
+
<body onload="setTimeout(showPrompt, 1000)">
|
11
|
+
<h1>RAutomation testing page</h1>
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe RAutomation::TextField do
|
4
|
+
it "#text_field" do
|
5
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).
|
6
|
+
text_field(:class_name => SpecHelper::DATA[:window2_text_field_class_name]).should exist
|
7
|
+
lambda {RAutomation::Window.new(:title => "non-existent-window").
|
8
|
+
text_field(:class_name => SpecHelper::DATA[:window2_text_field_class_name])}.
|
9
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "#set" do
|
13
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
14
|
+
window.text_field(:class_name => SpecHelper::DATA[:window2_text_field_class_name]).set "hello!"
|
15
|
+
lambda {window.text_field(:class_name => "non-existing-field").set "hello!"}.
|
16
|
+
should raise_exception(RAutomation::UnknownTextFieldException)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#clear"do
|
20
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
21
|
+
field = window.text_field(:class_name => SpecHelper::DATA[:window2_text_field_class_name])
|
22
|
+
field.set "hello!"
|
23
|
+
field.value.should == "hello!"
|
24
|
+
field.clear
|
25
|
+
field.value.should be_empty
|
26
|
+
|
27
|
+
lambda {window.text_field(:class_name => "non-existent-field").clear}.
|
28
|
+
should raise_exception(RAutomation::UnknownTextFieldException)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "#value" do
|
32
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
33
|
+
field = window.text_field(:class_name => SpecHelper::DATA[:window2_text_field_class_name])
|
34
|
+
field.set "hello!"
|
35
|
+
field.value.should == "hello!"
|
36
|
+
|
37
|
+
lambda {window.text_field(:class_name => "non-existent-field").value}.
|
38
|
+
should raise_exception(RAutomation::UnknownTextFieldException)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "#exists?" do
|
42
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
43
|
+
field = window.text_field(:class_name => SpecHelper::DATA[:window2_text_field_class_name])
|
44
|
+
field.should exist
|
45
|
+
window.text_field(:class_name => "non-existent-field").should_not exist
|
46
|
+
end
|
47
|
+
end
|
data/spec/window_spec.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe RAutomation::Window do
|
4
|
+
it "RAutomation::Window.implementation" do
|
5
|
+
RAutomation::Window.new(:title => "random").implementation.should == (ENV["RAUTOMATION_IMPLEMENTATION"] || RAutomation::Implementations::Helper.default_implementation)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "Window#new by full title" do
|
9
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).should exist
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Window#new by regexp title" do
|
13
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).should exist
|
14
|
+
end
|
15
|
+
|
16
|
+
it "Window#new by hwnd" do
|
17
|
+
hwnd = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).hwnd
|
18
|
+
window = RAutomation::Window.new(:hwnd => hwnd)
|
19
|
+
window.should exist
|
20
|
+
window.title.should == SpecHelper::DATA[:window2_title]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "#exists?" do
|
24
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).should exist
|
25
|
+
RAutomation::Window.new(:title => "non-existing-window").should_not exist
|
26
|
+
end
|
27
|
+
|
28
|
+
it "#visible?"do
|
29
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).should be_visible
|
30
|
+
lambda{RAutomation::Window.new(:title => "non-existing-window").visible?}.
|
31
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "#present?"do
|
35
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).should be_present
|
36
|
+
RAutomation::Window.new(:title => "non-existing-window").should_not be_present
|
37
|
+
end
|
38
|
+
|
39
|
+
it "#hwnd" do
|
40
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).hwnd.should be_a(Fixnum)
|
41
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").hwnd}.
|
42
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "#title" do
|
46
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).title.should == SpecHelper::DATA[:window2_title]
|
47
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").title}.
|
48
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "#activate & #active?" do
|
52
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
53
|
+
window.activate
|
54
|
+
window.should be_active
|
55
|
+
non_existing_window = RAutomation::Window.new(:title => "non-existing-window")
|
56
|
+
non_existing_window.activate
|
57
|
+
non_existing_window.should_not be_active
|
58
|
+
end
|
59
|
+
|
60
|
+
it "#text" do
|
61
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title]).text.should include(SpecHelper::DATA[:window2_text])
|
62
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").text}.
|
63
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "#maximize" do
|
67
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).maximize
|
68
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").maximize}.
|
69
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "#minimize && #minimized?" do
|
73
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
74
|
+
window.should_not be_minimized
|
75
|
+
window.minimize
|
76
|
+
window.should be_minimized
|
77
|
+
|
78
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").minimize}.
|
79
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
80
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").minimized?}.
|
81
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "#restore" do
|
85
|
+
RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title]).restore
|
86
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").restore}.
|
87
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "#send_keys"do
|
91
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window2_title])
|
92
|
+
window.minimize # #send_keys should work even if window is minimized
|
93
|
+
window.send_keys(SpecHelper::DATA[:window2_send_keys])
|
94
|
+
RAutomation::WaitHelper.wait_until(15) {not window.exists?}
|
95
|
+
|
96
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").send_keys("123")}.
|
97
|
+
should raise_exception(RAutomation::UnknownWindowException)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "#close" do
|
101
|
+
window = RAutomation::Window.new(:title => SpecHelper::DATA[:window1_title])
|
102
|
+
window.should exist
|
103
|
+
window.close
|
104
|
+
window.should_not exist
|
105
|
+
|
106
|
+
lambda {RAutomation::Window.new(:title => "non-existing-window").close}.
|
107
|
+
should_not raise_exception
|
108
|
+
end
|
109
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rautomation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jarmo Pertman
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-13 00:00:00 +03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 27
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 3
|
33
|
+
- 0
|
34
|
+
version: 1.3.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
description: |-
|
38
|
+
RAutomation tries to be a small and easy to use library for helping out to automate windows and their controls
|
39
|
+
for automated testing.
|
40
|
+
|
41
|
+
RAutomation aims to provide:
|
42
|
+
* Easy to use and user-friendly API (inspired by Watir http://www.watir.com).
|
43
|
+
* Cross-platform compatibility
|
44
|
+
* Easy extensibility - have some application, which uses some specialized technology, but isn't supported by RAutomation?
|
45
|
+
You can get dirty and create new implementation for RAutomation, due to the applied Strategy Pattern!
|
46
|
+
email: jarmo.p@gmail.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- LICENSE
|
53
|
+
- README.rdoc
|
54
|
+
files:
|
55
|
+
- .document
|
56
|
+
- .gitignore
|
57
|
+
- LICENSE
|
58
|
+
- README.rdoc
|
59
|
+
- Rakefile
|
60
|
+
- VERSION
|
61
|
+
- ext/AutoItX/AutoItX.chm
|
62
|
+
- ext/AutoItX/AutoItX3.dll
|
63
|
+
- lib/rautomation.rb
|
64
|
+
- lib/rautomation/button.rb
|
65
|
+
- lib/rautomation/implementations/autoit.rb
|
66
|
+
- lib/rautomation/implementations/autoit/button.rb
|
67
|
+
- lib/rautomation/implementations/autoit/locators.rb
|
68
|
+
- lib/rautomation/implementations/autoit/text_field.rb
|
69
|
+
- lib/rautomation/implementations/autoit/window.rb
|
70
|
+
- lib/rautomation/implementations/helper.rb
|
71
|
+
- lib/rautomation/text_field.rb
|
72
|
+
- lib/rautomation/wait_helper.rb
|
73
|
+
- lib/rautomation/window.rb
|
74
|
+
- rautomation.gemspec
|
75
|
+
- spec/button_spec.rb
|
76
|
+
- spec/spec.opts
|
77
|
+
- spec/spec_helper.rb
|
78
|
+
- spec/test.html
|
79
|
+
- spec/text_field_spec.rb
|
80
|
+
- spec/window_spec.rb
|
81
|
+
has_rdoc: true
|
82
|
+
homepage: http://github.com/jarmo/RAutomation
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options:
|
87
|
+
- --charset=UTF-8
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 1.3.7
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Automate windows and their controls through user-friendly API with Ruby
|
115
|
+
test_files:
|
116
|
+
- spec/button_spec.rb
|
117
|
+
- spec/spec_helper.rb
|
118
|
+
- spec/text_field_spec.rb
|
119
|
+
- spec/window_spec.rb
|