iCuke 0.4.12 → 0.5.1
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/Rakefile +3 -3
- data/VERSION +1 -1
- data/app/AlertsViewController.h +59 -0
- data/app/AlertsViewController.m +341 -0
- data/app/AppDelegate.h +60 -0
- data/app/AppDelegate.m +101 -0
- data/app/ButtonsViewController.h +80 -0
- data/app/ButtonsViewController.m +448 -0
- data/app/Constants.h +58 -0
- data/app/ControlsViewController.h +72 -0
- data/app/ControlsViewController.m +379 -0
- data/app/ImagesViewController.h +62 -0
- data/app/ImagesViewController.m +137 -0
- data/app/{iCuke/iCuke-Info.plist → Info.plist} +4 -4
- data/app/MainViewController.h +57 -0
- data/app/MainViewController.m +262 -0
- data/app/Picker/CustomPickerDataSource.h +55 -0
- data/app/Picker/CustomPickerDataSource.m +135 -0
- data/app/Picker/CustomView.h +62 -0
- data/app/Picker/CustomView.m +119 -0
- data/app/PickerViewController.h +88 -0
- data/app/PickerViewController.m +402 -0
- data/app/Prefix.pch +5 -0
- data/app/ReadMe.txt +82 -0
- data/app/SearchBarController.h +58 -0
- data/app/SearchBarController.m +105 -0
- data/app/SegmentViewController.h +54 -0
- data/app/SegmentViewController.m +195 -0
- data/app/TextFieldController.h +67 -0
- data/app/TextFieldController.m +342 -0
- data/app/TextViewController.h +57 -0
- data/app/TextViewController.m +164 -0
- data/app/ToolbarViewController.h +74 -0
- data/app/ToolbarViewController.m +303 -0
- data/app/TransitionViewController.h +64 -0
- data/app/TransitionViewController.m +178 -0
- data/app/UICatalog.xcodeproj/project.pbxproj +615 -0
- data/app/WebViewController.h +57 -0
- data/app/WebViewController.m +173 -0
- data/app/en.lproj/AlertsViewController.xib +144 -0
- data/app/en.lproj/ButtonsViewController.xib +147 -0
- data/app/en.lproj/ControlsViewController.xib +147 -0
- data/app/en.lproj/ImagesViewController.xib +264 -0
- data/app/en.lproj/Localizable.strings +41 -0
- data/app/en.lproj/MainWindow.xib +306 -0
- data/app/en.lproj/PickerViewController.xib +415 -0
- data/app/en.lproj/SearchBarController.xib +142 -0
- data/app/en.lproj/SegmentViewController.xib +143 -0
- data/app/en.lproj/TextFieldController.xib +167 -0
- data/app/en.lproj/TextViewController.xib +149 -0
- data/app/en.lproj/ToolbarViewController.xib +491 -0
- data/app/en.lproj/TransitionViewController.xib +255 -0
- data/app/en.lproj/WebViewController.xib +141 -0
- data/app/images/12-6AM.png +0 -0
- data/app/images/12-6PM.png +0 -0
- data/app/images/6-12AM.png +0 -0
- data/app/images/6-12PM.png +0 -0
- data/app/images/Default.png +0 -0
- data/app/images/Icon.png +0 -0
- data/app/images/UIButton_custom.png +0 -0
- data/app/images/blueButton.png +0 -0
- data/app/images/orangeslide.png +0 -0
- data/app/images/scene1.jpg +0 -0
- data/app/images/scene2.jpg +0 -0
- data/app/images/scene3.jpg +0 -0
- data/app/images/scene4.jpg +0 -0
- data/app/images/scene5.jpg +0 -0
- data/app/images/segment_check.png +0 -0
- data/app/images/segment_search.png +0 -0
- data/app/images/segment_tools.png +0 -0
- data/app/images/slider_ball.png +0 -0
- data/app/images/whiteButton.png +0 -0
- data/app/images/yellowslide.png +0 -0
- data/app/main.m +58 -0
- data/ext/iCuke/DefaultsResponse.m +0 -1
- data/ext/iCuke/EventResponse.m +9 -1
- data/ext/iCuke/Rakefile +1 -1
- data/ext/iCuke/Recorder.h +3 -1
- data/ext/iCuke/Recorder.m +10 -5
- data/ext/iCuke/RecorderResponse.h +1 -0
- data/ext/iCuke/RecorderResponse.m +10 -1
- data/ext/iCuke/Viewer.m +5 -6
- data/ext/iCuke/iCukeHTTPServer.m +1 -1
- data/ext/iCuke/iCukeServer.m +24 -7
- data/ext/iCuke/libicuke.dylib +0 -0
- data/features/uicatalog.feature +20 -0
- data/iCuke.gemspec +81 -24
- data/lib/icuke/com.apple.Accessibility.plist +0 -0
- data/lib/icuke/core_ext.rb +26 -0
- data/lib/icuke/cucumber.rb +20 -12
- data/lib/icuke/headless.rb +55 -0
- data/lib/icuke/simulator.rb +7 -129
- data/lib/icuke/xcode.rb +136 -0
- metadata +82 -25
- data/app/iCuke/Classes/FlipsideView.h +0 -13
- data/app/iCuke/Classes/FlipsideView.m +0 -32
- data/app/iCuke/Classes/FlipsideViewController.h +0 -25
- data/app/iCuke/Classes/FlipsideViewController.m +0 -54
- data/app/iCuke/Classes/MainView.h +0 -15
- data/app/iCuke/Classes/MainView.m +0 -32
- data/app/iCuke/Classes/MainViewController.h +0 -16
- data/app/iCuke/Classes/MainViewController.m +0 -86
- data/app/iCuke/Classes/iCukeAppDelegate.h +0 -20
- data/app/iCuke/Classes/iCukeAppDelegate.m +0 -33
- data/app/iCuke/FlipsideView.xib +0 -444
- data/app/iCuke/MainView.xib +0 -520
- data/app/iCuke/MainWindow.xib +0 -355
- data/app/iCuke/SniffingView.h +0 -20
- data/app/iCuke/SniffingView.m +0 -191
- data/app/iCuke/iCuke.xcodeproj/project.pbxproj +0 -313
- data/app/iCuke/iCuke_Prefix.pch +0 -14
- data/app/iCuke/main.m +0 -16
- data/features/icuke.feature +0 -17
- /data/app/{iCuke/.gitignore → .gitignore} +0 -0
data/ext/iCuke/Viewer.m
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
#import "Viewer.h"
|
|
4
4
|
|
|
5
|
-
// AX API
|
|
6
|
-
extern Boolean AXAPIEnabled(void);
|
|
7
|
-
|
|
8
5
|
static Viewer *sharedViewer = nil;
|
|
9
6
|
|
|
10
7
|
@interface NSObject (UIAccessibilityViewer)
|
|
@@ -27,7 +24,8 @@ static Viewer *sharedViewer = nil;
|
|
|
27
24
|
if ([[self accessibilityLabel] length] > 0) {
|
|
28
25
|
NSString *escaped_label = [self accessibilityLabel];
|
|
29
26
|
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @"&" withString: @"&"];
|
|
30
|
-
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @"
|
|
27
|
+
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @"\"" withString: @"""];
|
|
28
|
+
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @"'" withString: @"'"];
|
|
31
29
|
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @"\\" withString: @"'"];
|
|
32
30
|
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @">" withString: @">"];
|
|
33
31
|
escaped_label = [escaped_label stringByReplacingOccurrencesOfString: @"<" withString: @"<"];
|
|
@@ -39,7 +37,8 @@ static Viewer *sharedViewer = nil;
|
|
|
39
37
|
if ([[self accessibilityValue] length] > 0) {
|
|
40
38
|
NSString *escaped_value = [self accessibilityValue];
|
|
41
39
|
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @"&" withString: @"&"];
|
|
42
|
-
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @"
|
|
40
|
+
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @"\"" withString: @"""];
|
|
41
|
+
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @"'" withString: @"'"];
|
|
43
42
|
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @"\\" withString: @"'"];
|
|
44
43
|
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @">" withString: @">"];
|
|
45
44
|
escaped_value = [escaped_value stringByReplacingOccurrencesOfString: @"<" withString: @"<"];
|
|
@@ -134,7 +133,7 @@ static Viewer *sharedViewer = nil;
|
|
|
134
133
|
for (UIView *view in self.subviews) {
|
|
135
134
|
[view appendToXml: xml];
|
|
136
135
|
}
|
|
137
|
-
|
|
136
|
+
|
|
138
137
|
[self appendChildrenToXml: xml];
|
|
139
138
|
[self appendCloseToXml: xml];
|
|
140
139
|
}
|
data/ext/iCuke/iCukeHTTPServer.m
CHANGED
data/ext/iCuke/iCukeServer.m
CHANGED
|
@@ -8,22 +8,29 @@
|
|
|
8
8
|
|
|
9
9
|
#import "iCukeServer.h"
|
|
10
10
|
#include <unistd.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
|
|
13
|
+
static NSAutoreleasePool *pool;
|
|
11
14
|
|
|
12
15
|
@implementation iCukeServer
|
|
13
16
|
|
|
14
17
|
+ (void)start {
|
|
18
|
+
pool = [[NSAutoreleasePool alloc] init];
|
|
19
|
+
|
|
15
20
|
[[iCukeHTTPServer sharediCukeHTTPServer] start];
|
|
16
21
|
|
|
17
22
|
NSFileManager *fileManager= [[NSFileManager alloc] init];
|
|
18
23
|
NSArray *paths;
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
if (!getenv("ICUKE_KEEP_PREFERENCES")) {
|
|
26
|
+
NSString *preferences = [NSHomeDirectory() stringByAppendingPathComponent: @"Library/Preferences"];
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
paths = [fileManager contentsOfDirectoryAtPath: preferences error: NULL];
|
|
29
|
+
for (NSString *path in paths) {
|
|
30
|
+
if (![path hasPrefix: @"."]) {
|
|
31
|
+
NSLog(@"Removing: %@", path);
|
|
32
|
+
unlink([[preferences stringByAppendingPathComponent: path] cStringUsingEncoding: [NSString defaultCStringEncoding]]);
|
|
33
|
+
}
|
|
27
34
|
}
|
|
28
35
|
}
|
|
29
36
|
|
|
@@ -37,10 +44,20 @@
|
|
|
37
44
|
}
|
|
38
45
|
}
|
|
39
46
|
|
|
47
|
+
+ (void)stop {
|
|
48
|
+
[pool release];
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
@end
|
|
41
52
|
|
|
42
53
|
void start_server(void) __attribute__((constructor));
|
|
43
54
|
void start_server(void)
|
|
44
55
|
{
|
|
45
|
-
|
|
56
|
+
[iCukeServer start];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
void stop_server(void) __attribute__((destructor));
|
|
60
|
+
void stop_server(void)
|
|
61
|
+
{
|
|
62
|
+
[iCukeServer stop];
|
|
46
63
|
}
|
data/ext/iCuke/libicuke.dylib
CHANGED
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Feature: iPhone integration tests
|
|
2
|
+
In order to test my iphone application
|
|
3
|
+
As a developer
|
|
4
|
+
I want cucumber to be able to drive the simulator
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given "app/UICatalog.xcodeproj" is loaded in the simulator
|
|
8
|
+
|
|
9
|
+
Scenario: Pressing buttons
|
|
10
|
+
When I tap "Buttons"
|
|
11
|
+
And I tap "Gray"
|
|
12
|
+
|
|
13
|
+
Scenario: Switches and sliders
|
|
14
|
+
When I tap "Controls"
|
|
15
|
+
And I tap "Standard switch"
|
|
16
|
+
|
|
17
|
+
Scenario: Entering text
|
|
18
|
+
When I tap "TextFields"
|
|
19
|
+
And I type "A string with symb0ls $!@ and spaces in it" in "Normal"
|
|
20
|
+
Then I should see "A string with symb0ls $!@ and spaces in it"
|
data/iCuke.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{iCuke}
|
|
8
|
-
s.version = "0.
|
|
8
|
+
s.version = "0.5.1"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Rob Holland"]
|
|
12
|
-
s.date = %q{2010-
|
|
12
|
+
s.date = %q{2010-05-11}
|
|
13
13
|
s.description = %q{Cucumber support for iPhone applications}
|
|
14
14
|
s.email = %q{rob@the-it-refinery.co.uk}
|
|
15
15
|
s.extensions = ["ext/iCuke/Rakefile"]
|
|
@@ -24,26 +24,79 @@ Gem::Specification.new do |s|
|
|
|
24
24
|
"README.rdoc",
|
|
25
25
|
"Rakefile",
|
|
26
26
|
"VERSION",
|
|
27
|
-
"app
|
|
28
|
-
"app/
|
|
29
|
-
"app/
|
|
30
|
-
"app/
|
|
31
|
-
"app/
|
|
32
|
-
"app/
|
|
33
|
-
"app/
|
|
34
|
-
"app/
|
|
35
|
-
"app/
|
|
36
|
-
"app/
|
|
37
|
-
"app/
|
|
38
|
-
"app/
|
|
39
|
-
"app/
|
|
40
|
-
"app/
|
|
41
|
-
"app/
|
|
42
|
-
"app/
|
|
43
|
-
"app/
|
|
44
|
-
"app/
|
|
45
|
-
"app/
|
|
46
|
-
"app/
|
|
27
|
+
"app/.gitignore",
|
|
28
|
+
"app/AlertsViewController.h",
|
|
29
|
+
"app/AlertsViewController.m",
|
|
30
|
+
"app/AppDelegate.h",
|
|
31
|
+
"app/AppDelegate.m",
|
|
32
|
+
"app/ButtonsViewController.h",
|
|
33
|
+
"app/ButtonsViewController.m",
|
|
34
|
+
"app/Constants.h",
|
|
35
|
+
"app/ControlsViewController.h",
|
|
36
|
+
"app/ControlsViewController.m",
|
|
37
|
+
"app/ImagesViewController.h",
|
|
38
|
+
"app/ImagesViewController.m",
|
|
39
|
+
"app/Info.plist",
|
|
40
|
+
"app/MainViewController.h",
|
|
41
|
+
"app/MainViewController.m",
|
|
42
|
+
"app/Picker/CustomPickerDataSource.h",
|
|
43
|
+
"app/Picker/CustomPickerDataSource.m",
|
|
44
|
+
"app/Picker/CustomView.h",
|
|
45
|
+
"app/Picker/CustomView.m",
|
|
46
|
+
"app/PickerViewController.h",
|
|
47
|
+
"app/PickerViewController.m",
|
|
48
|
+
"app/Prefix.pch",
|
|
49
|
+
"app/ReadMe.txt",
|
|
50
|
+
"app/SearchBarController.h",
|
|
51
|
+
"app/SearchBarController.m",
|
|
52
|
+
"app/SegmentViewController.h",
|
|
53
|
+
"app/SegmentViewController.m",
|
|
54
|
+
"app/TextFieldController.h",
|
|
55
|
+
"app/TextFieldController.m",
|
|
56
|
+
"app/TextViewController.h",
|
|
57
|
+
"app/TextViewController.m",
|
|
58
|
+
"app/ToolbarViewController.h",
|
|
59
|
+
"app/ToolbarViewController.m",
|
|
60
|
+
"app/TransitionViewController.h",
|
|
61
|
+
"app/TransitionViewController.m",
|
|
62
|
+
"app/UICatalog.xcodeproj/project.pbxproj",
|
|
63
|
+
"app/WebViewController.h",
|
|
64
|
+
"app/WebViewController.m",
|
|
65
|
+
"app/en.lproj/AlertsViewController.xib",
|
|
66
|
+
"app/en.lproj/ButtonsViewController.xib",
|
|
67
|
+
"app/en.lproj/ControlsViewController.xib",
|
|
68
|
+
"app/en.lproj/ImagesViewController.xib",
|
|
69
|
+
"app/en.lproj/Localizable.strings",
|
|
70
|
+
"app/en.lproj/MainWindow.xib",
|
|
71
|
+
"app/en.lproj/PickerViewController.xib",
|
|
72
|
+
"app/en.lproj/SearchBarController.xib",
|
|
73
|
+
"app/en.lproj/SegmentViewController.xib",
|
|
74
|
+
"app/en.lproj/TextFieldController.xib",
|
|
75
|
+
"app/en.lproj/TextViewController.xib",
|
|
76
|
+
"app/en.lproj/ToolbarViewController.xib",
|
|
77
|
+
"app/en.lproj/TransitionViewController.xib",
|
|
78
|
+
"app/en.lproj/WebViewController.xib",
|
|
79
|
+
"app/images/12-6AM.png",
|
|
80
|
+
"app/images/12-6PM.png",
|
|
81
|
+
"app/images/6-12AM.png",
|
|
82
|
+
"app/images/6-12PM.png",
|
|
83
|
+
"app/images/Default.png",
|
|
84
|
+
"app/images/Icon.png",
|
|
85
|
+
"app/images/UIButton_custom.png",
|
|
86
|
+
"app/images/blueButton.png",
|
|
87
|
+
"app/images/orangeslide.png",
|
|
88
|
+
"app/images/scene1.jpg",
|
|
89
|
+
"app/images/scene2.jpg",
|
|
90
|
+
"app/images/scene3.jpg",
|
|
91
|
+
"app/images/scene4.jpg",
|
|
92
|
+
"app/images/scene5.jpg",
|
|
93
|
+
"app/images/segment_check.png",
|
|
94
|
+
"app/images/segment_search.png",
|
|
95
|
+
"app/images/segment_tools.png",
|
|
96
|
+
"app/images/slider_ball.png",
|
|
97
|
+
"app/images/whiteButton.png",
|
|
98
|
+
"app/images/yellowslide.png",
|
|
99
|
+
"app/main.m",
|
|
47
100
|
"ext/iCuke/.gitignore",
|
|
48
101
|
"ext/iCuke/DefaultsResponse.h",
|
|
49
102
|
"ext/iCuke/DefaultsResponse.m",
|
|
@@ -79,13 +132,17 @@ Gem::Specification.new do |s|
|
|
|
79
132
|
"ext/iCuke/json/SBJsonWriter.h",
|
|
80
133
|
"ext/iCuke/json/SBJsonWriter.m",
|
|
81
134
|
"ext/iCuke/libicuke.dylib",
|
|
82
|
-
"features/icuke.feature",
|
|
83
135
|
"features/support/env.rb",
|
|
136
|
+
"features/uicatalog.feature",
|
|
84
137
|
"iCuke.gemspec",
|
|
85
138
|
"lib/icuke.rb",
|
|
139
|
+
"lib/icuke/com.apple.Accessibility.plist",
|
|
140
|
+
"lib/icuke/core_ext.rb",
|
|
86
141
|
"lib/icuke/cucumber.rb",
|
|
142
|
+
"lib/icuke/headless.rb",
|
|
87
143
|
"lib/icuke/simulate.rb",
|
|
88
|
-
"lib/icuke/simulator.rb"
|
|
144
|
+
"lib/icuke/simulator.rb",
|
|
145
|
+
"lib/icuke/xcode.rb"
|
|
89
146
|
]
|
|
90
147
|
s.homepage = %q{http://github.com/unboxed/iCuke}
|
|
91
148
|
s.rdoc_options = ["--charset=UTF-8"]
|
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
|
|
3
|
+
module RequestWithSocketCheck
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.instance_eval do
|
|
6
|
+
alias_method :request_without_socket_check, :request
|
|
7
|
+
alias_method :request, :request_with_socket_check
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def request_with_socket_check(*args)
|
|
12
|
+
begin
|
|
13
|
+
request_without_socket_check(*args)
|
|
14
|
+
rescue NoMethodError => e
|
|
15
|
+
if e.message =~ /undefined method `closed\?' for nil/
|
|
16
|
+
raise Errno::ECONNREFUSED
|
|
17
|
+
else
|
|
18
|
+
raise e
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if Net::HTTP::Revision.to_i == 25851
|
|
25
|
+
Net::HTTP.send :include, RequestWithSocketCheck
|
|
26
|
+
end
|
data/lib/icuke/cucumber.rb
CHANGED
|
@@ -48,19 +48,23 @@ class ICukeWorld
|
|
|
48
48
|
element =
|
|
49
49
|
page.xpath(
|
|
50
50
|
%Q{//*[#{trait(:button, :updates_frequently, :keyboard_key)} and @label="#{label}" and frame]},
|
|
51
|
-
%Q{//*[#{trait(:link)} and @value="#{label}" and frame]}
|
|
51
|
+
%Q{//*[#{trait(:link)} and @value="#{label}" and frame]},
|
|
52
|
+
%Q{//*[@label="#{label}" and frame]}
|
|
52
53
|
).first
|
|
53
54
|
|
|
54
|
-
raise %Q{No element labelled "#{label}" found in: #{
|
|
55
|
+
raise %Q{No element labelled "#{label}" found in: #{page}} unless element
|
|
55
56
|
|
|
56
57
|
# This seems brittle, revist how to fetch the frame without relying on it being the only child
|
|
57
58
|
frame = element.child
|
|
58
59
|
|
|
60
|
+
x = frame['x'].to_f
|
|
61
|
+
y = frame['y'].to_f
|
|
62
|
+
|
|
59
63
|
# Hit the element in the middle
|
|
60
|
-
x
|
|
61
|
-
y
|
|
64
|
+
x += (frame['width'].to_f / 2)
|
|
65
|
+
y += (frame['height'].to_f / 2)
|
|
62
66
|
|
|
63
|
-
raise %Q{Element "#{label}" is off screen in: #{
|
|
67
|
+
raise %Q{Element "#{label}" is off screen in: #{page}} unless onscreen?(x, y)
|
|
64
68
|
|
|
65
69
|
@simulator.fire_event(Tap.new(x, y, options))
|
|
66
70
|
|
|
@@ -73,7 +77,7 @@ class ICukeWorld
|
|
|
73
77
|
|
|
74
78
|
def swipe(direction, options = {})
|
|
75
79
|
modifier = [:up, :left].include?(direction) ? -1 : 1
|
|
76
|
-
|
|
80
|
+
|
|
77
81
|
# Just swipe from the middle of an iPhone-dimensioned screen for now
|
|
78
82
|
x = 320 / 2
|
|
79
83
|
y = 480 / 2
|
|
@@ -81,9 +85,9 @@ class ICukeWorld
|
|
|
81
85
|
y2 = y
|
|
82
86
|
|
|
83
87
|
if [:up, :down].include?(direction)
|
|
84
|
-
y2 = y + (
|
|
88
|
+
y2 = y + (y * modifier)
|
|
85
89
|
else
|
|
86
|
-
x2 = x + (
|
|
90
|
+
x2 = x + (x * modifier)
|
|
87
91
|
end
|
|
88
92
|
|
|
89
93
|
@simulator.fire_event(Swipe.new(x, y, x2, y2, options))
|
|
@@ -145,7 +149,7 @@ class ICukeWorld
|
|
|
145
149
|
previous_response = response.dup
|
|
146
150
|
while page.xpath(%Q{//*[contains(., "#{text}") or contains(@label, "#{text}") or contains(@value, "#{text}")]}).empty? do
|
|
147
151
|
scroll(options[:direction])
|
|
148
|
-
raise %Q{Content "#{text}" not found in: #{
|
|
152
|
+
raise %Q{Content "#{text}" not found in: #{page}} if response == previous_response
|
|
149
153
|
end
|
|
150
154
|
end
|
|
151
155
|
|
|
@@ -174,6 +178,10 @@ World do
|
|
|
174
178
|
ICukeWorld.new
|
|
175
179
|
end
|
|
176
180
|
|
|
181
|
+
After do
|
|
182
|
+
quit
|
|
183
|
+
end
|
|
184
|
+
|
|
177
185
|
LIBICUKE = File.expand_path(File.dirname(__FILE__) + '/../../ext/iCuke/libicuke.dylib')
|
|
178
186
|
|
|
179
187
|
Given /^(?:"([^\"]*)" from )?"([^\"]*)" is loaded in the simulator(?: using sdk (.*))?$/ do |target, project, sdk|
|
|
@@ -183,11 +191,11 @@ Given /^(?:"([^\"]*)" from )?"([^\"]*)" is loaded in the simulator(?: using sdk
|
|
|
183
191
|
end
|
|
184
192
|
|
|
185
193
|
Then /^I should see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, scope|
|
|
186
|
-
raise %Q{Content "#{text}" not found in: #{
|
|
194
|
+
raise %Q{Content "#{text}" not found in: #{page}} unless can_see?(text, scope)
|
|
187
195
|
end
|
|
188
196
|
|
|
189
197
|
Then /^I should not see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, scope|
|
|
190
|
-
raise %Q{Content "#{text}" was found but was not expected in: #{
|
|
198
|
+
raise %Q{Content "#{text}" was found but was not expected in: #{page}} if can_see?(text, scope)
|
|
191
199
|
end
|
|
192
200
|
|
|
193
201
|
When /^I tap "([^\"]*)"$/ do |label|
|
|
@@ -211,5 +219,5 @@ Then /^I put the phone into recording mode$/ do
|
|
|
211
219
|
end
|
|
212
220
|
|
|
213
221
|
Then /^show me the screen$/ do
|
|
214
|
-
puts
|
|
222
|
+
puts page.to_s
|
|
215
223
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'tmpdir'
|
|
2
|
+
require 'background_process'
|
|
3
|
+
|
|
4
|
+
module ICuke
|
|
5
|
+
class Simulator
|
|
6
|
+
include Timeout
|
|
7
|
+
|
|
8
|
+
def launch(project_file, options = {})
|
|
9
|
+
options = {
|
|
10
|
+
:configuration => 'Debug',
|
|
11
|
+
:env => {}
|
|
12
|
+
}.merge(options)
|
|
13
|
+
|
|
14
|
+
app_name = File.basename(project_file, '.xcodeproj')
|
|
15
|
+
directory = "#{File.dirname(project_file)}/build/#{options[:configuration]}-iphonesimulator"
|
|
16
|
+
|
|
17
|
+
ENV['DYLD_ROOT_PATH'] = '/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.1.2.sdk'
|
|
18
|
+
ENV['DYLD_FRAMEWORK_PATH'] = directory
|
|
19
|
+
ENV['IPHONE_SIMULATOR_ROOT'] = '/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.1.2.sdk'
|
|
20
|
+
home = Dir.mktmpdir
|
|
21
|
+
FileUtils.mkdir_p File.join(home, 'Library', 'Preferences')
|
|
22
|
+
FileUtils.cp File.join(File.dirname(__FILE__), 'com.apple.Accessibility.plist'), File.join(home, 'Library', 'Preferences')
|
|
23
|
+
FileUtils.mkdir File.join(home, 'Documents')
|
|
24
|
+
ENV['CFFIXED_USER_HOME'] = home
|
|
25
|
+
ENV['ICUKE_KEEP_PREFERENCES'] = '1'
|
|
26
|
+
|
|
27
|
+
options[:env].each_pair do |k, v|
|
|
28
|
+
ENV[k] = v
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
command = "#{directory}/#{app_name}.app/#{app_name} -RegisterForSystemEvents"
|
|
32
|
+
@pid = fork {
|
|
33
|
+
STDIN.close
|
|
34
|
+
STDERR.close
|
|
35
|
+
STDOUT.close
|
|
36
|
+
|
|
37
|
+
exec(command)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
timeout(30) do
|
|
41
|
+
begin
|
|
42
|
+
view
|
|
43
|
+
rescue Errno::ECONNREFUSED
|
|
44
|
+
sleep(0.5)
|
|
45
|
+
retry
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def quit
|
|
51
|
+
Process.kill('TERM', @pid)
|
|
52
|
+
Process.wait(@pid)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/icuke/simulator.rb
CHANGED
|
@@ -1,84 +1,13 @@
|
|
|
1
|
+
require 'icuke/core_ext'
|
|
2
|
+
if ENV['ICUKE_HEADLESS']
|
|
3
|
+
require 'icuke/headless'
|
|
4
|
+
else
|
|
5
|
+
require 'icuke/xcode'
|
|
6
|
+
end
|
|
7
|
+
|
|
1
8
|
require 'httparty'
|
|
2
|
-
require 'appscript'
|
|
3
|
-
require 'timeout'
|
|
4
9
|
|
|
5
10
|
module ICuke
|
|
6
|
-
class XCode
|
|
7
|
-
def self.app
|
|
8
|
-
@app ||= Appscript.app('Xcode.app')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.open_project(project_file)
|
|
12
|
-
unless open_project?(project_file)
|
|
13
|
-
app.launch
|
|
14
|
-
app.open project_file
|
|
15
|
-
end
|
|
16
|
-
app.active_project_document.project
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.open_project?(project_file)
|
|
20
|
-
running? and
|
|
21
|
-
app.active_project_document.get and
|
|
22
|
-
app.active_project_document.project.path.get == project_file
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.interface
|
|
26
|
-
Appscript.app('System Events').application_processes['Xcode']
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.running?
|
|
30
|
-
app.is_running?
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def self.quit
|
|
34
|
-
IPhoneSimulator.quit
|
|
35
|
-
app.quit if running?
|
|
36
|
-
sleep(0.2) until !running?
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.status
|
|
40
|
-
interface.windows[1].static_texts[0].value.get
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def self.launched_app?
|
|
44
|
-
status =~ /launched$/
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def self.installing_app?
|
|
48
|
-
status =~ /^Installing/
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.with_settings(project, settings, &block)
|
|
52
|
-
initial_settings = {}
|
|
53
|
-
|
|
54
|
-
settings.each_key { |setting| initial_settings[setting] = project.send(setting).get }
|
|
55
|
-
settings.each_pair do |setting, value|
|
|
56
|
-
project.send(setting).set value
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
yield
|
|
60
|
-
ensure
|
|
61
|
-
initial_settings.each_pair do |setting, value|
|
|
62
|
-
project.send(setting).set value
|
|
63
|
-
end if running?
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
class IPhoneSimulator
|
|
68
|
-
def self.app
|
|
69
|
-
@app ||= Appscript.app('iPhone Simulator.app')
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def self.quit
|
|
73
|
-
app.quit if running?
|
|
74
|
-
sleep(0.2) until !running?
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def self.running?
|
|
78
|
-
app.is_running?
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
11
|
class Simulator
|
|
83
12
|
include Timeout
|
|
84
13
|
include HTTParty
|
|
@@ -86,57 +15,6 @@ module ICuke
|
|
|
86
15
|
|
|
87
16
|
class Error < StandardError; end
|
|
88
17
|
|
|
89
|
-
def launch(project_file, options = {})
|
|
90
|
-
options = {
|
|
91
|
-
:target => nil,
|
|
92
|
-
:configuration => 'Debug'
|
|
93
|
-
}.merge(options)
|
|
94
|
-
|
|
95
|
-
# If we don't kill the simulator first the rest of this function becomes
|
|
96
|
-
# a no-op and we don't land on the applications first page
|
|
97
|
-
IPhoneSimulator.quit
|
|
98
|
-
|
|
99
|
-
begin
|
|
100
|
-
project = XCode.open_project(project_file)
|
|
101
|
-
|
|
102
|
-
settings = {
|
|
103
|
-
:active_build_configuration_type => project.build_configuration_types[options[:configuration]]
|
|
104
|
-
}
|
|
105
|
-
if options[:target]
|
|
106
|
-
settings[:active_target] = project.targets[options[:target]]
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
XCode.with_settings(project, settings) do
|
|
110
|
-
executable = project.active_executable.get
|
|
111
|
-
options[:env].each_pair do |name, value|
|
|
112
|
-
executable.make :new => :environment_variable,
|
|
113
|
-
:with_properties => { :name => name, :value => value, :active => true }
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
project.launch_
|
|
117
|
-
|
|
118
|
-
sleep(0.5) while XCode.installing_app?
|
|
119
|
-
|
|
120
|
-
unless XCode.launched_app?
|
|
121
|
-
XCode.quit
|
|
122
|
-
retry
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
timeout(30) do
|
|
126
|
-
begin
|
|
127
|
-
view
|
|
128
|
-
rescue Errno::ECONNREFUSED
|
|
129
|
-
sleep(0.5)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def quit
|
|
137
|
-
IPhoneSimulator.quit
|
|
138
|
-
end
|
|
139
|
-
|
|
140
18
|
def view
|
|
141
19
|
get('/view')
|
|
142
20
|
end
|