win32-autogui 0.2.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.
Files changed (72) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +10 -0
  3. data/.yardopts +6 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +60 -0
  6. data/HISTORY.markdown +11 -0
  7. data/LICENSE +20 -0
  8. data/README.markdown +265 -0
  9. data/Rakefile +55 -0
  10. data/TODO.markdown +9 -0
  11. data/VERSION +1 -0
  12. data/config/cucumber.yml +7 -0
  13. data/examples/quicknote/.gitignore +8 -0
  14. data/examples/quicknote/FormAboutU.dfm +44 -0
  15. data/examples/quicknote/FormAboutU.pas +36 -0
  16. data/examples/quicknote/FormMainU.dfm +110 -0
  17. data/examples/quicknote/FormMainU.pas +268 -0
  18. data/examples/quicknote/FormSplashU.dfm +32 -0
  19. data/examples/quicknote/FormSplashU.pas +52 -0
  20. data/examples/quicknote/LICENSE +20 -0
  21. data/examples/quicknote/README.markdown +28 -0
  22. data/examples/quicknote/Rakefile +12 -0
  23. data/examples/quicknote/TODO.markdown +15 -0
  24. data/examples/quicknote/dcu/.gitignore +1 -0
  25. data/examples/quicknote/exe/.gitignore +0 -0
  26. data/examples/quicknote/exe/quicknote.exe +0 -0
  27. data/examples/quicknote/lib/quicknote.rb +140 -0
  28. data/examples/quicknote/quicknote.cfg +37 -0
  29. data/examples/quicknote/quicknote.dof +158 -0
  30. data/examples/quicknote/quicknote.dpr +16 -0
  31. data/examples/quicknote/quicknote.res +0 -0
  32. data/examples/quicknote/spec/quicknote/form_about_spec.rb +50 -0
  33. data/examples/quicknote/spec/quicknote/form_main_spec.rb +274 -0
  34. data/examples/quicknote/spec/quicknote/form_splash_spec.rb +44 -0
  35. data/examples/quicknote/spec/spec.opts +2 -0
  36. data/examples/quicknote/spec/spec_helper.rb +34 -0
  37. data/examples/quicknote/spec/watchr.rb +143 -0
  38. data/examples/skeleton/.gitignore +8 -0
  39. data/examples/skeleton/LICENSE +20 -0
  40. data/examples/skeleton/README.markdown +62 -0
  41. data/examples/skeleton/Rakefile +21 -0
  42. data/examples/skeleton/TODO.markdown +9 -0
  43. data/examples/skeleton/config/cucumber.yml +7 -0
  44. data/examples/skeleton/dcu/.gitignore +1 -0
  45. data/examples/skeleton/exe/.gitignore +1 -0
  46. data/examples/skeleton/features/basic.feature +6 -0
  47. data/examples/skeleton/features/step_definitions/.gitignore +0 -0
  48. data/examples/skeleton/features/step_definitions/application_steps.rb +43 -0
  49. data/examples/skeleton/features/support/env.rb +5 -0
  50. data/examples/skeleton/lib/myapp.rb +73 -0
  51. data/examples/skeleton/spec/myapp/form_about_spec.rb +50 -0
  52. data/examples/skeleton/spec/myapp/form_main_spec.rb +60 -0
  53. data/examples/skeleton/spec/spec.opts +2 -0
  54. data/examples/skeleton/spec/spec_helper.rb +29 -0
  55. data/examples/skeleton/spec/watchr.rb +143 -0
  56. data/features/automating_an_application.feature +11 -0
  57. data/features/step_definitions/.gitignore +0 -0
  58. data/features/step_definitions/calculator_steps.rb +37 -0
  59. data/features/support/env.rb +4 -0
  60. data/lib/win32/autogui.rb +27 -0
  61. data/lib/win32/autogui/application.rb +249 -0
  62. data/lib/win32/autogui/input.rb +238 -0
  63. data/lib/win32/autogui/window.rb +191 -0
  64. data/lib/win32/autogui/windows/window.rb +22 -0
  65. data/spec/applications/calculator.rb +34 -0
  66. data/spec/auto_gui/application_spec.rb +132 -0
  67. data/spec/basic_gem/basic_gem_spec.rb +13 -0
  68. data/spec/spec.opts +2 -0
  69. data/spec/spec_helper.rb +31 -0
  70. data/spec/watchr.rb +144 -0
  71. data/win32-autogui.gemspec +43 -0
  72. metadata +329 -0
@@ -0,0 +1,8 @@
1
+ *.ddp
2
+ *.dsk
3
+ *.log
4
+ *.cfIndex
5
+ *.cfProject
6
+ tmp/aruba
7
+ tags
8
+ rerun.txt
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 GearheadForHire, LLC
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.
@@ -0,0 +1,62 @@
1
+ Skeleton README
2
+ ===============
3
+
4
+ This is a template of the file structure needed for jump-starting
5
+ GUI testing with the Win32-autogui RubyGem.
6
+
7
+
8
+ Usage Example
9
+ =============
10
+ Create a new Win32 application testing structure for the binary quicknote.exe.
11
+
12
+ NOTE: Replace 'quicknote' with the name of your application.
13
+
14
+ get the source for Win32-autogui
15
+
16
+ cd ~/workspace
17
+ git clone git://github.com/robertwahler/win32-autogui.git
18
+
19
+ copy the skeleton example to a new folder 'quicknote'
20
+
21
+ cp -r ~/workspace/win32-autogui/examples/skeleton quicknote
22
+
23
+ check it into SCM
24
+
25
+ cd quicknote
26
+ git init
27
+ git add .
28
+ git commit -m "initial commit"
29
+
30
+ rename skeleton app to 'quicknote'
31
+
32
+ git mv lib/myapp.rb lib/quicknote.rb
33
+ git mv spec/myapp spec/quicknote
34
+
35
+ # MyApp => QuickNote
36
+ find . -name *.rb -exec sed -i 's/MyApp/QuickNote/' '{}' +
37
+
38
+ # Myapp => Quicknote
39
+ find . -name *.rb -exec sed -i 's/Myapp/Quicknote/' '{}' +
40
+
41
+ # myapp => quicknote
42
+ find . -name *.rb -exec sed -i 's/myapp/quicknote/' '{}' +
43
+
44
+ customize docs
45
+
46
+ vim README.markdown LICENSE
47
+
48
+ test it
49
+
50
+ rake spec
51
+ rake features
52
+
53
+ commit it
54
+
55
+ git add .
56
+ git commit -m "renamed skelton app to MyApp"
57
+
58
+
59
+ Copyright
60
+ ---------
61
+
62
+ Copyright (c) 2010 GearheadForHire, LLC. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ require 'spec'
6
+ require 'spec/rake/spectask'
7
+ Spec::Rake::SpecTask.new(:spec) do |spec|
8
+ spec.libs << 'lib' << 'spec'
9
+ spec.spec_files = FileList['spec/**/*_spec.rb']
10
+ end
11
+
12
+ require 'cucumber'
13
+ require 'cucumber/rake/task'
14
+ Cucumber::Rake::Task.new(:features) do |task|
15
+ task.cucumber_opts = ["features"]
16
+ end
17
+
18
+ desc "Run specs and features"
19
+ task :test => [:spec, :features]
20
+
21
+ task :default => :test
@@ -0,0 +1,9 @@
1
+ MyApp TODO
2
+ ==========
3
+
4
+ general
5
+ -------
6
+
7
+ testing
8
+ -------
9
+
@@ -0,0 +1,7 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format pretty features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "#{rerun_opts} --format rerun --out rerun.txt --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %>
7
+ wip: --tags @wip:3 --wip features
@@ -0,0 +1 @@
1
+ *.dcu
@@ -0,0 +1 @@
1
+ *.exe
@@ -0,0 +1,6 @@
1
+ @application
2
+ Feature: BasicGem
3
+
4
+ This is a placeholder
5
+
6
+ Scenario: Replace or delete this file
@@ -0,0 +1,43 @@
1
+ require 'myapp'
2
+
3
+ include Autogui::Input
4
+
5
+ After('@application') do
6
+ if @application
7
+ @application.close(:wait_for_close => true) if @application.running?
8
+ @application.should be_running
9
+ end
10
+ end
11
+
12
+ Before('@applicaton') do
13
+ @application = Myapp.new
14
+ @application.should_not be_running
15
+
16
+ # debug
17
+ puts "application:"
18
+ puts @application.inspect
19
+ puts "application.combined_text"
20
+ puts @application.combined_text
21
+ end
22
+
23
+ When /^I type in "([^"]*)"$/ do |string|
24
+ @application.set_focus
25
+ type_in(string)
26
+ end
27
+
28
+ # "the window text should match" allows regex in the partial_output, if
29
+ # you don't need regex, use "the output should contain" instead since
30
+ # that way, you don't have to escape regex characters that
31
+ # appear naturally in the output
32
+ Then /^the edit window text should match \/([^\/]*)\/$/ do |partial_output|
33
+ @application.edit_window.text.should =~ /#{partial_output}/
34
+ end
35
+
36
+ Then /^the edit window text should contain exactly "([^"]*)"$/ do |exact_output|
37
+ @application.edit_window.text.should == unescape(exact_output)
38
+ end
39
+
40
+ Then /^the edit window text should contain exactly:$/ do |exact_output|
41
+ @application.edit_window.text.should == exact_output
42
+ end
43
+
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+
3
+ require 'win32/autogui'
4
+ require 'aruba'
5
+ require 'spec/expectations'
@@ -0,0 +1,73 @@
1
+ require 'win32/autogui'
2
+
3
+ APPNAME="exe\\myapp.exe" # relative path to app using Windows style path
4
+
5
+ class Myapp < Autogui::Application
6
+
7
+ def initialize(name=APPNAME, options = {:title=> "MyApp"})
8
+ super name, options
9
+ end
10
+
11
+ def edit_window
12
+ main_window.children.find {|w| w.window_class == 'TMemo'}
13
+ end
14
+
15
+ def status_bar
16
+ main_window.children.find {|w| w.window_class == 'TStatusBar'}
17
+ end
18
+
19
+ def dialog_about
20
+ Autogui::EnumerateDesktopWindows.new.find do |w|
21
+ w.title.match(/About MyApp/) && (w.pid == pid)
22
+ end
23
+ end
24
+
25
+ def message_dialog_confirm
26
+ Autogui::EnumerateDesktopWindows.new.find do |w|
27
+ w.title.match(/Confirm/) && (w.pid == pid)
28
+ end
29
+ end
30
+
31
+ # Title and class are the same as dialog_overwrite_confirm
32
+ # Use child windows to differentiate
33
+ def dialog_overwrite_confirm
34
+ Autogui::EnumerateDesktopWindows.new.find do |w|
35
+ w.title.match(/^Text File Save$/) &&
36
+ (w.pid == pid) &&
37
+ (w.window_class == "#32770") &&
38
+ (w.combined_text.match(/already exists/))
39
+ end
40
+ end
41
+
42
+ # title and class are the same as dialog_overwrite_confirm
43
+ def file_save_as_dialog
44
+ Autogui::EnumerateDesktopWindows.new.find do |w|
45
+ w.title.match(/Text File Save/) &&
46
+ (w.pid == pid) &&
47
+ (w.window_class == "#32770") &&
48
+ (w.combined_text.match(/Save \&in:/))
49
+ end
50
+ end
51
+
52
+ def file_open_dialog
53
+ Autogui::EnumerateDesktopWindows.new.find do |w|
54
+ w.title.match(/Text File Open/) && (w.pid == pid)
55
+ end
56
+ end
57
+
58
+ def error_dialog
59
+ Autogui::EnumerateDesktopWindows.new.find do |w|
60
+ w.title.match(/^MyApp$/) && (w.pid == pid) && (w.window_class == "#32770")
61
+ end
62
+ end
63
+
64
+ # menu action File, Exit
65
+ def file_exit
66
+ set_focus
67
+ keystroke(VK_N) if message_dialog_confirm
68
+ keystroke(VK_ESCAPE) if file_open_dialog
69
+ keystroke(VK_MENU, VK_F, VK_X)
70
+ keystroke(VK_N) if message_dialog_confirm
71
+ end
72
+
73
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Autogui::Input
4
+
5
+ describe "FormAbout" do
6
+
7
+ before(:all) do
8
+ @application = Myapp.new
9
+ end
10
+
11
+ after(:all) do
12
+ @application.close(:wait_for_close => true) if @application.running?
13
+ @application.should_not be_running
14
+ end
15
+
16
+ before(:each) do
17
+ @application.dialog_about.should be_nil
18
+ @application.set_focus
19
+ keystroke(VK_MENU, VK_H, VK_A)
20
+ @dialog_about = @application.dialog_about
21
+ @dialog_about.should_not be_nil
22
+ @dialog_about.is_window?.should == true
23
+ end
24
+
25
+ after(:each) do
26
+ @dialog_about.close if @dialog_about.is_window?
27
+ @dialog_about.is_window?.should == false
28
+ end
29
+
30
+ it "should open with the hotkey combination VK_MENU, VK_H, VK_A" do
31
+ @dialog_about.is_window?.should == true
32
+ end
33
+
34
+ it "should close by hitting return" do
35
+ @dialog_about.set_focus
36
+ keystroke(VK_RETURN)
37
+ @application.dialog_about.should be_nil
38
+ end
39
+
40
+ it "should have the title 'About MyApp'" do
41
+ @dialog_about.title.should == "About MyApp"
42
+ end
43
+
44
+ it "should have an 'Ok' button" do
45
+ button = @dialog_about.children.find {|w| w.window_class == 'TButton'}
46
+ button.should_not be_nil
47
+ button.text.should match(/Ok/)
48
+ end
49
+
50
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Autogui::Input
4
+
5
+ describe "FormMain" do
6
+ before(:all) do
7
+ @debug = false
8
+ @verbose = true
9
+ @application = Myapp.new
10
+ FileUtils.rm_rf(current_dir)
11
+ puts "FormMain before(:all)" if @debug
12
+ puts "application:\n#{@application.inspect}\n" if @debug && @verbose
13
+ puts "application.combined_text:\n #{@application.combined_text}\n" if @debug && @verbose
14
+ end
15
+ before(:each) do
16
+ @application = Myapp.new unless @application.running?
17
+ @application.should be_running
18
+ @application.set_focus
19
+ puts "FormMain before(:each)" if @debug
20
+ end
21
+ after(:all) do
22
+ if @application.running?
23
+ @application.file_exit
24
+ # still running? force it to close
25
+ @application.close(:wait_for_close => true)
26
+ @application.should_not be_running
27
+ end
28
+ puts "FormMain after(:all)" if @debug
29
+ end
30
+ after(:each) do
31
+ if @application.running?
32
+ keystroke(VK_N) if @application.message_dialog_confirm || @application.dialog_overwrite_confirm
33
+ keystroke(VK_ESCAPE) if @application.error_dialog
34
+ end
35
+ puts "FormMain after(:each)" if @debug
36
+ end
37
+
38
+ describe "after startup" do
39
+ it "should have the title 'Myapp" do
40
+ @application.main_window.title.should match(/MyApp/)
41
+ end
42
+ end
43
+
44
+ describe "file exit (VK_MENU, VK_F, VK_X)" do
45
+ it "should prompt and save with modified text" do
46
+ type_in("anything")
47
+ keystroke(VK_MENU, VK_F, VK_X)
48
+ @application.message_dialog_confirm.should_not be_nil
49
+ @application.main_window.is_window?.should == true
50
+ @application.should be_running
51
+ end
52
+ it "should not prompt to save with unmodified text" do
53
+ keystroke(VK_MENU, VK_F, VK_X)
54
+ @application.message_dialog_confirm.should be_nil
55
+ @application.main_window.is_window?.should == false
56
+ @application.should_not be_running
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format nested
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.unshift File.expand_path('..', __FILE__) unless
2
+ $LOAD_PATH.include? File.expand_path('..', __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) unless
4
+ $LOAD_PATH.include? File.expand_path('../../lib', __FILE__)
5
+
6
+ require 'rubygems'
7
+ require 'win32/autogui'
8
+ require 'myapp'
9
+ require 'spec'
10
+ require 'spec/autorun'
11
+ require 'aruba/api'
12
+
13
+ # aruba helper, returns full path to files in the aruba tmp folder
14
+ def fullpath(filename)
15
+ path = File.expand_path(File.join(current_dir, filename))
16
+ path = `cygpath -w #{path}`.chomp if path.match(/^\/cygdrive/) # cygwin?
17
+ path
18
+ end
19
+
20
+ # return the contents of "filename" in the aruba tmp folder
21
+ def get_file_content(filename)
22
+ in_current_dir do
23
+ IO.read(filename)
24
+ end
25
+ end
26
+
27
+ Spec::Runner.configure do |config|
28
+ config.include Aruba::Api
29
+ end
@@ -0,0 +1,143 @@
1
+ # Watchr: Autotest like functionality
2
+ #
3
+ # gem install watchr
4
+ #
5
+ # Run me with:
6
+ #
7
+ # $ watchr spec/watchr.rb
8
+
9
+ require 'term/ansicolor'
10
+
11
+ $c = Term::ANSIColor
12
+
13
+ def getch
14
+ state = `stty -g`
15
+ begin
16
+ `stty raw -echo cbreak`
17
+ $stdin.getc
18
+ ensure
19
+ `stty #{state}`
20
+ end
21
+ end
22
+
23
+ # --------------------------------------------------
24
+ # Convenience Methods
25
+ # --------------------------------------------------
26
+ def all_feature_files
27
+ Dir['features/*.feature']
28
+ end
29
+
30
+ def all_spec_files
31
+ files = Dir['spec/**/*_spec\.rb']
32
+ end
33
+
34
+ def run(cmd)
35
+
36
+ pid = fork do
37
+ puts "\n"
38
+ print $c.cyan, cmd, $c.clear, "\n"
39
+ exec(cmd)
40
+ end
41
+ Signal.trap('INT') do
42
+ puts "sending KILL to pid: #{pid}"
43
+ Process.kill("KILL", pid)
44
+ end
45
+ Process.waitpid(pid)
46
+
47
+ prompt
48
+ end
49
+
50
+ def run_all
51
+ run_all_specs
52
+ run_default_cucumber
53
+ end
54
+
55
+ # allow cucumber rerun.txt smarts
56
+ def run_default_cucumber
57
+ cmd = "cucumber"
58
+ run(cmd)
59
+ end
60
+
61
+ def run_all_features
62
+ cmd = "cucumber #{all_feature_files.join(' ')}"
63
+ run(cmd)
64
+ end
65
+
66
+ def run_feature(feature)
67
+ cmd = "cucumber #{feature}"
68
+ $last_feature = feature
69
+ run(cmd)
70
+ end
71
+
72
+ def run_last_feature
73
+ run_feature($last_feature) if $last_feature
74
+ end
75
+
76
+ def run_default_spec
77
+ cmd = "spec _1.3.1_ --color --format s ./spec"
78
+ run(cmd)
79
+ end
80
+
81
+ def run_all_specs
82
+ cmd = "spec _1.3.1_ --color --format s #{all_spec_files.join(' ')}"
83
+ p cmd
84
+ run(cmd)
85
+ end
86
+
87
+ def run_spec(spec)
88
+ cmd = "spec _1.3.1_ --color --format s #{spec}"
89
+ $last_spec = spec
90
+ run(cmd)
91
+ end
92
+
93
+ def run_last_spec
94
+ run_spec($last_spec) if $last_spec
95
+ end
96
+
97
+ def prompt
98
+ puts "Ctrl-\\ for menu, Ctrl-C to quit"
99
+ end
100
+
101
+ # init
102
+ $last_feature = nil
103
+ prompt
104
+
105
+ # --------------------------------------------------
106
+ # Watchr Rules
107
+ # --------------------------------------------------
108
+ watch( '^features/(.*)\.feature' ) { run_default_cucumber }
109
+
110
+ #watch( '^bin/(.*)' ) { run_default_cucumber }
111
+ watch( '^lib/(.*)' ) { run_default_cucumber }
112
+
113
+ watch( '^features/step_definitions/(.*)\.rb' ) { run_default_cucumber }
114
+ watch( '^features/support/(.*)\.rb' ) { run_default_cucumber }
115
+
116
+ watch( '^spec/(.*)_spec\.rb' ) { |m| run_spec(m[0]) }
117
+ # specify just the lib files that have specs
118
+ # TODO: This can be determined automatically from the spec file naming convention
119
+ watch( '^lib/(.*)' ) { run_default_spec }
120
+
121
+ # --------------------------------------------------
122
+ # Signal Handling
123
+ # --------------------------------------------------
124
+
125
+ # Ctrl-\
126
+ Signal.trap('QUIT') do
127
+
128
+ puts "\n\nMENU: a = all , f = features s = specs, l = last feature (#{$last_feature ? $last_feature : 'none'}), q = quit\n\n"
129
+ c = getch
130
+ puts c.chr
131
+ if c.chr == "a"
132
+ run_all
133
+ elsif c.chr == "f"
134
+ run_default_cucumber
135
+ elsif c.chr == "s"
136
+ run_all_specs
137
+ elsif c.chr == "q"
138
+ abort("exiting\n")
139
+ elsif c.chr == "l"
140
+ run_last_feature
141
+ end
142
+
143
+ end