gutkumber 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +2 -0
- data/LICENSE +20 -0
- data/README.md +94 -0
- data/Rakefile +20 -0
- data/VERSION +1 -0
- data/gutkumber.gemspec +62 -0
- data/lib/gutkumber.rb +27 -0
- data/lib/gutkumber/features_helper.rb +36 -0
- data/lib/gutkumber/finders.rb +68 -0
- data/lib/gutkumber/formatter/gtk_formatter.rb +16 -0
- data/lib/gutkumber/formatter/gtk_progress_formatter.rb +16 -0
- data/lib/gutkumber/gtk/dialog.rb +19 -0
- data/lib/gutkumber/steps/clicking_steps.rb +32 -0
- data/lib/gutkumber/steps/common_steps.rb +27 -0
- data/lib/gutkumber/steps/gtk_steps.rb +63 -0
- data/lib/gutkumber/steps/keypress_steps.rb +60 -0
- data/lib/gutkumber/steps/menu_steps.rb +28 -0
- data/lib/gutkumber/steps/window_steps.rb +8 -0
- metadata +93 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Daniel Lucraft
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
Gutkumber
|
2
|
+
=========
|
3
|
+
|
4
|
+
by Daniel Lucraft (dan@fluentradical.com)
|
5
|
+
|
6
|
+
Description
|
7
|
+
-----------
|
8
|
+
|
9
|
+
A set Ruby-GNOME2 automation helpers. Comes with Cucumber
|
10
|
+
formatters and steps for writing features.
|
11
|
+
|
12
|
+
Features
|
13
|
+
--------
|
14
|
+
|
15
|
+
* Interact with dialogs using Cucumber steps:
|
16
|
+
|
17
|
+
When I click on "OK" in the "Save changes?" dialog
|
18
|
+
|
19
|
+
* Make keypresses:
|
20
|
+
|
21
|
+
When I press "Shift+K"
|
22
|
+
|
23
|
+
* and mouse clicks:
|
24
|
+
|
25
|
+
When I right click on ....
|
26
|
+
|
27
|
+
* Type into TextEntrys or TextViews
|
28
|
+
|
29
|
+
When I type "hello"
|
30
|
+
|
31
|
+
Install & Requirements
|
32
|
+
----------------------
|
33
|
+
|
34
|
+
Clone from git://github.com/danlucraft/gutkumber.git
|
35
|
+
Requires Cucumber >= 0.3
|
36
|
+
|
37
|
+
Usage
|
38
|
+
-----
|
39
|
+
|
40
|
+
Gutkumber requires that the Gtk main loop NOT be started, in order that it
|
41
|
+
can control the flow of events between steps. Therefore the code that starts the main
|
42
|
+
loop should be modified to look like this:
|
43
|
+
|
44
|
+
unless $gutkumber
|
45
|
+
Gtk.main_with_queue(100)
|
46
|
+
end
|
47
|
+
|
48
|
+
Other than that, you can load your application normally, from your Cucumber env.rb file.
|
49
|
+
|
50
|
+
When you run your Cucumber tests, you must specify one of the Gtk formatters, like this:
|
51
|
+
|
52
|
+
--format Cucumber::Formatter::GtkFormatter
|
53
|
+
--format Cucumber::Formatter::GtkProgressFormatter
|
54
|
+
|
55
|
+
Writing a testable Ruby-GNOME2 application
|
56
|
+
------------------------------------------
|
57
|
+
|
58
|
+
In normal Gtk, Dialog#run *blocks*. This is no good for testing. To see why, imagine
|
59
|
+
these (imaginary) steps:
|
60
|
+
|
61
|
+
When I open the "Save" dialog
|
62
|
+
And I fill in a filename of "Foo.rb"
|
63
|
+
And I click on "Save"
|
64
|
+
|
65
|
+
Since the Dialog#run method blocks (makes your application do nothing until it receives
|
66
|
+
some input into the dialog), the second two steps will never be reached.
|
67
|
+
|
68
|
+
Therefore Gutkumber overrides Dialog#run to just show the Dialog, and not block.
|
69
|
+
|
70
|
+
So if you use Dialog#run in your application, then the implication is that you MUST make
|
71
|
+
sure that ALL effects from the Dialog are handled in response blocks. The following will
|
72
|
+
not work anymore:
|
73
|
+
|
74
|
+
response = dialog.run
|
75
|
+
# ... do stuff based on response
|
76
|
+
|
77
|
+
Previously the other stuff would only be run after the dialog closed, but in the testing
|
78
|
+
environment, dialog.run will just show the dialog and return nil immediately. Change this code
|
79
|
+
to:
|
80
|
+
|
81
|
+
dialog.run do |response|
|
82
|
+
# ... do stuff based on response.
|
83
|
+
end
|
84
|
+
# absolutely nothing can go here.
|
85
|
+
|
86
|
+
This is not ideal. But I haven't been able to come up with any other way to make testing
|
87
|
+
dialogs possible.
|
88
|
+
|
89
|
+
License
|
90
|
+
-------
|
91
|
+
|
92
|
+
Gutkumber is copyright 2009 Daniel B. Lucraft and contributors. It is licensed under the GPL2.
|
93
|
+
|
94
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "gutkumber"
|
8
|
+
gem.summary = %Q{Ruby-GNOME2 integration testing library}
|
9
|
+
gem.description = %Q{Gutkumber adds support to running cucumber tests for Ruby-Gnome 2 applications}
|
10
|
+
gem.email = "dan@fluentradical.com"
|
11
|
+
gem.homepage = "http://github.com/danlucraft/gutkumber"
|
12
|
+
gem.authors = ["Daniel Lucraft"]
|
13
|
+
gem.add_dependency(%q<rspec>, [">= 1.2.0"])
|
14
|
+
gem.add_dependency(%q<cucumber>, [">= 0.3.0"])
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/gutkumber.gemspec
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{gutkumber}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Lucraft"]
|
12
|
+
s.date = %q{2010-02-19}
|
13
|
+
s.description = %q{Gutkumber adds support to running cucumber tests for Ruby-Gnome 2 applications}
|
14
|
+
s.email = %q{dan@fluentradical.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"gutkumber.gemspec",
|
27
|
+
"lib/gutkumber.rb",
|
28
|
+
"lib/gutkumber/features_helper.rb",
|
29
|
+
"lib/gutkumber/finders.rb",
|
30
|
+
"lib/gutkumber/formatter/gtk_formatter.rb",
|
31
|
+
"lib/gutkumber/formatter/gtk_progress_formatter.rb",
|
32
|
+
"lib/gutkumber/gtk/dialog.rb",
|
33
|
+
"lib/gutkumber/steps/clicking_steps.rb",
|
34
|
+
"lib/gutkumber/steps/common_steps.rb",
|
35
|
+
"lib/gutkumber/steps/gtk_steps.rb",
|
36
|
+
"lib/gutkumber/steps/keypress_steps.rb",
|
37
|
+
"lib/gutkumber/steps/menu_steps.rb",
|
38
|
+
"lib/gutkumber/steps/window_steps.rb"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/danlucraft/gutkumber}
|
41
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.3.5}
|
44
|
+
s.summary = %q{Ruby-GNOME2 integration testing library}
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_runtime_dependency(%q<rspec>, [">= 1.2.0"])
|
52
|
+
s.add_runtime_dependency(%q<cucumber>, [">= 0.3.0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<rspec>, [">= 1.2.0"])
|
55
|
+
s.add_dependency(%q<cucumber>, [">= 0.3.0"])
|
56
|
+
end
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<rspec>, [">= 1.2.0"])
|
59
|
+
s.add_dependency(%q<cucumber>, [">= 0.3.0"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/lib/gutkumber.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
$:.push(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
$gutkumber = true
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'gtk2'
|
8
|
+
require 'spec/expectations'
|
9
|
+
|
10
|
+
require 'cucumber/formatter/progress'
|
11
|
+
require 'cucumber/formatter/pretty'
|
12
|
+
|
13
|
+
require 'gutkumber/formatter/gtk_formatter'
|
14
|
+
require 'gutkumber/formatter/gtk_progress_formatter'
|
15
|
+
require 'gutkumber/features_helper'
|
16
|
+
require 'gutkumber/gtk/dialog'
|
17
|
+
require 'gutkumber/finders'
|
18
|
+
|
19
|
+
Dir[File.dirname(__FILE__) + "/gutkumber/steps/*_steps.rb"].each {|fn| require fn }
|
20
|
+
|
21
|
+
module Gutkumber
|
22
|
+
def self.in_test_process?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
World(FeaturesHelper)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
module FeaturesHelper
|
3
|
+
STRING_RE = /"((?:[^"]|\\")+)"/
|
4
|
+
NUMBER_RE = /(\d+|zero|one|two|three|four|five|six|seven|eight|nine|ten)/
|
5
|
+
ORDINALS = {
|
6
|
+
"first" => 1,
|
7
|
+
"second" => 2,
|
8
|
+
"third" => 3,
|
9
|
+
"fourth" => 4,
|
10
|
+
"fifth" => 5,
|
11
|
+
"sixth" => 6,
|
12
|
+
"seventh" => 7,
|
13
|
+
"eighth" => 8,
|
14
|
+
"ninth" => 9,
|
15
|
+
"tenth" => 10
|
16
|
+
}
|
17
|
+
ORDINAL_RE = /(#{ORDINALS.keys.join("|")})/
|
18
|
+
|
19
|
+
def parse_number(number)
|
20
|
+
numbers = %w(zero one two three four five six seven eight nine ten)
|
21
|
+
numbers.index(number) || number.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_string(string)
|
25
|
+
string.gsub("\\\"", "\"")
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_ordinal(ordinal)
|
29
|
+
ORDINALS[ordinal]
|
30
|
+
end
|
31
|
+
|
32
|
+
def only(array)
|
33
|
+
array.length.should == 1
|
34
|
+
array.first
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
module Gutkumber
|
3
|
+
TICK_SIZE = ENV["GUTKUMBER_TICK_SIZE"] || 0.3
|
4
|
+
|
5
|
+
def self.find_gtk_window(title)
|
6
|
+
Gtk::Window.toplevels.detect do |window|
|
7
|
+
if title.is_a?(Regexp)
|
8
|
+
window.title =~ title
|
9
|
+
else
|
10
|
+
window.title =~ Regexp.new(Regexp.escape(title))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.dialogs
|
16
|
+
Gtk::Window.toplevels.select do |window|
|
17
|
+
window.class.ancestors.include?(Gtk::Dialog)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find_all_gtk_windows
|
22
|
+
Gtk::Window.toplevels
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.window_buttons(window)
|
26
|
+
buttons = window.child_widgets_with_class(Gtk::Button)
|
27
|
+
buttons.map {|button| button.child_widgets_with_class(Gtk::Label).map{|la| la.text}.join(" ") }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.label_texts(widget)
|
31
|
+
widget.child_widgets_with_class(Gtk::Label).map do |label|
|
32
|
+
label.text
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.find_button(window, button_label)
|
37
|
+
buttons = window.child_widgets_with_class(Gtk::Button)
|
38
|
+
buttons.each do |button|
|
39
|
+
label = button.child_widgets_with_class(Gtk::Label).map{|la| la.text}.join(" ")
|
40
|
+
return button if label =~ Regexp.new(Regexp.escape(button_label))
|
41
|
+
end
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.tick
|
46
|
+
Gtk.main_iteration while Gtk.events_pending?
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.wait_tick
|
50
|
+
tick
|
51
|
+
sleep TICK_SIZE
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Gtk::Widget
|
56
|
+
|
57
|
+
def child_widgets_with_class(klass, acc=[])
|
58
|
+
if self.is_a? klass
|
59
|
+
acc << self
|
60
|
+
end
|
61
|
+
if self.respond_to?(:children)
|
62
|
+
self.children.each do |gtk_child|
|
63
|
+
gtk_child.child_widgets_with_class(klass, acc)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
acc
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Cucumber
|
3
|
+
module Formatter
|
4
|
+
class GtkFormatter < Pretty
|
5
|
+
|
6
|
+
def visit_step(*)
|
7
|
+
Gtk.main_iteration while Gtk.events_pending?
|
8
|
+
Gtk.execute_pending_blocks
|
9
|
+
super
|
10
|
+
if time_str = ENV['GUTKUMBER_SLEEP']
|
11
|
+
sleep time_str.to_f
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Cucumber
|
3
|
+
module Formatter
|
4
|
+
class GtkProgressFormatter < Progress
|
5
|
+
|
6
|
+
def visit_step(*)
|
7
|
+
Gtk.main_iteration while Gtk.events_pending?
|
8
|
+
Gtk.execute_pending_blocks
|
9
|
+
super
|
10
|
+
if time_str = ENV['GUTKUMBER_SLEEP']
|
11
|
+
sleep time_str.to_f
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Gtk
|
3
|
+
class Dialog
|
4
|
+
class << self
|
5
|
+
def _cucumber_running_dialogs
|
6
|
+
@_cucumber_running_dialogs ||= []
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(*args, &block)
|
11
|
+
show_all
|
12
|
+
Dialog._cucumber_running_dialogs << self
|
13
|
+
signal_connect('response') do |_, response|
|
14
|
+
block.call(response)
|
15
|
+
Dialog._cucumber_running_dialogs.delete(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
def make_event_button(window, x, y, button, type)
|
3
|
+
case type
|
4
|
+
when :press
|
5
|
+
event_button = Gdk::EventButton.new(Gdk::Event::BUTTON_PRESS)
|
6
|
+
when :press2
|
7
|
+
event_button = Gdk::EventButton.new(Gdk::Event::BUTTON2_PRESS)
|
8
|
+
when :press3
|
9
|
+
event_button = Gdk::EventButton.new(Gdk::Event::BUTTON3_PRESS)
|
10
|
+
when :release
|
11
|
+
event_button = Gdk::EventButton.new(Gdk::Event::BUTTON_RELEASE)
|
12
|
+
end
|
13
|
+
event_button.x = x
|
14
|
+
event_button.y = y
|
15
|
+
event_button.button = button
|
16
|
+
event_button.time = Gdk::Event::CURRENT_TIME
|
17
|
+
event_button.window = window
|
18
|
+
event_button
|
19
|
+
end
|
20
|
+
|
21
|
+
def right_click_on(widget)
|
22
|
+
make_event_button(widget.window, 0, 0, 3, :press).put
|
23
|
+
make_event_button(widget.window, 0, 0, 3, :release).put
|
24
|
+
end
|
25
|
+
|
26
|
+
def left_click_on(widget)
|
27
|
+
allocation = widget.allocation
|
28
|
+
x = allocation.x + allocation.width/2
|
29
|
+
y = allocation.y + allocation.height/2
|
30
|
+
make_event_button(widget.window, x, y, 1, :press).put
|
31
|
+
make_event_button(widget.window, x, y, 1, :release).put
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
When /I wait (?:for )?(\d+)(?: seconds)?/ do |num|
|
3
|
+
sleep num.to_i
|
4
|
+
end
|
5
|
+
|
6
|
+
When /I wait a tick/ do
|
7
|
+
sleep 1
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^the file "([^"]+)" does not exist$/ do |filename|
|
11
|
+
FileUtils.rm_f(filename)
|
12
|
+
end
|
13
|
+
|
14
|
+
Given /^the file #{FeaturesHelper::STRING_RE} contains #{FeaturesHelper::STRING_RE}$/ do |filename, contents|
|
15
|
+
File.open(filename, "w") do |f|
|
16
|
+
f.puts contents
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^the file #{FeaturesHelper::STRING_RE} should contain #{FeaturesHelper::STRING_RE}$/ do |filename, contents|
|
21
|
+
IO.read(filename).chomp.should == contents
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^the file #{FeaturesHelper::STRING_RE} should not exist$/ do |filename|
|
25
|
+
File.exist?(filename).should_not be_true
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
When /^I left click on the button #{FeaturesHelper::STRING_RE} in the window #{FeaturesHelper::STRING_RE}$/ do |button, window|
|
2
|
+
button = parse_string(button)
|
3
|
+
window = Regexp.new(parse_string(window))
|
4
|
+
|
5
|
+
window = Gutkumber.find_gtk_window(window)
|
6
|
+
button = Gutkumber.find_button(window, button)
|
7
|
+
|
8
|
+
button.clicked
|
9
|
+
end
|
10
|
+
|
11
|
+
When /I click the button #{FeaturesHelper::STRING_RE} in the dialog #{FeaturesHelper::STRING_RE}/ do |button, dialog|
|
12
|
+
button, dialog = parse_string(button), parse_string(dialog)
|
13
|
+
dialog = Gutkumber.find_gtk_window(dialog)
|
14
|
+
button = Gutkumber.find_button(dialog, button)
|
15
|
+
|
16
|
+
dialog.response(dialog.get_response(button))
|
17
|
+
# sadly necessary for some reason. Please tell me why!
|
18
|
+
Gutkumber.wait_tick
|
19
|
+
end
|
20
|
+
|
21
|
+
When /^I save as #{FeaturesHelper::STRING_RE}$/ do |filename|
|
22
|
+
filename = parse_string(filename)
|
23
|
+
dialog = Gutkumber.find_gtk_window("Save As")
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^I set the #{FeaturesHelper::STRING_RE} dialog's filename to #{FeaturesHelper::STRING_RE}$/ do |dialog_name, filename|
|
27
|
+
dialog_name, filename = parse_string(dialog_name), parse_string(filename)
|
28
|
+
dialog = Gutkumber.find_gtk_window(dialog_name)
|
29
|
+
if dialog_name == "Open"
|
30
|
+
dialog.filename = filename
|
31
|
+
else
|
32
|
+
table = dialog.child_widgets_with_class(Gtk::Table).first
|
33
|
+
mystery_gtk = table.children[2]
|
34
|
+
dialog.filename = filename
|
35
|
+
mystery_gtk.text = filename.split("/").last
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Then /I should see a dialog "([^"]+)" with buttons "([^"]+)"/ do |title, button_names| # "
|
40
|
+
dialog = Gutkumber.find_gtk_window(title)
|
41
|
+
raise "couldn't find dialog #{title.inspect}" unless dialog
|
42
|
+
buttons = Gutkumber.window_buttons(dialog)
|
43
|
+
button_names.split(",").map(&:strip).each do |name|
|
44
|
+
buttons.should include(name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Then /I should see #{FeaturesHelper::STRING_RE} in a dialog/ do |text|
|
49
|
+
labels = Gutkumber.dialogs.map {|dialog| Gutkumber.label_texts(dialog) }
|
50
|
+
labels.any?{|label| label.any?{|l| l.include? text}}.should be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
Then /there should be no dialog called "([^"]+)"/ do |title|
|
54
|
+
Gutkumber.find_gtk_window(title).should be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
Then /^I should see #{FeaturesHelper::STRING_RE} in the window #{FeaturesHelper::STRING_RE}$/ do |label_text, window_name|
|
58
|
+
label_text, window = parse_string(label_text), Regexp.new(parse_string(window_name))
|
59
|
+
|
60
|
+
window = Gutkumber.find_gtk_window(window)
|
61
|
+
labels = Gutkumber.label_texts(window)
|
62
|
+
labels.any?{|label| label.include? label_text}.should be_true, "Coundn't find '#{label_text}' in window '#{window_name}', available labels in this window: #{labels.collect { |label| "'#{label}'" }.join(', ')}"
|
63
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
def make_event_key(key, type)
|
3
|
+
bits = key.split("+")
|
4
|
+
ctrl = (bits.include?("Ctrl") ? true : false)
|
5
|
+
alt = (bits.include?("Alt") ? true : false)
|
6
|
+
supr = (bits.include?("Super") ? true : false)
|
7
|
+
letter = bits.last
|
8
|
+
|
9
|
+
shift = (bits.include?("Shift") && (letter =~ /^[[:alpha:]]$/ or letter.length > 1)? true : false)
|
10
|
+
case type
|
11
|
+
when :release
|
12
|
+
new_event_key = Gdk::EventKey.new(Gdk::Event::KEY_RELEASE)
|
13
|
+
when :press
|
14
|
+
new_event_key = Gdk::EventKey.new(Gdk::Event::KEY_PRESS)
|
15
|
+
end
|
16
|
+
|
17
|
+
new_mod_mask = 0
|
18
|
+
new_mod_mask |= Gdk::Window::ModifierType::SHIFT_MASK if shift
|
19
|
+
new_mod_mask |= Gdk::Window::ModifierType::CONTROL_MASK if ctrl
|
20
|
+
new_mod_mask |= Gdk::Window::ModifierType::MOD1_MASK if alt
|
21
|
+
new_mod_mask |= Gdk::Window::ModifierType::SUPER_MASK if supr
|
22
|
+
new_mod_mask = Gdk::Window::ModifierType.new(new_mod_mask)
|
23
|
+
new_event_key.state = new_mod_mask
|
24
|
+
if letter.length > 1
|
25
|
+
keyval = Gdk::Keyval.from_name(letter)
|
26
|
+
if keyval == 0
|
27
|
+
keyval = Gdk::Keyval.from_name(letter.downcase)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
keyval = letter[0]
|
31
|
+
end
|
32
|
+
new_event_key.keyval = keyval
|
33
|
+
new_event_key.hardware_keycode = Gdk::Keymap.default.get_entries_for_keyval(keyval).first.first
|
34
|
+
new_event_key.window = Gtk::Window.toplevels.first.window
|
35
|
+
new_event_key
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect_event_key(gdk_event_key)
|
39
|
+
kv = gdk_event_key.keyval
|
40
|
+
ks = gdk_event_key.state - Gdk::Window::MOD2_MASK
|
41
|
+
ks = ks - Gdk::Window::MOD4_MASK
|
42
|
+
key = Gtk::Accelerator.get_label(kv, ks)
|
43
|
+
# puts "pressing: #{key.inspect}"
|
44
|
+
return kv, ks, key
|
45
|
+
end
|
46
|
+
|
47
|
+
def press_key(key)
|
48
|
+
make_event_key(key, :press).put
|
49
|
+
make_event_key(key, :release).put
|
50
|
+
end
|
51
|
+
|
52
|
+
When /^I (?:have pressed|press) #{FeaturesHelper::STRING_RE}(?: then #{FeaturesHelper::STRING_RE})?$/ do |key1, key2|
|
53
|
+
press_key(parse_string(key1))
|
54
|
+
press_key(parse_string(key2)) if key2
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
def open_menus
|
3
|
+
menus = []
|
4
|
+
ObjectSpace.each_object(Gtk::Menu) { |m| menus << m if m.visible? }
|
5
|
+
menus
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^I choose "([^"]+)" from the menu$/ do |option| # "
|
9
|
+
only(open_menus).children.each do |child|
|
10
|
+
child.activate if child.child.text == option
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Then /^I should see a menu with "([^"]+)"$/ do |option| # "
|
15
|
+
options = []
|
16
|
+
only(open_menus).children.each do |child|
|
17
|
+
if child.child.respond_to?(:text)
|
18
|
+
options << child.child.text
|
19
|
+
else
|
20
|
+
child.child.children.each do |child2|
|
21
|
+
if child2.respond_to?(:text)
|
22
|
+
options << child2.text
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
options.include?(option).should be_true
|
28
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
Then /^I should see a window titled #{FeaturesHelper::STRING_RE}$/ do |string|
|
3
|
+
Gutkumber.find_gtk_window(parse_string(string)).should_not be_nil
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /^I should see a window with title like #{FeaturesHelper::STRING_RE}$/ do |string|
|
7
|
+
Gutkumber.find_gtk_window(Regexp.new(parse_string(string))).should_not be_nil
|
8
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gutkumber
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Lucraft
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-19 00:00:00 -02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cucumber
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.0
|
34
|
+
version:
|
35
|
+
description: Gutkumber adds support to running cucumber tests for Ruby-Gnome 2 applications
|
36
|
+
email: dan@fluentradical.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.md
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.md
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- gutkumber.gemspec
|
52
|
+
- lib/gutkumber.rb
|
53
|
+
- lib/gutkumber/features_helper.rb
|
54
|
+
- lib/gutkumber/finders.rb
|
55
|
+
- lib/gutkumber/formatter/gtk_formatter.rb
|
56
|
+
- lib/gutkumber/formatter/gtk_progress_formatter.rb
|
57
|
+
- lib/gutkumber/gtk/dialog.rb
|
58
|
+
- lib/gutkumber/steps/clicking_steps.rb
|
59
|
+
- lib/gutkumber/steps/common_steps.rb
|
60
|
+
- lib/gutkumber/steps/gtk_steps.rb
|
61
|
+
- lib/gutkumber/steps/keypress_steps.rb
|
62
|
+
- lib/gutkumber/steps/menu_steps.rb
|
63
|
+
- lib/gutkumber/steps/window_steps.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/danlucraft/gutkumber
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- --charset=UTF-8
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Ruby-GNOME2 integration testing library
|
92
|
+
test_files: []
|
93
|
+
|