osaka 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/osaka/applicationwrapper.rb +58 -26
- data/lib/osaka/applicationwrapperexpectations.rb +28 -17
- data/lib/osaka/calculator.rb +32 -0
- data/lib/osaka/textedit.rb +28 -0
- data/lib/osaka/typicalapplication.rb +51 -3
- data/lib/osaka/version.rb +1 -1
- data/lib/osaka.rb +3 -0
- data/spec/applicationwrapper_spec.rb +83 -15
- data/spec/calculator_spec.rb +47 -0
- data/spec/integration_calculator_spec.rb +43 -0
- data/spec/integration_textedit_spec.rb +38 -0
- data/spec/textedit_spec.rb +39 -0
- data/spec/typicalapplication_spec.rb +56 -1
- metadata +8 -2
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
module Osaka
|
|
3
3
|
|
|
4
|
+
class InvalidLocation < RuntimeError
|
|
5
|
+
end
|
|
6
|
+
|
|
4
7
|
class ConditionProxy
|
|
5
8
|
|
|
6
9
|
def initialize(wrapper, action)
|
|
@@ -28,37 +31,45 @@ module Osaka
|
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
class CheckAction
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
end
|
|
34
|
+
def execute(wrapper, condition, *args, &block)
|
|
35
|
+
wrapper.system_event!("#{condition.as_script(*args)};").strip == "true"
|
|
34
36
|
end
|
|
37
|
+
end
|
|
35
38
|
|
|
36
39
|
class ExistsCondition
|
|
37
|
-
def as_script(
|
|
38
|
-
"exists #{
|
|
40
|
+
def as_script(element_to_check)
|
|
41
|
+
"exists #{element_to_check}"
|
|
39
42
|
end
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
class Not_existsCondition
|
|
43
|
-
def as_script(
|
|
44
|
-
"not exists #{
|
|
46
|
+
def as_script(element_to_check)
|
|
47
|
+
"not exists #{element_to_check}"
|
|
45
48
|
end
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
class ApplicationWrapper
|
|
49
52
|
|
|
53
|
+
attr_accessor :window
|
|
54
|
+
|
|
50
55
|
def initialize(name)
|
|
51
56
|
@name = name
|
|
52
57
|
end
|
|
53
58
|
|
|
59
|
+
def tell(command)
|
|
60
|
+
ScriptRunner::execute("tell application \"#{@name}\"; #{command}; end tell")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def system_event!(event)
|
|
64
|
+
ScriptRunner::execute("tell application \"System Events\"; tell process \"#{@name}\"; #{event}; end tell; end tell")
|
|
65
|
+
end
|
|
66
|
+
|
|
54
67
|
def print_warning(action, message)
|
|
55
68
|
puts "Osaka WARNING while doing #{action}: #{message}"
|
|
56
69
|
end
|
|
57
70
|
|
|
58
71
|
def check_output(output, action)
|
|
59
|
-
|
|
60
|
-
print_warning(action, output)
|
|
61
|
-
end
|
|
72
|
+
print_warning(action, output) unless output.empty?
|
|
62
73
|
output
|
|
63
74
|
end
|
|
64
75
|
|
|
@@ -67,16 +78,8 @@ module Osaka
|
|
|
67
78
|
end
|
|
68
79
|
|
|
69
80
|
def quit
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def tell(command)
|
|
74
|
-
ScriptRunner::execute("tell application \"#{@name}\"; #{command}; end tell")
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def system_event!(event)
|
|
78
|
-
ScriptRunner::execute("tell application \"System Events\"; tell process \"#{@name}\"; #{event}; end tell; end tell")
|
|
79
|
-
end
|
|
81
|
+
keystroke("q", :command)
|
|
82
|
+
end
|
|
80
83
|
|
|
81
84
|
def system_event(event)
|
|
82
85
|
activate
|
|
@@ -92,13 +95,13 @@ module Osaka
|
|
|
92
95
|
ConditionProxy.new(self, CheckAction.new)
|
|
93
96
|
end
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
ConditionProxy.new(self, RepeatAction.new)
|
|
97
|
-
end
|
|
98
|
+
alias check! check
|
|
98
99
|
|
|
99
100
|
def until!
|
|
100
101
|
ConditionProxy.new(self, RepeatAction.new)
|
|
101
102
|
end
|
|
103
|
+
|
|
104
|
+
alias wait_until! until!
|
|
102
105
|
|
|
103
106
|
def construct_modifier_statement(modifier_keys)
|
|
104
107
|
modified_key_string = [ modifier_keys ].flatten.collect! { |mod_key| mod_key.to_s + " down"}.join(", ")
|
|
@@ -113,6 +116,7 @@ module Osaka
|
|
|
113
116
|
|
|
114
117
|
def keystroke(key, modifier_keys = [])
|
|
115
118
|
activate
|
|
119
|
+
focus
|
|
116
120
|
keystroke!(key, modifier_keys)
|
|
117
121
|
end
|
|
118
122
|
|
|
@@ -128,16 +132,44 @@ module Osaka
|
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
def set!(element, location, value)
|
|
131
|
-
|
|
135
|
+
encoded_value = (value.class == String) ? "\"#{value}\"" : value.to_s
|
|
136
|
+
check_output( system_event!("set #{element} of #{location} to #{encoded_value}"), "set")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def focus
|
|
140
|
+
current_windows = window_list
|
|
141
|
+
@window = current_windows[0] if @window.nil? || current_windows.index(@window).nil?
|
|
142
|
+
set!("value", "attribute \"AXMain\" of window \"#{window}\"", true) if current_windows[0] != @window
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def construct_window_info(location)
|
|
146
|
+
location_string = ""
|
|
147
|
+
location_string += " of #{location}" unless location.empty?
|
|
148
|
+
location_string += " of window \"#{window}\"" unless window.nil?
|
|
149
|
+
|
|
150
|
+
raise(Osaka::InvalidLocation, "Invalid location for command:#{location_string}") if location_string.scan("of window").length > 1
|
|
151
|
+
|
|
152
|
+
location_string
|
|
132
153
|
end
|
|
133
154
|
|
|
134
|
-
def get!(element, location)
|
|
135
|
-
system_event!("get #{element}
|
|
155
|
+
def get!(element, location = "")
|
|
156
|
+
system_event!("get #{element}#{construct_window_info(location)}").strip
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def get_app!(element)
|
|
160
|
+
system_event!("get #{element}").strip
|
|
136
161
|
end
|
|
137
162
|
|
|
138
163
|
def set(element, location, value)
|
|
139
164
|
activate
|
|
140
165
|
set!(element, location, value)
|
|
141
166
|
end
|
|
167
|
+
|
|
168
|
+
def window_list
|
|
169
|
+
windows = get_app!("windows").strip.split(',')
|
|
170
|
+
windows.collect { |window|
|
|
171
|
+
window[7...window =~ / of application process/].strip
|
|
172
|
+
}
|
|
173
|
+
end
|
|
142
174
|
end
|
|
143
175
|
end
|
|
@@ -2,33 +2,37 @@
|
|
|
2
2
|
module Osaka
|
|
3
3
|
module ApplicationWrapperExpectations
|
|
4
4
|
|
|
5
|
-
def should_wait(wait_command, wait_condition, wait_element)
|
|
6
|
-
condition = double(:ConditionAndActionProxy)
|
|
7
|
-
@wrapper.should_receive(wait_command).and_return(condition)
|
|
8
|
-
condition.should_receive(wait_condition).with(wait_element)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
5
|
def should_wait_until(wait_condition, wait_element)
|
|
12
|
-
|
|
6
|
+
should_do_with_condition(:wait_until, wait_condition, wait_element)
|
|
13
7
|
end
|
|
14
|
-
|
|
8
|
+
|
|
15
9
|
def should_wait_until!(wait_condition, wait_element)
|
|
16
|
-
|
|
10
|
+
should_do_with_condition(:wait_until!, wait_condition, wait_element)
|
|
17
11
|
end
|
|
18
|
-
|
|
19
|
-
def
|
|
20
|
-
|
|
12
|
+
|
|
13
|
+
def should_check!(condition, element, return_value)
|
|
14
|
+
should_do_with_condition(:check!, condition, element).and_return(return_value)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def should_do_until!(condition, element)
|
|
18
|
+
should_do_with_condition(:until!, condition, element).and_yield
|
|
21
19
|
yield
|
|
22
20
|
end
|
|
23
|
-
|
|
24
|
-
def expect_keystroke(key, modifier)
|
|
25
|
-
@wrapper.should_receive(:keystroke).with(key, modifier).and_return(@wrapper)
|
|
21
|
+
|
|
22
|
+
def expect_keystroke(key, modifier = [])
|
|
23
|
+
@wrapper.should_receive(:keystroke).with(key, modifier).and_return(@wrapper) unless modifier.empty?
|
|
24
|
+
@wrapper.should_receive(:keystroke).with(key).and_return(@wrapper) if modifier.empty?
|
|
26
25
|
end
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
def expect_keystroke!(key, modifier = [])
|
|
28
|
+
@wrapper.should_receive(:keystroke!).with(key, modifier).and_return(@wrapper) unless modifier.empty?
|
|
29
|
+
@wrapper.should_receive(:keystroke!).with(key).and_return(@wrapper) if modifier.empty?
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
def expect_click!(location)
|
|
29
33
|
@wrapper.should_receive(:click!).with(location).and_return(@wrapper)
|
|
30
34
|
end
|
|
31
|
-
|
|
35
|
+
|
|
32
36
|
def expect_click(location)
|
|
33
37
|
@wrapper.should_receive(:click).with(location).and_return(@wrapper)
|
|
34
38
|
end
|
|
@@ -41,6 +45,13 @@ module Osaka
|
|
|
41
45
|
@wrapper.should_receive(:system_event).with(event)
|
|
42
46
|
end
|
|
43
47
|
|
|
48
|
+
private
|
|
49
|
+
def should_do_with_condition(command, condition, element)
|
|
50
|
+
condition_proxy = double(:ConditionAndActionProxy)
|
|
51
|
+
@wrapper.should_receive(command).and_return(condition_proxy)
|
|
52
|
+
condition_proxy.should_receive(condition).with(element)
|
|
53
|
+
end
|
|
54
|
+
|
|
44
55
|
|
|
45
56
|
end
|
|
46
57
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
module Osaka
|
|
3
|
+
class Calculator < TypicalApplication
|
|
4
|
+
attr_accessor :wrapper
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@name = "Calculator"
|
|
8
|
+
@wrapper = ApplicationWrapper.new("Calculator")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def activate
|
|
12
|
+
super
|
|
13
|
+
if (@wrapper.window.nil?)
|
|
14
|
+
wait_for_new_window([])
|
|
15
|
+
@wrapper.window = @wrapper.window_list[0]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def click(key)
|
|
20
|
+
@wrapper.click!("button \"#{key}\" of group 2 of window \"#{@name}\"")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def key(k)
|
|
24
|
+
@wrapper.keystroke(k)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def result
|
|
28
|
+
@wrapper.get!('value', "static text 1 of group 1")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
module Osaka
|
|
3
|
+
class TextEdit < TypicalApplication
|
|
4
|
+
attr_accessor :wrapper
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@name = "TextEdit"
|
|
8
|
+
@wrapper = ApplicationWrapper.new("TextEdit")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def activate
|
|
12
|
+
super
|
|
13
|
+
if (@wrapper.window.nil?)
|
|
14
|
+
wait_for_new_window([])
|
|
15
|
+
@wrapper.window = @wrapper.window_list[0]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def type(text)
|
|
20
|
+
@wrapper.keystroke(text)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def text
|
|
24
|
+
@wrapper.get!("value", 'text area 1 of scroll area 1')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -56,27 +56,75 @@ module Osaka
|
|
|
56
56
|
}
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
class ApplicationInfo
|
|
61
|
+
|
|
62
|
+
attr_reader :name
|
|
63
|
+
|
|
64
|
+
def initialize(script_info)
|
|
65
|
+
@name = script_info.match(/name:(.+?), creation date/)[1]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
59
69
|
|
|
60
70
|
class TypicalApplication
|
|
61
71
|
|
|
62
72
|
attr_accessor :wrapper
|
|
63
73
|
|
|
64
74
|
def initialize(name)
|
|
75
|
+
@name = name
|
|
65
76
|
@wrapper = ApplicationWrapper.new(name)
|
|
66
77
|
end
|
|
78
|
+
|
|
79
|
+
def get_info
|
|
80
|
+
script_info = @wrapper.tell("get info for (path to application \"#{@name}\")")
|
|
81
|
+
ApplicationInfo.new(script_info)
|
|
82
|
+
end
|
|
67
83
|
|
|
68
84
|
def open (filename)
|
|
69
85
|
abolutePathFileName = File.absolute_path(filename)
|
|
70
86
|
@wrapper.tell("open \"#{abolutePathFileName}\"")
|
|
87
|
+
@wrapper.window = filename
|
|
71
88
|
end
|
|
72
|
-
|
|
73
|
-
def
|
|
89
|
+
|
|
90
|
+
def wait_for_window_and_dialogs_to_close(option)
|
|
91
|
+
if (option != :user_chose)
|
|
92
|
+
@wrapper.until!.not_exists("window \"#{wrapper.window}\"") {
|
|
93
|
+
if (@wrapper.check!.exists("sheet 1 of window \"#{wrapper.window}\""))
|
|
94
|
+
@wrapper.click!("button 2 of sheet 1 of window \"#{wrapper.window}\"")
|
|
95
|
+
end
|
|
96
|
+
}
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def quit(option = :user_chose)
|
|
74
101
|
@wrapper.quit
|
|
102
|
+
wait_for_window_and_dialogs_to_close(option)
|
|
75
103
|
end
|
|
76
104
|
|
|
105
|
+
def wait_for_new_window(original_window_list)
|
|
106
|
+
latest_window_list = original_window_list
|
|
107
|
+
while (original_window_list == latest_window_list)
|
|
108
|
+
latest_window_list = @wrapper.window_list
|
|
109
|
+
end
|
|
110
|
+
(latest_window_list - original_window_list)[0]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def new_document
|
|
114
|
+
window_list = @wrapper.window_list
|
|
115
|
+
@wrapper.keystroke("n", :command)
|
|
116
|
+
@wrapper.window = wait_for_new_window(window_list)
|
|
117
|
+
@wrapper.focus
|
|
118
|
+
end
|
|
119
|
+
|
|
77
120
|
def save
|
|
78
121
|
@wrapper.keystroke("s", :command)
|
|
79
122
|
end
|
|
123
|
+
|
|
124
|
+
def close(option = :user_chose)
|
|
125
|
+
@wrapper.keystroke("w", :command)
|
|
126
|
+
wait_for_window_and_dialogs_to_close(option)
|
|
127
|
+
end
|
|
80
128
|
|
|
81
129
|
def activate
|
|
82
130
|
@wrapper.activate
|
|
@@ -87,7 +135,7 @@ module Osaka
|
|
|
87
135
|
end
|
|
88
136
|
|
|
89
137
|
def print_dialog
|
|
90
|
-
location = "sheet 1
|
|
138
|
+
location = "sheet 1#{@wrapper.construct_window_info}"
|
|
91
139
|
@wrapper.keystroke("p", :command).wait_until.exists(location)
|
|
92
140
|
create_print_dialog(location)
|
|
93
141
|
end
|
data/lib/osaka/version.rb
CHANGED
data/lib/osaka.rb
CHANGED
|
@@ -27,26 +27,16 @@ describe "Osaka::ApplicationWrapper" do
|
|
|
27
27
|
subject.print_warning("action", "Message")
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
it "Has a short-cut method for activation" do
|
|
31
|
-
Osaka::ScriptRunner.should_receive(:execute).with(/activate/).and_return("")
|
|
32
|
-
subject.activate
|
|
33
|
-
end
|
|
34
|
-
|
|
35
30
|
it "Should print an Warning message with the ScriptRunner returns text when doing activate" do
|
|
36
31
|
check_for_warning("activate")
|
|
37
32
|
subject.activate
|
|
38
33
|
end
|
|
39
34
|
|
|
40
35
|
it "Has a short-cut method for quitting" do
|
|
41
|
-
|
|
36
|
+
subject.should_receive(:keystroke).with("q", :command)
|
|
42
37
|
subject.quit
|
|
43
38
|
end
|
|
44
39
|
|
|
45
|
-
it "Prints a warning message when quit results in some output" do
|
|
46
|
-
check_for_warning("quit")
|
|
47
|
-
subject.quit
|
|
48
|
-
end
|
|
49
|
-
|
|
50
40
|
it "Should be able to generate events via the Systems Events" do
|
|
51
41
|
Osaka::ScriptRunner.should_receive(:execute).with(/tell application "System Events"; tell process #{quoted_name}; quit; end tell; end tell/)
|
|
52
42
|
subject.system_event!("quit")
|
|
@@ -95,6 +85,7 @@ describe "Osaka::ApplicationWrapper" do
|
|
|
95
85
|
|
|
96
86
|
it "Should be able to keystroke and activate" do
|
|
97
87
|
subject.should_receive(:activate)
|
|
88
|
+
subject.should_receive(:focus)
|
|
98
89
|
subject.should_receive(:keystroke!).with("a", [])
|
|
99
90
|
subject.keystroke("a", [])
|
|
100
91
|
end
|
|
@@ -117,6 +108,7 @@ describe "Osaka::ApplicationWrapper" do
|
|
|
117
108
|
|
|
118
109
|
it "Should be able to keystroke_and_wait_until_exists and activate" do
|
|
119
110
|
subject.should_receive(:activate)
|
|
111
|
+
subject.should_receive(:focus)
|
|
120
112
|
Osaka::ScriptRunner.should_receive(:execute).with(/keystroke "p"/).and_return("")
|
|
121
113
|
Osaka::ScriptRunner.should_receive(:execute).with(/exists window 1/).and_return("true")
|
|
122
114
|
subject.keystroke("p", []).wait_until!.exists("window 1")
|
|
@@ -147,26 +139,53 @@ describe "Osaka::ApplicationWrapper" do
|
|
|
147
139
|
end
|
|
148
140
|
|
|
149
141
|
it "Should be able to set a value to an element" do
|
|
150
|
-
|
|
142
|
+
subject.should_receive(:system_event!).with(/set value of window to "newvalue"/).and_return("")
|
|
151
143
|
subject.set!("value", "window", "newvalue")
|
|
152
144
|
end
|
|
153
145
|
|
|
154
146
|
it "Prints a warning when setting and element and output is received" do
|
|
155
|
-
|
|
147
|
+
check_for_warning("set")
|
|
156
148
|
subject.set!("value", "window", "newvalue")
|
|
157
149
|
end
|
|
158
150
|
|
|
151
|
+
it "Should be able to set to boolean values" do
|
|
152
|
+
subject.should_receive(:system_event!).with(/set value of window to true/).and_return("")
|
|
153
|
+
subject.set!("value", "window", true)
|
|
154
|
+
end
|
|
155
|
+
|
|
159
156
|
it "Should be able to get a value from an element" do
|
|
160
|
-
subject.should_receive(:system_event!).with(/get value of window/).and_return("1")
|
|
157
|
+
subject.should_receive(:system_event!).with(/get value of window/).and_return("1\n")
|
|
161
158
|
subject.get!("value", "window").should == "1"
|
|
162
159
|
end
|
|
163
160
|
|
|
161
|
+
it "Should use the locally stored window when that one is set." do
|
|
162
|
+
subject.window = "1"
|
|
163
|
+
subject.should_receive(:system_event!).with(/get value of window \"1\"/).and_return("1\n")
|
|
164
|
+
subject.get!("value").should == "1"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "Should throw an exception when window is set multiple times." do
|
|
168
|
+
subject.window = "Untitled"
|
|
169
|
+
lambda {subject.get!("value", "window 1")}.should raise_error(Osaka::InvalidLocation, "Invalid location for command: of window 1 of window \"Untitled\"")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "Should combine the location and the window" do
|
|
173
|
+
subject.window = "1"
|
|
174
|
+
subject.should_receive(:system_event!).with(/get value of dialog 2 of window "1"/).and_return("1\n")
|
|
175
|
+
subject.get!("value", "dialog 2").should == "1"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it "Should be able to get values from the application itself" do
|
|
179
|
+
subject.should_receive(:system_event!).with("get value").and_return("1\n")
|
|
180
|
+
subject.get_app!("value").should == "1"
|
|
181
|
+
end
|
|
182
|
+
|
|
164
183
|
it "Should be able to set a value and activate" do
|
|
165
184
|
subject.should_receive(:activate)
|
|
166
185
|
subject.should_receive(:set!).with("value", "window", "newvalue")
|
|
167
186
|
subject.set("value", "window", "newvalue")
|
|
168
187
|
end
|
|
169
|
-
|
|
188
|
+
|
|
170
189
|
it "Should be able to loop over some script until something happens" do
|
|
171
190
|
counter = 0
|
|
172
191
|
Osaka::ScriptRunner.should_receive(:execute).exactly(3).times.with(/exists window/).and_return {
|
|
@@ -183,4 +202,53 @@ describe "Osaka::ApplicationWrapper" do
|
|
|
183
202
|
}
|
|
184
203
|
end
|
|
185
204
|
|
|
205
|
+
it "Should be able to get an empty array when requesting for the window list and there are none" do
|
|
206
|
+
subject.should_receive(:get_app!).with("windows").and_return("\n")
|
|
207
|
+
subject.window_list.should == []
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it "Should be able get an array with one window name when there is exactly one window" do
|
|
211
|
+
subject.should_receive(:get_app!).with("windows").and_return("window one of application process process\n")
|
|
212
|
+
subject.window_list.should == ["one"]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "Should be able to get an array of multiple window names" do
|
|
216
|
+
subject.should_receive(:get_app!).with("windows").and_return("window one of application process process, window two of application process process\n")
|
|
217
|
+
subject.window_list.should == ["one", "two"]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "Should initialize the current window when it is not focused yet" do
|
|
221
|
+
subject.should_receive(:window_list).and_return(["1"])
|
|
222
|
+
subject.focus
|
|
223
|
+
subject.window.should == "1"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "Shouldn't initialize current window when it is already set" do
|
|
227
|
+
subject.should_receive(:window_list).and_return(["1"])
|
|
228
|
+
subject.focus
|
|
229
|
+
|
|
230
|
+
subject.should_receive(:window_list).and_return(["2", "1"])
|
|
231
|
+
subject.should_receive(:set!)
|
|
232
|
+
subject.focus
|
|
233
|
+
subject.window.should == "1"
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it "Should re-initialize the current window when it doesn't exist anymore" do
|
|
237
|
+
subject.should_receive(:window_list).and_return(["1"])
|
|
238
|
+
subject.focus
|
|
239
|
+
|
|
240
|
+
subject.should_receive(:window_list).and_return(["2"])
|
|
241
|
+
subject.focus
|
|
242
|
+
subject.window.should == "2"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
it "Should focus the current window when it doesn't have focus" do
|
|
246
|
+
subject.should_receive(:window_list).and_return(["1"])
|
|
247
|
+
subject.focus
|
|
248
|
+
|
|
249
|
+
subject.should_receive(:window_list).and_return(["2", "1"])
|
|
250
|
+
subject.should_receive(:set!).with("value", "attribute \"AXMain\" of window \"1\"", true )
|
|
251
|
+
subject.focus
|
|
252
|
+
end
|
|
253
|
+
|
|
186
254
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
require 'osaka'
|
|
3
|
+
|
|
4
|
+
describe "Mac GUI Calculator" do
|
|
5
|
+
|
|
6
|
+
include(*Osaka::ApplicationWrapperExpectations)
|
|
7
|
+
|
|
8
|
+
subject { Osaka::Calculator.new }
|
|
9
|
+
|
|
10
|
+
before (:each) do
|
|
11
|
+
@wrapper = subject.wrapper = double("Osaka::ApplicationWrapper")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "Should be setting the window when starting the Calculator" do
|
|
15
|
+
|
|
16
|
+
# TODO: Fix this duplication between this and TextEdit.
|
|
17
|
+
|
|
18
|
+
@wrapper.should_receive(:activate)
|
|
19
|
+
@wrapper.should_receive(:window).and_return(nil)
|
|
20
|
+
subject.should_receive(:wait_for_new_window).with([])
|
|
21
|
+
@wrapper.should_receive(:window_list).and_return(["Calculator"])
|
|
22
|
+
@wrapper.should_receive(:window=).with("Calculator")
|
|
23
|
+
subject.activate
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
it "Should be able to click a button on the calculator" do
|
|
28
|
+
expect_click!('button "1" of group 2 of window "Calculator"')
|
|
29
|
+
subject.click("1")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "Should be able to use keystroke on the calculator" do
|
|
33
|
+
expect_keystroke("1")
|
|
34
|
+
subject.key("1")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "Should be able to quit the calculator" do
|
|
38
|
+
@wrapper.should_receive(:quit)
|
|
39
|
+
subject.quit
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "Should be able to get the value from the screen" do
|
|
43
|
+
@wrapper.should_receive(:get!).with("value", 'static text 1 of group 1').and_return("0")
|
|
44
|
+
subject.result.should == "0"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
require 'osaka'
|
|
3
|
+
|
|
4
|
+
describe "Integration test using the Calculator" do
|
|
5
|
+
|
|
6
|
+
subject { Osaka::Calculator.new }
|
|
7
|
+
|
|
8
|
+
before (:each) do
|
|
9
|
+
subject.activate
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
after (:each) do
|
|
13
|
+
subject.quit
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "Should be able to get info from the calculator" do
|
|
17
|
+
app_info = subject.get_info
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "Should be able to do calculations with mouse" do
|
|
22
|
+
subject.click("1")
|
|
23
|
+
subject.click("+")
|
|
24
|
+
subject.click("1")
|
|
25
|
+
subject.click("=")
|
|
26
|
+
subject.result.should == "2"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "Should be able to do calculations using keyboard" do
|
|
30
|
+
subject.key("10")
|
|
31
|
+
subject.key("*")
|
|
32
|
+
subject.key("10")
|
|
33
|
+
subject.key("=")
|
|
34
|
+
subject.result.should == "100"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "Should do whole formulas using key" do
|
|
38
|
+
subject.key("100+10*3+99=")
|
|
39
|
+
sleep 0.5
|
|
40
|
+
subject.result.should == "229"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
require 'osaka'
|
|
3
|
+
|
|
4
|
+
describe "Integration test using TextEdit" do
|
|
5
|
+
|
|
6
|
+
subject { Osaka::TextEdit.new }
|
|
7
|
+
|
|
8
|
+
before (:each) do
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after (:each) do
|
|
12
|
+
subject.quit(:dont_save)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "can type in the window" do
|
|
16
|
+
subject.activate
|
|
17
|
+
subject.type("Hello World")
|
|
18
|
+
subject.text.should == "Hello World"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "can type in two windows using two instances" do
|
|
22
|
+
editor1 = subject
|
|
23
|
+
editor2 = Osaka::TextEdit.new
|
|
24
|
+
|
|
25
|
+
editor1.activate
|
|
26
|
+
editor2.new_document
|
|
27
|
+
|
|
28
|
+
editor1.type("Typing in window 1")
|
|
29
|
+
editor2.type("Typing in window 2")
|
|
30
|
+
|
|
31
|
+
editor1.text.should == "Typing in window 1"
|
|
32
|
+
editor2.text.should == "Typing in window 2"
|
|
33
|
+
|
|
34
|
+
editor1.close(:dont_save)
|
|
35
|
+
editor2.close(:dont_save)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
require 'osaka'
|
|
3
|
+
|
|
4
|
+
describe "TextEdit" do
|
|
5
|
+
|
|
6
|
+
include(*Osaka::ApplicationWrapperExpectations)
|
|
7
|
+
|
|
8
|
+
subject { Osaka::TextEdit.new }
|
|
9
|
+
|
|
10
|
+
before (:each) do
|
|
11
|
+
@wrapper = subject.wrapper = double("Osaka::ApplicationWrapper")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should set the window on activation" do
|
|
15
|
+
@wrapper.should_receive(:activate)
|
|
16
|
+
@wrapper.should_receive(:window).and_return(nil)
|
|
17
|
+
subject.should_receive(:wait_for_new_window).with([])
|
|
18
|
+
@wrapper.should_receive(:window_list).and_return(["Untitled"])
|
|
19
|
+
@wrapper.should_receive(:window=).with("Untitled")
|
|
20
|
+
subject.activate
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "shouldn't set the window on activation when it is already set" do
|
|
24
|
+
@wrapper.should_receive(:activate)
|
|
25
|
+
@wrapper.should_receive(:window).and_return("Untitled")
|
|
26
|
+
subject.activate
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "Should be able to type some text" do
|
|
30
|
+
expect_keystroke('Hello World')
|
|
31
|
+
subject.type("Hello World")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "Should be able to get the text from the document" do
|
|
35
|
+
subject.wrapper.should_receive(:get!).with("value", 'text area 1 of scroll area 1').and_return("Hello")
|
|
36
|
+
subject.text.should == "Hello"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -14,6 +14,7 @@ describe "Osaka::TypicalApplication" do
|
|
|
14
14
|
it "Should pass the right open string to the Keynote application osascript" do
|
|
15
15
|
filename = "filename.key"
|
|
16
16
|
expect_tell("open \"#{File.absolute_path(filename)}\"")
|
|
17
|
+
@wrapper.should_receive(:window=).with(filename)
|
|
17
18
|
subject.open(filename)
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -22,11 +23,56 @@ describe "Osaka::TypicalApplication" do
|
|
|
22
23
|
subject.quit
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
it "Should be able to quit without saving" do
|
|
27
|
+
@wrapper.should_receive(:window).any_number_of_times.and_return("Untitled")
|
|
28
|
+
@wrapper.should_receive(:quit)
|
|
29
|
+
should_do_until!(:not_exists, "window \"Untitled\"") {
|
|
30
|
+
should_check!(:exists, "sheet 1 of window \"Untitled\"", true)
|
|
31
|
+
expect_click!('button 2 of sheet 1 of window "Untitled"')
|
|
32
|
+
}
|
|
33
|
+
subject.quit(:dont_save)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "Should be able to wait until a new window exists" do
|
|
37
|
+
subject.wrapper.should_receive(:window_list).and_return(["new window"])
|
|
38
|
+
subject.wait_for_new_window([])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "Should be able to wait until a new window exists and it takes 4 calls" do
|
|
42
|
+
counter = 0
|
|
43
|
+
subject.wrapper.should_receive(:window_list).exactly(4).times.and_return(["new window"]) {
|
|
44
|
+
counter = counter + 1
|
|
45
|
+
counter.should <= 5 # Added here so that the test won't end up in an endless loop.
|
|
46
|
+
counter >= 4 ? [ "new window" ] : []
|
|
47
|
+
}
|
|
48
|
+
subject.wait_for_new_window([])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "Should be able to create a new document" do
|
|
52
|
+
subject.wrapper.should_receive(:window_list)
|
|
53
|
+
expect_keystroke("n", :command)
|
|
54
|
+
subject.should_receive(:wait_for_new_window).and_return("new_window")
|
|
55
|
+
subject.wrapper.should_receive(:window=).with("new_window")
|
|
56
|
+
subject.wrapper.should_receive(:focus)
|
|
57
|
+
subject.new_document
|
|
58
|
+
end
|
|
59
|
+
|
|
25
60
|
it "Should be able to save" do
|
|
26
61
|
expect_keystroke("s", :command)
|
|
27
62
|
subject.save
|
|
28
63
|
end
|
|
29
64
|
|
|
65
|
+
it "Should be able to close" do
|
|
66
|
+
expect_keystroke("w", :command)
|
|
67
|
+
subject.close
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "Should be able to close and don't save" do
|
|
71
|
+
expect_keystroke("w", :command)
|
|
72
|
+
subject.should_receive(:wait_for_window_and_dialogs_to_close).with(:dont_save)
|
|
73
|
+
subject.close(:dont_save)
|
|
74
|
+
end
|
|
75
|
+
|
|
30
76
|
it "Should be able to activate keynote" do
|
|
31
77
|
@wrapper.should_receive(:activate)
|
|
32
78
|
subject.activate
|
|
@@ -34,9 +80,18 @@ describe "Osaka::TypicalApplication" do
|
|
|
34
80
|
|
|
35
81
|
it "Should be able to retrieve a print dialog" do
|
|
36
82
|
expect_keystroke("p", :command)
|
|
83
|
+
@wrapper.should_receive(:construct_window_info).and_return(" of window 1")
|
|
37
84
|
should_wait_until(:exists, "sheet 1 of window 1")
|
|
38
85
|
subject.print_dialog
|
|
39
|
-
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe "Application info" do
|
|
89
|
+
it "Should be able to retrieve an application info object and parse it" do
|
|
90
|
+
@wrapper.should_receive(:tell).with('get info for (path to application "ApplicationName")').and_return('name:ApplicationName.app, creation date:date "Sunday, December 21, 2008 PM 06:14:11"}')
|
|
91
|
+
app_info = subject.get_info
|
|
92
|
+
app_info.name.should == "ApplicationName.app"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
40
95
|
|
|
41
96
|
describe "Generic Print Dialog" do
|
|
42
97
|
|
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: osaka
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 0.2.
|
|
5
|
+
version: 0.2.3
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Bas Vodde
|
|
@@ -10,7 +10,7 @@ autorequire:
|
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
12
|
|
|
13
|
-
date: 2012-
|
|
13
|
+
date: 2012-04-14 00:00:00 +08:00
|
|
14
14
|
default_executable:
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
@@ -49,18 +49,24 @@ files:
|
|
|
49
49
|
- lib/osaka.rb
|
|
50
50
|
- lib/osaka/applicationwrapper.rb
|
|
51
51
|
- lib/osaka/applicationwrapperexpectations.rb
|
|
52
|
+
- lib/osaka/calculator.rb
|
|
52
53
|
- lib/osaka/keynote.rb
|
|
53
54
|
- lib/osaka/numbers.rb
|
|
54
55
|
- lib/osaka/pages.rb
|
|
55
56
|
- lib/osaka/scriptrunner.rb
|
|
57
|
+
- lib/osaka/textedit.rb
|
|
56
58
|
- lib/osaka/typicalapplication.rb
|
|
57
59
|
- lib/osaka/version.rb
|
|
58
60
|
- osaka.gemfile
|
|
59
61
|
- spec/applicationwrapper_spec.rb
|
|
62
|
+
- spec/calculator_spec.rb
|
|
63
|
+
- spec/integration_calculator_spec.rb
|
|
64
|
+
- spec/integration_textedit_spec.rb
|
|
60
65
|
- spec/keynote_spec.rb
|
|
61
66
|
- spec/numbers_spec.rb
|
|
62
67
|
- spec/pages_spec.rb
|
|
63
68
|
- spec/scriptrunner_spec.rb
|
|
69
|
+
- spec/textedit_spec.rb
|
|
64
70
|
- spec/typicalapplication_spec.rb
|
|
65
71
|
has_rdoc: true
|
|
66
72
|
homepage: https://github.com/basvodde/osaka
|