win_gui 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +43 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/book_code/early_success/bundle.rb +34 -0
- data/book_code/early_success/english.txt +1 -0
- data/book_code/early_success/jruby_basics.rb +47 -0
- data/book_code/early_success/windows_basics.rb +97 -0
- data/book_code/guessing/locknote.rb +379 -0
- data/book_code/guessing/monkeyshines.rb +14 -0
- data/book_code/guessing/note.rb +120 -0
- data/book_code/guessing/note_spec.rb +175 -0
- data/book_code/guessing/replay.rb +21 -0
- data/book_code/guessing/seed.rb +9 -0
- data/book_code/guessing/spec_helper.rb +69 -0
- data/book_code/guessing/windows_gui.rb +247 -0
- data/book_code/home_stretch/junquenote.rb +151 -0
- data/book_code/home_stretch/locknote.rb +180 -0
- data/book_code/home_stretch/note.rb +144 -0
- data/book_code/home_stretch/note_spec.rb +191 -0
- data/book_code/home_stretch/spec_helper.rb +55 -0
- data/book_code/home_stretch/swing_gui.rb +50 -0
- data/book_code/home_stretch/windows_gui.rb +232 -0
- data/book_code/junquenote/exports.sh +10 -0
- data/book_code/junquenote/jruby_mac.sh +10 -0
- data/book_code/junquenote/junquenote_app.rb +262 -0
- data/book_code/novite/Rakefile +10 -0
- data/book_code/novite/app/controllers/application.rb +18 -0
- data/book_code/novite/app/controllers/guests_controller.rb +28 -0
- data/book_code/novite/app/controllers/parties_controller.rb +77 -0
- data/book_code/novite/app/helpers/application_helper.rb +11 -0
- data/book_code/novite/app/helpers/guests_helper.rb +10 -0
- data/book_code/novite/app/helpers/parties_helper.rb +10 -0
- data/book_code/novite/app/models/guest.rb +11 -0
- data/book_code/novite/app/models/party.rb +32 -0
- data/book_code/novite/app/models/party_mailer.rb +19 -0
- data/book_code/novite/app/views/layouts/application.rhtml +44 -0
- data/book_code/novite/app/views/parties/new.html.erb +42 -0
- data/book_code/novite/app/views/parties/show.html.erb +43 -0
- data/book_code/novite/app/views/party_mailer/invite.erb +17 -0
- data/book_code/novite/config/boot.rb +117 -0
- data/book_code/novite/config/database.yml +19 -0
- data/book_code/novite/config/environment.rb +67 -0
- data/book_code/novite/config/environments/development.rb +29 -0
- data/book_code/novite/config/environments/production.rb +27 -0
- data/book_code/novite/config/environments/test.rb +30 -0
- data/book_code/novite/config/initializers/inflections.rb +18 -0
- data/book_code/novite/config/initializers/mime_types.rb +13 -0
- data/book_code/novite/config/routes.rb +47 -0
- data/book_code/novite/db/migrate/001_create_parties.rb +26 -0
- data/book_code/novite/db/migrate/002_create_guests.rb +23 -0
- data/book_code/novite/db/schema.rb +41 -0
- data/book_code/novite/log/empty.txt +0 -0
- data/book_code/novite/public/.htaccess +40 -0
- data/book_code/novite/public/404.html +38 -0
- data/book_code/novite/public/422.html +38 -0
- data/book_code/novite/public/500.html +38 -0
- data/book_code/novite/public/dispatch.cgi +10 -0
- data/book_code/novite/public/dispatch.fcgi +24 -0
- data/book_code/novite/public/dispatch.rb +18 -0
- data/book_code/novite/public/favicon.ico +0 -0
- data/book_code/novite/public/images/rails.png +0 -0
- data/book_code/novite/public/index.html +285 -0
- data/book_code/novite/public/javascripts/application.js +10 -0
- data/book_code/novite/public/javascripts/controls.js +971 -0
- data/book_code/novite/public/javascripts/dragdrop.js +980 -0
- data/book_code/novite/public/javascripts/effects.js +1128 -0
- data/book_code/novite/public/javascripts/prototype.js +4233 -0
- data/book_code/novite/public/robots.txt +5 -0
- data/book_code/novite/script/about +3 -0
- data/book_code/novite/script/console +3 -0
- data/book_code/novite/script/destroy +3 -0
- data/book_code/novite/script/generate +3 -0
- data/book_code/novite/script/performance/benchmarker +3 -0
- data/book_code/novite/script/performance/profiler +3 -0
- data/book_code/novite/script/performance/request +3 -0
- data/book_code/novite/script/plugin +3 -0
- data/book_code/novite/script/process/inspector +3 -0
- data/book_code/novite/script/process/reaper +3 -0
- data/book_code/novite/script/process/spawner +3 -0
- data/book_code/novite/script/runner +3 -0
- data/book_code/novite/script/server +3 -0
- data/book_code/novite/test/test_helper.rb +46 -0
- data/book_code/one_more_thing/applescript.rb +68 -0
- data/book_code/one_more_thing/note_spec.rb +50 -0
- data/book_code/one_more_thing/spec_helper.rb +17 -0
- data/book_code/one_more_thing/textedit-pure.rb +28 -0
- data/book_code/one_more_thing/textedit.applescript +26 -0
- data/book_code/one_more_thing/textedit.rb +32 -0
- data/book_code/one_more_thing/textnote.rb +87 -0
- data/book_code/simplify/junquenote.rb +48 -0
- data/book_code/simplify/locknote.rb +46 -0
- data/book_code/simplify/note.rb +35 -0
- data/book_code/simplify/note_spec.rb +28 -0
- data/book_code/simplify/swing_gui.rb +45 -0
- data/book_code/simplify/windows_gui.rb +232 -0
- data/book_code/simplify/windows_gui_spec.rb +35 -0
- data/book_code/story/invite.story +19 -0
- data/book_code/story/journal.txt +29 -0
- data/book_code/story/novite_stories.rb +156 -0
- data/book_code/story/party.rb +149 -0
- data/book_code/story/password.rb +61 -0
- data/book_code/story/password.story +26 -0
- data/book_code/story/rsvp.story +29 -0
- data/book_code/tables/TestTime.html +93 -0
- data/book_code/tables/TestTimeSample.html +63 -0
- data/book_code/tables/calculate_time.rb +39 -0
- data/book_code/tables/calculator.rb +108 -0
- data/book_code/tables/calculator_actions.rb +27 -0
- data/book_code/tables/calculator_spec.rb +47 -0
- data/book_code/tables/fit.rb +32 -0
- data/book_code/tables/matrix.rb +109 -0
- data/book_code/tables/pseudocode.rb +17 -0
- data/book_code/tubes/book_selenium.rb +67 -0
- data/book_code/tubes/book_watir.rb +60 -0
- data/book_code/tubes/dragdrop.html +81 -0
- data/book_code/tubes/html_capture.rb +33 -0
- data/book_code/tubes/joke_list.rb +67 -0
- data/book_code/tubes/list_spec.rb +41 -0
- data/book_code/tubes/search_spec.rb +32 -0
- data/book_code/tubes/selenium_example.rb +66 -0
- data/book_code/tubes/selenium_link.rb +23 -0
- data/book_code/tubes/web_server.rb +14 -0
- data/book_code/windows/wgui.rb +29 -0
- data/book_code/windows/wobj.rb +25 -0
- data/book_code/windows/wsh.rb +25 -0
- data/book_code/with_rspec/empty_spec.rb +13 -0
- data/book_code/with_rspec/junquenote.rb +60 -0
- data/book_code/with_rspec/locknote.rb +129 -0
- data/book_code/with_rspec/note_spec.rb +32 -0
- data/book_code/with_rspec/should_examples.rb +18 -0
- data/exp/exp.rb +6 -0
- data/exp/exp_encodings.rb +40 -0
- data/exp/exp_enum_windows.rb +60 -0
- data/exp/exp_quik.rb +38 -0
- data/exp/exp_wsh.rb +115 -0
- data/exp/old/windows_basics.rb +80 -0
- data/exp/old/wnote.rb +80 -0
- data/exp/old/wnote_spec.rb +20 -0
- data/features/step_definitions/win_gui_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/features/win_gui.feature +9 -0
- data/lib/note/java/jemmy.jar +0 -0
- data/lib/note/java/jnote.rb +48 -0
- data/lib/note/java/jruby_basics.rb +37 -0
- data/lib/note/java/junquenote_app.rb +262 -0
- data/lib/note/java/note_spec.rb +20 -0
- data/lib/note/win/locknote.rb +19 -0
- data/lib/note.rb +15 -0
- data/lib/win_gui/constants.rb +66 -0
- data/lib/win_gui/string_extensions.rb +24 -0
- data/lib/win_gui/win_gui.rb +274 -0
- data/lib/win_gui/window.rb +70 -0
- data/lib/win_gui.rb +3 -0
- data/spec/note/win/locknote_spec.rb +7 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/test_apps/locknote/LockNote.exe +0 -0
- data/spec/win_gui/string_extensions_spec.rb +61 -0
- data/spec/win_gui/win_gui_spec.rb +733 -0
- data/spec/win_gui/window_spec.rb +124 -0
- metadata +251 -0
@@ -0,0 +1,733 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper" )
|
2
|
+
|
3
|
+
module GuiTest
|
4
|
+
|
5
|
+
# def enum_callback
|
6
|
+
# @enum_callback ||= callback('LP', 'I'){|handle, message| true }
|
7
|
+
# end
|
8
|
+
|
9
|
+
describe WinGui, ' defines wrappers for Win32::API functions' do
|
10
|
+
|
11
|
+
context 'defining a valid API function' do
|
12
|
+
before(:each) { hide_method :find_window_w } # hide original method if it is defined
|
13
|
+
after(:each) { restore_method :find_window_w } # restore original method if it was hidden
|
14
|
+
|
15
|
+
spec{ use{ WinGui.def_api('FindWindowW', 'PP', 'L', :rename => nil, :boolean => nil, :zeronil => nil, &any_block) }}
|
16
|
+
|
17
|
+
it 'defines new instance method with appropriate name' do
|
18
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
19
|
+
respond_to?(:find_window_w).should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'constructs argument prototype from uppercase string' do
|
23
|
+
expect { WinGui.def_api 'FindWindowW', 'PP', 'L' }.to_not raise_error
|
24
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
25
|
+
expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'constructs argument prototype from lowercase string' do
|
29
|
+
expect { WinGui.def_api 'FindWindowW', 'pp', 'l' }.to_not raise_error
|
30
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
31
|
+
expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'constructs argument prototype from (mixedcase) array' do
|
35
|
+
expect { WinGui.def_api 'FindWindowW', ['p', 'P'], 'L' }.to_not raise_error
|
36
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
37
|
+
expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count'
|
38
|
+
end
|
39
|
+
|
40
|
+
it ':rename option overrides standard name for defined method' do
|
41
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L', :rename=> 'my_own_find'
|
42
|
+
expect {find_window_w(nil, nil)}.to raise_error
|
43
|
+
expect {my_own_find(nil, nil)}.to_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'defined method works properly when called with a valid args' do
|
47
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
48
|
+
expect {find_window_w(nil, nil)}.to_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'defined method returns expected value when called' do
|
52
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
53
|
+
test_app do |app|
|
54
|
+
find_window_w(nil, TEST_WIN_TITLE.to_w).should_not == 0
|
55
|
+
find_window_w(TEST_WIN_CLASS.to_w, nil).should_not == 0
|
56
|
+
end
|
57
|
+
find_window_w(nil, nil).should_not == 0
|
58
|
+
find_window_w(nil, TEST_IMPOSSIBLE).should == 0
|
59
|
+
find_window_w(TEST_IMPOSSIBLE, nil).should == 0
|
60
|
+
find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'defined method enforces the argument count when called' do
|
64
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
65
|
+
expect { find_window_w }.to raise_error 'Invalid args count'
|
66
|
+
expect { find_window_w(nil) }.to raise_error 'Invalid args count'
|
67
|
+
expect { find_window_w('Str') }.to raise_error 'Invalid args count'
|
68
|
+
expect { find_window_w([nil, nil]) }.to raise_error 'Invalid args count'
|
69
|
+
expect { find_window_w('Str', 'Str', 'Str') }.to raise_error 'Invalid args count'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'defined method called with (:api) argument returns underlying Win32::API object' do
|
73
|
+
WinGui.def_api 'FindWindowW', 'PP', 'L'
|
74
|
+
expect {@api = find_window_w(:api)}.to_not raise_error
|
75
|
+
@api.dll_name.should == 'user32' # The name of the DLL that exports the API function
|
76
|
+
@api.effective_function_name.should == 'FindWindowW' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
|
77
|
+
@api.function_name.should == 'FindWindowW' # The name of the function passed to the constructor
|
78
|
+
@api.prototype.should == ['P', 'P'] # The prototype, returned as an array of characters
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'auto-defining Ruby-like boolean methods if API function name starts with "Is_"' do
|
83
|
+
before(:each) do
|
84
|
+
hide_method :window?
|
85
|
+
WinGui.def_api 'IsWindow', 'L', 'L'
|
86
|
+
end
|
87
|
+
after(:each) { restore_method :window? }
|
88
|
+
|
89
|
+
it 'defines new instance method name dropping Is_ and adding ?' do
|
90
|
+
respond_to?(:window?).should be_true
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'defined method returns true instead of non-zero' do
|
94
|
+
window?(any_handle).should == true
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'defined method returns false instead of zero' do
|
98
|
+
window?(123).should == false
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'defined method enforces the argument count' do
|
102
|
+
expect {window?}.to raise_error 'Invalid args count'
|
103
|
+
expect {window?(123, nil)}.to raise_error 'Invalid args count'
|
104
|
+
expect {window?(nil, nil)}.to raise_error 'Invalid args count'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'defining API with :boolean option converts result to boolean' do
|
109
|
+
before(:each) do
|
110
|
+
hide_method :show_window
|
111
|
+
WinGui.def_api 'ShowWindow', 'LI', 'I', :boolean => true
|
112
|
+
end
|
113
|
+
after(:each) { restore_method :show_window }
|
114
|
+
|
115
|
+
it 'defines new instance method' do
|
116
|
+
respond_to?(:show_window).should be_true
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'defined method returns true instead of non-zero' do
|
120
|
+
test_app {|app| show_window(app.handle, SW_SHOWNA).should == true }
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'defined method returns false instead of zero' do
|
124
|
+
test_app do |app|
|
125
|
+
show_window(app.handle, SW_HIDE)
|
126
|
+
show_window(app.handle, SW_HIDE).should == false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'defined method enforces the argument count' do
|
131
|
+
test_app do |app|
|
132
|
+
expect {show_window}.to raise_error 'Invalid args count'
|
133
|
+
expect {show_window(app.handle, SW_HIDE, nil)}.to raise_error 'Invalid args count'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'defining API with :zeronil option converts zero result to nil' do
|
139
|
+
before(:each) do
|
140
|
+
hide_method :show_window
|
141
|
+
WinGui.def_api 'ShowWindow', 'LI', 'I', :zeronil => true
|
142
|
+
end
|
143
|
+
after(:each) { restore_method :show_window }
|
144
|
+
|
145
|
+
it 'defines new instance method' do
|
146
|
+
respond_to?(:show_window).should be_true
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'defined method returns nil (but NOT false) instead of zero' do
|
150
|
+
test_app do |app|
|
151
|
+
show_window(app.handle, SW_HIDE)
|
152
|
+
show_window(app.handle, SW_HIDE).should == nil
|
153
|
+
show_window(app.handle, SW_HIDE).should_not == false
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'defined method does not return true when result is non-zero' do
|
158
|
+
test_app do |app|
|
159
|
+
result = show_window(app.handle, SW_SHOWNA)
|
160
|
+
result.should_not == 0
|
161
|
+
result.should_not == true
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'defined method enforces the argument count' do
|
166
|
+
test_app do |app|
|
167
|
+
expect {show_window}.to raise_error 'Invalid args count'
|
168
|
+
expect {show_window(app.handle, SW_HIDE, nil)}.to raise_error 'Invalid args count'
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'trying to define an invalid API function' do
|
174
|
+
it 'raises error when trying to define function with a wrong function name' do
|
175
|
+
expect { WinGui.def_api 'FindWindowImpossible', 'PP', 'L' }.
|
176
|
+
to raise_error( /Unable to load function 'FindWindowImpossible'/ )
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'defining API function using definition blocks' do
|
181
|
+
before(:each) { hide_method :get_window_text } # hide original method if it is defined
|
182
|
+
after(:each) { restore_method :get_window_text } # restore original method if it was hidden
|
183
|
+
|
184
|
+
it 'defines new instance method' do
|
185
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
186
|
+
end
|
187
|
+
respond_to?(:get_window_text).should be_true
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'does not enforce argument count outside of block' do
|
191
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
192
|
+
end
|
193
|
+
expect { get_window_text }.to_not raise_error 'Invalid args count'
|
194
|
+
expect { get_window_text(nil) }.to_not raise_error 'Invalid args count'
|
195
|
+
expect { get_window_text(nil, 'Str') }.to_not raise_error 'Invalid args count'
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'returns block return value when defined method is called' do
|
199
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
200
|
+
'Value'
|
201
|
+
end
|
202
|
+
get_window_text(nil).should == 'Value'
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'passes arguments and underlying Win32::API object to the block' do
|
206
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
207
|
+
@api=api; @args = args
|
208
|
+
end
|
209
|
+
get_window_text(1, 2, 3)
|
210
|
+
@args.should == [1, 2, 3]
|
211
|
+
@api.function_name.should == 'GetWindowText' # The name of the function passed to the constructor
|
212
|
+
end
|
213
|
+
|
214
|
+
it ':rename option overrides standard name for defined method' do
|
215
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L', :rename => 'my_name' do |api, *args|
|
216
|
+
end
|
217
|
+
expect {get_window_text(nil, nil, nil)}.to raise_error
|
218
|
+
expect {my_name(nil, nil)}.to_not raise_error
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'calling defined method with (:api) argument returns underlying Win32::API object' do
|
222
|
+
WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args|
|
223
|
+
end
|
224
|
+
expect {@api = get_window_text(:api)}.to_not raise_error
|
225
|
+
@api.dll_name.should == 'user32' # The name of the DLL that exports the API function
|
226
|
+
@api.effective_function_name.should == 'GetWindowTextA' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
|
227
|
+
@api.function_name.should == 'GetWindowText' # The name of the function passed to the constructor
|
228
|
+
@api.prototype.should == ['L', 'P', 'L'] # The prototype, returned as an array of characters
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'providing API function with callback' do
|
233
|
+
# before(:each) { hide_method :enum_windows } # hide original find_window method if it is defined
|
234
|
+
# after(:each) { restore_method :enum_window } # restore original find_window method if it was hidden
|
235
|
+
#
|
236
|
+
it '#callback method creates a valid callback object' do
|
237
|
+
pending 'callback is now a class method of WinGui, not available here (exept through module_eval)'
|
238
|
+
expect { @callback = callback('LP', 'I') {|handle, message| true} }.to_not raise_error
|
239
|
+
@callback.should be_a_kind_of(Win32::API::Callback)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'created callback object can be used as a valid arg of API function expecting callback' do
|
243
|
+
pending 'API changed - callback arg is no longer valid, block is used instead'
|
244
|
+
# WinGui.def_api 'EnumWindows', 'KP', 'L'
|
245
|
+
expect { enum_windows(enum_callback, 'Message') }.to_not raise_error
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'defined API functions expecting callback recognize/accept blocks' do
|
249
|
+
pending ' API is not exactly clear atm (what about prototype?)(.with_callback method?)'
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe WinGui, ' contains a set of pre-defined GUI functions' do
|
255
|
+
describe '#window?' do
|
256
|
+
spec{ use{ window?(handle = 0) }}
|
257
|
+
# Tests whether the specified window handle identifies an existing window.
|
258
|
+
# A thread should not use IsWindow for a window that it did not create because the window could be destroyed after this
|
259
|
+
# function was called. Further, because window handles are recycled the handle could even point to a different window.
|
260
|
+
|
261
|
+
it 'returns true if window exists' do
|
262
|
+
test_app do |app|
|
263
|
+
window?(app.handle).should == true
|
264
|
+
window?(app.textarea.handle).should == true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'returns false if window does not exist' do
|
269
|
+
test_app do |app|
|
270
|
+
@app_handle = app.handle
|
271
|
+
@ta_handle = app.textarea.handle
|
272
|
+
end
|
273
|
+
window?(@app_handle).should == false
|
274
|
+
window?(@ta_handle).should == false
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe '#window_visible?' do
|
279
|
+
spec{ use{ window_visible?(handle = any_handle) }}
|
280
|
+
spec{ use{ visible?(handle = any_handle) }}
|
281
|
+
# Tests if the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style.
|
282
|
+
# Because the return value specifies whether the window has the WS_VISIBLE style, it may be true even if the window is totally obscured by other windows.
|
283
|
+
|
284
|
+
it 'returns true if window is visible' do
|
285
|
+
test_app do |app|
|
286
|
+
visible?(app.handle).should == true
|
287
|
+
window_visible?(app.handle).should == true
|
288
|
+
window_visible?(app.textarea.handle).should == true
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'returns false if window is not visible' do
|
293
|
+
test_app do |app|
|
294
|
+
hide_window(app.handle)
|
295
|
+
visible?(app.handle).should == false
|
296
|
+
window_visible?(app.handle).should == false
|
297
|
+
window_visible?(app.textarea.handle).should == false
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe '#maximized?' do
|
303
|
+
spec{ use{ zoomed?(handle = 0) }}
|
304
|
+
spec{ use{ maximized?(handle = 0) }}
|
305
|
+
# Tests whether the specified window is maximized.
|
306
|
+
|
307
|
+
it 'returns false if window is not maximized' do
|
308
|
+
test_app do |app|
|
309
|
+
zoomed?(app.handle).should == false
|
310
|
+
maximized?(app.handle).should == false
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'returns true if the window is maximized' do
|
315
|
+
test_app do |app|
|
316
|
+
show_window(app.handle, SW_MAXIMIZE)
|
317
|
+
maximized?(app.handle).should == true
|
318
|
+
zoomed?(app.handle).should == true
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe '#minimized?' do
|
324
|
+
spec{ use{ iconic?(handle = 0) }}
|
325
|
+
spec{ use{ minimized?(handle = 0) }}
|
326
|
+
# Tests whether the specified window is minimized.
|
327
|
+
|
328
|
+
it 'returns false if window is not minimized' do
|
329
|
+
test_app do |app|
|
330
|
+
iconic?(app.handle).should == false
|
331
|
+
minimized?(app.handle).should == false
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'returns true if the window is minimized' do
|
336
|
+
test_app do |app|
|
337
|
+
show_window(app.handle, SW_MINIMIZE)
|
338
|
+
iconic?(app.handle).should == true
|
339
|
+
minimized?(app.handle).should == true
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
describe '#child?' do
|
345
|
+
spec{ use{ child?(parent_handle = any_handle, handle = any_handle) }}
|
346
|
+
# Tests whether a window is a child (or descendant) window of a specified parent window. A child window is the direct descendant
|
347
|
+
# of a specified parent window if that parent window is in the chain of parent windows; the chain of parent windows leads from
|
348
|
+
# the original overlapped or pop-up window to the child window.
|
349
|
+
|
350
|
+
it 'returns true if the window is a child' do
|
351
|
+
test_app do |app|
|
352
|
+
child?(app.handle, app.textarea.handle).should == true
|
353
|
+
end
|
354
|
+
end
|
355
|
+
it 'returns false if window is not a child' do
|
356
|
+
test_app do |app|
|
357
|
+
child?(app.handle, any_handle).should == false
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
describe '#find_window' do
|
363
|
+
spec{ use{ find_window(class_name = nil, win_name = nil) }}
|
364
|
+
|
365
|
+
it 'returns either Integer Window handle or nil' do
|
366
|
+
find_window(nil, nil).should be_a_kind_of Integer
|
367
|
+
nil.class.should === find_window(TEST_IMPOSSIBLE, nil)
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'returns nil if Window is not found' do
|
371
|
+
find_window(TEST_IMPOSSIBLE, nil).should == nil
|
372
|
+
find_window(nil, TEST_IMPOSSIBLE).should == nil
|
373
|
+
find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'finds at least one window if both args are nils' do
|
377
|
+
find_window(nil, nil).should_not == nil
|
378
|
+
end
|
379
|
+
|
380
|
+
it 'finds top-level window by window class' do
|
381
|
+
test_app {|app| find_window(TEST_WIN_CLASS, nil).should == app.handle }
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'finds top-level window by title' do
|
385
|
+
test_app {|app| find_window(nil, TEST_WIN_TITLE).should == app.handle }
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
describe '#find_window_w' do
|
390
|
+
spec{ use{ find_window_w(class_name = nil, win_name = nil) }}
|
391
|
+
|
392
|
+
it 'returns zero if Window is not found' do
|
393
|
+
find_window_w(TEST_IMPOSSIBLE, nil).should == nil
|
394
|
+
find_window_w(nil, TEST_IMPOSSIBLE).should == nil
|
395
|
+
find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil
|
396
|
+
end
|
397
|
+
|
398
|
+
it 'finds at least one window if given two nils' do
|
399
|
+
find_window_w(nil, nil).should_not == nil
|
400
|
+
end
|
401
|
+
|
402
|
+
it 'finds top-level window by window class' do
|
403
|
+
test_app {|app| find_window_w(TEST_WIN_CLASS.to_w, nil).should == app.handle }
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'finds top-level window by title' do
|
407
|
+
test_app {|app| find_window_w(nil, TEST_WIN_TITLE.to_w).should == app.handle }
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
describe '#find_window_ex' do
|
412
|
+
spec{ use{ control_handle = find_window_ex(parent = any_handle, after_child = 0, win_class = nil, win_title = nil) }}
|
413
|
+
|
414
|
+
it 'returns nil if wrong control is given' do
|
415
|
+
parent_handle = any_handle
|
416
|
+
find_window_ex(parent_handle, 0, TEST_IMPOSSIBLE, nil).should == nil
|
417
|
+
find_window_ex(parent_handle, 0, nil, TEST_IMPOSSIBLE).should == nil
|
418
|
+
end
|
419
|
+
|
420
|
+
it 'finds child window/control by class' do
|
421
|
+
test_app do |app|
|
422
|
+
ta_handle = find_window_ex(app.handle, 0, TEST_TEXTAREA_CLASS, nil)
|
423
|
+
ta_handle.should_not == nil
|
424
|
+
ta_handle.should == app.textarea.handle
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'finds child window/control by text/title' do
|
429
|
+
pending 'Identify appropriate (short name) control'
|
430
|
+
test_app do |app|
|
431
|
+
keystroke(VK_CONTROL, 'A'.ord)
|
432
|
+
keystroke('1'.ord, '2'.ord)
|
433
|
+
ta_handle = find_window_ex(app.handle, 0, nil, '12')
|
434
|
+
ta_handle.should_not == 0
|
435
|
+
ta_handle.should == app.textarea.handle
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
describe '#get_window_thread_process_id' do
|
441
|
+
spec{ use{ thread, process = get_window_thread_process_id(handle = any_handle) }}
|
442
|
+
# Improved with block to accept window handle as a single arg and return a pair of [thread, process]
|
443
|
+
|
444
|
+
it 'returns a pair of nonzero Integer ids (window thread and process)' do
|
445
|
+
thread, process = get_window_thread_process_id(handle = any_handle)
|
446
|
+
thread.should be_a_kind_of Integer
|
447
|
+
thread.should be > 0
|
448
|
+
process.should be_a_kind_of Integer
|
449
|
+
process.should be > 0
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
describe '#get_window_text' do
|
454
|
+
spec{ use{ text = get_window_text(handle = 0)}}
|
455
|
+
# Improved with block to accept window handle as a single arg and return (rstripped) text string
|
456
|
+
|
457
|
+
it 'returns correct window text' do
|
458
|
+
test_app {|app| get_window_text(app.handle).should == TEST_WIN_TITLE }
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
describe '#get_window_text_w' do
|
463
|
+
spec{ use{ class_name = get_window_text_w(handle = 0)}} # result encoded as utf-8
|
464
|
+
# Unicode version of get_window_text (strings returned encoded as utf-8)
|
465
|
+
|
466
|
+
it 'returns correct window text' do
|
467
|
+
test_app {|app| get_window_text_w(app.handle).should == TEST_WIN_TITLE }
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
describe '#get_class_name' do
|
472
|
+
spec{ use{ class_name = get_class_name(handle = 0)}}
|
473
|
+
# Improved with block to accept window handle as a single arg and return class name string
|
474
|
+
|
475
|
+
it 'returns correct window class name' do
|
476
|
+
test_app {|app| get_class_name(app.handle).should == TEST_WIN_CLASS }
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
describe '#get_class_name_w' do
|
481
|
+
spec{ use{ class_name = get_class_name_w(handle = 0)}} # result encoded as utf-8
|
482
|
+
# Unicode version of get_class_name (strings returned encoded as utf-8)
|
483
|
+
|
484
|
+
it 'returns correct window class name' do
|
485
|
+
test_app {|app| get_class_name_w(app.handle).should == TEST_WIN_CLASS }
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
describe '#get_window_rect' do
|
490
|
+
spec{ use{ left, top, right, bottom = get_window_rect(any_handle)}}
|
491
|
+
|
492
|
+
it 'returns windows rectangle' do
|
493
|
+
test_app do |app|
|
494
|
+
get_window_rect(app.handle).should == TEST_WIN_RECT
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
describe '#show_window ', 'LI', 'I' do
|
500
|
+
spec{ use{ was_visible = show_window(handle = any_handle, cmd = SW_SHOWNA) }}
|
501
|
+
|
502
|
+
it 'was_visible = hide_window(handle = any_handle) # alias method (not a separate API function)' do
|
503
|
+
test_app do |app|
|
504
|
+
use{ hide_window(app.handle) }
|
505
|
+
visible?(app.handle).should == false
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'returns true if the window was PREVIOUSLY visible' do
|
510
|
+
test_app {|app| show_window(app.handle, SW_HIDE).should == true }
|
511
|
+
end
|
512
|
+
|
513
|
+
it 'returns false if the window was PREVIOUSLY not visible' do
|
514
|
+
test_app do |app|
|
515
|
+
show_window(app.handle, SW_HIDE)
|
516
|
+
show_window(app.handle, SW_HIDE).should == false
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
it 'SW_HIDE command hides window' do
|
521
|
+
test_app do |app|
|
522
|
+
show_window(app.handle, SW_HIDE)
|
523
|
+
visible?(app.handle).should == false
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
it 'SW_SHOW command shows hidden window' do
|
528
|
+
test_app do |app|
|
529
|
+
show_window(app.handle, SW_HIDE)
|
530
|
+
show_window(app.handle, SW_SHOW)
|
531
|
+
visible?(app.handle).should == true
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
it 'SW_MAXIMIZE maximizes window' do
|
536
|
+
test_app do |app|
|
537
|
+
show_window(app.handle, SW_MAXIMIZE)
|
538
|
+
maximized?(app.handle).should == true
|
539
|
+
end
|
540
|
+
pending 'Need to make sure window is maximized but NOT activated '
|
541
|
+
end
|
542
|
+
|
543
|
+
it 'SW_MINIMIZE minimizes window and activates the next top-level window in the Z order' do
|
544
|
+
test_app do |app|
|
545
|
+
show_window(app.handle, SW_MINIMIZE)
|
546
|
+
minimized?(app.handle).should == true
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'SW_SHOWMAXIMIZED activates the window and displays it as a maximized window' do
|
551
|
+
pending 'Need to make sure window is maximized AND activated '
|
552
|
+
test_app do |app|
|
553
|
+
show_window(app.handle, SW_SHOWMAXIMIZED)
|
554
|
+
get_window_rect(app.handle)
|
555
|
+
#.should == TEST_MAX_RECT
|
556
|
+
end
|
557
|
+
|
558
|
+
end
|
559
|
+
it 'SW_SHOWMINIMIZED activates the window and displays it as a minimized window' do
|
560
|
+
pending 'Need to make sure window is minimized AND activated '
|
561
|
+
test_app do |app|
|
562
|
+
show_window(app.handle, SW_SHOWMINIMIZED)
|
563
|
+
p get_window_rect(app.handle)
|
564
|
+
#.should == TEST_MAX_RECT
|
565
|
+
end
|
566
|
+
|
567
|
+
end
|
568
|
+
it 'SW_SHOWMINNOACTIVE displays the window as a minimized window (similar to SW_SHOWMINIMIZED, but window is not activated)'
|
569
|
+
it 'SW_SHOWNA displays the window in its current size and position (similar to SW_SHOW, but window is not activated)'
|
570
|
+
it 'SW_SHOWNOACTIVATE displays the window in its current size and position (similar to SW_SHOW, but window is not activated)'
|
571
|
+
it 'SW_SHOWNORMAL activates and displays a window. Restores minimized/maximized window to original size/position. Use it to show window for the first time'
|
572
|
+
it 'SW_RESTORE activates and displays the window. Restores minimized/maximized window to original size/position. Use it to restore minimized windows'
|
573
|
+
it 'SW_SHOWDEFAULT sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application'
|
574
|
+
it 'SW_FORCEMINIMIZE minimizes a window, even if the thread that owns the window is not responding - only Win2000/XP'
|
575
|
+
end
|
576
|
+
|
577
|
+
describe '#keydb_event' do
|
578
|
+
spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
|
579
|
+
# vkey (I) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
580
|
+
# bscan (I) - Specifies a hardware scan code for the key.
|
581
|
+
# flags (L) - Specifies various aspects of function operation. This parameter can be one or more of the following values.
|
582
|
+
# KEYEVENTF_EXTENDEDKEY - If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
|
583
|
+
# KEYEVENTF_KEYUP - If specified, the key is being released. If not specified, the key is being depressed.
|
584
|
+
# extra_info (L) - Specifies an additional value associated with the key stroke.
|
585
|
+
# no return value
|
586
|
+
|
587
|
+
it 'synthesizes a numeric keystroke, emulating keyboard driver' do
|
588
|
+
test_app do |app|
|
589
|
+
text = '123 456'
|
590
|
+
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
591
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
592
|
+
sleep TEST_KEY_DELAY
|
593
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
594
|
+
sleep TEST_KEY_DELAY
|
595
|
+
end
|
596
|
+
app.textarea.text.should =~ Regexp.new(text)
|
597
|
+
7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
it 'synthesizes a letter keystroke, emulating keyboard driver'
|
602
|
+
end
|
603
|
+
|
604
|
+
describe '#post_message' do
|
605
|
+
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
|
606
|
+
# handle (L) - Handle to the window whose window procedure will receive the message.
|
607
|
+
# If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or
|
608
|
+
# invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
|
609
|
+
# msg (L) - Specifies the message to be posted.
|
610
|
+
# w_param (L) - Specifies additional message-specific information.
|
611
|
+
# l_param (L) - Specifies additional message-specific information.
|
612
|
+
# returns (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
|
613
|
+
|
614
|
+
it 'places (posts) a message in the message queue associated with the thread that created the specified window'
|
615
|
+
it 'returns without waiting for the thread to process the message'
|
616
|
+
end
|
617
|
+
|
618
|
+
describe '#send_message' do
|
619
|
+
spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
|
620
|
+
# handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
|
621
|
+
# HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
|
622
|
+
# overlapped windows, and pop-up windows. The message is not posted to child windows.
|
623
|
+
# NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
|
624
|
+
# msg (L) - Specifies the message to be posted.
|
625
|
+
# w_param (L) - Specifies additional message-specific information.
|
626
|
+
# l_param (L) - Specifies additional message-specific information.
|
627
|
+
# return (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
|
628
|
+
|
629
|
+
it 'sends the specified message to a window or windows'
|
630
|
+
it 'calls the window procedure and does not return until the window procedure has processed the message'
|
631
|
+
end
|
632
|
+
|
633
|
+
describe '#get_dlg_item' do
|
634
|
+
spec{ use{ control_handle = get_dlg_item(handle = 0, item_id = 1) }}
|
635
|
+
# handle (L) - Handle of the dialog box that contains the control.
|
636
|
+
# item_id (I) - Specifies the identifier of the control to be retrieved.
|
637
|
+
# Returns (L) - handle of the specified control if success or nil for invalid dialog box handle or a nonexistent control.
|
638
|
+
# To get extended error information, call GetLastError.
|
639
|
+
# You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle
|
640
|
+
# parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the
|
641
|
+
# CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.
|
642
|
+
|
643
|
+
it 'returns handle to correctly specified control'
|
644
|
+
end
|
645
|
+
|
646
|
+
describe '#enum_windows' do
|
647
|
+
spec{ use{ enum_windows(message = 'Message') }}
|
648
|
+
|
649
|
+
it 'return an array of top-level window handles if block is not given' do
|
650
|
+
enum = enum_windows(message = 'Message')
|
651
|
+
enum.should be_a_kind_of Array
|
652
|
+
enum.should_not be_empty
|
653
|
+
enum.should have_at_least(60).elements # typical number of top windows in WinXP system?
|
654
|
+
enum.compact.size.should == enum.size # should not contain nils
|
655
|
+
end
|
656
|
+
|
657
|
+
it 'iterates through all the top-level windows, passing each found window handle and message to a given block'
|
658
|
+
|
659
|
+
end
|
660
|
+
|
661
|
+
describe '#enum_child_windows' do
|
662
|
+
spec{ use{ enum_child_windows(parent = any_handle, message = 'Message') }}
|
663
|
+
|
664
|
+
it 'return an array of child window handles if block is not given' do
|
665
|
+
test_app do |app|
|
666
|
+
enum = enum_child_windows(app.handle, message = 'Message')
|
667
|
+
enum.should be_a_kind_of Array
|
668
|
+
enum.should_not be_empty
|
669
|
+
enum.should have(2).elements
|
670
|
+
p get_class_name(enum.first), get_class_name(enum.last)
|
671
|
+
get_class_name(enum.last).should == TEST_TEXTAREA_CLASS
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
it 'loops through all children of given window, passing each found window handle and a message to a given block'
|
676
|
+
end
|
677
|
+
|
678
|
+
it 'GetForegroundWindow ', 'V', 'L'
|
679
|
+
it 'GetActiveWindow ', 'V', 'L'
|
680
|
+
end
|
681
|
+
|
682
|
+
describe WinGui, ' convenience wrapper methods' do
|
683
|
+
describe '#keystroke' do
|
684
|
+
spec{ use{ keystroke( vkey = 30, vkey = 30) }}
|
685
|
+
# this service method emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
|
686
|
+
# vkey (int) - Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see msdn:Virtual Key Codes.
|
687
|
+
|
688
|
+
it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
|
689
|
+
test_app do |app|
|
690
|
+
keystroke(VK_CONTROL, 'A'.ord)
|
691
|
+
keystroke(VK_SPACE)
|
692
|
+
app.textarea.text.should == ' '
|
693
|
+
2.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
|
694
|
+
end
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
describe '#type_in' do
|
699
|
+
spec{ use{ type_in(message = '') }}
|
700
|
+
# this service method types text message into window holding the focus
|
701
|
+
|
702
|
+
it 'types text message into window holding the focus' do
|
703
|
+
test_app do |app|
|
704
|
+
text = '123 456'
|
705
|
+
type_in(text)
|
706
|
+
app.textarea.text.should =~ Regexp.new(text)
|
707
|
+
7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
|
708
|
+
end
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
describe 'dialog' do
|
713
|
+
spec{ use{ dialog( title ='Dialog Title', timeout_sec = 0.001, &any_block) }}
|
714
|
+
# me od finds top-level dialog window by title and yields found dialog window to block if given
|
715
|
+
|
716
|
+
it 'finds top-level dialog window by title' do
|
717
|
+
pending 'Some problems (?with timeouts?) leave window open ~half of the runs'
|
718
|
+
test_app do |app|
|
719
|
+
keystroke(VK_ALT, 'F'.ord, 'A'.ord)
|
720
|
+
@found = false
|
721
|
+
dialog('Save As', 0.5) do |dialog_window|
|
722
|
+
@found = true
|
723
|
+
keystroke(VK_ESCAPE)
|
724
|
+
dialog_window
|
725
|
+
end
|
726
|
+
@found.should == true
|
727
|
+
end
|
728
|
+
end
|
729
|
+
it 'yields found dialog window to a given block'
|
730
|
+
end
|
731
|
+
|
732
|
+
end
|
733
|
+
end
|