kraken-mobile 1.0.1 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +251 -77
  3. data/bin/kraken-mobile +64 -67
  4. data/bin/kraken_mobile_calabash_android.rb +39 -0
  5. data/bin/kraken_mobile_helpers.rb +107 -0
  6. data/bin/kraken_mobile_setup.rb +138 -0
  7. data/calabash-android-features-skeleton/step_definitions/mobile_steps.rb +1 -0
  8. data/calabash-android-features-skeleton/support/app_installation_hooks.rb +2 -0
  9. data/calabash-android-features-skeleton/support/app_life_cycle_hooks.rb +3 -4
  10. data/calabash-android-features-skeleton/support/env.rb +1 -1
  11. data/calabash-android-features-skeleton/web/step_definitions/web_steps.rb +3 -0
  12. data/calabash-android-features-skeleton/web/support/app_life_cycle_hooks.rb +15 -0
  13. data/lib/kraken-mobile/device_process.rb +130 -0
  14. data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
  15. data/lib/kraken-mobile/helpers/kraken_faker.rb +108 -0
  16. data/lib/kraken-mobile/helpers/reporter.rb +3 -0
  17. data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
  18. data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
  19. data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
  20. data/lib/kraken-mobile/mobile/adb.rb +66 -0
  21. data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
  22. data/lib/kraken-mobile/mobile/mobile_process.rb +101 -0
  23. data/lib/kraken-mobile/models/android_device.rb +121 -0
  24. data/lib/kraken-mobile/models/device.rb +113 -31
  25. data/lib/kraken-mobile/models/feature_file.rb +135 -0
  26. data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
  27. data/lib/kraken-mobile/models/web_device.rb +89 -0
  28. data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
  29. data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
  30. data/lib/kraken-mobile/monkeys/web/web_monkey.rb +63 -0
  31. data/lib/kraken-mobile/runners/calabash/android/monkey_helper.rb +2 -2
  32. data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +18 -2
  33. data/lib/kraken-mobile/runners/calabash/monkey/monkey_runner.rb +2 -2
  34. data/lib/kraken-mobile/steps/general_steps.rb +83 -0
  35. data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
  36. data/lib/kraken-mobile/steps/web/kraken_steps.rb +91 -0
  37. data/lib/kraken-mobile/test_scenario.rb +227 -0
  38. data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
  39. data/lib/kraken-mobile/utils/k.rb +68 -0
  40. data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
  41. data/lib/kraken-mobile/utils/reporter.rb +500 -0
  42. data/lib/kraken-mobile/version.rb +2 -2
  43. data/lib/kraken-mobile/web/web_process.rb +41 -0
  44. data/lib/kraken_mobile.rb +81 -0
  45. data/reporter/assets/css/scenario_index.css +20 -0
  46. data/reporter/assets/images/krakenThumbnail.jpg +0 -0
  47. data/reporter/assets/js/sankey.js +56 -24
  48. data/reporter/feature_report.html.erb +5 -1
  49. data/reporter/index.html.erb +15 -8
  50. data/reporter/scenario_report.html.erb +73 -31
  51. metadata +95 -14
  52. data/bin/kraken-mobile-calabash-android.rb +0 -85
  53. data/bin/kraken-mobile-generate.rb +0 -19
  54. data/bin/kraken-mobile-helpers.rb +0 -48
  55. data/bin/kraken-mobile-setup.rb +0 -50
  56. data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
  57. data/lib/kraken-mobile.rb +0 -29
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # encoding: utf-8
2
+
3
3
  module KrakenMobile
4
- VERSION = "1.0.1"
4
+ VERSION = '1.0.8'
5
5
  end
@@ -0,0 +1,41 @@
1
+ require 'kraken-mobile/device_process.rb'
2
+
3
+ class WebProcess < DeviceProcess
4
+ #-------------------------------
5
+ # Required methods
6
+ #-------------------------------
7
+ def before_execute
8
+ register_process_to_directory
9
+ device.create_inbox
10
+ end
11
+
12
+ def after_execute
13
+ unregister_process_from_directory
14
+ device.delete_inbox
15
+ end
16
+
17
+ def execute
18
+ open(execution_command, 'r') do |output|
19
+ loop do
20
+ $stdout.print output.readline.to_s
21
+ $stdout.flush
22
+ end
23
+ end
24
+ $CHILD_STATUS.exitstatus
25
+ rescue EOFError
26
+ nil
27
+ end
28
+
29
+ private
30
+
31
+ def execution_command
32
+ feature_path = test_scenario.feature_file.file_path
33
+ raise 'ERROR: Invalid feature file path' if feature_path.nil?
34
+
35
+ "|cucumber #{feature_path} --tags @user#{id} \
36
+ --require features/web/step_definitions/web_steps.rb \
37
+ --require features/web/support/app_life_cycle_hooks.rb \
38
+ --format pretty --format json -o \
39
+ #{K::REPORT_PATH}/#{@test_scenario.execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}"
40
+ end
41
+ end
@@ -0,0 +1,81 @@
1
+ require 'kraken-mobile/utils/feature_reader'
2
+ require 'kraken-mobile/test_scenario'
3
+
4
+ class KrakenApp
5
+ include Utils::FeatureReader
6
+
7
+ #-------------------------------
8
+ # Fields
9
+ #-------------------------------
10
+
11
+ attr_accessor :apk_path
12
+ attr_accessor :scenarios_queue
13
+
14
+ #-------------------------------
15
+ # Constructors
16
+ #-------------------------------
17
+ def initialize(apk_path:, properties_path: nil, config_path: nil)
18
+ @apk_path = apk_path
19
+ @scenarios_queue = []
20
+ save_path_in_environment_variable_with_name(
21
+ name: K::PROPERTIES_PATH, path: properties_path
22
+ )
23
+ save_path_in_environment_variable_with_name(
24
+ name: K::CONFIG_PATH, path: config_path
25
+ )
26
+
27
+ build_scenarios_queue
28
+ end
29
+
30
+ #-------------------------------
31
+ # Observers
32
+ #-------------------------------
33
+ def on_test_scenario_finished
34
+ execute_next_scenario
35
+ end
36
+
37
+ #-------------------------------
38
+ # Helpers
39
+ #-------------------------------
40
+
41
+ def start
42
+ execute_next_scenario
43
+ end
44
+
45
+ def save_path_in_environment_variable_with_name(name:, path:)
46
+ return if path.nil?
47
+
48
+ absolute_path = File.expand_path(path)
49
+ save_value_in_environment_variable_with_name(
50
+ name: name,
51
+ value: absolute_path
52
+ )
53
+ end
54
+
55
+ def save_value_in_environment_variable_with_name(name:, value:)
56
+ return if name.nil? || value.nil?
57
+
58
+ ENV[name] = value
59
+ end
60
+
61
+ private
62
+
63
+ def build_scenarios_queue
64
+ feature_files.each do |feature_path|
65
+ scenarios_queue.unshift(
66
+ TestScenario.new(
67
+ kraken_app: self,
68
+ feature_file_path: feature_path
69
+ )
70
+ )
71
+ end
72
+ end
73
+
74
+ def execute_next_scenario
75
+ return if scenarios_queue.count.zero?
76
+
77
+ scenario = scenarios_queue.pop
78
+ scenario.run
79
+ scenario
80
+ end
81
+ end
@@ -459,3 +459,23 @@ background-color: #E74C3C;
459
459
  padding: 50px 0;
460
460
  text-align: center;
461
461
  }
462
+
463
+ .step_title {
464
+ margin-bottom: 10px;
465
+ white-space:nowrap;
466
+ overflow-x: hidden;
467
+ text-overflow: ellipsis;
468
+ }
469
+
470
+ .step_title_icon {
471
+ margin-right: 5px;
472
+ }
473
+
474
+ .not_available {
475
+ text-align: center;
476
+ width: 100%;
477
+ }
478
+
479
+ .step_image {
480
+ cursor: pointer;
481
+ }
@@ -110,11 +110,21 @@
110
110
  return 10;
111
111
  })
112
112
  .style("fill", e)
113
+ .style("cursor", function(t) {
114
+ if(t.image) {
115
+ return "pointer";
116
+ } else {
117
+ return "default";
118
+ }
119
+ })
113
120
  .on("mouseover", function(t) {
114
121
  mouseover(t, i);
115
122
  }).on("mouseout", function(t) {
116
123
  mouseout(t, i);
117
124
  })
125
+ .on("click", function(t) {
126
+ click(t, i);
127
+ })
118
128
  },
119
129
  exit: function() {
120
130
  this.remove()
@@ -442,7 +452,7 @@ function mouseover(d, contexter) {
442
452
  computedHeight = boundingRect.height;
443
453
 
444
454
  let xPosition = d.x + margins.left + d.dx + 10;
445
- let yPosition = margins.top;
455
+ let yPosition = d.y + d.dy/2;
446
456
  let endXPosition = xPosition + computedWidth;
447
457
 
448
458
  if(endXPosition > width) {
@@ -457,38 +467,50 @@ function mouseover(d, contexter) {
457
467
  im.id = "scene" + d.id;
458
468
  im.src = "data:image/png;base64," + d.image
459
469
  im.onload = function(e) {
460
- var w = this.width;
461
- var h = this.height;
470
+ var h = 100;
462
471
  var ixPosition = d.x + margins.left + d.dx + 10; // 10 of separation from node
463
- var iyPosition = computedHeight + 10; // 10 of separation from label
464
- let endiXPosition = ixPosition + w;
465
- let endiYPosition = iyPosition + h;
466
-
467
- var i = 1
468
- while(w/i > 100 || h/i > 100) {
469
- i++;
470
- }
471
-
472
- h = h/i;
473
- w = w/i;
474
-
475
- endiXPosition = ixPosition + w;
476
- endiYPosition = iyPosition + h;
472
+ var iyPosition = d.y + d.dy/2 + 10; // 10 of separation from label
477
473
 
478
- if(endiXPosition > width) {
479
- ixPosition -= (endiXPosition-width)
480
- }
481
-
482
- contexter.base.append("image")
474
+ image = contexter.base.append("image")
483
475
  .data([this])
484
476
  .attr("x", ixPosition)
485
477
  .attr("y", iyPosition)
478
+ .attr("height", 100)
479
+ .attr("width", 50)
480
+ .style("width", "auto")
486
481
  .attr("xlink:href", this.src)
487
482
  .attr("transform", null)
488
483
  .attr("id", this.id)
489
484
  .attr("class", "scene-image")
490
- .attr("width", w)
491
- .attr("height", h)
485
+
486
+ imageBoundingRect = image.node().getBoundingClientRect();
487
+ computedImageWidth = imageBoundingRect.width;
488
+ computedImageHeight = imageBoundingRect.height;
489
+ let endImageXPosition = ixPosition + computedImageWidth;
490
+ let endImageYPosition = iyPosition + computedImageHeight;
491
+
492
+ if(endImageXPosition > width) {
493
+ ixPosition -= (endImageXPosition-width)
494
+ }
495
+
496
+ if(endImageYPosition > height + margins.bottom) {
497
+ iyPosition -= (endImageYPosition-(height+margins.bottom))
498
+ }
499
+
500
+ image.attr("x", ixPosition)
501
+ .attr("y", iyPosition);
502
+
503
+ text.attr("y", iyPosition - 10);
504
+
505
+ contexter.base.append('rect')
506
+ .attr('class', 'scene-image')
507
+ .attr('width', computedImageWidth)
508
+ .attr('height', computedImageHeight)
509
+ .attr('fill', 'transparent')
510
+ .attr('stroke', 'black')
511
+ .style('opacity', 0.25)
512
+ .attr("x", ixPosition)
513
+ .attr("y", iyPosition);
492
514
  }
493
515
  }
494
516
  }
@@ -497,6 +519,16 @@ function mouseout(d, svg) {
497
519
  d3.selectAll("[class=\"scene-image\"]").remove();
498
520
  }
499
521
 
522
+ function click(d, svg) {
523
+ if(d.image) {
524
+ var im = new Image();
525
+ im.src = "data:image/png;base64," + d.image
526
+ var w = window.open("",'_blank');
527
+ w.document.write(im.outerHTML);
528
+ w.document.close();
529
+ }
530
+ }
531
+
500
532
  function label(node) {
501
533
  return node.name.replace(/\s*\(.*?\)$/, '');
502
534
  }
@@ -175,7 +175,11 @@
175
175
  <%= device.model %> - <%= device.id %>
176
176
  </td>
177
177
  <td>
178
- <i class="fa fa-android fa-lg"><span>android</span></i>
178
+ <% if device.type == K::ANDROID_DEVICE %>
179
+ <i class="fa fa-android fa-lg"><span>android</span></i>
180
+ <% else %>
181
+ <i class="fa fa-globe fa-lg"><span>web</span></i>
182
+ <% end %>
179
183
  </td>
180
184
  <td>
181
185
  <%= @apk_path %>
@@ -595,18 +595,24 @@
595
595
  <div class="clearfix"></div>
596
596
  </div>
597
597
  <div class="row">
598
- <% @devices.each do |device| %>
598
+ <% devices_json.each do |device| %>
599
599
  <div class="ui-card col-md-3">
600
600
  <div class="container device-container">
601
601
  <div class="row device-os-icon">
602
- <i class="fa fa-android fa-lg"></i>
602
+ <% if device[:type] == K::ANDROID_DEVICE %>
603
+ <i class="fa fa-android fa-lg"></i>
604
+ <% else %>
605
+ <i class="fa fa-globe fa-lg"></i>
606
+ <% end %>
603
607
  </div>
604
- <div class="row device-title"><%= device['model'] %></div>
605
- <div class="row device-info">ID - <%= device['id'] %></div>
606
- <div class="row device-info">SDK Version - <%= device['sdk'] %></div>
607
- <div class="row device-info">Screen Size - <%= "#{device['screen_height']}x#{device['screen_width']}" %></div>
608
+ <div class="row device-title"><%= device[:model] %></div>
609
+ <div class="row device-info">ID - <%= device[:id] %></div>
610
+ <% if device[:type] == K::ANDROID_DEVICE %>
611
+ <div class="row device-info">SDK Version - <%= device[:sdk] %></div>
612
+ <div class="row device-info">Screen Size - <%= "#{device[:screen_height]}x#{device[:screen_width]}" %></div>
613
+ <% end %>
608
614
  <div class="row device-info result-btn">
609
- <a href='<%= "./#{device['id']}/feature_report.html" %>'>See Results</a>
615
+ <a href='<%= "./#{device[:id]}/feature_report.html" %>'>See Results</a>
610
616
  </div>
611
617
  </div>
612
618
  </div>
@@ -643,7 +649,8 @@
643
649
  }
644
650
  devices = Array.from(devicesSet);
645
651
  // GRAPH
646
- var height = 150*(devices.length-1);
652
+ let devicesLength = devices.length > 1 ? (devices.length-1) : 1;
653
+ var height = 150*devicesLength;
647
654
  var c20c = d3.scale.category10();
648
655
  d3.select("#chart_row" + (i+1))
649
656
  .text(jsonObject["name"])
@@ -125,9 +125,42 @@
125
125
  </div>
126
126
  </div>
127
127
  </div>
128
- </div>
128
+ </div> <!-- Closes scenario row -->
129
+
130
+ <div class="row">
131
+ <div class="col-md-12 col-sm-12 col-xs-12">
132
+ <div class="x_panel" style="height: auto;">
133
+ <div class="x_title">
134
+ <h2>Screenshots</h2>
135
+ <div class="clearfix"></div>
136
+ </div>
137
+ <div class="x_content">
138
+ <div class="container">
139
+ <div class="row">
140
+ <% f["steps"].each do |s| %>
141
+ <div class="col-md-2">
142
+ <div class="step_title">
143
+ <i class="fa fa-arrow-right step_title_icon"></i>
144
+ <%= s["keyword"] %> <%= s["name"] %>
145
+ </div>
146
+ <% if(s["after"] && s["after"].count > 0 && s["after"].first["embeddings"] && s["after"].first["embeddings"].count > 0) %>
147
+ <% step_image = s["after"].first["embeddings"].first["data"] %>
148
+ <img src='<%= "data:image/png;base64,#{step_image}" %>' alt="" class="img-responsive step_image" onclick='<%= "openImageNewTab(\"#{step_image}\")" %>'>
149
+ <% else %>
150
+ <div class="not_available">
151
+ NO IMAGE AVAILABLE
152
+ </div>
153
+ <% end %>
154
+ </div>
155
+ <% end %>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ </div> <!-- Closes screenshots row -->
162
+ <% end %>
129
163
  </div>
130
- <% end %>
131
164
 
132
165
  <script src="../../assets/js/jquery-3.2.1.min.js" ></script>
133
166
  <script src="../../assets/js/bootstrap.min.js"></script>
@@ -136,39 +169,48 @@
136
169
  <script src="../../assets/js/dataTables.responsive.min.js"></script>
137
170
  <script src="../../assets/js/Chart.min.js"></script>
138
171
  <script>
139
- $(document).ready(function () {
140
- passed_scenarios = parseInt("<%= passed_scenarios(@feature).count %>")
141
- failed_scenarios = parseInt("<%= failed_scenarios(@feature).count %>")
172
+ function openImageNewTab(imageData) {
173
+ var im = new Image();
174
+ im.src = "data:image/png;base64," + imageData
175
+ var w = window.open("",'_blank');
176
+ w.document.write(im.outerHTML);
177
+ w.document.close();
178
+ }
142
179
 
143
- scenarios_data = [passed_scenarios,failed_scenarios];
144
- var scenarioOptions = {
145
- legend: false,
146
- responsive: false
147
- };
180
+ $(document).ready(function () {
148
181
 
149
- new Chart(document.getElementById("scenario-chart"), {
150
- type: 'doughnut',
151
- tooltipFillColor: "rgba(51, 51, 51, 0.55)",
152
- data: {
153
- labels: [
154
- "Passed",
155
- "Failed"
156
- ],
157
- datasets: [{
158
- data: scenarios_data,
159
- backgroundColor: [
160
- "#26B99A",
161
- "#E74C3C"
162
- ]
163
- }]
164
- },
165
- options: scenarioOptions
166
- });
182
+ passed_scenarios = parseInt("<%= passed_scenarios(@feature).count %>")
183
+ failed_scenarios = parseInt("<%= failed_scenarios(@feature).count %>")
184
+
185
+ scenarios_data = [passed_scenarios,failed_scenarios];
186
+ var scenarioOptions = {
187
+ legend: false,
188
+ responsive: false
189
+ };
190
+
191
+ new Chart(document.getElementById("scenario-chart"), {
192
+ type: 'doughnut',
193
+ tooltipFillColor: "rgba(51, 51, 51, 0.55)",
194
+ data: {
195
+ labels: [
196
+ "Passed",
197
+ "Failed"
198
+ ],
199
+ datasets: [{
200
+ data: scenarios_data,
201
+ backgroundColor: [
202
+ "#26B99A",
203
+ "#E74C3C"
204
+ ]
205
+ }]
206
+ },
207
+ options: scenarioOptions
208
+ });
167
209
 
168
- $('body').tooltip({
169
- selector: '[data-toggle="tooltip"]'
210
+ $('body').tooltip({
211
+ selector: '[data-toggle="tooltip"]'
212
+ });
170
213
  });
171
- });
172
214
  </script>
173
215
  </body>
174
216
  </html>