win_gui 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/VERSION +1 -1
- data/lib/win_gui/convenience.rb +67 -0
- data/lib/win_gui/window.rb +67 -38
- data/spec/spec_helper.rb +10 -9
- data/spec/win_gui/convenience_spec.rb +68 -0
- data/spec/win_gui/window_spec.rb +51 -35
- metadata +6 -3
data/HISTORY
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'win/gui'
|
2
|
+
|
3
|
+
module WinGui
|
4
|
+
include Win::Gui
|
5
|
+
# extend Win::Gui
|
6
|
+
|
7
|
+
# Delay between key commands/events (in sec)
|
8
|
+
KEY_DELAY = 0.00001
|
9
|
+
# Delay when sleeping (in sec)
|
10
|
+
SLEEP_DELAY = 0.001
|
11
|
+
# Timeout waiting for Window to be closed (in sec)
|
12
|
+
CLOSE_TIMEOUT = 1
|
13
|
+
# Default timeout for dialog operations (in sec)
|
14
|
+
LOOKUP_TIMEOUT = 3
|
15
|
+
DIALOG_WINDOW_CLASS = '#32770'
|
16
|
+
|
17
|
+
# Module defines convenience methods on top of straightforward Win32 API functions.
|
18
|
+
|
19
|
+
# Finds top-level dialog window by title and yields found dialog window to attached block.
|
20
|
+
# We work with dialog window in a block, and then we wait for it to close before proceeding.
|
21
|
+
# That is, unless your block returns nil, in which case dialog is ignored and method immediately returns nil
|
22
|
+
# If no block is given, method just returns found dialog window or nil
|
23
|
+
def dialog(title, timeout=LOOKUP_TIMEOUT)
|
24
|
+
dialog = Window.top_level(class: DIALOG_WINDOW_CLASS, title: title, timeout: timeout)
|
25
|
+
#set_foreground_window dialog.handle if dialog # TODO: Should be converted to d_w.s_f_g call!
|
26
|
+
wait = block_given? ? yield(dialog) : false
|
27
|
+
dialog.wait_for_close if dialog && wait
|
28
|
+
dialog
|
29
|
+
end
|
30
|
+
|
31
|
+
# Emulates combinations of (any amount of) keys pressed one after another (Ctrl+Alt+P) and then released
|
32
|
+
# *keys should be a sequence of a virtual-key codes. The codes must be a value in the range 1 to 254.
|
33
|
+
# For a complete list, see msdn:Virtual Key Codes.
|
34
|
+
def keystroke(*keys)
|
35
|
+
return if keys.empty?
|
36
|
+
keybd_event keys.first, 0, KEYEVENTF_KEYDOWN, 0
|
37
|
+
sleep KEY_DELAY
|
38
|
+
keystroke *keys[1..-1]
|
39
|
+
sleep KEY_DELAY
|
40
|
+
keybd_event keys.first, 0, KEYEVENTF_KEYUP, 0
|
41
|
+
end
|
42
|
+
|
43
|
+
# types text message into window holding the focus
|
44
|
+
def type_in(message)
|
45
|
+
message.scan(/./m) do |char|
|
46
|
+
keystroke(*char.to_vkeys)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# DialogWndClass = '#32770'
|
52
|
+
# def dialog(title, seconds=5)
|
53
|
+
# close, dlg = begin
|
54
|
+
# sleep 0.25
|
55
|
+
# w = Gui.top_level(title, seconds, DialogWndClass)
|
56
|
+
# Gui.set_foreground_window w.handle
|
57
|
+
# sleep 0.25
|
58
|
+
#
|
59
|
+
# [yield(w), w]
|
60
|
+
# rescue TimeoutError
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# dlg.wait_for_close if dlg && close
|
64
|
+
# return dlg
|
65
|
+
# end
|
66
|
+
|
67
|
+
end
|
data/lib/win_gui/window.rb
CHANGED
@@ -1,79 +1,108 @@
|
|
1
|
-
require 'win/gui'
|
2
|
-
|
3
1
|
module WinGui
|
4
|
-
# Delay between key commands (events)
|
5
|
-
WG_KEY_DELAY = 0.00001
|
6
|
-
# Wait delay quant
|
7
|
-
WG_SLEEP_DELAY = 0.001
|
8
|
-
# Timeout waiting for Window to be closed
|
9
|
-
WG_CLOSE_TIMEOUT = 1
|
10
2
|
|
3
|
+
# This class is a wrapper around window handle
|
11
4
|
class Window
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
# Make convenience methods from both WinGui and Win::Gui available as both class and instance methods
|
6
|
+
# Looks a bit circular though...
|
7
|
+
include WinGui
|
8
|
+
extend WinGui
|
9
|
+
|
15
10
|
def initialize(handle)
|
16
11
|
@handle = handle
|
17
12
|
end
|
18
13
|
|
19
14
|
attr_reader :handle
|
20
|
-
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
|
16
|
+
# Finds top level window by title/class, returns wrapped Window object or nil.
|
17
|
+
# If timeout option given, waits for window to appear within timeout, returns nil if it didn't
|
18
|
+
# Options:
|
19
|
+
# :title:: window title
|
20
|
+
# :class:: window class
|
21
|
+
# :timeout:: timeout (seconds)
|
22
|
+
def self.top_level(opts={})
|
23
|
+
window_title = opts[:title]
|
24
|
+
window_class = opts[:class]
|
25
|
+
timeout = opts[:timeout] # || LOOKUP_TIMEOUT
|
26
|
+
|
27
|
+
if timeout
|
28
|
+
begin
|
29
|
+
timeout(timeout) do
|
30
|
+
sleep SLEEP_DELAY while (@handle = find_window window_class, window_title) == nil
|
31
|
+
end
|
32
|
+
rescue TimeoutError
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
else
|
36
|
+
@handle = find_window window_class, window_title
|
25
37
|
end
|
26
|
-
Window.new @handle
|
27
|
-
end
|
28
|
-
|
38
|
+
Window.new(@handle) if @handle
|
39
|
+
end
|
40
|
+
|
41
|
+
# def self.top_level(title, seconds=10, wnd_class = nil)
|
42
|
+
# @handle = timeout(seconds) do
|
43
|
+
# loop do
|
44
|
+
# h = find_window wnd_class, title
|
45
|
+
# break h if h > 0
|
46
|
+
# sleep 0.3
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# Gui.new @handle
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
|
29
54
|
# find child window (control) by title, window class, or control ID:
|
30
55
|
def child(id)
|
31
56
|
result = case id
|
32
57
|
when String
|
33
|
-
|
34
|
-
|
35
|
-
|
58
|
+
by_title = find_window_ex @handle, 0, nil, id.gsub('_', '&' )
|
59
|
+
by_class = find_window_ex @handle, 0, id, nil
|
60
|
+
by_title ? by_title : by_class
|
36
61
|
when Fixnum
|
37
|
-
|
62
|
+
get_dlg_item @handle, id
|
38
63
|
when nil
|
39
|
-
|
40
|
-
|
41
|
-
|
64
|
+
find_window_ex @handle, 0, nil, nil
|
65
|
+
else
|
66
|
+
nil
|
42
67
|
end
|
43
68
|
raise "Control '#{id}' not found" unless result
|
44
69
|
Window.new result
|
45
70
|
end
|
46
71
|
|
72
|
+
# returns array of Windows that are descendants (not only DIRECTchildren) of a given Window
|
47
73
|
def children
|
48
74
|
enum_child_windows(@handle).map{|child_handle| Window.new child_handle}
|
49
75
|
end
|
50
76
|
|
51
77
|
# emulate click of the control identified by id
|
52
78
|
def click(id)
|
53
|
-
|
54
|
-
rectangle = [0, 0, 0, 0].pack 'LLLL'
|
55
|
-
get_window_rect h, rectangle
|
56
|
-
left, top, right, bottom = rectangle.unpack 'LLLL'
|
79
|
+
left, top, right, bottom = get_window_rect child(id).handle
|
57
80
|
center = [(left + right) / 2, (top + bottom) / 2]
|
58
81
|
set_cursor_pos *center
|
59
82
|
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
60
83
|
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
61
84
|
end
|
62
|
-
|
85
|
+
|
63
86
|
def close
|
64
87
|
post_message @handle, WM_SYSCOMMAND, SC_CLOSE, nil
|
65
88
|
end
|
66
|
-
|
89
|
+
|
67
90
|
def wait_for_close
|
68
|
-
timeout(
|
69
|
-
sleep
|
91
|
+
timeout(CLOSE_TIMEOUT) do
|
92
|
+
sleep SLEEP_DELAY while window_visible?(@handle)
|
70
93
|
end
|
71
94
|
end
|
72
|
-
|
95
|
+
|
96
|
+
# Window class name property - static (not changing)
|
97
|
+
def class_name
|
98
|
+
@class_name ||= get_class_name @handle
|
99
|
+
end
|
100
|
+
|
101
|
+
# Window text/title property - dynamic (changing)
|
73
102
|
def text
|
74
|
-
buffer = "\x0" * 2048
|
75
|
-
|
76
|
-
|
103
|
+
buffer = FFI::MemoryPointer.from_string("\x0" * 2048)
|
104
|
+
num_chars = send_message @handle, WM_GETTEXT, buffer.size, buffer # length?
|
105
|
+
num_chars == 0 ? '' : buffer.read_string
|
77
106
|
end
|
78
107
|
end
|
79
108
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -22,7 +22,8 @@ end
|
|
22
22
|
Spec::Runner.configure { |config| config.extend(SpecMacros) }
|
23
23
|
|
24
24
|
module WinGuiTest
|
25
|
-
include Win::Gui
|
25
|
+
include Win::Gui # This is a namespace from win gem.
|
26
|
+
include WinGui # This is our own main namespace. TODO: looks confusing... better names?
|
26
27
|
|
27
28
|
# Test related Constants:
|
28
29
|
TIMEOUT = 0.001
|
@@ -30,9 +31,8 @@ module WinGuiTest
|
|
30
31
|
SLEEP_DELAY = 0.01
|
31
32
|
APP_PATH = File.join(File.dirname(__FILE__), "../misc/locknote/LockNote.exe" )
|
32
33
|
APP_START = RUBY_PLATFORM =~ /cygwin/ ? "cmd /c start `cygpath -w #{APP_PATH}`" : "start #{APP_PATH}"
|
33
|
-
#
|
34
|
-
|
35
|
-
# 'start "" "' + APP_PATH + '"'
|
34
|
+
# 'start "" "' + APP_PATH + '"'
|
35
|
+
DIALOG_TITLE = "Save As"
|
36
36
|
WIN_TITLE = 'LockNote - Steganos LockNote'
|
37
37
|
WIN_CLASS = 'ATL:00434098'
|
38
38
|
WIN_RECT = [710, 400, 1210, 800]
|
@@ -49,7 +49,6 @@ module WinGuiTest
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def any_handle
|
52
|
-
WinGui.def_api 'FindWindow', 'PP', 'L' unless respond_to? :find_window
|
53
52
|
find_window(nil, nil)
|
54
53
|
end
|
55
54
|
|
@@ -65,6 +64,12 @@ module WinGuiTest
|
|
65
64
|
system APP_START
|
66
65
|
sleep SLEEP_DELAY until (handle = find_window(nil, WIN_TITLE))
|
67
66
|
@launched_test_app = Window.new handle
|
67
|
+
|
68
|
+
def @launched_test_app.textarea #define singleton method retrieving app's text area
|
69
|
+
Window.new find_window_ex(self.handle, 0, TEXTAREA_CLASS, nil)
|
70
|
+
end
|
71
|
+
|
72
|
+
@launched_test_app
|
68
73
|
end
|
69
74
|
|
70
75
|
def close_test_app(app = @launched_test_app)
|
@@ -79,10 +84,6 @@ module WinGuiTest
|
|
79
84
|
def test_app
|
80
85
|
app = launch_test_app
|
81
86
|
|
82
|
-
def app.textarea #define singleton method retrieving app's text area
|
83
|
-
Window.new find_window_ex(self.handle, 0, TEXTAREA_CLASS, nil)
|
84
|
-
end
|
85
|
-
|
86
87
|
yield app
|
87
88
|
close_test_app
|
88
89
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper" )
|
2
|
+
|
3
|
+
module WinGuiTest
|
4
|
+
|
5
|
+
describe 'Convenience methods' do
|
6
|
+
before(:each){ @app = launch_test_app }
|
7
|
+
after(:each) { close_test_app }
|
8
|
+
|
9
|
+
describe '#dialog' do
|
10
|
+
before(:each){ keystroke(VK_ALT, 'F'.ord, 'A'.ord) }
|
11
|
+
after(:each) { keystroke(VK_ESCAPE) }
|
12
|
+
|
13
|
+
it 'returns top-level dialog window with given title if no block attached' do
|
14
|
+
dialog_window = dialog(DIALOG_TITLE, 0.1)
|
15
|
+
dialog_window.should_not == nil
|
16
|
+
dialog_window.should be_a Window
|
17
|
+
dialog_window.text.should == DIALOG_TITLE
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'yields found dialog window to block if block is attached' do
|
21
|
+
dialog(DIALOG_TITLE, 0.1) do |dialog_window|
|
22
|
+
dialog_window.should_not == nil
|
23
|
+
dialog_window.should be_a Window
|
24
|
+
dialog_window.text.should == DIALOG_TITLE
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns nil if there is no dialog with given title' do
|
29
|
+
dialog(IMPOSSIBLE, 0.1).should == nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'yields nil to attached block if no dialog found' do
|
33
|
+
dialog(IMPOSSIBLE, 0.1) do |dialog_window|
|
34
|
+
dialog_window.should == nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'considers timeout argument optional' do
|
39
|
+
dialog_window = dialog(DIALOG_TITLE)
|
40
|
+
dialog_window.text.should == DIALOG_TITLE
|
41
|
+
end
|
42
|
+
end # describe dialog
|
43
|
+
|
44
|
+
describe 'convenience input methods on top of Windows API' do
|
45
|
+
describe '#keystroke' do
|
46
|
+
spec{ use{ keystroke( vkey = 30, vkey = 30) }}
|
47
|
+
|
48
|
+
it 'emulates combinations of keys pressed (Ctrl+Alt+P+M, etc)' do
|
49
|
+
keystroke(VK_CONTROL, 'A'.ord)
|
50
|
+
keystroke(VK_SPACE)
|
51
|
+
@app.textarea.text.should.should == ' '
|
52
|
+
2.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
53
|
+
end
|
54
|
+
end # describe '#keystroke'
|
55
|
+
|
56
|
+
describe '#type_in' do
|
57
|
+
it 'types text message into the window holding the focus' do
|
58
|
+
text = '12 34'
|
59
|
+
type_in(text)
|
60
|
+
@app.textarea.text.should =~ Regexp.new(text)
|
61
|
+
5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
62
|
+
end
|
63
|
+
end # describe '#type_in'
|
64
|
+
|
65
|
+
end # Input methods
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/spec/win_gui/window_spec.rb
CHANGED
@@ -1,27 +1,29 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), ".."
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper" )
|
2
2
|
|
3
3
|
module WinGuiTest
|
4
|
-
include WinGui
|
5
4
|
|
6
5
|
describe Window do
|
7
6
|
before(:each) { @app = launch_test_app }
|
8
7
|
after(:each){ close_test_app }
|
9
|
-
|
8
|
+
|
10
9
|
context 'initializing' do
|
11
10
|
it 'can be wrapped around any existing window' do
|
12
11
|
any_handle = find_window(nil, nil)
|
13
12
|
use{ Window.new any_handle }
|
14
13
|
end
|
15
14
|
end
|
16
|
-
|
15
|
+
|
17
16
|
context 'manipulating' do
|
18
|
-
|
17
|
+
|
19
18
|
it 'has handle property equal to underlying window handle' do
|
20
|
-
any_handle = find_window(nil, nil)
|
21
19
|
any = Window.new any_handle
|
22
20
|
any.handle.should == any_handle
|
23
21
|
end
|
24
|
-
|
22
|
+
|
23
|
+
it 'has class_name property' do
|
24
|
+
@app.class_name.should == WIN_CLASS
|
25
|
+
end
|
26
|
+
|
25
27
|
it 'has text property equal to underlying window text(title)' do
|
26
28
|
@app.text.should == WIN_TITLE
|
27
29
|
end
|
@@ -31,39 +33,57 @@ module WinGuiTest
|
|
31
33
|
sleep SLEEP_DELAY # needed to ensure window had enough time to close down
|
32
34
|
find_window(nil, WIN_TITLE).should == nil
|
33
35
|
end
|
34
|
-
|
35
|
-
it 'waits
|
36
|
-
start = Time.now
|
36
|
+
|
37
|
+
it 'waits for window to disappear (NB: this happens before handle is released!)' do
|
38
|
+
start = Time.now
|
37
39
|
@app.close
|
38
40
|
@app.wait_for_close
|
39
|
-
|
41
|
+
(Time.now - start).should be <= CLOSE_TIMEOUT
|
40
42
|
window_visible?(@app.handle).should be false
|
43
|
+
window?(@app.handle).should be false
|
41
44
|
end
|
42
45
|
end
|
43
|
-
|
44
|
-
|
45
|
-
it 'finds any top-level window (title = nil) and wraps it in a Window object' do
|
46
|
-
use { @win = Window.top_level(title = nil, timeout_sec = 3) }
|
47
|
-
Window.should === @win
|
48
|
-
end
|
49
|
-
|
46
|
+
|
47
|
+
describe '.top_level' do
|
50
48
|
it 'finds top-level window by title and wraps it in a Window object' do
|
51
|
-
win = Window.top_level( WIN_TITLE, 1)
|
49
|
+
win = Window.top_level( title: WIN_TITLE, timeout: 1)
|
52
50
|
win.handle.should == @app.handle
|
53
51
|
end
|
52
|
+
|
53
|
+
it 'finds top-level window by class and wraps it in a Window object' do
|
54
|
+
win = Window.top_level( class: WIN_CLASS, timeout: 1)
|
55
|
+
win.handle.should == @app.handle
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'finds ANY top-level window without args and wraps it in a Window object' do
|
59
|
+
use { @win = Window.top_level() }
|
60
|
+
Window.should === @win
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns nil immediately if top-level window with given title not found' do
|
64
|
+
start = Time.now
|
65
|
+
Window.top_level( title: IMPOSSIBLE).should == nil
|
66
|
+
(Time.now - start).should be_close 0, 0.02
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns nil after timeout if top-level window with given title not found' do
|
70
|
+
start = Time.now
|
71
|
+
Window.top_level( title: IMPOSSIBLE, timeout: 1).should == nil
|
72
|
+
(Time.now - start).should be_close 1, 0.02
|
73
|
+
end
|
54
74
|
end
|
55
|
-
|
56
|
-
|
57
|
-
spec { use { @control = @app.child(title_class_id = nil) }}
|
75
|
+
|
76
|
+
describe '#child' do
|
77
|
+
spec { use { @control = @app.child(title_class_id = nil) }}
|
58
78
|
|
59
79
|
it 'finds any child window(control) if given nil' do
|
60
80
|
@app.child(nil).should_not == nil
|
61
81
|
end
|
62
|
-
|
82
|
+
|
63
83
|
it 'finds child window(control) by class' do
|
64
84
|
@app.child(TEXTAREA_CLASS).should_not == nil
|
65
85
|
end
|
66
|
-
|
86
|
+
|
67
87
|
it 'finds child window(control) by name' do
|
68
88
|
pending 'Need to find control with short name'
|
69
89
|
@app.child(TEXTAREA_TEXT).should_not == nil
|
@@ -73,22 +93,18 @@ module WinGuiTest
|
|
73
93
|
pending 'Need to find some control ID'
|
74
94
|
@app.child(TEXTAREA_ID).should_not == nil
|
75
95
|
end
|
76
|
-
|
96
|
+
|
77
97
|
it 'raises error if wrong control is given' do
|
78
98
|
expect { @app.child('Impossible Control')}.to raise_error "Control 'Impossible Control' not found"
|
79
99
|
end
|
80
|
-
|
81
|
-
|
100
|
+
|
101
|
+
it 'substitutes & for _ when searching by title ("&Yes" type controls)' # Why?
|
82
102
|
end
|
83
|
-
|
84
|
-
context '#children' do
|
85
|
-
spec { use { children = @app.children }}
|
86
103
|
|
87
|
-
|
88
|
-
|
89
|
-
end
|
104
|
+
describe '#children' do
|
105
|
+
spec { use { children = @app.children }}
|
90
106
|
|
91
|
-
it 'returns an array of
|
107
|
+
it 'returns an array of Windows that are descendants (not only DIRECTchildren) of a given Window' do
|
92
108
|
children = @app.children
|
93
109
|
children.should be_a_kind_of Array
|
94
110
|
children.should_not be_empty
|
@@ -111,7 +127,7 @@ module WinGuiTest
|
|
111
127
|
# expect { @app.child('Impossible Control')}.to raise_error "Control 'Impossible Control' not found"
|
112
128
|
# end
|
113
129
|
# it 'substitutes & for _ when searching by title ("&Yes" type controls)'
|
114
|
-
|
130
|
+
|
115
131
|
end
|
116
132
|
|
117
133
|
context '#click' do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 1
|
9
|
+
version: 0.2.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- arvicco
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-31 00:00:00 +04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -69,10 +69,12 @@ extra_rdoc_files:
|
|
69
69
|
- README.rdoc
|
70
70
|
files:
|
71
71
|
- lib/version.rb
|
72
|
+
- lib/win_gui/convenience.rb
|
72
73
|
- lib/win_gui/window.rb
|
73
74
|
- lib/win_gui.rb
|
74
75
|
- spec/spec.opts
|
75
76
|
- spec/spec_helper.rb
|
77
|
+
- spec/win_gui/convenience_spec.rb
|
76
78
|
- spec/win_gui/window_spec.rb
|
77
79
|
- features/step_definitions/win_gui_steps.rb
|
78
80
|
- features/support/env.rb
|
@@ -127,4 +129,5 @@ summary: Abstractions/wrappers around GUI-related Win32 API functions
|
|
127
129
|
test_files:
|
128
130
|
- spec/spec.opts
|
129
131
|
- spec/spec_helper.rb
|
132
|
+
- spec/win_gui/convenience_spec.rb
|
130
133
|
- spec/win_gui/window_spec.rb
|