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.
- checksums.yaml +5 -5
- data/README.md +251 -77
- data/bin/kraken-mobile +64 -67
- data/bin/kraken_mobile_calabash_android.rb +39 -0
- data/bin/kraken_mobile_helpers.rb +107 -0
- data/bin/kraken_mobile_setup.rb +138 -0
- data/calabash-android-features-skeleton/step_definitions/mobile_steps.rb +1 -0
- data/calabash-android-features-skeleton/support/app_installation_hooks.rb +2 -0
- data/calabash-android-features-skeleton/support/app_life_cycle_hooks.rb +3 -4
- data/calabash-android-features-skeleton/support/env.rb +1 -1
- data/calabash-android-features-skeleton/web/step_definitions/web_steps.rb +3 -0
- data/calabash-android-features-skeleton/web/support/app_life_cycle_hooks.rb +15 -0
- data/lib/kraken-mobile/device_process.rb +130 -0
- data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
- data/lib/kraken-mobile/helpers/kraken_faker.rb +108 -0
- data/lib/kraken-mobile/helpers/reporter.rb +3 -0
- data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
- data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
- data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
- data/lib/kraken-mobile/mobile/adb.rb +66 -0
- data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
- data/lib/kraken-mobile/mobile/mobile_process.rb +101 -0
- data/lib/kraken-mobile/models/android_device.rb +121 -0
- data/lib/kraken-mobile/models/device.rb +113 -31
- data/lib/kraken-mobile/models/feature_file.rb +135 -0
- data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
- data/lib/kraken-mobile/models/web_device.rb +89 -0
- data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
- data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
- data/lib/kraken-mobile/monkeys/web/web_monkey.rb +63 -0
- data/lib/kraken-mobile/runners/calabash/android/monkey_helper.rb +2 -2
- data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +18 -2
- data/lib/kraken-mobile/runners/calabash/monkey/monkey_runner.rb +2 -2
- data/lib/kraken-mobile/steps/general_steps.rb +83 -0
- data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
- data/lib/kraken-mobile/steps/web/kraken_steps.rb +91 -0
- data/lib/kraken-mobile/test_scenario.rb +227 -0
- data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
- data/lib/kraken-mobile/utils/k.rb +68 -0
- data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
- data/lib/kraken-mobile/utils/reporter.rb +500 -0
- data/lib/kraken-mobile/version.rb +2 -2
- data/lib/kraken-mobile/web/web_process.rb +41 -0
- data/lib/kraken_mobile.rb +81 -0
- data/reporter/assets/css/scenario_index.css +20 -0
- data/reporter/assets/images/krakenThumbnail.jpg +0 -0
- data/reporter/assets/js/sankey.js +56 -24
- data/reporter/feature_report.html.erb +5 -1
- data/reporter/index.html.erb +15 -8
- data/reporter/scenario_report.html.erb +73 -31
- metadata +95 -14
- data/bin/kraken-mobile-calabash-android.rb +0 -85
- data/bin/kraken-mobile-generate.rb +0 -19
- data/bin/kraken-mobile-helpers.rb +0 -48
- data/bin/kraken-mobile-setup.rb +0 -50
- data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
- data/lib/kraken-mobile.rb +0 -29
@@ -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
|
+
}
|
Binary file
|
@@ -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 =
|
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
|
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 =
|
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
|
-
|
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
|
-
|
491
|
-
.
|
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
|
-
|
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 %>
|
data/reporter/index.html.erb
CHANGED
@@ -595,18 +595,24 @@
|
|
595
595
|
<div class="clearfix"></div>
|
596
596
|
</div>
|
597
597
|
<div class="row">
|
598
|
-
<%
|
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
|
-
|
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[
|
605
|
-
<div class="row device-info">ID - <%= device[
|
606
|
-
|
607
|
-
|
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[
|
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
|
-
|
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
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
144
|
-
var scenarioOptions = {
|
145
|
-
legend: false,
|
146
|
-
responsive: false
|
147
|
-
};
|
180
|
+
$(document).ready(function () {
|
148
181
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
169
|
-
|
210
|
+
$('body').tooltip({
|
211
|
+
selector: '[data-toggle="tooltip"]'
|
212
|
+
});
|
170
213
|
});
|
171
|
-
});
|
172
214
|
</script>
|
173
215
|
</body>
|
174
216
|
</html>
|