osaka 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +32 -8
- data/lib/osaka/calculator.rb +10 -9
- data/lib/osaka/keynote.rb +4 -4
- data/lib/osaka/location.rb +4 -0
- data/lib/osaka/numbers.rb +1 -1
- data/lib/osaka/osakaexpectations.rb +132 -0
- data/lib/osaka/pages.rb +13 -13
- data/lib/osaka/{applicationwrapper.rb → remotecontrol.rb} +68 -31
- data/lib/osaka/scriptrunner.rb +9 -1
- data/lib/osaka/textedit.rb +4 -4
- data/lib/osaka/typicalapplication.rb +49 -107
- data/lib/osaka/typicalprintdialog.rb +32 -0
- data/lib/osaka/typicalsavedialog.rb +33 -0
- data/lib/osaka/version.rb +1 -1
- data/lib/osaka.rb +4 -2
- data/spec/assets/mail_merge_data.numbers +0 -0
- data/spec/assets/mail_merge_template.pages +0 -0
- data/spec/calculator_spec.rb +10 -12
- data/spec/integration_keynote_spec.rb +1 -0
- data/spec/integration_pages_numbers_mail_merge_spec.rb +1 -1
- data/spec/keynote_flows_spec.rb +4 -4
- data/spec/keynote_spec.rb +4 -4
- data/spec/location_spec.rb +6 -0
- data/spec/mailmergeflow_spec.rb +2 -2
- data/spec/numbers_spec.rb +2 -3
- data/spec/osakaexpectations_spec.rb +26 -0
- data/spec/pages_spec.rb +8 -8
- data/spec/remotecontrol_spec.rb +411 -0
- data/spec/scriptrunner_spec.rb +12 -0
- data/spec/textedit_spec.rb +2 -2
- data/spec/typicalapplication_spec.rb +195 -221
- data/spec/typicalprintdialog_spec.rb +33 -0
- data/spec/typicalsavedialog_spec.rb +51 -0
- metadata +10 -5
- data/lib/osaka/applicationwrapperexpectations.rb +0 -91
- data/spec/applicationwrapper_spec.rb +0 -296
@@ -0,0 +1,411 @@
|
|
1
|
+
|
2
|
+
require 'osaka'
|
3
|
+
|
4
|
+
describe "Osaka::RemoteControl" do
|
5
|
+
|
6
|
+
include(*Osaka::OsakaExpectations)
|
7
|
+
|
8
|
+
name = "ApplicationName"
|
9
|
+
|
10
|
+
subject { Osaka::RemoteControl.new(name) }
|
11
|
+
let(:control) { subject }
|
12
|
+
|
13
|
+
before (:each) do
|
14
|
+
Osaka::ScriptRunner.enable_debug_prints
|
15
|
+
end
|
16
|
+
|
17
|
+
after (:each) do
|
18
|
+
Osaka::ScriptRunner.disable_debug_prints
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def expect_execute_and_warning_for(action)
|
23
|
+
expect_execute_osascript.and_return("An Error")
|
24
|
+
subject.should_receive(:puts).with(/#{action}/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "Should be able to print warning messages" do
|
28
|
+
subject.should_receive(:puts).with("Osaka WARNING while doing ThisAction: Message")
|
29
|
+
subject.print_warning("ThisAction", "Message")
|
30
|
+
end
|
31
|
+
|
32
|
+
context "Query things from the OS" do
|
33
|
+
|
34
|
+
it "Should be possible to check whether an application is still running" do
|
35
|
+
expect_execute_osascript("tell application \"System Events\"; (name of processes) contains \"#{name}\"; end tell").and_return("false")
|
36
|
+
subject.running?.should be_false
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Can get the OS version (lion)" do
|
40
|
+
expect_execute_osascript("system version of (system info)").and_return("10.7.4\n")
|
41
|
+
subject.mac_version.should == :lion
|
42
|
+
subject.mac_version_string.should == "10.7.4"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "Can get the OS version (mountain lion)" do
|
46
|
+
expect_execute_osascript("system version of (system info)").and_return("10.8\n")
|
47
|
+
subject.mac_version.should == :mountain_lion
|
48
|
+
end
|
49
|
+
|
50
|
+
it "Can get the OS version (snow leopard)" do
|
51
|
+
expect_execute_osascript("system version of (system info)").and_return("10.6\n")
|
52
|
+
subject.mac_version.should == :snow_leopard
|
53
|
+
end
|
54
|
+
|
55
|
+
it "Can get the OS version (snow leopard)" do
|
56
|
+
expect_execute_osascript("system version of (system info)").and_return("1\n")
|
57
|
+
subject.mac_version.should == :other
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "Able to compare different remote controls" do
|
62
|
+
|
63
|
+
it "Should be able to clone controls" do
|
64
|
+
subject.set_current_window "Window"
|
65
|
+
new_control = subject.clone
|
66
|
+
new_control.should == subject
|
67
|
+
new_control.should_not equal(subject)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "Should be having different current window instances when cloning" do
|
71
|
+
subject.set_current_window "Window"
|
72
|
+
new_control = subject.clone
|
73
|
+
new_control.set_current_window "Not the same"
|
74
|
+
subject.current_window_name.should_not == new_control.current_window_name
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
it "Should be able to compare objects using names" do
|
79
|
+
subject.should == Osaka::RemoteControl.new(name)
|
80
|
+
subject.should_not == Osaka::RemoteControl.new("otherName")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "Should be able to compare objects using window" do
|
84
|
+
equal_object = Osaka::RemoteControl.new(name)
|
85
|
+
unequal_object = Osaka::RemoteControl.new(name)
|
86
|
+
equal_object.set_current_window("Window")
|
87
|
+
subject.set_current_window("Window")
|
88
|
+
unequal_object.set_current_window "Another Window"
|
89
|
+
|
90
|
+
subject.should == equal_object
|
91
|
+
subject.should_not == unequal_object
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "Basic control functionality of telling and sending system events" do
|
96
|
+
|
97
|
+
quoted_name = "\"#{name}\""
|
98
|
+
|
99
|
+
it "Should be able to tell applications to do something" do
|
100
|
+
expect_execute_osascript("tell application #{quoted_name}; command; end tell")
|
101
|
+
subject.tell("command")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "Can also pass multi-line commands to telling an application what to do" do
|
105
|
+
expect_execute_osascript("tell application #{quoted_name}; command1; command2; end tell")
|
106
|
+
subject.tell("command1; command2")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "Should be able to generate events via the Systems Events" do
|
110
|
+
expect_execute_osascript(/tell application "System Events"; tell process #{quoted_name}; quit; end tell; end tell/)
|
111
|
+
subject.system_event!("quit")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "Should be able to generate events via the Systems Events (with activate)" do
|
115
|
+
expect_activate
|
116
|
+
expect_system_event!("quit")
|
117
|
+
subject.system_event("quit")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "Check whether things exist or not" do
|
122
|
+
|
123
|
+
it "Should be able to check whether a location exists" do
|
124
|
+
expect_execute_osascript(/exists button 1/).and_return("true\n")
|
125
|
+
subject.exists?(at.button(1)).should be_true
|
126
|
+
end
|
127
|
+
|
128
|
+
it "Should be able to check whether a location does not exists" do
|
129
|
+
expect_execute_osascript(/not exists window 1/).and_return("true\n")
|
130
|
+
subject.not_exists?(at.window(1)).should be_true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "Waiting and doing until elements exist or not" do
|
135
|
+
|
136
|
+
it "Should be able to wait for only one location to exist" do
|
137
|
+
expect_exists?(at.button(1)).and_return(false, false, true)
|
138
|
+
subject.wait_until_exists!(at.button(1)).should == at.button(1)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "Should be able to wait for only one location to exist (with activate)" do
|
142
|
+
expect_activate
|
143
|
+
expect_exists?(at.button(1)).and_return(false, false, true)
|
144
|
+
subject.wait_until_exists(at.button(1)).should == at.button(1)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "Should be able to wait until multiple locations exists and return the one that happened" do
|
148
|
+
expect_exists?(at.button(1)).and_return(false, false, false)
|
149
|
+
expect_exists?(at.sheet(5)).and_return(false, false, true)
|
150
|
+
subject.wait_until_exists!(at.button(1), at.sheet(5)).should == at.sheet(5)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "Should be able to wait until multiple locations exists and return the one that happened (with activate)" do
|
154
|
+
expect_activate
|
155
|
+
expect_exists?(at.button(1)).and_return(false, false)
|
156
|
+
expect_exists?(at.sheet(5)).and_return(false, true)
|
157
|
+
subject.wait_until_exists(at.button(1), at.sheet(5)).should == at.sheet(5)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "Should be able to wait for one location to NOT exist" do
|
161
|
+
expect_not_exists?(at.button(1)).and_return(false, false, true)
|
162
|
+
subject.wait_until_not_exists!(at.button(1)).should == at.button(1)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "Should be able to wait for one location to NOT exist (with activate)" do
|
166
|
+
expect_activate
|
167
|
+
expect_not_exists?(at.button(4)).and_return(false, true)
|
168
|
+
subject.wait_until_not_exists(at.button(4)).should == at.button(4)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "Should be able to loop over some script until something happens" do
|
172
|
+
Timeout.should_receive(:timeout).with(5).and_yield
|
173
|
+
expect_execute_osascript.and_return("false", "false", "true")
|
174
|
+
expect_activate.twice
|
175
|
+
|
176
|
+
|
177
|
+
subject.until_exists!(at.window(1)) {
|
178
|
+
subject.activate
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
it "Should print a proper error message when it times out while waiting for something" do
|
183
|
+
Timeout.should_receive(:timeout).with(5).and_raise(Timeout::Error.new)
|
184
|
+
lambda { subject.until_exists!(at.window(1)) }.should raise_error(Osaka::TimeoutError, "Timed out while waiting for: [window 1]")
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "Short convenient methods for different actions" do
|
189
|
+
|
190
|
+
it "Has a short-cut method for quitting" do
|
191
|
+
expect_keystroke("q", :command)
|
192
|
+
subject.quit
|
193
|
+
end
|
194
|
+
|
195
|
+
it "Should print an Warning message with the ScriptRunner returns text when doing activate" do
|
196
|
+
expect_execute_and_warning_for("activate")
|
197
|
+
subject.activate
|
198
|
+
end
|
199
|
+
|
200
|
+
it "Should be able to launch and deal with the warning" do
|
201
|
+
expect_execute_and_warning_for("launch")
|
202
|
+
subject.launch
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
context "Can send keystrokes to the application" do
|
209
|
+
|
210
|
+
it "Should be able to generate keystroke events" do
|
211
|
+
expect_execute_osascript(/keystroke "p"/).and_return("")
|
212
|
+
subject.keystroke!("p")
|
213
|
+
end
|
214
|
+
|
215
|
+
it "Should be able to generate return keystroke event" do
|
216
|
+
expect_execute_osascript(/keystroke return/).and_return("")
|
217
|
+
subject.keystroke!(:return)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "Prints a warning when keystroke results in some outputShould be able to generate keystroke events" do
|
221
|
+
expect_execute_and_warning_for("keystroke")
|
222
|
+
subject.keystroke!("p")
|
223
|
+
end
|
224
|
+
|
225
|
+
it "Should be able to keystroke and activate" do
|
226
|
+
expect_activate
|
227
|
+
expect_focus
|
228
|
+
expect_keystroke!("a")
|
229
|
+
subject.keystroke("a")
|
230
|
+
end
|
231
|
+
|
232
|
+
it "Should be able to do keystrokes with command down" do
|
233
|
+
expect_execute_osascript(/keystroke "p" using {command down}/).and_return("")
|
234
|
+
subject.keystroke!("p", :command)
|
235
|
+
end
|
236
|
+
|
237
|
+
it "Should be able to do keystrokes with option and command down" do
|
238
|
+
expect_execute_osascript(/keystroke "p" using {option down, command down}/).and_return("")
|
239
|
+
subject.keystroke!("p", [ :option, :command ])
|
240
|
+
end
|
241
|
+
|
242
|
+
it "Should be able to do a keystroke and wait until something happen in one easy line" do
|
243
|
+
expect_execute_osascript(/keystroke "p"/).and_return("")
|
244
|
+
expect_execute_osascript(/exists window 1/).and_return("true")
|
245
|
+
subject.keystroke!("p", []).wait_until_exists!(at.window(1))
|
246
|
+
end
|
247
|
+
|
248
|
+
it "Should be able to keystroke_and_wait_until_exists and activate" do
|
249
|
+
expect_activate
|
250
|
+
expect_focus
|
251
|
+
expect_execute_osascript(/keystroke "p"/).and_return("")
|
252
|
+
expect_execute_osascript(/exists window 1/).and_return("true")
|
253
|
+
subject.keystroke("p").wait_until_exists!(at.window(1))
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
context "Can send mouse clicks to the application" do
|
259
|
+
|
260
|
+
it "Should be able to do clicks" do
|
261
|
+
expect_execute_osascript(/click menu button "PDF"/).and_return("")
|
262
|
+
subject.click!(at.menu_button("PDF"))
|
263
|
+
end
|
264
|
+
|
265
|
+
it "Should be able to do click and activate" do
|
266
|
+
expect_activate
|
267
|
+
expect_click!("button")
|
268
|
+
subject.click("button")
|
269
|
+
end
|
270
|
+
|
271
|
+
it "Should be able to do clicks and wait until something happened in one easy line" do
|
272
|
+
expect_execute_osascript(/click/).and_return("")
|
273
|
+
expect_execute_osascript(/exists window 1/).and_return("true")
|
274
|
+
subject.click!("button").wait_until_exists!(at.window(1))
|
275
|
+
end
|
276
|
+
|
277
|
+
it "Should be able to click_and_wait_until_exists and activate" do
|
278
|
+
expect_activate
|
279
|
+
expect_execute_osascript(/click/).and_return("")
|
280
|
+
expect_execute_osascript(/exists window 1/).and_return("true")
|
281
|
+
subject.click("button").wait_until_exists!(at.window(1))
|
282
|
+
end
|
283
|
+
|
284
|
+
it "Should be able to click on menu bar items" do
|
285
|
+
expect_activate
|
286
|
+
expect_click!(at.menu_item("Hey").menu(1).menu_bar_item("File").menu_bar(1))
|
287
|
+
subject.click_menu_bar(at.menu_item("Hey"), "File")
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
context "Control should be able to set and get different application values" do
|
293
|
+
|
294
|
+
it "Should be able to set a value to an element" do
|
295
|
+
expect_system_event!(/set value of window 1 to "newvalue"/).and_return("")
|
296
|
+
subject.set!("value", at.window(1), "newvalue")
|
297
|
+
end
|
298
|
+
|
299
|
+
it "Prints a warning when setting and element and output is received" do
|
300
|
+
expect_execute_and_warning_for("set")
|
301
|
+
subject.set!("value", at.window(1), "newvalue")
|
302
|
+
end
|
303
|
+
|
304
|
+
it "Should be able to set to boolean values" do
|
305
|
+
expect_system_event!(/set value of window 1 to true/).and_return("")
|
306
|
+
subject.set!("value", at.window(1), true)
|
307
|
+
end
|
308
|
+
|
309
|
+
it "Should be able to get a value from an element" do
|
310
|
+
expect_system_event!(/get value of window 1/).and_return("1\n")
|
311
|
+
subject.get!("value", at.window(1)).should == "1"
|
312
|
+
end
|
313
|
+
|
314
|
+
it "Should use the locally stored window when that one is set." do
|
315
|
+
subject.set_current_window("1")
|
316
|
+
expect_system_event!(/get value of window \"1\"/).and_return("1\n")
|
317
|
+
subject.get!("value").should == "1"
|
318
|
+
end
|
319
|
+
|
320
|
+
it "Should combine the location and the window" do
|
321
|
+
subject.set_current_window("1")
|
322
|
+
expect_system_event!(/get value of dialog 2 of window "1"/).and_return("1\n")
|
323
|
+
subject.get!("value", at.dialog(2)).should == "1"
|
324
|
+
end
|
325
|
+
|
326
|
+
it "Should be able to get values from the application itself" do
|
327
|
+
expect_system_event!("get value").and_return("1\n")
|
328
|
+
subject.get_app!("value").should == "1"
|
329
|
+
end
|
330
|
+
|
331
|
+
it "Should be able to set a value and activate" do
|
332
|
+
expect_activate
|
333
|
+
expect_set!("value", at.window(1), "newvalue")
|
334
|
+
subject.set("value", at.window(1), "newvalue")
|
335
|
+
end
|
336
|
+
|
337
|
+
it "Should be able to get an empty array when requesting for the window list and there are none" do
|
338
|
+
expect_get_app!("windows").and_return("\n")
|
339
|
+
subject.window_list.should == []
|
340
|
+
end
|
341
|
+
|
342
|
+
it "Should be able get an array with one window name when there is exactly one window" do
|
343
|
+
expect_get_app!("windows").and_return("window one of application process process\n")
|
344
|
+
subject.window_list.should == ["one"]
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
describe "Dealing with base locations and window lists" do
|
350
|
+
|
351
|
+
it "Should be possible to pass a base location in the creation" do
|
352
|
+
subject = Osaka::RemoteControl.new("Application", at.window("Window"))
|
353
|
+
subject.base_location.should == at.window("Window")
|
354
|
+
end
|
355
|
+
|
356
|
+
it "Should be able to get an array of multiple window names" do
|
357
|
+
expect_get_app!("windows").and_return("window one of application process process, window two of application process process\n")
|
358
|
+
subject.window_list.should == ["one", "two"]
|
359
|
+
end
|
360
|
+
|
361
|
+
it "Should be able to focus the currently active window" do
|
362
|
+
subject.base_location = at.sheet(1).window("boo")
|
363
|
+
expect_system_event!("set value of attribute \"AXMain\" of window \"boo\" to true")
|
364
|
+
subject.focus!
|
365
|
+
end
|
366
|
+
|
367
|
+
it "Should initialize the current window when it is not focused yet" do
|
368
|
+
expect_window_list.and_return(["1"])
|
369
|
+
expect_focus!
|
370
|
+
subject.focus
|
371
|
+
subject.current_window_name.should == "1"
|
372
|
+
end
|
373
|
+
|
374
|
+
it "Should be able to extract the current window name also when the base location has more than just a window " do
|
375
|
+
subject.base_location = at.sheet(1).window("Window")
|
376
|
+
subject.current_window_name.should == "Window"
|
377
|
+
end
|
378
|
+
|
379
|
+
it "Shouldn't initialize current window when it is already set" do
|
380
|
+
subject.set_current_window("1")
|
381
|
+
expect_not_exists?(at.window("1")).and_return(false)
|
382
|
+
expect_focus!
|
383
|
+
|
384
|
+
subject.focus
|
385
|
+
subject.base_location.should == at.window("1")
|
386
|
+
end
|
387
|
+
|
388
|
+
it "Should re-initialize the current window when it doesn't exist anymore" do
|
389
|
+
subject.set_current_window("1")
|
390
|
+
expect_not_exists?(at.window("1")).and_return(true)
|
391
|
+
expect_window_list.and_return(["2"])
|
392
|
+
expect_focus!
|
393
|
+
|
394
|
+
subject.focus
|
395
|
+
subject.current_window_name.should == "2"
|
396
|
+
end
|
397
|
+
|
398
|
+
it "Should focus the current window when it doesn't have focus" do
|
399
|
+
subject.set_current_window("1")
|
400
|
+
expect_not_exists?(at.window("1")).and_return(false)
|
401
|
+
expect_focus!
|
402
|
+
subject.focus
|
403
|
+
end
|
404
|
+
|
405
|
+
it "Shouldn't focus when there is no window set at all" do
|
406
|
+
expect_window_list.and_return([""])
|
407
|
+
subject.focus
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|
411
|
+
end
|
data/spec/scriptrunner_spec.rb
CHANGED
@@ -32,6 +32,17 @@ describe "Osaka::ScriptRunner" do
|
|
32
32
|
Osaka::ScriptRunner::disable_debug_prints
|
33
33
|
end
|
34
34
|
|
35
|
+
it "Should be able to generate a script of the run for later debugging purposes" do
|
36
|
+
subject.should_receive(:do_system).and_return("Blah blah blah")
|
37
|
+
file = mock("Mocked output file")
|
38
|
+
File.should_receive(:open).with("output_script", File::WRONLY|File::APPEND|File::CREAT, 0755).and_yield(file)
|
39
|
+
file.should_receive(:puts).with("osascript -e \"random number\"")
|
40
|
+
Osaka::ScriptRunner.enable_debug_prints(:script, "output_script")
|
41
|
+
subject.execute("random number")
|
42
|
+
Osaka::ScriptRunner::disable_debug_prints
|
43
|
+
end
|
44
|
+
|
45
|
+
|
35
46
|
it "Should not print any debugging information by default " do
|
36
47
|
subject.should_receive(:do_system).and_return("")
|
37
48
|
subject.should_not_receive(:puts)
|
@@ -57,4 +68,5 @@ describe "Osaka::ScriptRunner" do
|
|
57
68
|
subject.should_receive(:do_system).with('osascript script.scpt a b c').and_return(true)
|
58
69
|
subject.execute_file("script.scpt", "a b c")
|
59
70
|
end
|
71
|
+
|
60
72
|
end
|
data/spec/textedit_spec.rb
CHANGED
@@ -3,11 +3,11 @@ require 'osaka'
|
|
3
3
|
|
4
4
|
describe "TextEdit" do
|
5
5
|
|
6
|
-
include(*Osaka::
|
6
|
+
include(*Osaka::OsakaExpectations)
|
7
7
|
|
8
8
|
subject { Osaka::TextEdit.new }
|
9
9
|
|
10
|
-
let(:
|
10
|
+
let(:control) { subject.control = mock("RemoteControl") }
|
11
11
|
|
12
12
|
it "Should be able to type some text" do
|
13
13
|
expect_keystroke('Hello World')
|