require File.join(File.dirname(__FILE__), "..", "spec_helper" ) module GuiTest # def enum_callback # @enum_callback ||= callback('LP', 'I'){|handle, message| true } # end describe WinGui, ' defines wrappers for Win32::API functions' do context 'defining a valid API function' do before(:each) { hide_method :find_window_w } # hide original method if it is defined after(:each) { restore_method :find_window_w } # restore original method if it was hidden spec{ use{ WinGui.def_api('FindWindowW', 'PP', 'L', :rename => nil, :boolean => nil, :zeronil => nil, &any_block) }} it 'defines new instance method with appropriate name' do WinGui.def_api 'FindWindowW', 'PP', 'L' respond_to?(:find_window_w).should be_true end it 'constructs argument prototype from uppercase string' do expect { WinGui.def_api 'FindWindowW', 'PP', 'L' }.to_not raise_error expect { find_window_w(nil) }.to raise_error 'Invalid args count' expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count' end it 'constructs argument prototype from lowercase string' do expect { WinGui.def_api 'FindWindowW', 'pp', 'l' }.to_not raise_error expect { find_window_w(nil) }.to raise_error 'Invalid args count' expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count' end it 'constructs argument prototype from (mixedcase) array' do expect { WinGui.def_api 'FindWindowW', ['p', 'P'], 'L' }.to_not raise_error expect { find_window_w(nil) }.to raise_error 'Invalid args count' expect { find_window_w(nil, nil) }.to_not raise_error 'Invalid args count' end it ':rename option overrides standard name for defined method' do WinGui.def_api 'FindWindowW', 'PP', 'L', :rename=> 'my_own_find' expect {find_window_w(nil, nil)}.to raise_error expect {my_own_find(nil, nil)}.to_not raise_error end it 'defined method works properly when called with a valid args' do WinGui.def_api 'FindWindowW', 'PP', 'L' expect {find_window_w(nil, nil)}.to_not raise_error end it 'defined method returns expected value when called' do WinGui.def_api 'FindWindowW', 'PP', 'L' test_app do |app| find_window_w(nil, TEST_WIN_TITLE.to_w).should_not == 0 find_window_w(TEST_WIN_CLASS.to_w, nil).should_not == 0 end find_window_w(nil, nil).should_not == 0 find_window_w(nil, TEST_IMPOSSIBLE).should == 0 find_window_w(TEST_IMPOSSIBLE, nil).should == 0 find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0 end it 'defined method enforces the argument count when called' do WinGui.def_api 'FindWindowW', 'PP', 'L' expect { find_window_w }.to raise_error 'Invalid args count' expect { find_window_w(nil) }.to raise_error 'Invalid args count' expect { find_window_w('Str') }.to raise_error 'Invalid args count' expect { find_window_w([nil, nil]) }.to raise_error 'Invalid args count' expect { find_window_w('Str', 'Str', 'Str') }.to raise_error 'Invalid args count' end it 'defined method called with (:api) argument returns underlying Win32::API object' do WinGui.def_api 'FindWindowW', 'PP', 'L' expect {@api = find_window_w(:api)}.to_not raise_error @api.dll_name.should == 'user32' # The name of the DLL that exports the API function @api.effective_function_name.should == 'FindWindowW' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW' @api.function_name.should == 'FindWindowW' # The name of the function passed to the constructor @api.prototype.should == ['P', 'P'] # The prototype, returned as an array of characters end end context 'auto-defining Ruby-like boolean methods if API function name starts with "Is_"' do before(:each) do hide_method :window? WinGui.def_api 'IsWindow', 'L', 'L' end after(:each) { restore_method :window? } it 'defines new instance method name dropping Is_ and adding ?' do respond_to?(:window?).should be_true end it 'defined method returns true instead of non-zero' do window?(any_handle).should == true end it 'defined method returns false instead of zero' do window?(123).should == false end it 'defined method enforces the argument count' do expect {window?}.to raise_error 'Invalid args count' expect {window?(123, nil)}.to raise_error 'Invalid args count' expect {window?(nil, nil)}.to raise_error 'Invalid args count' end end context 'defining API with :boolean option converts result to boolean' do before(:each) do hide_method :show_window WinGui.def_api 'ShowWindow', 'LI', 'I', :boolean => true end after(:each) { restore_method :show_window } it 'defines new instance method' do respond_to?(:show_window).should be_true end it 'defined method returns true instead of non-zero' do test_app {|app| show_window(app.handle, SW_SHOWNA).should == true } end it 'defined method returns false instead of zero' do test_app do |app| show_window(app.handle, SW_HIDE) show_window(app.handle, SW_HIDE).should == false end end it 'defined method enforces the argument count' do test_app do |app| expect {show_window}.to raise_error 'Invalid args count' expect {show_window(app.handle, SW_HIDE, nil)}.to raise_error 'Invalid args count' end end end context 'defining API with :zeronil option converts zero result to nil' do before(:each) do hide_method :show_window WinGui.def_api 'ShowWindow', 'LI', 'I', :zeronil => true end after(:each) { restore_method :show_window } it 'defines new instance method' do respond_to?(:show_window).should be_true end it 'defined method returns nil (but NOT false) instead of zero' do test_app do |app| show_window(app.handle, SW_HIDE) show_window(app.handle, SW_HIDE).should == nil show_window(app.handle, SW_HIDE).should_not == false end end it 'defined method does not return true when result is non-zero' do test_app do |app| result = show_window(app.handle, SW_SHOWNA) result.should_not == 0 result.should_not == true end end it 'defined method enforces the argument count' do test_app do |app| expect {show_window}.to raise_error 'Invalid args count' expect {show_window(app.handle, SW_HIDE, nil)}.to raise_error 'Invalid args count' end end end context 'trying to define an invalid API function' do it 'raises error when trying to define function with a wrong function name' do expect { WinGui.def_api 'FindWindowImpossible', 'PP', 'L' }. to raise_error( /Unable to load function 'FindWindowImpossible'/ ) end end context 'defining API function using definition blocks' do before(:each) { hide_method :get_window_text } # hide original method if it is defined after(:each) { restore_method :get_window_text } # restore original method if it was hidden it 'defines new instance method' do WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args| end respond_to?(:get_window_text).should be_true end it 'does not enforce argument count outside of block' do WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args| end expect { get_window_text }.to_not raise_error 'Invalid args count' expect { get_window_text(nil) }.to_not raise_error 'Invalid args count' expect { get_window_text(nil, 'Str') }.to_not raise_error 'Invalid args count' end it 'returns block return value when defined method is called' do WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args| 'Value' end get_window_text(nil).should == 'Value' end it 'passes arguments and underlying Win32::API object to the block' do WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args| @api=api; @args = args end get_window_text(1, 2, 3) @args.should == [1, 2, 3] @api.function_name.should == 'GetWindowText' # The name of the function passed to the constructor end it ':rename option overrides standard name for defined method' do WinGui.def_api 'GetWindowText', 'LPL', 'L', :rename => 'my_name' do |api, *args| end expect {get_window_text(nil, nil, nil)}.to raise_error expect {my_name(nil, nil)}.to_not raise_error end it 'calling defined method with (:api) argument returns underlying Win32::API object' do WinGui.def_api 'GetWindowText', 'LPL', 'L' do |api, *args| end expect {@api = get_window_text(:api)}.to_not raise_error @api.dll_name.should == 'user32' # The name of the DLL that exports the API function @api.effective_function_name.should == 'GetWindowTextA' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW' @api.function_name.should == 'GetWindowText' # The name of the function passed to the constructor @api.prototype.should == ['L', 'P', 'L'] # The prototype, returned as an array of characters end end context 'providing API function with callback' do # before(:each) { hide_method :enum_windows } # hide original find_window method if it is defined # after(:each) { restore_method :enum_window } # restore original find_window method if it was hidden # it '#callback method creates a valid callback object' do pending 'callback is now a class method of WinGui, not available here (exept through module_eval)' expect { @callback = callback('LP', 'I') {|handle, message| true} }.to_not raise_error @callback.should be_a_kind_of(Win32::API::Callback) end it 'created callback object can be used as a valid arg of API function expecting callback' do pending 'API changed - callback arg is no longer valid, block is used instead' # WinGui.def_api 'EnumWindows', 'KP', 'L' expect { enum_windows(enum_callback, 'Message') }.to_not raise_error end it 'defined API functions expecting callback recognize/accept blocks' do pending ' API is not exactly clear atm (what about prototype?)(.with_callback method?)' end end end describe WinGui, ' contains a set of pre-defined GUI functions' do describe '#window?' do spec{ use{ window?(handle = 0) }} # Tests whether the specified window handle identifies an existing window. # A thread should not use IsWindow for a window that it did not create because the window could be destroyed after this # function was called. Further, because window handles are recycled the handle could even point to a different window. it 'returns true if window exists' do test_app do |app| window?(app.handle).should == true window?(app.textarea.handle).should == true end end it 'returns false if window does not exist' do test_app do |app| @app_handle = app.handle @ta_handle = app.textarea.handle end window?(@app_handle).should == false window?(@ta_handle).should == false end end describe '#window_visible?' do spec{ use{ window_visible?(handle = any_handle) }} spec{ use{ visible?(handle = any_handle) }} # Tests if the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style. # 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. it 'returns true if window is visible' do test_app do |app| visible?(app.handle).should == true window_visible?(app.handle).should == true window_visible?(app.textarea.handle).should == true end end it 'returns false if window is not visible' do test_app do |app| hide_window(app.handle) visible?(app.handle).should == false window_visible?(app.handle).should == false window_visible?(app.textarea.handle).should == false end end end describe '#maximized?' do spec{ use{ zoomed?(handle = 0) }} spec{ use{ maximized?(handle = 0) }} # Tests whether the specified window is maximized. it 'returns false if window is not maximized' do test_app do |app| zoomed?(app.handle).should == false maximized?(app.handle).should == false end end it 'returns true if the window is maximized' do test_app do |app| show_window(app.handle, SW_MAXIMIZE) maximized?(app.handle).should == true zoomed?(app.handle).should == true end end end describe '#minimized?' do spec{ use{ iconic?(handle = 0) }} spec{ use{ minimized?(handle = 0) }} # Tests whether the specified window is minimized. it 'returns false if window is not minimized' do test_app do |app| iconic?(app.handle).should == false minimized?(app.handle).should == false end end it 'returns true if the window is minimized' do test_app do |app| show_window(app.handle, SW_MINIMIZE) iconic?(app.handle).should == true minimized?(app.handle).should == true end end end describe '#child?' do spec{ use{ child?(parent_handle = any_handle, handle = any_handle) }} # Tests whether a window is a child (or descendant) window of a specified parent window. A child window is the direct descendant # of a specified parent window if that parent window is in the chain of parent windows; the chain of parent windows leads from # the original overlapped or pop-up window to the child window. it 'returns true if the window is a child' do test_app do |app| child?(app.handle, app.textarea.handle).should == true end end it 'returns false if window is not a child' do test_app do |app| child?(app.handle, any_handle).should == false end end end describe '#find_window' do spec{ use{ find_window(class_name = nil, win_name = nil) }} it 'returns either Integer Window handle or nil' do find_window(nil, nil).should be_a_kind_of Integer nil.class.should === find_window(TEST_IMPOSSIBLE, nil) end it 'returns nil if Window is not found' do find_window(TEST_IMPOSSIBLE, nil).should == nil find_window(nil, TEST_IMPOSSIBLE).should == nil find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil end it 'finds at least one window if both args are nils' do find_window(nil, nil).should_not == nil end it 'finds top-level window by window class' do test_app {|app| find_window(TEST_WIN_CLASS, nil).should == app.handle } end it 'finds top-level window by title' do test_app {|app| find_window(nil, TEST_WIN_TITLE).should == app.handle } end end describe '#find_window_w' do spec{ use{ find_window_w(class_name = nil, win_name = nil) }} it 'returns zero if Window is not found' do find_window_w(TEST_IMPOSSIBLE, nil).should == nil find_window_w(nil, TEST_IMPOSSIBLE).should == nil find_window_w(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == nil end it 'finds at least one window if given two nils' do find_window_w(nil, nil).should_not == nil end it 'finds top-level window by window class' do test_app {|app| find_window_w(TEST_WIN_CLASS.to_w, nil).should == app.handle } end it 'finds top-level window by title' do test_app {|app| find_window_w(nil, TEST_WIN_TITLE.to_w).should == app.handle } end end describe '#find_window_ex' do spec{ use{ control_handle = find_window_ex(parent = any_handle, after_child = 0, win_class = nil, win_title = nil) }} it 'returns nil if wrong control is given' do parent_handle = any_handle find_window_ex(parent_handle, 0, TEST_IMPOSSIBLE, nil).should == nil find_window_ex(parent_handle, 0, nil, TEST_IMPOSSIBLE).should == nil end it 'finds child window/control by class' do test_app do |app| ta_handle = find_window_ex(app.handle, 0, TEST_TEXTAREA_CLASS, nil) ta_handle.should_not == nil ta_handle.should == app.textarea.handle end end it 'finds child window/control by text/title' do pending 'Identify appropriate (short name) control' test_app do |app| keystroke(VK_CONTROL, 'A'.ord) keystroke('1'.ord, '2'.ord) ta_handle = find_window_ex(app.handle, 0, nil, '12') ta_handle.should_not == 0 ta_handle.should == app.textarea.handle end end end describe '#get_window_thread_process_id' do spec{ use{ thread, process = get_window_thread_process_id(handle = any_handle) }} # Improved with block to accept window handle as a single arg and return a pair of [thread, process] it 'returns a pair of nonzero Integer ids (window thread and process)' do thread, process = get_window_thread_process_id(handle = any_handle) thread.should be_a_kind_of Integer thread.should be > 0 process.should be_a_kind_of Integer process.should be > 0 end end describe '#get_window_text' do spec{ use{ text = get_window_text(handle = 0)}} # Improved with block to accept window handle as a single arg and return (rstripped) text string it 'returns correct window text' do test_app {|app| get_window_text(app.handle).should == TEST_WIN_TITLE } end end describe '#get_window_text_w' do spec{ use{ class_name = get_window_text_w(handle = 0)}} # result encoded as utf-8 # Unicode version of get_window_text (strings returned encoded as utf-8) it 'returns correct window text' do test_app {|app| get_window_text_w(app.handle).should == TEST_WIN_TITLE } end end describe '#get_class_name' do spec{ use{ class_name = get_class_name(handle = 0)}} # Improved with block to accept window handle as a single arg and return class name string it 'returns correct window class name' do test_app {|app| get_class_name(app.handle).should == TEST_WIN_CLASS } end end describe '#get_class_name_w' do spec{ use{ class_name = get_class_name_w(handle = 0)}} # result encoded as utf-8 # Unicode version of get_class_name (strings returned encoded as utf-8) it 'returns correct window class name' do test_app {|app| get_class_name_w(app.handle).should == TEST_WIN_CLASS } end end describe '#get_window_rect' do spec{ use{ left, top, right, bottom = get_window_rect(any_handle)}} it 'returns windows rectangle' do test_app do |app| get_window_rect(app.handle).should == TEST_WIN_RECT end end end describe '#show_window ', 'LI', 'I' do spec{ use{ was_visible = show_window(handle = any_handle, cmd = SW_SHOWNA) }} it 'was_visible = hide_window(handle = any_handle) # alias method (not a separate API function)' do test_app do |app| use{ hide_window(app.handle) } visible?(app.handle).should == false end end it 'returns true if the window was PREVIOUSLY visible' do test_app {|app| show_window(app.handle, SW_HIDE).should == true } end it 'returns false if the window was PREVIOUSLY not visible' do test_app do |app| show_window(app.handle, SW_HIDE) show_window(app.handle, SW_HIDE).should == false end end it 'SW_HIDE command hides window' do test_app do |app| show_window(app.handle, SW_HIDE) visible?(app.handle).should == false end end it 'SW_SHOW command shows hidden window' do test_app do |app| show_window(app.handle, SW_HIDE) show_window(app.handle, SW_SHOW) visible?(app.handle).should == true end end it 'SW_MAXIMIZE maximizes window' do test_app do |app| show_window(app.handle, SW_MAXIMIZE) maximized?(app.handle).should == true end pending 'Need to make sure window is maximized but NOT activated ' end it 'SW_MINIMIZE minimizes window and activates the next top-level window in the Z order' do test_app do |app| show_window(app.handle, SW_MINIMIZE) minimized?(app.handle).should == true end end it 'SW_SHOWMAXIMIZED activates the window and displays it as a maximized window' do pending 'Need to make sure window is maximized AND activated ' test_app do |app| show_window(app.handle, SW_SHOWMAXIMIZED) get_window_rect(app.handle) #.should == TEST_MAX_RECT end end it 'SW_SHOWMINIMIZED activates the window and displays it as a minimized window' do pending 'Need to make sure window is minimized AND activated ' test_app do |app| show_window(app.handle, SW_SHOWMINIMIZED) p get_window_rect(app.handle) #.should == TEST_MAX_RECT end end it 'SW_SHOWMINNOACTIVE displays the window as a minimized window (similar to SW_SHOWMINIMIZED, but window is not activated)' it 'SW_SHOWNA displays the window in its current size and position (similar to SW_SHOW, but window is not activated)' it 'SW_SHOWNOACTIVATE displays the window in its current size and position (similar to SW_SHOW, but window is not activated)' 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' it 'SW_RESTORE activates and displays the window. Restores minimized/maximized window to original size/position. Use it to restore minimized windows' 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' it 'SW_FORCEMINIMIZE minimizes a window, even if the thread that owns the window is not responding - only Win2000/XP' end describe '#keydb_event' do spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }} # 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. # bscan (I) - Specifies a hardware scan code for the key. # flags (L) - Specifies various aspects of function operation. This parameter can be one or more of the following values. # KEYEVENTF_EXTENDEDKEY - If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224). # KEYEVENTF_KEYUP - If specified, the key is being released. If not specified, the key is being depressed. # extra_info (L) - Specifies an additional value associated with the key stroke. # no return value it 'synthesizes a numeric keystroke, emulating keyboard driver' do test_app do |app| text = '123 456' text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0) sleep TEST_KEY_DELAY keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0) sleep TEST_KEY_DELAY end app.textarea.text.should =~ Regexp.new(text) 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack! end end it 'synthesizes a letter keystroke, emulating keyboard driver' end describe '#post_message' do spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }} # handle (L) - Handle to the window whose window procedure will receive the message. # If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or # invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows. # msg (L) - Specifies the message to be posted. # w_param (L) - Specifies additional message-specific information. # l_param (L) - Specifies additional message-specific information. # returns (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError. it 'places (posts) a message in the message queue associated with the thread that created the specified window' it 'returns without waiting for the thread to process the message' end describe '#send_message' do spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }} # handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings. # HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows, # overlapped windows, and pop-up windows. The message is not posted to child windows. # NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread. # msg (L) - Specifies the message to be posted. # w_param (L) - Specifies additional message-specific information. # l_param (L) - Specifies additional message-specific information. # return (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError. it 'sends the specified message to a window or windows' it 'calls the window procedure and does not return until the window procedure has processed the message' end describe '#get_dlg_item' do spec{ use{ control_handle = get_dlg_item(handle = 0, item_id = 1) }} # handle (L) - Handle of the dialog box that contains the control. # item_id (I) - Specifies the identifier of the control to be retrieved. # Returns (L) - handle of the specified control if success or nil for invalid dialog box handle or a nonexistent control. # To get extended error information, call GetLastError. # You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the handle # parameter specifies a parent window and the child window has a unique id (as specified by the hMenu parameter in the # CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window. it 'returns handle to correctly specified control' end describe '#enum_windows' do spec{ use{ enum_windows(message = 'Message') }} it 'return an array of top-level window handles if block is not given' do enum = enum_windows(message = 'Message') enum.should be_a_kind_of Array enum.should_not be_empty enum.should have_at_least(60).elements # typical number of top windows in WinXP system? enum.compact.size.should == enum.size # should not contain nils end it 'iterates through all the top-level windows, passing each found window handle and message to a given block' end describe '#enum_child_windows' do spec{ use{ enum_child_windows(parent = any_handle, message = 'Message') }} it 'return an array of child window handles if block is not given' do test_app do |app| enum = enum_child_windows(app.handle, message = 'Message') enum.should be_a_kind_of Array enum.should_not be_empty enum.should have(2).elements p get_class_name(enum.first), get_class_name(enum.last) get_class_name(enum.last).should == TEST_TEXTAREA_CLASS end end it 'loops through all children of given window, passing each found window handle and a message to a given block' end it 'GetForegroundWindow ', 'V', 'L' it 'GetActiveWindow ', 'V', 'L' end describe WinGui, ' convenience wrapper methods' do describe '#keystroke' do spec{ use{ keystroke( vkey = 30, vkey = 30) }} # this service method emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released # 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. it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do test_app do |app| keystroke(VK_CONTROL, 'A'.ord) keystroke(VK_SPACE) app.textarea.text.should == ' ' 2.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack! end end end describe '#type_in' do spec{ use{ type_in(message = '') }} # this service method types text message into window holding the focus it 'types text message into window holding the focus' do test_app do |app| text = '123 456' type_in(text) app.textarea.text.should =~ Regexp.new(text) 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack! end end end describe 'dialog' do spec{ use{ dialog( title ='Dialog Title', timeout_sec = 0.001, &any_block) }} # me od finds top-level dialog window by title and yields found dialog window to block if given it 'finds top-level dialog window by title' do pending 'Some problems (?with timeouts?) leave window open ~half of the runs' test_app do |app| keystroke(VK_ALT, 'F'.ord, 'A'.ord) @found = false dialog('Save As', 0.5) do |dialog_window| @found = true keystroke(VK_ESCAPE) dialog_window end @found.should == true end end it 'yields found dialog window to a given block' end end end