frank-cucumber 0.9.4 → 0.9.5.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/Gemfile.lock +58 -0
  2. data/frank-cucumber.gemspec +1 -0
  3. data/frank-skeleton/features/support/env.rb +2 -2
  4. data/frank-skeleton/frank_static_resources.bundle/_solarized_colors.scss +16 -0
  5. data/frank-skeleton/frank_static_resources.bundle/coffee-script.js +8 -0
  6. data/frank-skeleton/frank_static_resources.bundle/images/loader.gif +0 -0
  7. data/frank-skeleton/frank_static_resources.bundle/images/loader.png +0 -0
  8. data/frank-skeleton/frank_static_resources.bundle/index.haml +61 -47
  9. data/frank-skeleton/frank_static_resources.bundle/index.html +82 -71
  10. data/frank-skeleton/frank_static_resources.bundle/jquery.min.js +4 -19
  11. data/frank-skeleton/frank_static_resources.bundle/jquery.treeview.css +19 -17
  12. data/frank-skeleton/frank_static_resources.bundle/pictos/index.html +329 -0
  13. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.eot +0 -0
  14. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.svg +114 -0
  15. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.ttf +0 -0
  16. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos-web.woff +0 -0
  17. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos.css +20 -0
  18. data/frank-skeleton/frank_static_resources.bundle/pictos/pictos_base64.css +18 -0
  19. data/frank-skeleton/frank_static_resources.bundle/reset.css +32 -0
  20. data/frank-skeleton/frank_static_resources.bundle/symbiote.css +407 -61
  21. data/frank-skeleton/frank_static_resources.bundle/symbiote.js +127 -54
  22. data/frank-skeleton/frank_static_resources.bundle/symbiote_ui.coffee +39 -0
  23. data/lib/frank-cucumber/cli.rb +12 -2
  24. data/lib/frank-cucumber/core_frank_steps.rb +11 -1
  25. data/lib/frank-cucumber/frank_helper.rb +142 -27
  26. data/lib/frank-cucumber/version.rb +1 -1
  27. data/lib/frank-cucumber/wait_helper.rb +26 -27
  28. metadata +36 -6
  29. data/frank-skeleton/frank_static_resources.bundle/jquery-ui.css +0 -571
@@ -1,7 +1,6 @@
1
1
  /*jslint browser: true, white: false, devel: true */
2
2
  /*global window: true, Raphael: true, $: true, _: true */
3
3
 
4
-
5
4
  var symbiote = {};
6
5
 
7
6
  symbiote.baseUrlFor = function(path){ return window.location.protocol + "//" + window.location.host + "/" + path; };
@@ -10,6 +9,7 @@ symbiote.UiLocator = function(){
10
9
  var allViews = [],
11
10
  paper = new Raphael( 'ui-locator-view'),
12
11
  viewIndicator = { remove: _.identity },
12
+ viewIndicators = [],
13
13
  screenshotUrl = symbiote.baseUrlFor( "screenshot" ),
14
14
  backdrop = null,
15
15
  erstaz = null;
@@ -110,27 +110,33 @@ symbiote.UiLocator = function(){
110
110
 
111
111
  }
112
112
 
113
- function showViewLocation( view ) {
114
- var screenOffset = erstaz.screenOffset();
115
-
116
- viewIndicator.remove();
113
+ function removeHighlights() {
114
+ _.each( viewIndicators, function(v){ v.remove(); } );
115
+ }
117
116
 
118
- viewIndicator = paper.rect(
119
- view.accessibilityFrame.origin.x,
120
- view.accessibilityFrame.origin.y,
121
- view.accessibilityFrame.size.width,
122
- view.accessibilityFrame.size.height
123
- )
124
- .attr({
125
- fill: '#aaff00',
126
- opacity: 0.8,
127
- stroke: 'black',
128
- })
129
- .translate( screenOffset.x, screenOffset.y );
117
+ function highlightAccessibilityFrames( frames ) {
118
+ var screenOffset = erstaz.screenOffset();
119
+
120
+ removeHighlights();
121
+
122
+ viewIndicators = _.map( frames, function(frame){
123
+ return paper.rect(
124
+ frame.origin.x,
125
+ frame.origin.y,
126
+ frame.size.width,
127
+ frame.size.height
128
+ )
129
+ .attr({
130
+ fill: '#aaff00',
131
+ opacity: 0.8,
132
+ stroke: 'black',
133
+ })
134
+ .translate( screenOffset.x, screenOffset.y );
135
+ });
130
136
  }
131
137
 
132
- function hideViewLocation() {
133
- viewIndicator.remove();
138
+ function highlightAccessibilityFrame( frame ) {
139
+ highlightAccessibilityFrames( [frame] );
134
140
  }
135
141
 
136
142
  function addBackdropImage(){
@@ -163,17 +169,24 @@ symbiote.UiLocator = function(){
163
169
  }
164
170
  }
165
171
 
172
+ function updateOrientation(orientation){
173
+ // $(paper.canvas).parent().removeClass('landscape').removeClass('portrait').addClass(orientation);
174
+ $('#ui-locator-view, .the-columns').removeClass('landscape').removeClass('portrait').addClass(orientation);
175
+ }
176
+
166
177
  function updateViews(views){
167
178
  allViews = views;
168
179
  }
169
180
 
170
181
 
171
182
  return {
172
- showViewLocation: showViewLocation,
173
- hideViewLocation: hideViewLocation,
183
+ highlightAccessibilityFrame: highlightAccessibilityFrame,
184
+ highlightAccessibilityFrames: highlightAccessibilityFrames,
185
+ removeHighlights: removeHighlights,
174
186
  updateBackdrop: updateBackdrop,
175
187
  updateViews: updateViews,
176
- updateDeviceFamily: updateDeviceFamily
188
+ updateDeviceFamily: updateDeviceFamily,
189
+ updateOrientation: updateOrientation
177
190
  };
178
191
  };
179
192
 
@@ -209,7 +222,7 @@ $(document).ready(function() {
209
222
  var $domDetails = $('#dom_detail'),
210
223
  $domList = $('div#dom_dump > ul'),
211
224
  $domAccessibleDump = $('div#accessible-views'),
212
- $loading = $('#loading'),
225
+ $loading = $(''),
213
226
  INTERESTING_PROPERTIES = ['class', 'accessibilityLabel', 'tag', 'alpha', 'isHidden'],
214
227
  uiLocator = symbiote.UiLocator(),
215
228
  liveView;
@@ -248,31 +261,31 @@ $(document).ready(function() {
248
261
  }
249
262
 
250
263
  function showLoadingUI() {
251
- $loading.show();
264
+ $('body').addClass('working');
252
265
  }
253
266
 
254
267
  function hideLoadingUI() {
255
- $loading.hide();
268
+ $('body').removeClass('working');
256
269
  }
257
270
 
258
271
 
259
272
  function displayDetailsFor( view ) {
260
273
  console.debug( 'displaying details for:', view );
261
274
 
262
- var $table = $('<table/>');
275
+ var $ul = $('<ul/>');
263
276
 
264
- function tableRow( propertyName, propertyValue, cssClass ){
277
+ function createListItem( propertyName, propertyValue, cssClass ){
265
278
  if( propertyValue === null ){
266
279
  propertyValue = 'null';
267
280
  }else if( typeof propertyValue === 'object' ){
268
281
  propertyValue = JSON.stringify(propertyValue);
269
282
  }
270
283
 
271
- return $('<tr/>').addClass(cssClass)
284
+ return $('<li/>').addClass(cssClass)
272
285
  .append(
273
- $('<td/>').text(propertyName),
274
- $('<td/>').text(propertyValue) )
275
- .appendTo( $table );
286
+ $('<div/>').addClass('key').text(propertyName),
287
+ $('<div/>').addClass('value').text(propertyValue) )
288
+ .appendTo( $ul );
276
289
  }
277
290
 
278
291
 
@@ -280,7 +293,7 @@ $(document).ready(function() {
280
293
  if( !view.hasOwnProperty(propertyName) ){ return; }
281
294
 
282
295
  var propertyValue = view[propertyName];
283
- $table.append( tableRow( propertyName, propertyValue, 'interesting' ) );
296
+ $ul.append( createListItem( propertyName, propertyValue, 'interesting' ) );
284
297
  });
285
298
 
286
299
 
@@ -289,11 +302,11 @@ $(document).ready(function() {
289
302
  if( _.contains( INTERESTING_PROPERTIES, propertyName ) ){ return; } // don't want to include the interesting properties twice
290
303
 
291
304
  var propertyValue = view[propertyName];
292
- $table.append( tableRow( propertyName, propertyValue ) );
305
+ $ul.append( createListItem( propertyName, propertyValue ) );
293
306
  });
294
307
 
295
- $domDetails.children().remove();
296
- $table.appendTo( $domDetails );
308
+ $domDetails.empty();
309
+ $ul.appendTo( $domDetails );
297
310
  }
298
311
 
299
312
  function treeElementSelected(){
@@ -308,11 +321,11 @@ $(document).ready(function() {
308
321
 
309
322
  function treeElementEntered(){
310
323
  var view = $(this).data('rawView');
311
- uiLocator.showViewLocation( view );
324
+ uiLocator.highlightAccessibilityFrame( view.accessibilityFrame );
312
325
  }
313
326
 
314
327
  function treeElementLeft(){
315
- uiLocator.hideViewLocation();
328
+ uiLocator.removeHighlights();
316
329
  }
317
330
 
318
331
  function listItemTitleFor( rawView ) {
@@ -379,18 +392,19 @@ $(document).ready(function() {
379
392
  }
380
393
 
381
394
 
382
-
383
- function sendFlashCommand( selector, engine ) {
384
- var command = {
385
- query: selector,
386
- selector_engine: engine ? engine : 'uiquery' ,
387
- operation: {
388
- method_name: 'flash',
389
- arguments: []
390
- }
391
- };
395
+ function sendMapRequest( selector, engine, method_name, method_args ) {
396
+ var deferable = new $.Deferred(),
397
+ command = {
398
+ query: selector,
399
+ selector_engine: engine ? engine : 'uiquery' ,
400
+ operation: {
401
+ method_name: method_name,
402
+ arguments: method_args || []
403
+ }
404
+ };
392
405
 
393
406
  showLoadingUI();
407
+
394
408
  $.ajax({
395
409
  type: "POST",
396
410
  dataType: "json",
@@ -399,20 +413,46 @@ $(document).ready(function() {
399
413
  success: function(data) {
400
414
  if( isErrorResponse( data ) ) {
401
415
  displayErrorResponse( data );
416
+ deferable.reject(data);
402
417
  }
418
+ deferable.resolve(data);
403
419
  },
404
420
  error: function(xhr,status,error) {
405
421
  alert( "Error while talking to Frank: " + status );
422
+ deferable.reject(error);
406
423
  },
407
424
  complete: function(xhr,status) {
408
425
  hideLoadingUI();
409
426
  }
410
427
  });
411
428
 
412
- return false;
429
+ return deferable.promise();
430
+ }
431
+
432
+ function highlightViewLocations( selector, engine ){
433
+ sendMapRequest( selector, engine, 'accessibilityFrame' ).done( function(data){
434
+ locations = data.results;
435
+ if( locations.length < 1 ){
436
+ alert( 'no views found for that selector' );
437
+ return;
438
+ }
439
+
440
+ uiLocator.highlightAccessibilityFrames( locations );
441
+ window.setTimeout( function(){
442
+ uiLocator.removeHighlights();
443
+ }, 1000 );
444
+ });
445
+ }
446
+
447
+ function sendFlashCommand( selector, engine ) {
448
+ sendMapRequest(selector,engine,'FEX_flash');
449
+ }
450
+
451
+ function sendTouchCommand( selector, engine ) {
452
+ sendMapRequest(selector,engine,'touch');
413
453
  }
414
454
 
415
- function updateAccessibleViews( views ) {
455
+ function updateAccessibleViews( views ) {
416
456
  var accessibleViews = filterAccessibleViews( views ),
417
457
  divTemplate = _.template( '<div><a href="#" title="<%=selector%>"><span class="viewClass"><%=viewClass%></span> with label "<span class="viewLabel"><%=viewLabel%></span>"</a></div>' );
418
458
 
@@ -424,7 +464,9 @@ $(document).ready(function() {
424
464
 
425
465
  $(divHtml)
426
466
  .click( function(){
467
+ $('#query').val( selector );
427
468
  sendFlashCommand( selector );
469
+ highlightViewLocations( selector );
428
470
  return false;
429
471
  })
430
472
  .appendTo( $domAccessibleDump );
@@ -432,6 +474,9 @@ $(document).ready(function() {
432
474
  }
433
475
 
434
476
  function guessAtDeviceFamilyBasedOnViewDump(data){
477
+ var firstChildViewFrame = data.subviews[0].accessibilityFrame;
478
+
479
+ console.log( JSON.stringify( firstChildViewFrame ) ) ;
435
480
  switch( data.accessibilityFrame.size.height ){
436
481
  case 1024:
437
482
  return 'ipad';
@@ -443,10 +488,30 @@ $(document).ready(function() {
443
488
  }
444
489
  }
445
490
 
491
+ function refreshOrientation(){
492
+ $.ajax({
493
+ type: 'GET',
494
+ dataType: 'json',
495
+ url: symbiote.baseUrlFor("/orientation"),
496
+ success: function(data) {
497
+ var orientation = data.orientation;
498
+
499
+ console.debug( 'device orientation is '+orientation );
500
+ uiLocator.updateOrientation(orientation);
501
+ },
502
+ error: function(xhr,status,error) {
503
+ alert( "Error while talking to Frank: " + status );
504
+ }
505
+ });
506
+ }
507
+
508
+
446
509
 
447
510
  function refreshViewHeirarchy(){
448
511
  showLoadingUI();
449
512
 
513
+ refreshOrientation();
514
+
450
515
  $.ajax({
451
516
  type: "POST",
452
517
  dataType: "json",
@@ -475,15 +540,22 @@ $(document).ready(function() {
475
540
  }
476
541
 
477
542
 
478
-
479
543
  $('#dump_button').click( function(){
480
544
  refreshViewHeirarchy();
481
545
  uiLocator.updateBackdrop();
482
546
  });
483
547
 
484
- $('#flash_button').click( function(){
548
+ $('button#flash').click( function(){
485
549
  sendFlashCommand( $("input#query").val(), $("input#selector_engine").val() );
486
550
  });
551
+
552
+ $('button#touch').click( function(){
553
+ sendTouchCommand( $("input#query").val(), $("input#selector_engine").val() );
554
+ });
555
+
556
+ $('button#highlight').click( function(){
557
+ highlightViewLocations( $("input#query").val(), $("input#selector_engine").val() );
558
+ });
487
559
 
488
560
  liveView = symbiote.LiveView( uiLocator.updateBackdrop, refreshViewHeirarchy );
489
561
 
@@ -491,17 +563,18 @@ $(document).ready(function() {
491
563
  $(this).toggleClass('down');
492
564
  if( $(this).hasClass('down') ){
493
565
  liveView.start();
494
- $(this).text('stop Live View');
495
566
  }else{
496
567
  liveView.stop();
497
- $(this).text('start Live View');
498
568
  }
499
569
  });
500
570
 
571
+ $('#ui-locator-rotator').click( function(){
572
+ $('#ui-locator-view, .the-columns').toggleClass('landscape');
573
+ });
501
574
 
502
575
  //initial UI setup
503
576
 
504
- $('#loading').hide();
577
+ // $('#loading').hide();
505
578
 
506
579
  // do initial DOM dump straight after page has finished loading
507
580
  $('#dump_button').click();
@@ -0,0 +1,39 @@
1
+ setupDropdowns = ->
2
+ $extraActionsList = $('.action-buttons .extra-actions')
3
+ $se_option_list = $('ul#selector_engine_options')
4
+ $se_option_input = $('input#selector_engine')
5
+
6
+ $('button#selector_engine_dropdown').on 'click', (e)->
7
+ e.stopPropagation()
8
+ $se_option_list.toggleClass('shown')
9
+
10
+ $('li', $se_option_list).on 'click', (e)->
11
+ $se_option_input.val( $(e.target).text() )
12
+
13
+ $('.action-buttons .drop-indicator').on 'click', (e)->
14
+ e.stopPropagation()
15
+ $extraActionsList.toggleClass('shown')
16
+
17
+ $('button',$extraActionsList).on 'click', ->
18
+ $selectedButton = $(this)
19
+ $currentTopButton = $('.action-buttons > button')
20
+
21
+ return if $selectedButton[0] == $currentTopButton[0]
22
+
23
+ # shove the button that was just selected into the 'top'
24
+ # action button area
25
+ $currentTopButton.after($selectedButton)
26
+ # push the current top button to the top of the 'extra'
27
+ # action button area. This will also remove it from the 'top' area
28
+ $extraActionsList.prepend($currentTopButton)
29
+
30
+
31
+ # remove button from top and but to top of extra buttons
32
+ # move tapped butotn
33
+
34
+ $('body').on 'click', ->
35
+ $extraActionsList.removeClass('shown')
36
+ $se_option_list.removeClass('shown')
37
+
38
+ $ ->
39
+ setupDropdowns()
@@ -30,7 +30,11 @@ module Frank
30
30
  directory( 'frank_static_resources.bundle', 'Frank/frank_static_resources.bundle', :force => true )
31
31
  end
32
32
 
33
+ XCODEBUILD_OPTIONS = %w{workspace scheme target}
33
34
  desc "build", "builds a Frankified version of your native app"
35
+ XCODEBUILD_OPTIONS.each do |option|
36
+ method_option option
37
+ end
34
38
  def build
35
39
 
36
40
  in_root do
@@ -49,7 +53,9 @@ module Frank
49
53
 
50
54
  remove_dir build_output_dir
51
55
 
52
- run "xcodebuild -xcconfig Frank/frankify.xcconfig install -configuration Debug -sdk iphonesimulator DSTROOT=#{build_output_dir} WRAPPER_NAME=#{app_bundle_name}"
56
+ extra_opts = XCODEBUILD_OPTIONS.map{ |o| "-#{o} #{options[o]}" if options[o] }.compact.join(' ')
57
+
58
+ run "xcodebuild -xcconfig Frank/frankify.xcconfig install #{extra_opts} -configuration Debug -sdk iphonesimulator DSTROOT=#{build_output_dir} PRODUCT_NAME=#{product_name}"
53
59
 
54
60
  in_root do
55
61
  FileUtils.cp_r(
@@ -114,8 +120,12 @@ module Frank
114
120
 
115
121
  private
116
122
 
123
+ def product_name
124
+ "Frankified"
125
+ end
126
+
117
127
  def app_bundle_name
118
- "Frankified.app"
128
+ "#{product_name}.app"
119
129
  end
120
130
 
121
131
  def build_output_dir
@@ -60,7 +60,7 @@ Then /I should not see the following:/ do |table|
60
60
  end
61
61
 
62
62
  Then /^I should see an alert view titled "([^\"]*)"$/ do |expected_mark|
63
- values = frankly_map( 'alertView', 'message')
63
+ values = frankly_map( 'alertView', 'title')
64
64
  values.should include(expected_mark)
65
65
  end
66
66
 
@@ -176,6 +176,7 @@ Then /^I rotate to the "([^\"]*)"$/ do |direction|
176
176
  end
177
177
 
178
178
  # -- touch -- #
179
+ # generic views
179
180
  When /^I touch "([^\"]*)"$/ do |mark|
180
181
  selector = "view marked:'#{mark}' first"
181
182
  if element_exists(selector)
@@ -195,6 +196,7 @@ When /^I touch "([^\"]*)" if exists$/ do |mark|
195
196
  end
196
197
  end
197
198
 
199
+ # table cells
198
200
  When /^I touch the first table cell$/ do
199
201
  touch("tableViewCell first")
200
202
  end
@@ -216,10 +218,12 @@ Then /I touch the following:/ do |table|
216
218
  end
217
219
  end
218
220
 
221
+ # buttons
219
222
  When /^I touch the button marked "([^\"]*)"$/ do |mark|
220
223
  touch( "button marked:'#{mark}'" )
221
224
  end
222
225
 
226
+ # action sheets
223
227
  When /^I touch the "([^\"]*)" action sheet button$/ do |mark|
224
228
  touch( "actionSheet threePartButton marked:'#{mark}'" )
225
229
  end
@@ -229,6 +233,11 @@ When /^I touch the (\d*)(?:st|nd|rd|th)? action sheet button$/ do |ordinal|
229
233
  touch( "actionSheet threePartButton tag:#{ordinal}" )
230
234
  end
231
235
 
236
+ # alert views
237
+ When /^I touch the "([^\"]*)" alert view button$/ do |mark|
238
+ touch( "alertView threePartButton marked:'#{mark}'" )
239
+ end
240
+
232
241
  When /^I touch the (\d*)(?:st|nd|rd|th)? alert view button$/ do |ordinal|
233
242
  ordinal = ordinal.to_i
234
243
  touch( "alertView threePartButton tag:#{ordinal}" )
@@ -268,6 +277,7 @@ end
268
277
 
269
278
  Then /^I navigate back$/ do
270
279
  touch( "navigationItemButtonView" )
280
+ wait_for_nothing_to_be_animating
271
281
  end
272
282
 
273
283
  When /^I dump the DOM$/ do