mohawk 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "mohawk-testing-app"]
2
+ path = mohawk-testing-app
3
+ url = git://github.com/leviwilson/mohawk-testing-app.git
data/Changelog CHANGED
@@ -1,3 +1,8 @@
1
+ === Version 0.0.4 / 2013-05-24
2
+ * Enhancements
3
+ * sped up table access when there are many rows
4
+ * caches controls based on locator for quicker lookups
5
+
1
6
  === Version 0.0.3 / 2013-04-26
2
7
  * Enhancements
3
8
  * Bumped the RAutomation dependency so we can now interact with controls
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
+ gem 'coveralls', require: false
3
4
  gemspec
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mohawk
2
-
3
2
  [![Build Status](https://travis-ci.org/leviwilson/mohawk.png)](https://travis-ci.org/leviwilson/mohawk)
3
+ [![Coverage Status](https://coveralls.io/repos/leviwilson/mohawk/badge.png?branch=master)](https://coveralls.io/r/leviwilson/mohawk?branch=master)
4
4
 
5
5
  A gem to assist in building page-object like structures for testing Windows applications.
6
6
 
@@ -15,3 +15,7 @@ Scenario: Determining if a window has text
15
15
  Scenario: Waiting for a particular control
16
16
  When we are using the "MainScreen"
17
17
  Then we can wait for the control with a value of "Data Entry Form"
18
+
19
+ Scenario: Specifying a parent container
20
+ When we are using the "ScreenWithContainer"
21
+ Then our parent is the container, not the main window
@@ -16,4 +16,9 @@ end
16
16
 
17
17
  Then /^we can wait for the control with a value of "(.*?)"$/ do |value|
18
18
  @screen.wait_for_control :value => value
19
- end
19
+ end
20
+
21
+ Then /^our parent is the container, not the main window$/ do
22
+ @screen.adapter.window.title.should_not match(/MainForm/)
23
+ @screen.up_view.control_name.should eq('Forward')
24
+ end
@@ -36,4 +36,18 @@ end
36
36
 
37
37
  Then /^the "(.*?)" for the row at index "(.*?)" is "(.*?)"$/ do |header, which_row, expected_value|
38
38
  on(DataEntryForm).people[which_row.to_i].send(header).should eq(expected_value)
39
- end
39
+ end
40
+
41
+ When(/^there are a lot of records in a table$/) do
42
+ on(DataEntryForm) do |screen|
43
+ 5.times { screen.add_more }
44
+ end
45
+ end
46
+
47
+ Then(/^the table count responds in a reasonable amount of time$/) do
48
+ Timeout.timeout(5.0) { on(DataEntryForm).people.count.should eq(252) }
49
+ end
50
+
51
+ Then(/^accessing the values in row "([^"]*)" should be snappy$/) do |which_row|
52
+ Timeout.timeout(5.0) { on(DataEntryForm).people[which_row.to_i].cells.should_not be_empty }
53
+ end
Binary file
@@ -3,6 +3,7 @@ class DataEntryForm
3
3
  window(:title => /DataEntry/)
4
4
 
5
5
  table(:people, :id => "personListView")
6
+ button(:add_more, :value => 'Add Many')
6
7
 
7
8
  def wait_until_present
8
9
  super
@@ -0,0 +1,8 @@
1
+ class ScreenWithContainer
2
+ include Mohawk
3
+ window(:title => /MainForm/)
4
+ parent(:id => 'numericUpDown')
5
+
6
+ button(:up, :id => 'SmallIncrement')
7
+ button(:down, :id => 'SmallDecrement')
8
+ end
@@ -31,3 +31,11 @@ Scenario: Retrieving the headers
31
31
 
32
32
  Scenario: Retrieving a row value by its header
33
33
  Then the "date_of_birth" for the row at index "1" is "3/4/1975"
34
+
35
+ Scenario: Working with lots of records counts
36
+ When there are a lot of records in a table
37
+ Then the table count responds in a reasonable amount of time
38
+
39
+ Scenario: Working with a row when there are a lot of records
40
+ When there are a lot of records in a table
41
+ Then accessing the values in row "12" should be snappy
@@ -18,11 +18,11 @@ module Mohawk
18
18
  end
19
19
 
20
20
  def [](row)
21
- TableRow.new(self, view.row(:index => row))
21
+ TableRow.new(self, row)
22
22
  end
23
23
 
24
24
  def each
25
- view.rows.map do |row|
25
+ view.row_count.times.map do |row|
26
26
  yield TableRow.new(self, row)
27
27
  end
28
28
  end
@@ -1,13 +1,15 @@
1
1
  module Mohawk
2
2
  module Accessors
3
3
  class TableRow
4
+ include RAutomation::Adapter::MsUia
5
+
4
6
  attr_reader :row
5
7
 
6
- def initialize(table, row)
7
- @row = row
8
+ def initialize(table, row_index)
8
9
  @table = table
10
+ @row = Row.new(@table.view, :index => row_index)
9
11
  end
10
-
12
+
11
13
  def selected?
12
14
  @table.view.selected? row.row
13
15
  end
@@ -23,7 +25,7 @@ module Mohawk
23
25
  def value_from_header(name)
24
26
  which_column = header_methods.index(name)
25
27
  raise ArgumentError, "#{name} column does not exist in #{header_methods}" if which_column.nil?
26
- cells[which_column]
28
+ Cell.new(row, :index => which_column).text
27
29
  end
28
30
 
29
31
  def method_missing(name, *args)
@@ -1,6 +1,6 @@
1
1
  module Mohawk
2
2
  module Accessors
3
-
3
+
4
4
  #
5
5
  # Defines the locator indicating the top-level window that will be used
6
6
  # to find controls in the page
@@ -11,11 +11,26 @@ module Mohawk
11
11
  # @param [Hash] locator for the top-level window that hosts the page
12
12
  #
13
13
  def window(locator)
14
- define_method("which_window") do
14
+ define_method(:which_window) do
15
15
  locator
16
16
  end
17
17
  end
18
-
18
+
19
+ #
20
+ # Defines a locator indicating a child container that is a descendant of
21
+ # the top-level window
22
+ #
23
+ # @example
24
+ # parent(:id => 'someOtherContainer')
25
+ #
26
+ # @param [Hash] locator for a more specific parent container
27
+ #
28
+ def parent(locator)
29
+ define_method(:parent_container) do
30
+ locator
31
+ end
32
+ end
33
+
19
34
  #
20
35
  # Generates methods to enter text into a text field, get its value
21
36
  # and clear the text field
@@ -28,7 +43,7 @@ module Mohawk
28
43
  # @param [Hash] locator for how the text is found
29
44
  #
30
45
  def text(name, locator)
31
- define_method("#{name}") do
46
+ define_method("#{name}") do
32
47
  adapter.text(locator).value
33
48
  end
34
49
  define_method("#{name}=") do |text|
@@ -44,9 +59,9 @@ module Mohawk
44
59
  adapter.text(locator).view
45
60
  end
46
61
  end
47
-
62
+
48
63
  #
49
- # Generates methods to click on a button as well as get the value of
64
+ # Generates methods to click on a button as well as get the value of
50
65
  # the button text
51
66
  #
52
67
  # @example
@@ -239,7 +254,7 @@ module Mohawk
239
254
  # @example
240
255
  # tree_view(:tree, :id => "treeId")
241
256
  # # will generate 'tree', 'tree=', 'tree_items', 'expand_tree_item' and 'collapse_tree_item'
242
- # # methods to get the tree value, set the tree value (index or string), get all of the
257
+ # # methods to get the tree value, set the tree value (index or string), get all of the
243
258
  # # items, expand an item (index or string) and collapse an item (index or string)
244
259
  #
245
260
  # @param [String] the name used for the generated methods
@@ -1,38 +1,55 @@
1
1
  module Mohawk
2
2
  module Adapters
3
3
  class UiaAdapter
4
- attr_reader :window
5
-
6
- def initialize(locator)
4
+ def initialize(locator, container=nil)
7
5
  @window = RAutomation::Window.new(locator.merge(:adapter => :ms_uia))
6
+ @container = container
7
+ end
8
+
9
+ def window
10
+ @actual_window ||= begin
11
+ if @container
12
+ control = @window.control(@container)
13
+ RAutomation::WaitHelper.wait_until { control.exist? }
14
+ @window = RAutomation::Window.new(:hwnd => control.hwnd, :adapter => :ms_uia)
15
+ end
16
+ @window
17
+ end
8
18
  end
9
19
 
10
20
  def combo(locator)
11
- Mohawk::Accessors::Combo.new(self, locator)
21
+ @combos ||= {}
22
+ @combos[locator] ||= Mohawk::Accessors::Combo.new(self, locator)
12
23
  end
13
24
 
14
25
  def checkbox(locator)
15
- Mohawk::Accessors::CheckBox.new(self, locator)
26
+ @checkbox ||= {}
27
+ @checkbox[locator] ||= Mohawk::Accessors::CheckBox.new(self, locator)
16
28
  end
17
29
 
18
30
  def text(locator)
19
- Mohawk::Accessors::Text.new(self, locator)
31
+ @text_fields ||= {}
32
+ @text_fields[locator] ||= Mohawk::Accessors::Text.new(self, locator)
20
33
  end
21
34
 
22
35
  def button(locator)
23
- Mohawk::Accessors::Button.new(self, locator)
36
+ @buttons ||= {}
37
+ @buttons[locator] ||= Mohawk::Accessors::Button.new(self, locator)
24
38
  end
25
39
 
26
40
  def radio(locator)
27
- Mohawk::Accessors::Radio.new(self, locator)
41
+ @radios ||= {}
42
+ @radios[locator] ||= Mohawk::Accessors::Radio.new(self, locator)
28
43
  end
29
44
 
30
45
  def label(locator)
31
- Mohawk::Accessors::Label.new(self, locator)
46
+ @labels ||= {}
47
+ @labels[locator] ||= Mohawk::Accessors::Label.new(self, locator)
32
48
  end
33
49
 
34
50
  def link(locator)
35
- Mohawk::Accessors::Link.new(self, locator)
51
+ @links ||= {}
52
+ @links[locator] ||= Mohawk::Accessors::Link.new(self, locator)
36
53
  end
37
54
 
38
55
  def menu_item(locator)
@@ -40,15 +57,18 @@ module Mohawk
40
57
  end
41
58
 
42
59
  def table(locator)
43
- Mohawk::Accessors::Table.new(self, locator)
60
+ @tables ||= {}
61
+ @tables[locator] ||= Mohawk::Accessors::Table.new(self, locator)
44
62
  end
45
63
 
46
64
  def tree_view(locator)
47
- Mohawk::Accessors::TreeView.new(self, locator)
65
+ @trees ||= {}
66
+ @trees[locator] ||= Mohawk::Accessors::TreeView.new(self, locator)
48
67
  end
49
68
 
50
69
  def value_control(locator)
51
- Mohawk::Accessors::Control.new(self, locator)
70
+ @controls ||= {}
71
+ @controls[locator] ||= Mohawk::Accessors::Control.new(self, locator)
52
72
  end
53
73
  end
54
74
  end
@@ -1,3 +1,3 @@
1
1
  module Mohawk
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/mohawk.rb CHANGED
@@ -17,8 +17,10 @@ module Mohawk
17
17
  end
18
18
 
19
19
  def initialize(extra={})
20
- @adapter = Mohawk::Adapters::UiaAdapter.new(which_window.merge(extra))
21
- end
20
+ locator = [which_window.merge(extra)]
21
+ locator << parent_container if respond_to?(:parent_container)
22
+ @adapter = Mohawk::Adapters::UiaAdapter.new(*locator)
23
+ end
22
24
 
23
25
  #
24
26
  # Returns whether or not the window exists
data/mohawk.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
- gem.add_dependency 'rautomation', '>= 0.9.1'
20
+ gem.add_dependency 'rautomation', '>= 0.9.2'
21
21
  gem.add_dependency 'require_all'
22
22
  gem.add_dependency 'page_navigation', '>= 0.7'
23
23
 
@@ -29,4 +29,5 @@ Gem::Specification.new do |gem|
29
29
  gem.add_development_dependency 'guard'
30
30
  gem.add_development_dependency 'guard-rspec'
31
31
  gem.add_development_dependency 'terminal-notifier-guard'
32
+ gem.add_development_dependency 'json', '~> 1.7.7'
32
33
  end
data/spec/ffi_stub.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'ffi'
2
+
3
+ module FFI
4
+ module Library
5
+ def ffi_lib(*names)
6
+ end
7
+
8
+ def ffi_libraries
9
+ end
10
+
11
+ def attach_function(name, func, args, returns = nil, options = nil)
12
+ end
13
+ end
14
+ end
15
+
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'ffi'
3
2
 
4
3
  class TableScreen
5
4
  include Mohawk
@@ -21,19 +20,6 @@ class FakeTableRow
21
20
  end
22
21
  end
23
22
 
24
- module FFI
25
- module Library
26
- def ffi_lib(*names)
27
- end
28
-
29
- def ffi_libraries
30
- end
31
-
32
- def attach_function(name, func, args, returns = nil, options = nil)
33
- end
34
- end
35
- end
36
-
37
23
  describe Mohawk::Accessors::Table do
38
24
  let(:screen) { TableScreen.new }
39
25
  let(:window) { double("RAutomation Window") }
@@ -59,9 +45,12 @@ describe Mohawk::Accessors::Table do
59
45
  end
60
46
 
61
47
  it "has rows" do
62
- fake_rows = [FakeTableRow.new("First Row", 0), FakeTableRow.new("Second Row", 1)]
63
- expected_rows = fake_rows.map {|r| {:text => r.text, :row => r.row} }
64
- table.should_receive(:rows).and_return(fake_rows)
48
+ first_row = FakeTableRow.new "First Row", 0
49
+ second_row = FakeTableRow.new "Second Row", 1
50
+ expected_rows = [first_row, second_row].map {|r| {:text => r.text, :row => r.row} }
51
+ table.should_receive(:row_count).and_return(2)
52
+ RAutomation::Adapter::MsUia::Row.should_receive(:new).with(table, :index => 0).and_return(first_row)
53
+ RAutomation::Adapter::MsUia::Row.should_receive(:new).with(table, :index => 1).and_return(second_row)
65
54
  screen.top.map(&:to_hash).should eq(expected_rows)
66
55
  end
67
56
 
@@ -80,7 +69,7 @@ describe Mohawk::Accessors::Table do
80
69
  let(:table_row) { double("RAutomation TableRow") }
81
70
 
82
71
  before(:each) do
83
- table.should_receive(:row).with(:index => 0).and_return(table_row)
72
+ RAutomation::Adapter::MsUia::Row.should_receive(:new).with(table, :index => 0).and_return(table_row)
84
73
  table_row.stub(:row).and_return 0
85
74
  end
86
75
 
@@ -107,8 +96,10 @@ describe Mohawk::Accessors::Table do
107
96
  it "can get cell values by header name" do
108
97
  RAutomation::Adapter::MsUia::UiaDll.should_receive(:table_headers).and_return(["First Header", "Second Header"])
109
98
  table.should_receive(:search_information)
110
- expected_cells = [FakeTableRow.new("Item 1", 0), FakeTableRow.new("Item 2", 1)]
111
- table_row.should_receive(:cells).and_return(expected_cells)
99
+
100
+ expected_cell = double('RAutomation Cell')
101
+ expected_cell.should_receive(:text).and_return('Item 2')
102
+ RAutomation::Adapter::MsUia::Cell.should_receive(:new).with(table_row, :index => 1).and_return(expected_cell)
112
103
  screen.top[0].second_header.should eq("Item 2")
113
104
  end
114
105
 
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ class AnyScreen
4
+ include Mohawk
5
+ window(:title => /Some Title/)
6
+ end
7
+
8
+ RSpec::Matchers.define(:use_the_cached) do |control_type, the_alias=nil|
9
+ match do |screen|
10
+ screen.adapter.window.stub(the_alias || control_type).and_return(double('first control'), double('second control'))
11
+ first, second = 2.times.map { screen.adapter.send(control_type, :id => 'id') }
12
+ first.eql?(second)
13
+ end
14
+ end
15
+
16
+ describe Mohawk::Adapters::UiaAdapter do
17
+ subject(:screen) { AnyScreen.new }
18
+
19
+ let(:window) { double('RAutomation Window') }
20
+ before(:each) { RAutomation::Window.stub(:new).and_return(window) }
21
+
22
+ context 'caching controls' do
23
+ it { should use_the_cached(:combo, :select_list) }
24
+ it { should use_the_cached(:checkbox) }
25
+ it { should use_the_cached(:text, :text_field) }
26
+ it { should use_the_cached(:button) }
27
+ it { should use_the_cached(:radio) }
28
+ it { should use_the_cached(:label) }
29
+ it { should use_the_cached(:link, :label) }
30
+ it { should use_the_cached(:table) }
31
+ it { should use_the_cached(:tree_view, :select_list) }
32
+ it { should use_the_cached(:value_control) }
33
+ end
34
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,4 +2,8 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
4
  require 'rspec'
5
+ require 'ffi_stub'
5
6
  require 'mohawk'
7
+ require 'coveralls'
8
+
9
+ Coveralls.wear!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mohawk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-26 00:00:00.000000000 Z
12
+ date: 2013-05-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rautomation
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.9.1
21
+ version: 0.9.2
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.9.1
29
+ version: 0.9.2
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: require_all
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -187,6 +187,22 @@ dependencies:
187
187
  - - ! '>='
188
188
  - !ruby/object:Gem::Version
189
189
  version: '0'
190
+ - !ruby/object:Gem::Dependency
191
+ name: json
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ~>
196
+ - !ruby/object:Gem::Version
197
+ version: 1.7.7
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ~>
204
+ - !ruby/object:Gem::Version
205
+ version: 1.7.7
190
206
  description: High level wrapper around windows applications
191
207
  email:
192
208
  - levi@leviwilson.com
@@ -195,6 +211,7 @@ extensions: []
195
211
  extra_rdoc_files: []
196
212
  files:
197
213
  - .gitignore
214
+ - .gitmodules
198
215
  - .travis.yml
199
216
  - Changelog
200
217
  - Gemfile
@@ -226,6 +243,7 @@ files:
226
243
  - features/step_definitions/table_steps.rb
227
244
  - features/step_definitions/text_steps.rb
228
245
  - features/step_definitions/tree_view_steps.rb
246
+ - features/support/FizzWare.NBuilder.dll
229
247
  - features/support/WindowsForms.exe
230
248
  - features/support/app/WindowsForms/WindowsForms.sln
231
249
  - features/support/app/WindowsForms/WindowsForms/AboutBox.Designer.cs
@@ -256,6 +274,7 @@ files:
256
274
  - features/support/screens/about_screen.rb
257
275
  - features/support/screens/data_entry_form.rb
258
276
  - features/support/screens/main_screen.rb
277
+ - features/support/screens/screen_with_container.rb
259
278
  - features/support/string.rb
260
279
  - features/table.feature
261
280
  - features/text.feature
@@ -279,6 +298,7 @@ files:
279
298
  - lib/mohawk/navigation.rb
280
299
  - lib/mohawk/version.rb
281
300
  - mohawk.gemspec
301
+ - spec/ffi_stub.rb
282
302
  - spec/lib/mohawk/accessors/button_spec.rb
283
303
  - spec/lib/mohawk/accessors/checkbox_spec.rb
284
304
  - spec/lib/mohawk/accessors/combo_spec.rb
@@ -290,6 +310,7 @@ files:
290
310
  - spec/lib/mohawk/accessors/table_spec.rb
291
311
  - spec/lib/mohawk/accessors/text_spec.rb
292
312
  - spec/lib/mohawk/accessors/tree_view_spec.rb
313
+ - spec/lib/mohawk/adapters/uia_adapter_spec.rb
293
314
  - spec/lib/mohawk_spec.rb
294
315
  - spec/lib/navigation_spec.rb
295
316
  - spec/spec_helper.rb
@@ -341,6 +362,7 @@ test_files:
341
362
  - features/step_definitions/table_steps.rb
342
363
  - features/step_definitions/text_steps.rb
343
364
  - features/step_definitions/tree_view_steps.rb
365
+ - features/support/FizzWare.NBuilder.dll
344
366
  - features/support/WindowsForms.exe
345
367
  - features/support/app/WindowsForms/WindowsForms.sln
346
368
  - features/support/app/WindowsForms/WindowsForms/AboutBox.Designer.cs
@@ -371,10 +393,12 @@ test_files:
371
393
  - features/support/screens/about_screen.rb
372
394
  - features/support/screens/data_entry_form.rb
373
395
  - features/support/screens/main_screen.rb
396
+ - features/support/screens/screen_with_container.rb
374
397
  - features/support/string.rb
375
398
  - features/table.feature
376
399
  - features/text.feature
377
400
  - features/tree_view.feature
401
+ - spec/ffi_stub.rb
378
402
  - spec/lib/mohawk/accessors/button_spec.rb
379
403
  - spec/lib/mohawk/accessors/checkbox_spec.rb
380
404
  - spec/lib/mohawk/accessors/combo_spec.rb
@@ -386,6 +410,7 @@ test_files:
386
410
  - spec/lib/mohawk/accessors/table_spec.rb
387
411
  - spec/lib/mohawk/accessors/text_spec.rb
388
412
  - spec/lib/mohawk/accessors/tree_view_spec.rb
413
+ - spec/lib/mohawk/adapters/uia_adapter_spec.rb
389
414
  - spec/lib/mohawk_spec.rb
390
415
  - spec/lib/navigation_spec.rb
391
416
  - spec/spec_helper.rb