kraken-mobile 1.0.1 → 1.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.
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>