wx-nobbie 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/KNOWN ISSUES +24 -0
- data/README +153 -0
- data/lib/nobbie/wx/acceptance_test.rb +19 -0
- data/lib/nobbie/wx/command.rb +63 -0
- data/lib/nobbie/wx/command/choose.rb +38 -0
- data/lib/nobbie/wx/command/click_on.rb +35 -0
- data/lib/nobbie/wx/command/get_component.rb +17 -0
- data/lib/nobbie/wx/command/get_options.rb +27 -0
- data/lib/nobbie/wx/command/get_selected_values.rb +25 -0
- data/lib/nobbie/wx/command/is_chosen.rb +21 -0
- data/lib/nobbie/wx/command/is_enabled.rb +18 -0
- data/lib/nobbie/wx/command/select.rb +97 -0
- data/lib/nobbie/wx/command/type_into.rb +73 -0
- data/lib/nobbie/wx/command_executor.rb +25 -0
- data/lib/nobbie/wx/command_factory.rb +52 -0
- data/lib/nobbie/wx/driven.rb +7 -0
- data/lib/nobbie/wx/impl/element/element_path_builder.rb +42 -0
- data/lib/nobbie/wx/impl/operation/choosable.rb +31 -0
- data/lib/nobbie/wx/impl/operation/select.rb +37 -0
- data/lib/nobbie/wx/launcher.rb +75 -0
- data/lib/nobbie/wx/operations.rb +85 -0
- data/lib/nobbie/wx/platform.rb +31 -0
- data/test/all_tests.rb +6 -0
- data/test/suite/app.rb +144 -0
- data/test/suite/nobbie_test_case.rb +46 -0
- data/test/suite/test_choose.rb +52 -0
- data/test/suite/test_click.rb +28 -0
- data/test/suite/test_enabled.rb +13 -0
- data/test/suite/test_launcher.rb +22 -0
- data/test/suite/test_operations.rb +27 -0
- data/test/suite/test_selection.rb +138 -0
- data/test/suite/test_type.rb +59 -0
- metadata +94 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'nobbie/wx/platform'
|
2
|
+
require 'nobbie/wx/command_factory'
|
3
|
+
require 'nobbie/wx/launcher'
|
4
|
+
|
5
|
+
impl = File.dirname(__FILE__) + File::SEPARATOR + 'impl'
|
6
|
+
Dir.glob("#{impl}/**/*.rb") {|f| require "#{f}" }
|
7
|
+
|
8
|
+
module Nobbie
|
9
|
+
module Wx
|
10
|
+
|
11
|
+
module Operations
|
12
|
+
|
13
|
+
# Types text into the component specified in the path.
|
14
|
+
# Supported components: TextCtrl, ComboBox
|
15
|
+
def type(text, path)
|
16
|
+
execute(command_factory.create_type_into_command(coerce_path(path), text))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Clicks the component specified in the path.
|
20
|
+
# Supported components: Button
|
21
|
+
def click(path)
|
22
|
+
execute(command_factory.create_click_on_command(coerce_path(path)))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the component specified in the path. Useful for performing operations that Nobbie does not
|
26
|
+
# currently support.
|
27
|
+
# Supported components: Any
|
28
|
+
def component(path)
|
29
|
+
execute(command_factory.create_get_component_command(coerce_path(path)))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a SelectionOperations[link:classes/Nobbie/Wx/SelectOperations.html] for interacting with
|
33
|
+
# the component specified in the path
|
34
|
+
def selection(path)
|
35
|
+
SelectOperations.new(self, coerce_path(path))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a ChoosableOperations[link:classes/Nobbie/Wx/ChoosableOperations.html] for interacting with
|
39
|
+
# the component specified in the path
|
40
|
+
def choosable(path)
|
41
|
+
ChoosableOperations.new(self, coerce_path((path)))
|
42
|
+
end
|
43
|
+
|
44
|
+
# Determines if the component specified in the path is currently enabled.
|
45
|
+
# Supported components: Any
|
46
|
+
def enabled?(path)
|
47
|
+
execute(command_factory.create_is_enabled_command(coerce_path(path)))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates an instance of the default {path builder}[link:classes/Nobbie/Wx/ElementPathBuilder.html].
|
51
|
+
# Override this method if you wish to provide an alternative default path builder (because coerce_path
|
52
|
+
# uses in_() internally).
|
53
|
+
def in_(name)
|
54
|
+
ElementPathBuilder.new(name)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates an instance of the default {command factory}[link:classes/Nobbie/Wx/CommandFactory.html].
|
58
|
+
# Override this method if you wish to provide an alternative command factory.
|
59
|
+
def command_factory
|
60
|
+
Command::Factory.new
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def coerce_path(path)
|
66
|
+
return path if path.respond_to?(:find_component)
|
67
|
+
|
68
|
+
if path.is_a?(Hash) && path.has_key?(:in)
|
69
|
+
return path[:in].is_a?(String) ? in_(path[:in]) : path[:in]
|
70
|
+
end
|
71
|
+
|
72
|
+
return in_(path.id2name) if path.is_a?(Symbol)
|
73
|
+
return in_(path) if path.is_a?(String)
|
74
|
+
|
75
|
+
Kernel.raise("Unable to coerce path: #{path}")
|
76
|
+
end
|
77
|
+
|
78
|
+
#todo: pull up
|
79
|
+
def execute(command)
|
80
|
+
Command::Executor.new.execute(command)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wx'
|
3
|
+
|
4
|
+
#todo: move this into Nobbie::Wx namespace ... once name clash is fixed
|
5
|
+
class Platform #:nodoc:
|
6
|
+
include Wx
|
7
|
+
|
8
|
+
WINDOWS = 'WXMSW'
|
9
|
+
MAC = 'WXMAC'
|
10
|
+
SUPPORTED_PLATFORMS = [WINDOWS, MAC]
|
11
|
+
|
12
|
+
def self.windows?
|
13
|
+
name == WINDOWS
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.ensure_supported
|
17
|
+
Kernel.raise "Sorry '#{name}' is not currently supported, Nobbie-Wx is only available for the following platforms: [#{SUPPORTED_PLATFORMS.join(',')}]" unless supported?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def self.supported?
|
23
|
+
SUPPORTED_PLATFORMS.include?(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.name
|
27
|
+
Wx::PLATFORM
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Platform.ensure_supported
|
data/test/all_tests.rb
ADDED
data/test/suite/app.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'wx'
|
3
|
+
require 'wx_sugar'
|
4
|
+
|
5
|
+
include Wx
|
6
|
+
|
7
|
+
class TestFrame < Frame
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
|
11
|
+
#todo: sort out all this :minsize => true stuff out .. need some way to specify defaults
|
12
|
+
|
13
|
+
panel = add(Panel, :proportion => 1)
|
14
|
+
panel.arrange_vertically(:padding => 4)
|
15
|
+
|
16
|
+
test_notebook = name('test_notebook', panel.add(Notebook, :minsize => true, :proportion => 2))
|
17
|
+
|
18
|
+
test_notebook.add_page(name('type', test_notebook.add(Panel) {|p| p.arrange_vertically
|
19
|
+
listen(:text, name('text_ctrl', p.add(TextCtrl[:value => 'text_ctrl'], :minsize => true)), :update)
|
20
|
+
listen(:text, name('readonly_text_ctrl', p.add(TextCtrl[:value => 'readonly_text_ctrl', :style => TE_READONLY], :minsize => true)), :update)
|
21
|
+
listen(:text, disable(name('disabled_text_ctrl', p.add(TextCtrl[:value => 'disabled_text_ctrl'], :minsize => true))), :update)
|
22
|
+
|
23
|
+
listen(:text, name('combo_box', p.add(ComboBox[:value => 'combo_box'], :minsize => true)), :update)
|
24
|
+
readonly_combo_box = name('readonly_combo_box', p.add(ComboBox[:style => CB_READONLY], :minsize => true))
|
25
|
+
readonly_combo_box.append('readonly_combo_box')
|
26
|
+
readonly_combo_box.selection = 0
|
27
|
+
listen(:text, readonly_combo_box, :update)
|
28
|
+
listen(:text, disable(name('disabled_combo_box', p.add(ComboBox[:value => 'disabled_combo_box'], :minsize => true))), :update)
|
29
|
+
}), 'type')
|
30
|
+
|
31
|
+
test_notebook.add_page(name('click', test_notebook.add(Panel, :minsize => true) {|p| p.arrange_vertically
|
32
|
+
listen(:button, name('button', p.add(Button[:label => 'regular_button'], :minsize => true)), :update)
|
33
|
+
listen(:button, name('labelled_button_name', p.add(Button[:label => 'labelled_button'], :minsize => true)), :update)
|
34
|
+
listen(:button, disable(name('disabled_button', p.add(Button[:label => 'disabled_button'], :minsize => true))), :update)
|
35
|
+
name('static_text', p.add(StaticText[:label => 'static_text'], :minsize => true))
|
36
|
+
}), 'click')
|
37
|
+
|
38
|
+
test_notebook.add_page(name('selection', test_notebook.add(Panel) {|p| p.arrange_vertically
|
39
|
+
notebook = name('notebook', p.add(Notebook, :minsize => true))
|
40
|
+
notebook.add_page(name('notebook_page1', notebook.add(Panel)), 'notebook_page1')
|
41
|
+
notebook.add_page(name('notebook_page2', notebook.add(Panel)), 'notebook_page2')
|
42
|
+
notebook.evt_notebook_page_changing(notebook.get_id()) {|e| update(e) }
|
43
|
+
|
44
|
+
disabled_notebook = disable(name('disabled_notebook', p.add(Notebook, :minsize => true)))
|
45
|
+
disabled_notebook.add_page(name('disabled_notebook_page1', disabled_notebook.add(Panel)), 'disabled_notebook_page1')
|
46
|
+
disabled_notebook.add_page(name('disabled_notebook_page2', disabled_notebook.add(Panel)), 'disabled_notebook_page2')
|
47
|
+
disabled_notebook.evt_notebook_page_changing(disabled_notebook.get_id()) {|e| update(e) }
|
48
|
+
|
49
|
+
#todo: make me have a visible name on screen
|
50
|
+
combo_box_with_items = name('combo_box_with_items', p.add(ComboBox, :minsize => true))
|
51
|
+
combo_box_with_items.append('combo_box_item')
|
52
|
+
listen(:combobox, combo_box_with_items, :update)
|
53
|
+
|
54
|
+
disabled_combo_box_with_items = disable(name('disabled_combo_box_with_items', p.add(ComboBox, :minsize => true)))
|
55
|
+
disabled_combo_box_with_items.append('disabled_combo_box_item1')
|
56
|
+
disabled_combo_box_with_items.append('disabled_combo_box_item2')
|
57
|
+
listen(:combobox, disabled_combo_box_with_items, :update)
|
58
|
+
|
59
|
+
list_box_with_items = name('list_box_with_items', p.add(ListBox, :minsize => true))
|
60
|
+
list_box_with_items.append('list_box_item')
|
61
|
+
listen(:listbox, list_box_with_items, :update)
|
62
|
+
|
63
|
+
disabled_list_box_with_items = disable(name('disabled_list_box_with_items', p.add(ListBox, :minsize => true)))
|
64
|
+
disabled_list_box_with_items.append('disabled_list_box_item1')
|
65
|
+
disabled_list_box_with_items.append('disabled_list_box_item2')
|
66
|
+
listen(:listbox, disabled_list_box_with_items, :update)
|
67
|
+
|
68
|
+
choice_with_items = name('choice_with_items', p.add(Choice, :minsize => true))
|
69
|
+
choice_with_items.append('choice_item')
|
70
|
+
listen(:choice, choice_with_items, :update)
|
71
|
+
|
72
|
+
disabled_choice_with_items = disable(name('disabled_choice_with_items', p.add(Choice, :minsize => true)))
|
73
|
+
disabled_choice_with_items.append('disabled_choice_item1')
|
74
|
+
disabled_choice_with_items.append('disabled_choice_item2')
|
75
|
+
listen(:choice, disabled_choice_with_items, :update)
|
76
|
+
|
77
|
+
}), 'selection')
|
78
|
+
|
79
|
+
test_notebook.add_page(name('choose', test_notebook.add(Panel) {|p| p.arrange_vertically
|
80
|
+
#todo: make me have a visible name on screen
|
81
|
+
listen(:radiobutton, name('radio_button', p.add(RadioButton, :minsize => true)), :update)
|
82
|
+
|
83
|
+
#todo: make me have a visible name on screen
|
84
|
+
listen(:radiobutton, disable(name('disabled_radio_button', p.add(RadioButton, :minsize => true))), :update)
|
85
|
+
|
86
|
+
#todo: make me have a visible name on screen
|
87
|
+
listen(:checkbox, name('check_box', p.add(CheckBox, :minsize => true)), :update)
|
88
|
+
|
89
|
+
#todo: make me have a visible name on screen
|
90
|
+
listen(:checkbox, disable(name('disabled_check_box', p.add(CheckBox, :minsize => true))), :update)
|
91
|
+
|
92
|
+
}), 'choose')
|
93
|
+
|
94
|
+
@log = name('log', panel.add(TextCtrl[:style => TE_READONLY | TE_MULTILINE], :minsize => true, :proportion => 1))
|
95
|
+
|
96
|
+
menu_bar = MenuBar.new
|
97
|
+
file_menu = Menu.new
|
98
|
+
|
99
|
+
#todo: remove these crappy id's ... there must be a nice sugary way to build menu's
|
100
|
+
file_new = file_menu.append(101, "&New...\tCtrl+N")
|
101
|
+
file_disabled = file_menu.append(102, "&disabled")
|
102
|
+
|
103
|
+
menu_bar.append(file_menu, '&File')
|
104
|
+
set_menu_bar(menu_bar)
|
105
|
+
|
106
|
+
#todo: make disable() handle menus ...
|
107
|
+
menu_bar.enable(102, false)
|
108
|
+
|
109
|
+
#todo: make update() handle menus ...
|
110
|
+
listen(:menu, @file_new) {|e| log('file_new') }
|
111
|
+
end
|
112
|
+
|
113
|
+
def on_init
|
114
|
+
self.update
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def name(name, component)
|
120
|
+
component.name = name
|
121
|
+
component
|
122
|
+
end
|
123
|
+
|
124
|
+
def disable(component)
|
125
|
+
component.disable
|
126
|
+
component
|
127
|
+
end
|
128
|
+
|
129
|
+
def log(text)
|
130
|
+
@log.append_text(text)
|
131
|
+
end
|
132
|
+
|
133
|
+
def update(e)
|
134
|
+
@log.append_text("#{e.event_object.name}: #{e.string}\n")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class TestApp < App
|
139
|
+
def on_init
|
140
|
+
TestFrame.new(nil, :title => 'test', :size => [1024, 768]).show
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
TestApp.new.main_loop if __FILE__ == $0
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module NobbieTestCase
|
2
|
+
include Nobbie::Wx
|
3
|
+
|
4
|
+
def setup
|
5
|
+
puts "\n[Started: #{name}]"
|
6
|
+
begin
|
7
|
+
select_tab_for_test
|
8
|
+
rescue ValueNotFoundException
|
9
|
+
#ok - this test doesn't have its own tab'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
puts "\n[Finished: #{name}]"
|
15
|
+
end
|
16
|
+
|
17
|
+
def select_tab_for_test
|
18
|
+
clear_events
|
19
|
+
tab = self.class.name.gsub('Test', '').downcase
|
20
|
+
selection(:in => 'test_notebook').choose tab
|
21
|
+
assert_equal tab, selection(:in => 'test_notebook').selected_value
|
22
|
+
end
|
23
|
+
|
24
|
+
def text(component)
|
25
|
+
component.nil? ? nil : component.value
|
26
|
+
end
|
27
|
+
|
28
|
+
def clear_events
|
29
|
+
log.clear
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_exception(e)
|
33
|
+
assert_raise e do yield end
|
34
|
+
assert_events
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_events(expected_items=[])
|
38
|
+
expected_items = [expected_items] unless expected_items.is_a?(Array)
|
39
|
+
actual_items = text(log).split("\n")
|
40
|
+
assert_equal expected_items, actual_items
|
41
|
+
end
|
42
|
+
|
43
|
+
def log
|
44
|
+
component 'log'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class TestChoose < Test::Unit::TestCase
|
2
|
+
include NobbieTestCase
|
3
|
+
|
4
|
+
#todo: rename file to choosable
|
5
|
+
#todo: should be TestChoosable
|
6
|
+
def test_choose_with_radio_button
|
7
|
+
assert !choosable('radio_button').chosen?
|
8
|
+
choosable('radio_button').choose
|
9
|
+
assert choosable('radio_button').chosen?
|
10
|
+
assert_events 'radio_button: '
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_choose_with_check_box
|
14
|
+
assert !choosable('check_box').chosen?
|
15
|
+
choosable('check_box').choose
|
16
|
+
assert choosable('check_box').chosen?
|
17
|
+
assert_events 'check_box: '
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_choose_with_component_disabled_radio_button
|
21
|
+
assert_exception ComponentDisabledException do choosable('disabled_radio_button').choose end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_choose_with_component_disabled_check_box
|
25
|
+
assert_exception ComponentDisabledException do choosable('disabled_check_box').choose end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_choose_with_unsupported_operation_for_component
|
29
|
+
assert_exception UnsupportedOperationForComponentException do choosable('button').choose end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_choose_with_component_not_found
|
33
|
+
assert_exception ComponentNotFoundException do choosable('missing').choose end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_chosen_with_unsupported_operation_for_component
|
37
|
+
assert_exception UnsupportedOperationForComponentException do choosable('button').chosen? end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_chosen_with_component_not_found
|
41
|
+
assert_exception ComponentNotFoundException do choosable('missing').chosen? end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_chosen_with_component_disabled_radio_button
|
45
|
+
assert !choosable('disabled_radio_button').chosen?
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_chosen_with_component_disabled_check_box
|
49
|
+
assert !choosable('disabled_check_box').chosen?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class TestClick < Test::Unit::TestCase
|
2
|
+
include NobbieTestCase
|
3
|
+
|
4
|
+
def test_click_with_named_button
|
5
|
+
click 'button'
|
6
|
+
#todo: improve event detail
|
7
|
+
assert_events 'button: '
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_click_with_labelled_button
|
11
|
+
click 'labelled_button'
|
12
|
+
#todo: improve event detail
|
13
|
+
assert_events 'labelled_button_name: '
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_click_with_component_not_found
|
17
|
+
assert_exception ComponentNotFoundException do click 'missing' end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_click_with_component_disabled
|
21
|
+
assert_exception ComponentDisabledException do click 'disabled_button' end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_click_with_unsupported_operation_for_component
|
25
|
+
assert_exception UnsupportedOperationForComponentException do click 'static_text' end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class TestEnabled < Test::Unit::TestCase
|
2
|
+
include NobbieTestCase
|
3
|
+
|
4
|
+
def test_enabled
|
5
|
+
assert enabled?('text_ctrl')
|
6
|
+
assert !enabled?('disabled_text_ctrl')
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_enabled_with_component_not_found
|
10
|
+
assert_exception ComponentNotFoundException do enabled?('missing') end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class TestLauncher < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def test_application_under_test_is_not_defined
|
4
|
+
begin
|
5
|
+
Nobbie::Wx::ApplicationLauncher.module_eval('def get_application; raise NameError.new; end;')
|
6
|
+
Nobbie::Wx::ApplicationLauncher.new
|
7
|
+
fail
|
8
|
+
rescue RuntimeError => e
|
9
|
+
assert_equal Nobbie::Wx::ApplicationLauncher::AUT_NOT_DEFINED, e.message
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_application_under_test_is_not_a_wx_app
|
14
|
+
begin
|
15
|
+
Nobbie::Wx::ApplicationLauncher.module_eval('def get_application; String.new; end;')
|
16
|
+
Nobbie::Wx::ApplicationLauncher.new
|
17
|
+
fail
|
18
|
+
rescue RuntimeError => e
|
19
|
+
assert_equal Nobbie::Wx::ApplicationLauncher::AUT_NOT_WX_APP, e.message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class UserPathBuilder
|
2
|
+
def find_component
|
3
|
+
"something"
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestOperations < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def test_coerce_path
|
10
|
+
assert_path component('text_ctrl')
|
11
|
+
assert_path component(:in => 'text_ctrl')
|
12
|
+
assert_path component(in_('text_ctrl'))
|
13
|
+
assert_path component(Nobbie::Wx::ElementPathBuilder.new('text_ctrl'))
|
14
|
+
assert_path component(UserPathBuilder.new)
|
15
|
+
assert_path component(:text_ctrl)
|
16
|
+
begin
|
17
|
+
component(Hash.new)
|
18
|
+
fail
|
19
|
+
rescue RuntimeError => e
|
20
|
+
assert_equal 'Unable to coerce path: ', e.message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def assert_path(path)
|
25
|
+
assert_not_nil path
|
26
|
+
end
|
27
|
+
end
|