uia 0.0.7.3 → 0.0.8
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/ChangeLog +10 -0
- data/ext/UiaDll/Release/UIA.Helper.dll +0 -0
- data/ext/UiaDll/Release/UiaDll.dll +0 -0
- data/ext/UiaDll/UIA.Helper/Clicker.cs +1 -1
- data/ext/UiaDll/UIA.Helper/Element.cs +11 -0
- data/ext/UiaDll/UIA.Helper/Extensions.cs +8 -0
- data/ext/UiaDll/UiaDll/ElementMethods.cpp +8 -4
- data/ext/UiaDll/UiaDll/ElementStructures.h +0 -23
- data/ext/UiaDll/UiaDll/PatternInformationStructures.h +2 -22
- data/ext/UiaDll/UiaDll/TableMethods.cpp +11 -0
- data/ext/UiaDll/UiaDll/TextMethods.cpp +17 -0
- data/ext/UiaDll/UiaDll/UiaDll.cpp +6 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj +1 -0
- data/ext/UiaDll/UiaDll/UiaDll.vcxproj.filters +3 -0
- data/ext/UiaDll/UiaDll/WindowMethods.cpp +8 -0
- data/ext/UiaDll/UiaDll.Test/PatternInformationTest.cpp +0 -5
- data/ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj +0 -1
- data/ext/UiaDll/UiaDll.Test/UiaDll.Test.vcxproj.filters +0 -3
- data/lib/core_ext/symbol.rb +7 -0
- data/lib/uia/element.rb +9 -14
- data/lib/uia/finder.rb +67 -1
- data/lib/uia/keys.rb +76 -0
- data/lib/uia/library/element_structs.rb +0 -12
- data/lib/uia/library/pattern_structs.rb +1 -6
- data/lib/uia/library/win32.rb +35 -0
- data/lib/uia/library.rb +16 -0
- data/lib/uia/patterns/selection.rb +1 -1
- data/lib/uia/patterns/table.rb +3 -3
- data/lib/uia/patterns/text.rb +13 -0
- data/lib/uia/patterns/window.rb +4 -0
- data/lib/uia/version.rb +3 -3
- data/lib/uia.rb +1 -15
- data/spec/spec_helper.rb +10 -0
- data/spec/uia/element_spec.rb +22 -11
- data/spec/uia/keys_spec.rb +30 -0
- data/spec/uia/patterns/text_spec.rb +20 -0
- data/spec/uia/patterns/window_spec.rb +14 -0
- data/spec/uia_spec.rb +9 -2
- data/uia.gemspec +1 -1
- metadata +16 -9
- data/ext/UiaDll/UiaDll.Test/ElementsTest.cpp +0 -22
data/ChangeLog
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
=== Version 0.0.8 / 2013-12-02
|
2
|
+
* Enhancements
|
3
|
+
* Uia#find_element and Element#find can locate by :title
|
4
|
+
* Element#send_keys
|
5
|
+
* Window#close
|
6
|
+
* TextPattern support to get / set the text
|
7
|
+
|
8
|
+
* Bug Fixes
|
9
|
+
* Fix issue with selecting cells in a table
|
10
|
+
|
1
11
|
=== Version 0.0.7.3 / 2013-11-02
|
2
12
|
* Enhancements
|
3
13
|
* Element#visible?
|
Binary file
|
Binary file
|
@@ -23,7 +23,7 @@ namespace UIA.Helper
|
|
23
23
|
public static void MouseClick(AutomationElement element)
|
24
24
|
{
|
25
25
|
element.ScrollToIfPossible();
|
26
|
-
element.
|
26
|
+
element.TryToFocus();
|
27
27
|
|
28
28
|
var clickablePoint = element.GetClickablePoint();
|
29
29
|
Cursor.Position = new System.Drawing.Point((int)clickablePoint.X, (int)clickablePoint.Y);
|
@@ -22,6 +22,12 @@ namespace UIA.Helper
|
|
22
22
|
return (TPattern) _element.GetCurrentPattern(pattern);
|
23
23
|
}
|
24
24
|
|
25
|
+
public void SendKeys(string keysToSend)
|
26
|
+
{
|
27
|
+
_element.TryToFocus();
|
28
|
+
System.Windows.Forms.SendKeys.SendWait(keysToSend);
|
29
|
+
}
|
30
|
+
|
25
31
|
public virtual int[] RuntimeId
|
26
32
|
{
|
27
33
|
get { return _element.GetRuntimeId(); }
|
@@ -97,6 +103,11 @@ namespace UIA.Helper
|
|
97
103
|
return new Element(element);
|
98
104
|
}
|
99
105
|
|
106
|
+
public static Element[] From(AutomationElement[] elements)
|
107
|
+
{
|
108
|
+
return elements.Select(x => new Element(x)).ToArray();
|
109
|
+
}
|
110
|
+
|
100
111
|
public static Element ById(string automationId)
|
101
112
|
{
|
102
113
|
return FindFirst(automationId.IdCondition());
|
@@ -30,6 +30,14 @@ namespace UIA.Helper
|
|
30
30
|
|
31
31
|
public static class ElementExtensions
|
32
32
|
{
|
33
|
+
public static bool TryToFocus(this AutomationElement automationElement)
|
34
|
+
{
|
35
|
+
try
|
36
|
+
{
|
37
|
+
automationElement.SetFocus();
|
38
|
+
return true;
|
39
|
+
} catch { return false; }
|
40
|
+
}
|
33
41
|
|
34
42
|
public static bool ScrollToIfPossible(this AutomationElement automationElement)
|
35
43
|
{
|
@@ -15,10 +15,6 @@ extern "C" {
|
|
15
15
|
delete elementInformation;
|
16
16
|
}
|
17
17
|
|
18
|
-
__declspec(dllexport) void Element_ReleaseMany(ElementsPtr elements) {
|
19
|
-
delete elements;
|
20
|
-
}
|
21
|
-
|
22
18
|
__declspec(dllexport) void Element_Refresh(ElementInformationPtr element, char* errorInfo, const int errorInfoLength) {
|
23
19
|
try {
|
24
20
|
element->Refresh(Find(element));
|
@@ -27,6 +23,14 @@ extern "C" {
|
|
27
23
|
}
|
28
24
|
}
|
29
25
|
|
26
|
+
__declspec(dllexport) void Element_SendKeys(ElementInformationPtr element, const char* keysToSend, char* errorInfo, const int errorInfoLength) {
|
27
|
+
try {
|
28
|
+
Find(element)->SendKeys(gcnew String(keysToSend));
|
29
|
+
} catch(Exception^ e) {
|
30
|
+
StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
30
34
|
__declspec(dllexport) ElementInformationPtr Element_FindById(const char* automationId, char* errorInfo, const int errorLength) {
|
31
35
|
try {
|
32
36
|
return ElementInformation::From(Element::ById(gcnew String(automationId)));
|
@@ -65,26 +65,3 @@ private:
|
|
65
65
|
}
|
66
66
|
|
67
67
|
} ElementInformation, *ElementInformationPtr;
|
68
|
-
|
69
|
-
typedef struct _Elements {
|
70
|
-
int length;
|
71
|
-
ElementInformation* elements;
|
72
|
-
|
73
|
-
_Elements() : length(0), elements(NULL) {}
|
74
|
-
|
75
|
-
_Elements(array<Element^>^ elements) : length(0), elements(NULL) {
|
76
|
-
if( nullptr == elements ) return;
|
77
|
-
|
78
|
-
length = elements->Length;
|
79
|
-
if( length > 0 ) this->elements = new ElementInformation[length];
|
80
|
-
|
81
|
-
auto index = 0;
|
82
|
-
for each(auto element in elements) {
|
83
|
-
this->elements[index++].Refresh(element);
|
84
|
-
}
|
85
|
-
}
|
86
|
-
|
87
|
-
~_Elements() {
|
88
|
-
delete[] elements;
|
89
|
-
}
|
90
|
-
} Elements, *ElementsPtr;
|
@@ -127,31 +127,11 @@ private:
|
|
127
127
|
typedef struct _TableInformation {
|
128
128
|
int RowCount;
|
129
129
|
int ColumnCount;
|
130
|
-
ElementsPtr Headers;
|
131
|
-
|
132
|
-
_TableInformation(int rowCount, int columnCount, ...array<Element^> ^headers) {
|
133
|
-
init(rowCount, columnCount, headers);
|
134
|
-
}
|
135
130
|
|
136
131
|
_TableInformation(TablePattern::TablePatternInformation^ tableInfo) {
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
init(tableInfo->RowCount, tableInfo->ColumnCount, Enumerable::ToArray(Enumerable::Select<AutomationElement^, Element^>(headers, toElementFunc)));
|
141
|
-
}
|
142
|
-
|
143
|
-
~_TableInformation() {
|
144
|
-
delete Headers;
|
132
|
+
RowCount = tableInfo->RowCount;
|
133
|
+
ColumnCount = tableInfo->ColumnCount;
|
145
134
|
}
|
146
|
-
|
147
|
-
private:
|
148
|
-
void init(int rowCount, int columnCount, ...array<Element^> ^headers) {
|
149
|
-
RowCount = rowCount;
|
150
|
-
ColumnCount = columnCount;
|
151
|
-
|
152
|
-
Headers = new Elements(headers);
|
153
|
-
}
|
154
|
-
|
155
135
|
} TableInformation, *TableInformationPtr;
|
156
136
|
|
157
137
|
typedef struct _TableItemInformation {
|
@@ -13,4 +13,15 @@ extern "C" {
|
|
13
13
|
return NULL;
|
14
14
|
}
|
15
15
|
}
|
16
|
+
|
17
|
+
__declspec(dllexport) int Table_Headers(ElementInformationPtr element, ElementInformation** headers, char* errorInfo, const int errorInfoLength) {
|
18
|
+
try {
|
19
|
+
auto headerElements = Find(element)->As<TablePattern^>(TablePattern::Pattern)->Current.GetColumnHeaders();
|
20
|
+
*headers = ElementInformation::From(Element::From(headerElements));
|
21
|
+
return headerElements->Length;
|
22
|
+
} catch(Exception^ e) {
|
23
|
+
StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
|
24
|
+
return 0;
|
25
|
+
}
|
26
|
+
}
|
16
27
|
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#include "Stdafx.h"
|
2
|
+
|
3
|
+
extern "C" {
|
4
|
+
__declspec(dllexport) int Text_GetText(ElementInformationPtr element, char* text, const int textLength, char* errorInfo, const int errorInfoLength) {
|
5
|
+
try {
|
6
|
+
auto theText = Find(element)->As<TextPattern^>(TextPattern::Pattern)->DocumentRange->GetText(-1);
|
7
|
+
if( NULL != text ) {
|
8
|
+
StringHelper::CopyToUnmanagedString(theText, text, textLength);
|
9
|
+
}
|
10
|
+
|
11
|
+
return theText->Length;
|
12
|
+
} catch(Exception^ e) {
|
13
|
+
StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
|
14
|
+
return 0;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
@@ -5,5 +5,11 @@ extern "C" {
|
|
5
5
|
__declspec(dllexport) void initialize(char* privateAssemblyDirectory) {
|
6
6
|
DynamicAssemblyResolver::PrivatePath = gcnew String(privateAssemblyDirectory);
|
7
7
|
}
|
8
|
+
|
9
|
+
__declspec(dllexport) void Automation_WarmUp() {
|
10
|
+
try {
|
11
|
+
auto warmed = Element::Windows;
|
12
|
+
} catch(Exception^) {}
|
13
|
+
}
|
8
14
|
}
|
9
15
|
|
@@ -101,6 +101,7 @@
|
|
101
101
|
</ClCompile>
|
102
102
|
<ClCompile Include="TableItemMethods.cpp" />
|
103
103
|
<ClCompile Include="TableMethods.cpp" />
|
104
|
+
<ClCompile Include="TextMethods.cpp" />
|
104
105
|
<ClCompile Include="ToggleMethods.cpp" />
|
105
106
|
<ClCompile Include="UiaDll.cpp" />
|
106
107
|
<ClCompile Include="ValuePatternMethods.cpp" />
|
@@ -21,4 +21,12 @@ extern "C" {
|
|
21
21
|
StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
|
22
22
|
}
|
23
23
|
}
|
24
|
+
|
25
|
+
__declspec(dllexport) void Window_Close(ElementInformationPtr element, char* errorInfo, const int errorInfoLength) {
|
26
|
+
try {
|
27
|
+
Find(element)->As<WindowPattern^>(WindowPattern::Pattern)->Close();
|
28
|
+
} catch(Exception^ e) {
|
29
|
+
StringHelper::CopyToUnmanagedString(e->Message, errorInfo, errorInfoLength);
|
30
|
+
}
|
31
|
+
}
|
24
32
|
}
|
@@ -41,8 +41,3 @@ TEST(WindowInformation, CanBeInitialized) {
|
|
41
41
|
ASSERT_STREQ("Minimized", windowInformation.VisualState);
|
42
42
|
ASSERT_STREQ("Closing", windowInformation.InteractionState);
|
43
43
|
}
|
44
|
-
|
45
|
-
TEST(TableInformation, NullHeadersYieldsEmptyElements) {
|
46
|
-
auto tableInformation = TableInformation(0, 0, nullptr);
|
47
|
-
ASSERT_EQ(0, tableInformation.Headers->length);
|
48
|
-
}
|
@@ -105,7 +105,6 @@
|
|
105
105
|
<ItemGroup>
|
106
106
|
<ClCompile Include="AssemblyInfo.cpp" />
|
107
107
|
<ClCompile Include="ElementInformationTest.cpp" />
|
108
|
-
<ClCompile Include="ElementsTest.cpp" />
|
109
108
|
<ClCompile Include="PatternInformationTest.cpp" />
|
110
109
|
<ClCompile Include="stdafx.cpp">
|
111
110
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
@@ -52,9 +52,6 @@
|
|
52
52
|
<ClCompile Include="ElementInformationTest.cpp">
|
53
53
|
<Filter>Source Files</Filter>
|
54
54
|
</ClCompile>
|
55
|
-
<ClCompile Include="ElementsTest.cpp">
|
56
|
-
<Filter>Source Files</Filter>
|
57
|
-
</ClCompile>
|
58
55
|
<ClCompile Include="StringHelperTest.cpp">
|
59
56
|
<Filter>Source Files</Filter>
|
60
57
|
</ClCompile>
|
data/lib/core_ext/symbol.rb
CHANGED
@@ -2,4 +2,11 @@ class Symbol
|
|
2
2
|
def to_camelized_s
|
3
3
|
self.to_s.split('_').map(&:capitalize).join(' ')
|
4
4
|
end
|
5
|
+
|
6
|
+
# :selection_item => Uia::Patterns::SelectionItem
|
7
|
+
def to_pattern_const
|
8
|
+
"Uia::Patterns::#{self.to_s.capitalize}".split('::').reduce(Object) do |m, current|
|
9
|
+
m.const_get current.split('_').map(&:capitalize).join
|
10
|
+
end
|
11
|
+
end
|
5
12
|
end
|
data/lib/uia/element.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'uia/library/element_attributes'
|
2
2
|
require 'uia/library/pattern_info_attributes'
|
3
|
+
require 'uia/keys'
|
3
4
|
|
4
5
|
module Uia
|
5
6
|
class UnsupportedPattern < StandardError
|
@@ -9,6 +10,7 @@ module Uia
|
|
9
10
|
end
|
10
11
|
|
11
12
|
class Element
|
13
|
+
include Finder
|
12
14
|
extend ElementAttributes
|
13
15
|
|
14
16
|
def initialize(element)
|
@@ -24,20 +26,17 @@ module Uia
|
|
24
26
|
Library::Constants::ControlTypes.find(@default) { |_, v| v == @element.control_type_id }.first
|
25
27
|
end
|
26
28
|
|
29
|
+
def send_keys(*keys)
|
30
|
+
Library.send_keys @element, Keys.encode(keys)
|
31
|
+
end
|
32
|
+
|
27
33
|
def refresh
|
28
34
|
Library.refresh @element
|
29
35
|
self
|
30
36
|
end
|
31
37
|
|
32
38
|
def find(locator)
|
33
|
-
|
34
|
-
|
35
|
-
case
|
36
|
-
when locator[:id]
|
37
|
-
Library::find_child_by_id(@element, locator[:id], scope)
|
38
|
-
when locator[:name]
|
39
|
-
Library::find_child_by_name(@element, locator[:name], scope)
|
40
|
-
end
|
39
|
+
find_child(@element, locator)
|
41
40
|
end
|
42
41
|
|
43
42
|
def locators_match?(locator)
|
@@ -51,17 +50,13 @@ module Uia
|
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
54
|
-
def
|
53
|
+
def filter(locator)
|
55
54
|
descendants.select { |e| e.locators_match? locator }
|
56
55
|
end
|
57
56
|
|
58
57
|
def as(pattern)
|
59
58
|
raise UnsupportedPattern.new(pattern, patterns) unless patterns.include? pattern
|
60
|
-
|
61
|
-
which = "Uia::Patterns::#{pattern.to_s.capitalize}".split('::').reduce(Object) do |m, current|
|
62
|
-
m.const_get current.split('_').map(&:capitalize).join
|
63
|
-
end
|
64
|
-
extend which
|
59
|
+
extend pattern.to_pattern_const
|
65
60
|
end
|
66
61
|
|
67
62
|
def patterns
|
data/lib/uia/finder.rb
CHANGED
@@ -1,13 +1,66 @@
|
|
1
|
+
require 'uia/library/win32'
|
2
|
+
|
1
3
|
module Uia
|
4
|
+
class BadLocator < StandardError
|
5
|
+
def initialize(locator)
|
6
|
+
super "#{locator} is not a valid locator"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class BadChildLocator < BadLocator; end
|
10
|
+
|
2
11
|
module Finder
|
12
|
+
def find_from_root(locator)
|
13
|
+
case
|
14
|
+
when locator[:id]
|
15
|
+
find_by_id locator[:id]
|
16
|
+
when locator[:name], locator[:value]
|
17
|
+
find_by_name locator[:name] || locator[:value]
|
18
|
+
when locator[:pid]
|
19
|
+
find_by_pid locator[:pid]
|
20
|
+
when locator[:runtime_id]
|
21
|
+
find_by_runtime_id locator[:runtime_id]
|
22
|
+
when locator[:handle]
|
23
|
+
find_by_handle locator[:handle]
|
24
|
+
when locator[:title]
|
25
|
+
find_by_title locator[:title]
|
26
|
+
else
|
27
|
+
raise BadLocator, locator
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_child(parent, locator)
|
32
|
+
scope = (locator[:scope] || :descendants).to_s.capitalize
|
33
|
+
|
34
|
+
case
|
35
|
+
when locator[:id]
|
36
|
+
find_child_by_id parent, locator[:id], scope
|
37
|
+
when locator[:name], locator[:value]
|
38
|
+
name_or_value = locator[:name] || locator[:value]
|
39
|
+
find_child_by_name parent, name_or_value, scope
|
40
|
+
when locator[:title]
|
41
|
+
find_by_title locator[:title], parent.handle
|
42
|
+
else
|
43
|
+
raise BadChildLocator, locator
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
3
48
|
def find_by_id(id)
|
4
49
|
find_by_property(:id, id)
|
5
50
|
end
|
6
51
|
|
52
|
+
def find_child_by_id(parent, id, scope)
|
53
|
+
Library.find_child_by_id(parent, id, (scope || :descendants).to_s.capitalize)
|
54
|
+
end
|
55
|
+
|
7
56
|
def find_by_name(name)
|
8
57
|
find_by_property(:name, name)
|
9
58
|
end
|
10
59
|
|
60
|
+
def find_child_by_name(parent, name, scope)
|
61
|
+
Library.find_child_by_name(parent, name, (scope || :descendants).to_s.capitalize)
|
62
|
+
end
|
63
|
+
|
11
64
|
def find_by_pid(pid)
|
12
65
|
Library.find_by_pid(pid)
|
13
66
|
end
|
@@ -20,7 +73,20 @@ module Uia
|
|
20
73
|
Library.find_by_handle handle
|
21
74
|
end
|
22
75
|
|
23
|
-
|
76
|
+
def find_by_title(title, parent=0)
|
77
|
+
found_window = Win32.find_window(parent) do |handle|
|
78
|
+
case title
|
79
|
+
when Regexp
|
80
|
+
Win32.window_title(handle) =~ title
|
81
|
+
else
|
82
|
+
Win32.window_title(handle) == title
|
83
|
+
end
|
84
|
+
end
|
85
|
+
find_by_handle found_window if found_window
|
86
|
+
rescue
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
24
90
|
def find_by_property(property, what)
|
25
91
|
case what
|
26
92
|
when String
|
data/lib/uia/keys.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Uia
|
2
|
+
class InvalidKey < StandardError; end
|
3
|
+
class Keys
|
4
|
+
# http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys(v=vs.110).aspx
|
5
|
+
KEYS = {
|
6
|
+
:shift => '+',
|
7
|
+
:control => '^',
|
8
|
+
:alt => '%',
|
9
|
+
:space => ' ',
|
10
|
+
:backspace => '{BS}',
|
11
|
+
:break => '{BREAK}',
|
12
|
+
:caps_lock => '{CAPSLOCK}',
|
13
|
+
:delete => '{DEL}',
|
14
|
+
:down => '{DOWN}',
|
15
|
+
:end => '{END}',
|
16
|
+
:enter => '{ENTER}',
|
17
|
+
:escape => '{ESC}',
|
18
|
+
:help => '{HELP}',
|
19
|
+
:home => '{HOME}',
|
20
|
+
:insert => '{INS}',
|
21
|
+
:left => '{LEFT}',
|
22
|
+
:number_lock => '{NUMLOCK}',
|
23
|
+
:page_down => '{PGDN}',
|
24
|
+
:page_up => '{PGUP}',
|
25
|
+
:print_screen => '{PRTSC}',
|
26
|
+
:right => '{RIGHT}',
|
27
|
+
:scroll_lock => '{SCROLLLOCK}',
|
28
|
+
:tab => '{TAB}',
|
29
|
+
:up => '{UP}',
|
30
|
+
:f1 => '{F1}',
|
31
|
+
:f2 => '{F2}',
|
32
|
+
:f3 => '{F3}',
|
33
|
+
:f4 => '{F4}',
|
34
|
+
:f5 => '{F5}',
|
35
|
+
:f6 => '{F6}',
|
36
|
+
:f7 => '{F7}',
|
37
|
+
:f8 => '{F8}',
|
38
|
+
:f9 => '{F9}',
|
39
|
+
:f10 => '{F10}',
|
40
|
+
:f11 => '{F11}',
|
41
|
+
:f12 => '{F12}',
|
42
|
+
:f13 => '{F13}',
|
43
|
+
:f14 => '{F14}',
|
44
|
+
:f15 => '{F15}',
|
45
|
+
:f16 => '{F16}',
|
46
|
+
:add => '{ADD}',
|
47
|
+
:subtract => '{SUBTRACT}',
|
48
|
+
:multiply => '{MULTIPLY}',
|
49
|
+
:divide => '{DIVIDE}'}
|
50
|
+
|
51
|
+
SPECIAL_KEYS = ['\+', '\^', '%', '~', '\(', '\)', '\{', '\}', '\[', '\]']
|
52
|
+
|
53
|
+
def self.encode(keys)
|
54
|
+
keys.reduce('') do |encoded, key|
|
55
|
+
encoded << case key
|
56
|
+
when String
|
57
|
+
encode_str(key)
|
58
|
+
when Symbol
|
59
|
+
encode_sym(key)
|
60
|
+
when Array
|
61
|
+
"#{encode([key.shift])}(#{encode(key)})"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.encode_str(s)
|
67
|
+
s.gsub(/([#{SPECIAL_KEYS.join ''}])/, '{\1}')
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.encode_sym(sym)
|
71
|
+
found = KEYS[sym]
|
72
|
+
raise InvalidKey, "#{sym} is not a valid key" unless found
|
73
|
+
found
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -63,17 +63,5 @@ module Uia
|
|
63
63
|
class ElementStruct < FFI::Struct
|
64
64
|
include ElementLayout
|
65
65
|
end
|
66
|
-
|
67
|
-
class Elements < FFI::Struct
|
68
|
-
layout :length, :int,
|
69
|
-
:items, :pointer
|
70
|
-
|
71
|
-
def children
|
72
|
-
self[:length].times.collect do |i|
|
73
|
-
pointer = self[:items] + i * ElementStruct.size
|
74
|
-
Uia::Element.new(ElementStruct.new(pointer))
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
66
|
end
|
79
67
|
end
|
@@ -95,15 +95,10 @@ module Uia
|
|
95
95
|
extend StructAttributes
|
96
96
|
|
97
97
|
layout :row_count, :int,
|
98
|
-
:column_count, :int
|
99
|
-
:headers, Elements.ptr
|
98
|
+
:column_count, :int
|
100
99
|
|
101
100
|
struct_attr :row_count, :column_count
|
102
101
|
|
103
|
-
def headers
|
104
|
-
self[:headers].children
|
105
|
-
end
|
106
|
-
|
107
102
|
def self.release(pointer)
|
108
103
|
Library.release_table_info(pointer)
|
109
104
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Win32
|
4
|
+
extend FFI::Library
|
5
|
+
|
6
|
+
ffi_lib 'user32'
|
7
|
+
|
8
|
+
callback :enum_callback, [:long, :long], :bool
|
9
|
+
|
10
|
+
attach_function :enum_child_windows, :EnumChildWindows,
|
11
|
+
[:long, :enum_callback, :long], :long
|
12
|
+
attach_function :_window_title, :GetWindowTextA,
|
13
|
+
[:long, :pointer, :int], :int
|
14
|
+
attach_function :window_title_length, :GetWindowTextLengthA,
|
15
|
+
[:long], :int
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def window_title(handle)
|
19
|
+
length = window_title_length(handle) + 1
|
20
|
+
title = FFI::MemoryPointer.new :char, length
|
21
|
+
_window_title handle, title, length
|
22
|
+
title.read_string
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_window(parent, &block)
|
26
|
+
found_window = nil
|
27
|
+
window_callback = FFI::Function.new(:bool, [:long, :pointer], {convention: :stdcall}) do |handle, _|
|
28
|
+
found_window = handle if block.call handle
|
29
|
+
!found_window
|
30
|
+
end
|
31
|
+
Win32.enum_child_windows parent, window_callback, 0
|
32
|
+
found_window
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/uia/library.rb
CHANGED
@@ -16,6 +16,9 @@ module Uia
|
|
16
16
|
attach_function :init, :initialize, [:string], :void
|
17
17
|
init(uia_directory)
|
18
18
|
|
19
|
+
attach_function :warm_up_automation, :Automation_WarmUp, [], :void
|
20
|
+
warm_up_automation
|
21
|
+
|
19
22
|
def self.attach_throwable_function(name_alias, name, arg_types, return_type, &block)
|
20
23
|
attach_function name, arg_types + [:pointer, :int], return_type
|
21
24
|
define_singleton_method(name_alias) do |*args|
|
@@ -62,6 +65,7 @@ module Uia
|
|
62
65
|
attach_function :Element_FindByRuntimeId, [:pointer, :int, :pointer, :int], ManagedElementStruct.by_ref
|
63
66
|
|
64
67
|
# element methods
|
68
|
+
attach_throwable_function :send_keys, :Element_SendKeys, [:pointer, :string], :void
|
65
69
|
attach_throwable_function :find_child_by_id, :Element_FindChildById, [:pointer, :string, :string], ManagedElementStruct.by_ref, &element_or_nil
|
66
70
|
attach_throwable_function :find_child_by_name, :Element_FindChildByName, [:pointer, :string, :string], ManagedElementStruct.by_ref, &element_or_nil
|
67
71
|
elements_from :children, :Element_Children, [:pointer]
|
@@ -72,6 +76,7 @@ module Uia
|
|
72
76
|
# WindowPattern methods
|
73
77
|
attach_throwable_function :window_information, :Window_Information, [:pointer], WindowInformation.by_ref
|
74
78
|
attach_throwable_function :set_visual_state, :Window_SetVisualState, [:pointer, :string], :void
|
79
|
+
attach_throwable_function :close_window, :Window_Close, [:pointer], :void
|
75
80
|
|
76
81
|
# ValuePattern methods
|
77
82
|
attach_throwable_function :set_value, :Value_Set, [:pointer, :string], :void
|
@@ -100,6 +105,7 @@ module Uia
|
|
100
105
|
|
101
106
|
# TablePattern methods
|
102
107
|
attach_throwable_function :table_info, :Table_Information, [:pointer], TableInformation.by_ref
|
108
|
+
elements_from :table_headers, :Table_Headers, [:pointer]
|
103
109
|
|
104
110
|
# TableItemPattern methods
|
105
111
|
attach_throwable_function :table_item_info, :TableItem_Information, [:pointer], TableItemInformation.by_ref
|
@@ -108,6 +114,16 @@ module Uia
|
|
108
114
|
attach_throwable_function :range_value_info, :RangeValue_Information, [:pointer], RangeValueInformation.by_ref
|
109
115
|
attach_throwable_function :set_range_value, :RangeValue_SetValue, [:pointer, :double], :void
|
110
116
|
|
117
|
+
# TextPattern methods
|
118
|
+
attach_function :Text_GetText, [:pointer, :pointer, :int, :pointer, :int], :int
|
119
|
+
|
120
|
+
def self.get_text(element)
|
121
|
+
length = can_throw(:Text_GetText, element, nil, 0) + 1
|
122
|
+
p = FFI::MemoryPointer.new :pointer, length
|
123
|
+
can_throw(:Text_GetText, element, p, length)
|
124
|
+
p.read_string
|
125
|
+
end
|
126
|
+
|
111
127
|
def self.find_by_runtime_id(id)
|
112
128
|
p = FFI::MemoryPointer.new :int, id.count
|
113
129
|
p.write_array_of_int(id)
|
data/lib/uia/patterns/table.rb
CHANGED
@@ -3,7 +3,7 @@ module Uia
|
|
3
3
|
module Table
|
4
4
|
module Row
|
5
5
|
def items
|
6
|
-
|
6
|
+
filter(pattern: :table_item).each { |e| e.as :table_item }
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -16,11 +16,11 @@ module Uia
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def headers
|
19
|
-
|
19
|
+
Library.table_headers @element
|
20
20
|
end
|
21
21
|
|
22
22
|
def rows
|
23
|
-
|
23
|
+
filter(control_type: :data_item).each { |e| e.extend Row }
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
data/lib/uia/patterns/window.rb
CHANGED
data/lib/uia/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Uia
|
2
|
-
VERSION = '0.0.
|
3
|
-
end
|
1
|
+
module Uia
|
2
|
+
VERSION = '0.0.8'
|
3
|
+
end
|
data/lib/uia.rb
CHANGED
@@ -9,7 +9,6 @@ require_rel 'uia/patterns'
|
|
9
9
|
require_rel 'core_ext'
|
10
10
|
|
11
11
|
module Uia
|
12
|
-
class BadLocator < StandardError; end
|
13
12
|
extend Finder
|
14
13
|
|
15
14
|
def self.children
|
@@ -17,19 +16,6 @@ module Uia
|
|
17
16
|
end
|
18
17
|
|
19
18
|
def self.find_element(how)
|
20
|
-
|
21
|
-
when how[:id]
|
22
|
-
find_by_id how[:id]
|
23
|
-
when how[:name]
|
24
|
-
find_by_name how[:name]
|
25
|
-
when how[:pid]
|
26
|
-
find_by_pid how[:pid]
|
27
|
-
when how[:runtime_id]
|
28
|
-
find_by_runtime_id how[:runtime_id]
|
29
|
-
when how[:handle]
|
30
|
-
find_by_handle how[:handle]
|
31
|
-
else
|
32
|
-
raise BadLocator, "#{how} is not a valid locator"
|
33
|
-
end
|
19
|
+
find_from_root(how)
|
34
20
|
end
|
35
21
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,6 +9,16 @@ require 'uia'
|
|
9
9
|
|
10
10
|
include Uia
|
11
11
|
|
12
|
+
def wait_until(timeout=10, &block)
|
13
|
+
start = Time.now
|
14
|
+
until (result = block.call) || (Time.now - start > timeout)
|
15
|
+
sleep 0.25
|
16
|
+
end
|
17
|
+
|
18
|
+
raise 'Timed out' unless result
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
12
22
|
RSpec.configure do |config|
|
13
23
|
config.before(:all) do
|
14
24
|
@app = ChildProcess.build('spec/app/WindowsForms.exe').start
|
data/spec/uia/element_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Uia::Element do
|
4
|
-
Given(:element) { Uia.find_element(id: 'MainFormWindow') }
|
5
|
-
Given(:about_box) { Uia.find_element(id: 'AboutBox') }
|
4
|
+
Given(:element) { wait_until { Uia.find_element(id: 'MainFormWindow') } }
|
5
|
+
Given(:about_box) { wait_until { Uia.find_element(id: 'AboutBox') } }
|
6
6
|
Given { element.as(:window).visual_state = :normal }
|
7
7
|
|
8
8
|
context 'properties' do
|
@@ -54,15 +54,31 @@ describe Uia::Element do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
context '#send_keys' do
|
58
|
+
Given(:text_field) { element.find(id: 'textField').as :value }
|
59
|
+
When { text_field.send_keys 'abcde', [:left] * 3, ' fgh ' }
|
60
|
+
Then { text_field.value == 'ab fgh cde'}
|
61
|
+
end
|
62
|
+
|
57
63
|
context '#find' do
|
58
64
|
context 'id' do
|
59
65
|
Then { element.find(id: 'textField') != nil }
|
60
66
|
Then { element.find(id: 'does not exist') == nil }
|
61
67
|
end
|
62
68
|
|
63
|
-
context 'name' do
|
69
|
+
context 'name, value' do
|
64
70
|
Then { element.find(name: 'No option selected') != nil }
|
65
71
|
Then { element.find(name: 'does not exist') == nil }
|
72
|
+
Then { element.find(value: 'No option selected') != nil }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'title' do
|
76
|
+
Then { element.find(title: /Group.*of radio/i) != nil }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'invalid' do
|
80
|
+
When(:bad_locator) { element.find(bad_locator: 123) }
|
81
|
+
Then { bad_locator.should have_failed BadLocator, "{:bad_locator=>123} is not a valid locator" }
|
66
82
|
end
|
67
83
|
|
68
84
|
context 'limiting scope' do
|
@@ -72,16 +88,16 @@ describe Uia::Element do
|
|
72
88
|
|
73
89
|
context '#select' do
|
74
90
|
context 'control_type' do
|
75
|
-
When(:buttons) { element.
|
91
|
+
When(:buttons) { element.filter(control_type: :radio_button) }
|
76
92
|
Then { buttons.map(&:control_type) == [:radio_button] * 3 }
|
77
93
|
end
|
78
94
|
|
79
95
|
context 'pattern' do
|
80
|
-
Then { element.
|
96
|
+
Then { element.filter(pattern: :value).count == 4 }
|
81
97
|
end
|
82
98
|
|
83
99
|
context 'combinations' do
|
84
|
-
Then { element.
|
100
|
+
Then { element.filter(control_type: :button, name: 'About')[0].id == 'aboutButton' }
|
85
101
|
end
|
86
102
|
end
|
87
103
|
|
@@ -94,11 +110,6 @@ describe Uia::Element do
|
|
94
110
|
Then { about_box != nil }
|
95
111
|
And { about_box.children.find { |c| c.name == 'OK' }.click }
|
96
112
|
end
|
97
|
-
|
98
|
-
context 'disabled elements' do
|
99
|
-
When(:click_disabled) { disabled_checkbox.click }
|
100
|
-
Then { click_disabled.should have_failed('Target element cannot receive focus.') }
|
101
|
-
end
|
102
113
|
end
|
103
114
|
|
104
115
|
context '#children' do
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Uia::Keys do
|
4
|
+
def encode(*keys)
|
5
|
+
Keys.encode keys
|
6
|
+
end
|
7
|
+
|
8
|
+
Then { encode('Bacon sandwich') == 'Bacon sandwich' }
|
9
|
+
Then { encode([:control, :shift, 'a']) == '^(+a)' }
|
10
|
+
|
11
|
+
context 'special keys' do
|
12
|
+
Then { encode(:shift, :f2, :left) == '+{F2}{LEFT}' }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'special characters' do
|
16
|
+
Then { encode('1 + 2') == '1 {+} 2' }
|
17
|
+
Then { encode('1 ^^ 2') == '1 {^}{^} 2' }
|
18
|
+
Then { encode('a%b') == 'a{%}b' }
|
19
|
+
Then { encode('~ish') == '{~}ish' }
|
20
|
+
Then { encode('(1 - 2)') == '{(}1 - 2{)}' }
|
21
|
+
Then { encode('{DUDE}') == '{{}DUDE{}}' }
|
22
|
+
Then { encode('[DUDE]') == '{[}DUDE{]}' }
|
23
|
+
Then { encode('(Bacon + sand%wich^ [sweet] {}') == '{(}Bacon {+} sand{%}wich{^} {[}sweet{]} {{}{}}' }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'invalid' do
|
27
|
+
When(:bad_keys) { encode('something', :bad_key) }
|
28
|
+
Then { bad_keys.should have_failed InvalidKey, "#{:bad_key} is not a valid key" }
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Uia::Patterns::Text do
|
4
|
+
Given(:text_field) do
|
5
|
+
Uia.find_element(id: 'MainFormWindow').children.find { |e| e.id == 'multiLineTextField' }.as :text
|
6
|
+
end
|
7
|
+
|
8
|
+
context '#text' do
|
9
|
+
context 'getting / setting' do
|
10
|
+
When { text_field.text = '{text} to be expected!' }
|
11
|
+
Then { text_field.text == '{text} to be expected!' }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'updating' do
|
15
|
+
Given { text_field.text = 'about to be overwritten' }
|
16
|
+
When { text_field.text = 'expected update' }
|
17
|
+
Then { text_field.text == 'expected update' }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -28,4 +28,18 @@ describe Uia::Patterns::Window do
|
|
28
28
|
Then { window.visual_state == :normal }
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
context '#close' do
|
33
|
+
def notepad_window
|
34
|
+
Uia.find_element(title: /^Untitled.*Notepad/i)
|
35
|
+
end
|
36
|
+
|
37
|
+
Given(:notepad) do
|
38
|
+
ChildProcess.build('notepad.exe').start
|
39
|
+
wait_until { notepad_window }.as :window
|
40
|
+
end
|
41
|
+
When { notepad.close }
|
42
|
+
Then { notepad_window == nil }
|
43
|
+
end
|
44
|
+
|
31
45
|
end
|
data/spec/uia_spec.rb
CHANGED
@@ -14,9 +14,10 @@ describe Uia do
|
|
14
14
|
Then { Uia.find_element(id: 'not there') == nil }
|
15
15
|
end
|
16
16
|
|
17
|
-
context 'by name' do
|
17
|
+
context 'by name / value' do
|
18
18
|
Then { expect(Uia.find_element(name: 'MainFormWindow')).to be_instance_of(Element) }
|
19
|
-
Then { expect(Uia.find_element(name: /[Mm]ain.*Window/
|
19
|
+
Then { expect(Uia.find_element(name: /[Mm]ain.*Window/)).to be_instance_of(Element) }
|
20
|
+
Then { expect(Uia.find_element(value: /[Mm]ain.*Window/)).to be_instance_of(Element) }
|
20
21
|
Then { Uia.find_element(name: 'not there') == nil }
|
21
22
|
end
|
22
23
|
|
@@ -39,6 +40,12 @@ describe Uia do
|
|
39
40
|
Then { expect { Uia.find_element(handle: 0x0) }.to raise_error }
|
40
41
|
end
|
41
42
|
|
43
|
+
context 'by title' do
|
44
|
+
Then { expect(Uia.find_element(title: 'MainFormWindow')).to be_instance_of(Element) }
|
45
|
+
Then { expect(Uia.find_element(title: /Main[Ff]orm/)).to be_instance_of(Element) }
|
46
|
+
Then { Uia.find_element(title: 'probably will not find') == nil }
|
47
|
+
end
|
48
|
+
|
42
49
|
context 'invalid locators' do
|
43
50
|
When(:bad_input) { Uia.find_element(bad: 123) }
|
44
51
|
Then { bad_input.should have_failed(Uia::BadLocator, '{:bad=>123} is not a valid locator') }
|
data/uia.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
26
26
|
spec.require_paths = ['lib']
|
27
27
|
|
28
|
-
spec.add_runtime_dependency 'ffi'
|
28
|
+
spec.add_runtime_dependency 'ffi', '1.9.0'
|
29
29
|
spec.add_runtime_dependency 'require_all'
|
30
30
|
|
31
31
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - '='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 1.9.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 1.9.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: require_all
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,7 +147,6 @@ files:
|
|
147
147
|
- ext/UiaDll/UiaDll.Test/AssemblyInfo.cpp
|
148
148
|
- ext/UiaDll/UiaDll.Test/ElementInformationTest.cpp
|
149
149
|
- ext/UiaDll/UiaDll.Test/ElementStub.h
|
150
|
-
- ext/UiaDll/UiaDll.Test/ElementsTest.cpp
|
151
150
|
- ext/UiaDll/UiaDll.Test/MemoryLeakDetector.h
|
152
151
|
- ext/UiaDll/UiaDll.Test/PatternInformationTest.cpp
|
153
152
|
- ext/UiaDll/UiaDll.Test/ReadMe.txt
|
@@ -179,6 +178,7 @@ files:
|
|
179
178
|
- ext/UiaDll/UiaDll/StringHelper.h
|
180
179
|
- ext/UiaDll/UiaDll/TableItemMethods.cpp
|
181
180
|
- ext/UiaDll/UiaDll/TableMethods.cpp
|
181
|
+
- ext/UiaDll/UiaDll/TextMethods.cpp
|
182
182
|
- ext/UiaDll/UiaDll/ToggleMethods.cpp
|
183
183
|
- ext/UiaDll/UiaDll/UiaDll.cpp
|
184
184
|
- ext/UiaDll/UiaDll/UiaDll.h
|
@@ -192,6 +192,7 @@ files:
|
|
192
192
|
- lib/uia.rb
|
193
193
|
- lib/uia/element.rb
|
194
194
|
- lib/uia/finder.rb
|
195
|
+
- lib/uia/keys.rb
|
195
196
|
- lib/uia/library.rb
|
196
197
|
- lib/uia/library/constants.rb
|
197
198
|
- lib/uia/library/element_attributes.rb
|
@@ -199,6 +200,7 @@ files:
|
|
199
200
|
- lib/uia/library/pattern_info_attributes.rb
|
200
201
|
- lib/uia/library/pattern_structs.rb
|
201
202
|
- lib/uia/library/struct_attributes.rb
|
203
|
+
- lib/uia/library/win32.rb
|
202
204
|
- lib/uia/patterns/expand_collapse.rb
|
203
205
|
- lib/uia/patterns/invoke.rb
|
204
206
|
- lib/uia/patterns/range_value.rb
|
@@ -206,6 +208,7 @@ files:
|
|
206
208
|
- lib/uia/patterns/selection_item.rb
|
207
209
|
- lib/uia/patterns/table.rb
|
208
210
|
- lib/uia/patterns/table_item.rb
|
211
|
+
- lib/uia/patterns/text.rb
|
209
212
|
- lib/uia/patterns/toggle.rb
|
210
213
|
- lib/uia/patterns/value.rb
|
211
214
|
- lib/uia/patterns/window.rb
|
@@ -215,6 +218,7 @@ files:
|
|
215
218
|
- spec/app/WindowsForms.exe
|
216
219
|
- spec/spec_helper.rb
|
217
220
|
- spec/uia/element_spec.rb
|
221
|
+
- spec/uia/keys_spec.rb
|
218
222
|
- spec/uia/patterns/expand_collapse_spec.rb
|
219
223
|
- spec/uia/patterns/invoke_spec.rb
|
220
224
|
- spec/uia/patterns/range_value_spec.rb
|
@@ -222,6 +226,7 @@ files:
|
|
222
226
|
- spec/uia/patterns/selection_spec.rb
|
223
227
|
- spec/uia/patterns/table_item_spec.rb
|
224
228
|
- spec/uia/patterns/table_spec.rb
|
229
|
+
- spec/uia/patterns/text_spec.rb
|
225
230
|
- spec/uia/patterns/toggle_spec.rb
|
226
231
|
- spec/uia/patterns/value_spec.rb
|
227
232
|
- spec/uia/patterns/window_spec.rb
|
@@ -244,7 +249,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
244
249
|
version: '0'
|
245
250
|
segments:
|
246
251
|
- 0
|
247
|
-
hash:
|
252
|
+
hash: 720468909
|
248
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
249
254
|
none: false
|
250
255
|
requirements:
|
@@ -253,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
258
|
version: '0'
|
254
259
|
segments:
|
255
260
|
- 0
|
256
|
-
hash:
|
261
|
+
hash: 720468909
|
257
262
|
requirements: []
|
258
263
|
rubyforge_project:
|
259
264
|
rubygems_version: 1.8.24
|
@@ -266,6 +271,7 @@ test_files:
|
|
266
271
|
- spec/app/WindowsForms.exe
|
267
272
|
- spec/spec_helper.rb
|
268
273
|
- spec/uia/element_spec.rb
|
274
|
+
- spec/uia/keys_spec.rb
|
269
275
|
- spec/uia/patterns/expand_collapse_spec.rb
|
270
276
|
- spec/uia/patterns/invoke_spec.rb
|
271
277
|
- spec/uia/patterns/range_value_spec.rb
|
@@ -273,6 +279,7 @@ test_files:
|
|
273
279
|
- spec/uia/patterns/selection_spec.rb
|
274
280
|
- spec/uia/patterns/table_item_spec.rb
|
275
281
|
- spec/uia/patterns/table_spec.rb
|
282
|
+
- spec/uia/patterns/text_spec.rb
|
276
283
|
- spec/uia/patterns/toggle_spec.rb
|
277
284
|
- spec/uia/patterns/value_spec.rb
|
278
285
|
- spec/uia/patterns/window_spec.rb
|
@@ -1,22 +0,0 @@
|
|
1
|
-
#include "stdafx.h"
|
2
|
-
#include "ElementStub.h"
|
3
|
-
#include <ElementStructures.h>
|
4
|
-
|
5
|
-
class ElementsTest : public ::testing::Test {
|
6
|
-
public:
|
7
|
-
array<Element^>^ ElementsWithNames(...array<String^>^ names) {
|
8
|
-
auto elements = gcnew array<Element^>(names->Length);
|
9
|
-
auto index = 0;
|
10
|
-
for each(auto name in names) {
|
11
|
-
elements[index++] = gcnew ElementStub(name);
|
12
|
-
}
|
13
|
-
return elements;
|
14
|
-
}
|
15
|
-
};
|
16
|
-
|
17
|
-
TEST_F(ElementsTest, ItCanBeInitialized)
|
18
|
-
{
|
19
|
-
auto elements = Elements(ElementsWithNames("First", "Second"));
|
20
|
-
ASSERT_STREQ("First", elements.elements[0].name);
|
21
|
-
ASSERT_STREQ("Second", elements.elements[1].name);
|
22
|
-
}
|