iCuke 0.4.12 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|