nxgreport 0.6.0 → 0.11.0
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 +4 -4
- data/lib/nxgcore.rb +217 -0
- data/lib/nxgcss.rb +323 -0
- data/lib/nxghtml.rb +196 -0
- data/lib/nxgjs.rb +233 -0
- data/lib/nxgreport.rb +3 -363
- metadata +9 -8
data/lib/nxghtml.rb
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'nxgcss.rb'
|
2
|
+
require 'nxgjs.rb'
|
3
|
+
|
4
|
+
module NxgHTML
|
5
|
+
|
6
|
+
include NxgCss
|
7
|
+
include NxgJavascript
|
8
|
+
|
9
|
+
def html(data_provider)
|
10
|
+
@data_provider = data_provider
|
11
|
+
"<html lang=\"en\">
|
12
|
+
#{head()}
|
13
|
+
#{body()}
|
14
|
+
#{js(@data_provider)}
|
15
|
+
</html>"
|
16
|
+
end
|
17
|
+
|
18
|
+
def head()
|
19
|
+
"<head>
|
20
|
+
<meta charset=\"UTF-8\" />
|
21
|
+
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
|
22
|
+
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js\"></script>
|
23
|
+
<script> #{js_detect_system_dark_mode()}</script>
|
24
|
+
<title>Home | #{@data_provider[:title]}</title>
|
25
|
+
#{google_fonts_link()}
|
26
|
+
#{icons_link()}
|
27
|
+
#{css(@data_provider)}
|
28
|
+
</head>"
|
29
|
+
end
|
30
|
+
|
31
|
+
def google_fonts_link()
|
32
|
+
"<link
|
33
|
+
href=\"https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap\"
|
34
|
+
rel=\"stylesheet\"
|
35
|
+
/>"
|
36
|
+
end
|
37
|
+
|
38
|
+
def icons_link()
|
39
|
+
"<link
|
40
|
+
href=\"https://fonts.googleapis.com/icon?family=Material+Icons\"
|
41
|
+
rel=\"stylesheet\"
|
42
|
+
/>"
|
43
|
+
end
|
44
|
+
|
45
|
+
def body()
|
46
|
+
"<body id=\"app\" onload=\"onRefresh()\">
|
47
|
+
<div id=\"sidebar\" onclick=\"closeDetails(event)\">
|
48
|
+
<div id=\"sidebar-div\">
|
49
|
+
<div id=\"sidebar-title-wrap\">
|
50
|
+
<h1 id=\"sidebar-title\">Title</h1>
|
51
|
+
<i class=\"material-icons\" id=\"sidebar-status\">check_circle</i>
|
52
|
+
</div>
|
53
|
+
<div id=\"sidebar-catergories\">
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
<div id=\"sidebar-overlay\" onclick=\"closeDetails(event)\">
|
58
|
+
<div id=\"sidebar-overlay-grid\"></div>
|
59
|
+
</div>
|
60
|
+
<div id=\"body-wrap\">
|
61
|
+
#{header()}
|
62
|
+
#{config()}
|
63
|
+
#{features()}
|
64
|
+
#{footer()}
|
65
|
+
</div>
|
66
|
+
</body>"
|
67
|
+
end
|
68
|
+
|
69
|
+
def header()
|
70
|
+
"<div id=\"header\">
|
71
|
+
<h1 id=\"app-title\">#{@data_provider[:title]}</h1>
|
72
|
+
<div id=\"theme-wrap\">
|
73
|
+
<button id=\"theme-switch\" onclick=\"switchTheme()\">
|
74
|
+
<i class=\"material-icons\" id=\"theme-icon\">wb_sunny</i>
|
75
|
+
</button>
|
76
|
+
</div>
|
77
|
+
</div>"
|
78
|
+
end
|
79
|
+
|
80
|
+
def features()
|
81
|
+
"<div class=\"features-grid\"></div>"
|
82
|
+
end
|
83
|
+
|
84
|
+
def footer()
|
85
|
+
"<div id=\"footer\">
|
86
|
+
<p>
|
87
|
+
Developed by
|
88
|
+
<span>
|
89
|
+
<a
|
90
|
+
href=\"https://www.linkedin.com/in/balabharathijayaraman\"
|
91
|
+
rel=\"noopener\"
|
92
|
+
target=\"_blank\"
|
93
|
+
>Balabharathi Jayaraman</a
|
94
|
+
>
|
95
|
+
</span>
|
96
|
+
</p>
|
97
|
+
</div>"
|
98
|
+
end
|
99
|
+
|
100
|
+
def config()
|
101
|
+
return if @data_provider.length == 0
|
102
|
+
|
103
|
+
return "<div class=\"params-container\">
|
104
|
+
#{release_name()}
|
105
|
+
#{execution_date()}
|
106
|
+
#{device()}
|
107
|
+
#{os()}
|
108
|
+
#{app_version()}
|
109
|
+
#{environment()}
|
110
|
+
#{passed_tests()}
|
111
|
+
#{failed_tests()}
|
112
|
+
#{percentage_pass()}
|
113
|
+
#{execution_time()}
|
114
|
+
#{filter()}
|
115
|
+
</div>"
|
116
|
+
end
|
117
|
+
|
118
|
+
def execution_time()
|
119
|
+
return if !@data_provider.key?(:environment)
|
120
|
+
|
121
|
+
return config_item("Total execution time", @data_provider[:execution_time],'access_time')
|
122
|
+
end
|
123
|
+
|
124
|
+
def filter()
|
125
|
+
"<div class=\"param-wrap\" onclick=\"setFilter()\" id=\"filter\" title=\"Filter tests\">
|
126
|
+
<i class=\"pi material-icons\">filter_list</i>
|
127
|
+
<h5 id=\"pt\">Failed</h5>
|
128
|
+
</div>"
|
129
|
+
end
|
130
|
+
|
131
|
+
def passed_tests()
|
132
|
+
"<div class=\"param-wrap\" title=\"Passed tests\">
|
133
|
+
<i class=\"pi green-font material-icons\">check_circle</i>
|
134
|
+
<h5 id=\"pt\">#{@data_provider[:pass] == 0 ? "None" : @data_provider[:pass]}</h5>
|
135
|
+
</div>"
|
136
|
+
end
|
137
|
+
|
138
|
+
def failed_tests()
|
139
|
+
"<div class=\"param-wrap\" title=\"Failed tests\" #{@data_provider[:fail] > 0 ? "onclick=\"filterAllFailed()\" style=\"cursor: pointer\"" : ""}>
|
140
|
+
<i class=\"pi red-font material-icons\">cancel</i>
|
141
|
+
<h5 id=\"pt\">#{@data_provider[:fail] == 0 ? "None" : @data_provider[:fail]}</h5>
|
142
|
+
</div>"
|
143
|
+
end
|
144
|
+
|
145
|
+
def percentage_pass()
|
146
|
+
pass_percentage = ((@data_provider[:pass]/@data_provider[:total].to_f) * 100).round(2)
|
147
|
+
|
148
|
+
return "<div class=\"param-wrap\" title=\"Pass percentage\">
|
149
|
+
<i class=\"pi #{pass_percentage.to_i == 100 ? "green-font" : ""} material-icons\">equalizer</i>
|
150
|
+
<h5 id=\"pt\">#{pass_percentage.to_i == 100 ? pass_percentage.to_i : pass_percentage}%</h5>
|
151
|
+
</div>"
|
152
|
+
end
|
153
|
+
|
154
|
+
def environment()
|
155
|
+
return if !@data_provider.key?(:environment)
|
156
|
+
|
157
|
+
return config_item("Test environment", @data_provider[:environment], "layers")
|
158
|
+
end
|
159
|
+
|
160
|
+
def app_version()
|
161
|
+
return if !@data_provider.key?(:app_version)
|
162
|
+
|
163
|
+
return config_item("App version tested", @data_provider[:app_version], "info")
|
164
|
+
end
|
165
|
+
|
166
|
+
def release_name()
|
167
|
+
return if !@data_provider.key?(:release_name)
|
168
|
+
|
169
|
+
return config_item("Release", @data_provider[:release_name], "bookmark")
|
170
|
+
end
|
171
|
+
|
172
|
+
def os()
|
173
|
+
return if !@data_provider.key?(:os)
|
174
|
+
|
175
|
+
return config_item("Os tested", @data_provider[:os], "settings")
|
176
|
+
end
|
177
|
+
|
178
|
+
def device()
|
179
|
+
return if !@data_provider.key?(:device)
|
180
|
+
|
181
|
+
return config_item("Device tested", @data_provider[:device], "devices")
|
182
|
+
end
|
183
|
+
|
184
|
+
def execution_date()
|
185
|
+
@data_provider[:execution_date] = Time.now().strftime("%b %d, %Y") if !@data_provider.key?(:execution_date)
|
186
|
+
|
187
|
+
return config_item("Execution date", @data_provider[:execution_date], "event")
|
188
|
+
end
|
189
|
+
|
190
|
+
def config_item(toot_tip, name, icon)
|
191
|
+
"<div class=\"param-wrap\" title=\"#{toot_tip}\">
|
192
|
+
<i class=\"pi material-icons\">#{icon}</i>
|
193
|
+
<h5 id=\"pt\">#{name}</h5>
|
194
|
+
</div>"
|
195
|
+
end
|
196
|
+
end
|
data/lib/nxgjs.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
|
2
|
+
module NxgJavascript
|
3
|
+
|
4
|
+
def js_detect_system_dark_mode()
|
5
|
+
"if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
6
|
+
$(document.documentElement).attr(\"theme\", \"dark\");
|
7
|
+
}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def js(data_provider)
|
11
|
+
|
12
|
+
js_array = data_provider[:features].to_s.gsub("=>", ":")
|
13
|
+
|
14
|
+
return "<script>
|
15
|
+
const allFeatures = #{js_array};
|
16
|
+
const STATUS = { pass: \"check_circle\", fail: \"cancel\", };
|
17
|
+
var displayFailuresOnly = false;
|
18
|
+
var dataSource = [];
|
19
|
+
var catergories = [];
|
20
|
+
|
21
|
+
function onRefresh() {
|
22
|
+
dataSource = allFeatures;
|
23
|
+
setFilter();
|
24
|
+
currentTheme = $(document.documentElement).attr(\"theme\");
|
25
|
+
$(\"#theme-icon\").text(currentTheme === \"dark\" ? \"brightness_2\" : \"wb_sunny\");
|
26
|
+
}
|
27
|
+
|
28
|
+
function updateView() {
|
29
|
+
$(\".banner\").removeClass(\"banner\").addClass(\"features-grid\");
|
30
|
+
$(\".features-grid\").empty();
|
31
|
+
|
32
|
+
if (dataSource.length === 0) {
|
33
|
+
console.log(\"inside\");
|
34
|
+
$(\".features-grid\")
|
35
|
+
.removeClass(\"features-grid\")
|
36
|
+
.addClass(\"banner\")
|
37
|
+
.append(
|
38
|
+
`<i class=\"banner-text green-font material-icons\">done_all</i><h1>No Failures</>`
|
39
|
+
);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
|
43
|
+
dataSource.forEach((feature, index) => {
|
44
|
+
$(\".features-grid\").append(
|
45
|
+
`<div class=\"module dark ${
|
46
|
+
feature.fail > 0 ? \"red-bg\" : \"\"
|
47
|
+
}\" onclick=\"showDetails(${index})\"><div class=\"funcname\"><h4>${
|
48
|
+
feature.name
|
49
|
+
}</h4></div><div class=\"total\"><h6>Total</h6><h4>${
|
50
|
+
feature.total
|
51
|
+
}</h4></div><div class=\"pass green-font\"><h6>Passed</h6><h4>${
|
52
|
+
feature.pass
|
53
|
+
}</h4></div><div class=\"fail red-font\"><h6>Failed</h6><h4>${
|
54
|
+
feature.fail
|
55
|
+
}</h4></div></div>`
|
56
|
+
);
|
57
|
+
});
|
58
|
+
}
|
59
|
+
|
60
|
+
function setFilter() {
|
61
|
+
if (displayFailuresOnly) {
|
62
|
+
$(\"#filter h5\").text(\"Failed\");
|
63
|
+
dataSource = allFeatures.filter((feature) => {
|
64
|
+
return feature.fail > 0;
|
65
|
+
});
|
66
|
+
} else {
|
67
|
+
$(\"#filter h5\").text(\"All\");
|
68
|
+
dataSource = allFeatures;
|
69
|
+
}
|
70
|
+
updateView();
|
71
|
+
displayFailuresOnly = !displayFailuresOnly;
|
72
|
+
}
|
73
|
+
|
74
|
+
function filterAllFailed() {
|
75
|
+
allFailedTests = [];
|
76
|
+
catergories = [];
|
77
|
+
|
78
|
+
failedFeatures = allFeatures.filter((feature) => {
|
79
|
+
return feature.fail > 0;
|
80
|
+
});
|
81
|
+
|
82
|
+
for (index = 0; index < failedFeatures.length; index++) {
|
83
|
+
failedFeatures[index].tests.filter((test) => {
|
84
|
+
if (!test.testPass) {
|
85
|
+
allFailedTests.push(test);
|
86
|
+
}
|
87
|
+
});
|
88
|
+
}
|
89
|
+
|
90
|
+
$(\"#body-wrap\").css(\"overflow\", \"hidden\");
|
91
|
+
$(\"#sidebar-overlay\").css(\"overflow\", \"auto\");
|
92
|
+
$(\"#sidebar-overlay\").css(\"visibility\", \"visible\");
|
93
|
+
$(\"#sidebar-overlay\").css(\"margin-left\", \"40%\");
|
94
|
+
$(\"#sidebar\").css(\"width\", \"40%\");
|
95
|
+
$(\"#sidebar-title\").css(\"visibility\", \"visible\");
|
96
|
+
$(\"#sidebar-status\").css(\"visibility\", \"visible\");
|
97
|
+
$(\"#sidebar-title\").css(\"opacity\", \"1\");
|
98
|
+
$(\"#sidebar-status\").css(\"opacity\", \"1\");
|
99
|
+
$(\"#sidebar-catergories\").css(\"visibility\", \"visible\");
|
100
|
+
$(\"#sidebar-catergories\").css(\"opacity\", \"1\");
|
101
|
+
/* Update Test Information */
|
102
|
+
|
103
|
+
$(\"#sidebar-title\").text(\"Failed Tests\");
|
104
|
+
$(\"#sidebar-status\").text(STATUS.fail);
|
105
|
+
$(\"#sidebar-overlay-grid\").empty();
|
106
|
+
allFailedTests.forEach((test) => {
|
107
|
+
$(\"#sidebar-overlay-grid\").append(
|
108
|
+
`<div id=\"sidebar-overlay-test-info\" onclick=\"()=>{}\"><i class=\"${
|
109
|
+
test.testPass ? \"green-font\" : \"red-font\"
|
110
|
+
} material-icons\" style=\"font-size: 1em\">${
|
111
|
+
STATUS.fail
|
112
|
+
}</i> <h4 id=\"test-title\">${test.name}</h4><div><h4 id=\"test-execution-time\">${test.time} secs</h4></div>${
|
113
|
+
test.comments !== \"\"
|
114
|
+
? `<p id=\"error-message\">${test.comments}</p>`
|
115
|
+
: \"\"
|
116
|
+
}</div>`
|
117
|
+
);
|
118
|
+
categorize(test);
|
119
|
+
});
|
120
|
+
displayCategories();
|
121
|
+
}
|
122
|
+
|
123
|
+
function displayCategories() {
|
124
|
+
$(\"#sidebar-catergories\").empty();
|
125
|
+
if(catergories.length === 1) { return; }
|
126
|
+
catergories.forEach((cat) => {$(\"#sidebar-catergories\").append(`<div><h6>#${cat.name}</h6></div>`);});
|
127
|
+
}
|
128
|
+
|
129
|
+
function switchTheme() {
|
130
|
+
currentTheme = $(document.documentElement).attr(\"theme\");
|
131
|
+
$(document.documentElement).attr(\"theme\", currentTheme === \"dark\" ? \"light\" : \"dark\");
|
132
|
+
$(\"#theme-icon\").text(currentTheme === \"dark\" ? \"wb_sunny\" : \"brightness_2\");
|
133
|
+
}
|
134
|
+
|
135
|
+
function closeDetails(e) {
|
136
|
+
if (e.target.id === \"sidebar\" || e.target.id === \"sidebar-overlay\") {
|
137
|
+
$(\"#sidebar-catergories\").css(\"visibility\", \"hidden\");
|
138
|
+
$(\"#sidebar-catergories\").css(\"opacity\", \"0\");
|
139
|
+
$(\"#sidebar-title\").css(\"visibility\", \"hidden\");
|
140
|
+
$(\"#sidebar-status\").css(\"visibility\", \"hidden\");
|
141
|
+
$(\"#sidebar-title\").css(\"opacity\", \"0\");
|
142
|
+
$(\"#sidebar-status\").css(\"opacity\", \"0\");
|
143
|
+
$(\"#sidebar-overlay\").css(\"margin-left\", \"0\");
|
144
|
+
$(\"#sidebar-overlay\").css(\"visibility\", \"hidden\");
|
145
|
+
$(\"#sidebar\").css(\"width\", \"0\");
|
146
|
+
$(\"#body-wrap\").css(\"overflow\", \"auto\");
|
147
|
+
$(\"#sidebar-overlay\").css(\"overflow\", \"hidden\");
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
window
|
152
|
+
.matchMedia(\"(prefers-color-scheme: dark)\")
|
153
|
+
.addEventListener(\"change\", (e) => {
|
154
|
+
darkTheme = e.matches;
|
155
|
+
$(document.documentElement).attr(\"theme\", darkTheme ? \"dark\" : \"light\");
|
156
|
+
$(\"#theme-icon\").text(darkTheme ? \"brightness_2\" : \"wb_sunny\");
|
157
|
+
});
|
158
|
+
|
159
|
+
function showDetails(featureID) {
|
160
|
+
feature = dataSource[featureID];
|
161
|
+
catergories = [];
|
162
|
+
|
163
|
+
$(\"#body-wrap\").css(\"overflow\", \"hidden\");
|
164
|
+
$(\"#sidebar-overlay\").css(\"overflow\", \"auto\");
|
165
|
+
$(\"#sidebar-overlay\").css(\"visibility\", \"visible\");
|
166
|
+
$(\"#sidebar-overlay\").css(\"margin-left\", \"40%\");
|
167
|
+
$(\"#sidebar\").css(\"width\", \"40%\");
|
168
|
+
$(\"#sidebar-title\").css(\"visibility\", \"visible\");
|
169
|
+
$(\"#sidebar-status\").css(\"visibility\", \"visible\");
|
170
|
+
$(\"#sidebar-title\").css(\"opacity\", \"1\");
|
171
|
+
$(\"#sidebar-status\").css(\"opacity\", \"1\");
|
172
|
+
$(\"#sidebar-catergories\").css(\"visibility\", \"visible\");
|
173
|
+
$(\"#sidebar-catergories\").css(\"opacity\", \"1\");
|
174
|
+
/* Update Test Information */
|
175
|
+
|
176
|
+
$(\"#sidebar-title\").text(feature.name);
|
177
|
+
$(\"#sidebar-overlay-grid\").empty();
|
178
|
+
feature.tests.forEach((test) => {
|
179
|
+
$(\"#sidebar-overlay-grid\").append(
|
180
|
+
`<div id=\"sidebar-overlay-test-info\" onclick=\"()=>{}\"><i class=\"${
|
181
|
+
test.testPass ? \"green-font\" : \"red-font\"
|
182
|
+
} material-icons\" style=\"font-size: 1em\">${
|
183
|
+
test.testPass ? STATUS.pass : STATUS.fail
|
184
|
+
}</i> <h4 id=\"test-title\">${test.name}</h4><div><h4 id=\"test-execution-time\">${test.time} secs</h4></div>${
|
185
|
+
test.comments !== \"\"
|
186
|
+
? `<p id=\"error-message\">${test.comments}</p>`
|
187
|
+
: \"\"
|
188
|
+
}</div>`
|
189
|
+
);
|
190
|
+
categorize(test);
|
191
|
+
});
|
192
|
+
displayCategories();
|
193
|
+
|
194
|
+
for (index = 0; index < feature.tests.length; index++) {
|
195
|
+
if (!feature.tests[index].testPass) {
|
196
|
+
$(\"#sidebar-status\").text(STATUS.fail);
|
197
|
+
return;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
$(\"#sidebar-status\").text(STATUS.pass);
|
201
|
+
}
|
202
|
+
|
203
|
+
function categorize(test) {
|
204
|
+
if (test.tag === \"\") {
|
205
|
+
return;
|
206
|
+
}
|
207
|
+
if (!catergoryAdded(test.tag)) {
|
208
|
+
catergories.push({ name: test.tag.toLowerCase(), tests: [test] });
|
209
|
+
} else {
|
210
|
+
catergories[catergoryIndex(test.tag)].tests.push(test);
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
function catergoryAdded(category) {
|
215
|
+
for (var i = 0; i < catergories.length; i++) {
|
216
|
+
if (catergories[i].name === category.toLowerCase()) {
|
217
|
+
return true;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
return false;
|
221
|
+
}
|
222
|
+
|
223
|
+
function catergoryIndex(category) {
|
224
|
+
for (var i = 0; i < catergories.length; i++) {
|
225
|
+
if (catergories[i].name === category.toLowerCase()) {
|
226
|
+
return i;
|
227
|
+
}
|
228
|
+
}
|
229
|
+
return 0;
|
230
|
+
}
|
231
|
+
</script>"
|
232
|
+
end
|
233
|
+
end
|
data/lib/nxgreport.rb
CHANGED
@@ -1,365 +1,5 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
require 'fileutils'
|
3
|
+
require 'nxgcore.rb'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
def setup(location: "./NxgReport.html", title: "Features Summary")
|
7
|
-
@nxg_report_path = location
|
8
|
-
@title = title
|
9
|
-
@auto_open = false
|
10
|
-
@features = Hash.new()
|
11
|
-
end
|
12
|
-
|
13
|
-
def open_upon_execution(value:true)
|
14
|
-
@auto_open = value
|
15
|
-
end
|
16
|
-
|
17
|
-
def log_test(feature_name, test_status)
|
18
|
-
test_pass = test_status.downcase.include?('pass')
|
19
|
-
if @features.key? feature_name
|
20
|
-
@features[feature_name][0]+=1
|
21
|
-
@features[feature_name][(test_pass) ? 1 : 2]+=1
|
22
|
-
else
|
23
|
-
@features[feature_name]=[0,0,0]
|
24
|
-
@features[feature_name][0]+=1
|
25
|
-
@features[feature_name][(test_pass) ? 1 : 2]+=1
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def build()
|
30
|
-
write()
|
31
|
-
if @auto_open && report_success()
|
32
|
-
system("open #{@nxg_report_path}")
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Private methods
|
37
|
-
def log(message)
|
38
|
-
puts("🤖- #{message}")
|
39
|
-
end
|
40
|
-
|
41
|
-
def report_success()
|
42
|
-
return File.file?(@nxg_report_path)
|
43
|
-
end
|
44
|
-
|
45
|
-
def clean()
|
46
|
-
File.delete(@nxg_report_path) if File.file?(@nxg_report_path)
|
47
|
-
end
|
48
|
-
|
49
|
-
def htmlize(features)
|
50
|
-
html_content = ''
|
51
|
-
features.each do |name, metrics|
|
52
|
-
html_content += "\n<div class=\"module dark #{metrics[2] != 0 ? 'danger' : ''} \">
|
53
|
-
<div class=\"funcname\">
|
54
|
-
<h4>#{name}</h4>
|
55
|
-
</div>
|
56
|
-
<div class=\"total\">
|
57
|
-
<h6>Total</h6>
|
58
|
-
<h4>#{metrics[0]}</h4>
|
59
|
-
</div>
|
60
|
-
<div class=\"pass\">
|
61
|
-
<h6>Passed</h6>
|
62
|
-
<h4>#{metrics[1]}</h4>
|
63
|
-
</div>
|
64
|
-
<div class=\"fail\">
|
65
|
-
<h6>Failed</h6>
|
66
|
-
<h4>#{metrics[2]}</h4>
|
67
|
-
</div>
|
68
|
-
</div>"
|
69
|
-
end
|
70
|
-
return html_content
|
71
|
-
end
|
72
|
-
|
73
|
-
def write()
|
74
|
-
if @features.length == 0
|
75
|
-
log("No tests logged, cannot build empty report.")
|
76
|
-
return
|
77
|
-
end
|
78
|
-
clean()
|
79
|
-
template = File.new(@nxg_report_path, 'w')
|
80
|
-
template.puts("<html lang=\"en\">
|
81
|
-
<head>
|
82
|
-
<meta charset=\"UTF-8\" />
|
83
|
-
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
|
84
|
-
<title id=\"meta-app-title\"></title>
|
85
|
-
<link
|
86
|
-
href=\"https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap\"
|
87
|
-
rel=\"stylesheet\"
|
88
|
-
/>
|
89
|
-
<link
|
90
|
-
href=\"https://fonts.googleapis.com/icon?family=Material+Icons\"
|
91
|
-
rel=\"stylesheet\"
|
92
|
-
/>
|
93
|
-
<style>
|
94
|
-
:root {
|
95
|
-
--dark-bg: rgb(41, 40, 40);
|
96
|
-
--dark-primary: #050505;
|
97
|
-
--dark-font: rgb(201, 201, 201);
|
98
|
-
--dark-blue: rgb(0, 225, 255);
|
99
|
-
--dark-green: rgba(115, 255, 0, 0.89);
|
100
|
-
--dark-red: rgb(255, 0, 0);
|
101
|
-
|
102
|
-
--light-bg: rgb(226, 226, 226);
|
103
|
-
--light-primary: #fff;
|
104
|
-
--light-font: rgb(44, 44, 44);
|
105
|
-
--light-blue: rgb(1, 67, 165);
|
106
|
-
--light-green: rgb(14, 138, 2);
|
107
|
-
--light-red: rgb(255, 0, 0);
|
108
|
-
|
109
|
-
--font: \"Open Sans\", sans-serif;
|
110
|
-
--danger-bg: rgba(255, 0, 0, 0.185);
|
111
|
-
}
|
112
|
-
|
113
|
-
body {
|
114
|
-
font-family: var(--font);
|
115
|
-
margin: auto;
|
116
|
-
}
|
117
|
-
|
118
|
-
.wrapper {
|
119
|
-
display: grid;
|
120
|
-
grid-template-rows: auto 1fr;
|
121
|
-
height: 100vh;
|
122
|
-
width: 100vw;
|
123
|
-
}
|
124
|
-
|
125
|
-
.header {
|
126
|
-
display: grid;
|
127
|
-
grid-template-columns: 6fr 1fr;
|
128
|
-
text-align: center;
|
129
|
-
background: linear-gradient(to bottom right, #ff644e, #cb3018);
|
130
|
-
}
|
131
|
-
|
132
|
-
.mc {
|
133
|
-
display: grid;
|
134
|
-
grid-template-columns: 1fr 1fr 1fr;
|
135
|
-
grid-auto-rows: 70px;
|
136
|
-
grid-gap: 0.5em;
|
137
|
-
padding: 0.5em 2em;
|
138
|
-
padding-top: 2em;
|
139
|
-
}
|
140
|
-
|
141
|
-
.footer {
|
142
|
-
margin-bottom: 1em;
|
143
|
-
padding: 3em;
|
144
|
-
text-align: center;
|
145
|
-
font-size: 0.7rem;
|
146
|
-
font-weight: 600;
|
147
|
-
}
|
148
|
-
|
149
|
-
a {
|
150
|
-
cursor: pointer;
|
151
|
-
font-weight: 600;
|
152
|
-
}
|
153
|
-
|
154
|
-
.module {
|
155
|
-
display: grid;
|
156
|
-
place-items: center;
|
157
|
-
grid-template-columns: 3fr 1fr 1fr 1fr;
|
158
|
-
border-radius: 0.7rem;
|
159
|
-
padding: 10px 10px;
|
160
|
-
}
|
161
|
-
|
162
|
-
.button-wrapper {
|
163
|
-
place-items: center;
|
164
|
-
}
|
165
|
-
|
166
|
-
#theme-switch {
|
167
|
-
width: 5em;
|
168
|
-
height: 5em;
|
169
|
-
background-color: Transparent;
|
170
|
-
background-repeat: no-repeat;
|
171
|
-
border: none;
|
172
|
-
cursor: pointer;
|
173
|
-
overflow: hidden;
|
174
|
-
outline: none;
|
175
|
-
margin: 0;
|
176
|
-
position: relative;
|
177
|
-
top: 50%;
|
178
|
-
-ms-transform: translateY(-50%);
|
179
|
-
transform: translateY(-50%);
|
180
|
-
}
|
181
|
-
|
182
|
-
h2,
|
183
|
-
h3,
|
184
|
-
h4,
|
185
|
-
h5,
|
186
|
-
h6 {
|
187
|
-
text-align: center;
|
188
|
-
margin: auto;
|
189
|
-
}
|
190
|
-
|
191
|
-
.total,
|
192
|
-
.pass,
|
193
|
-
.fail {
|
194
|
-
display: grid;
|
195
|
-
width: 100%;
|
196
|
-
height: 100%;
|
197
|
-
place-items: center;
|
198
|
-
}
|
199
|
-
|
200
|
-
body.dark {
|
201
|
-
background-color: var(--dark-bg);
|
202
|
-
color: var(--dark-font);
|
203
|
-
}
|
204
|
-
|
205
|
-
body.dark > .wrapper > .footer {
|
206
|
-
color: var(--dark-font);
|
207
|
-
}
|
208
|
-
|
209
|
-
body.dark > .wrapper > .mc > .module {
|
210
|
-
background-color: var(--dark-primary);
|
211
|
-
color: var(--dark-font);
|
212
|
-
}
|
213
|
-
|
214
|
-
body.dark > .wrapper > .mc > .module > .total {
|
215
|
-
color: var(--dark-blue);
|
216
|
-
}
|
217
|
-
|
218
|
-
body.dark > .wrapper > .mc > .module > .pass {
|
219
|
-
color: var(--dark-green);
|
220
|
-
}
|
221
|
-
|
222
|
-
body.dark > .wrapper > .mc > .module > .fail {
|
223
|
-
color: var(--dark-red);
|
224
|
-
}
|
225
|
-
|
226
|
-
body.dark > .wrapper > .mc > .module.danger {
|
227
|
-
background-color: rgba(255, 0, 0, 0.185);
|
228
|
-
}
|
229
|
-
|
230
|
-
body.dark > .wrapper > .header {
|
231
|
-
color: var(--dark-primary);
|
232
|
-
}
|
233
|
-
|
234
|
-
body.dark > .wrapper > .footer > p > span > a {
|
235
|
-
color: var(--dark-font);
|
236
|
-
}
|
237
|
-
|
238
|
-
body.dark > .wrapper > .header > div > button > #theme-switch-icon {
|
239
|
-
color: var(--dark-primary);
|
240
|
-
}
|
241
|
-
|
242
|
-
body {
|
243
|
-
background-color: var(--light-bg);
|
244
|
-
color: var(--dark-font);
|
245
|
-
}
|
246
|
-
|
247
|
-
body > .wrapper > .footer {
|
248
|
-
color: var(--light-font);
|
249
|
-
}
|
250
|
-
|
251
|
-
body > .wrapper > .mc > .module {
|
252
|
-
background-color: var(--light-primary);
|
253
|
-
color: var(--light-font);
|
254
|
-
}
|
255
|
-
|
256
|
-
body > .wrapper > .mc > .module > .total {
|
257
|
-
color: var(--light-blue);
|
258
|
-
}
|
259
|
-
|
260
|
-
body > .wrapper > .mc > .module > .pass {
|
261
|
-
color: var(--light-green);
|
262
|
-
}
|
263
|
-
|
264
|
-
body > .wrapper > .mc > .module > .fail {
|
265
|
-
color: var(--light-red);
|
266
|
-
}
|
267
|
-
|
268
|
-
body > .wrapper > .mc > .module.danger {
|
269
|
-
background-color: var(--danger-bg);
|
270
|
-
}
|
271
|
-
|
272
|
-
body > .wrapper > .header {
|
273
|
-
color: var(--light-primary);
|
274
|
-
}
|
275
|
-
|
276
|
-
body > .wrapper > .footer > p > span > a {
|
277
|
-
color: var(--light-font);
|
278
|
-
}
|
279
|
-
|
280
|
-
body > .wrapper > .header > div > button > #theme-switch-icon {
|
281
|
-
color: var(--light-primary);
|
282
|
-
}
|
283
|
-
|
284
|
-
@media only screen and (max-width: 600px) {
|
285
|
-
h1 {
|
286
|
-
font-size: 24px;
|
287
|
-
}
|
288
|
-
|
289
|
-
.mc {
|
290
|
-
grid-template-columns: 1fr;
|
291
|
-
padding: 0.5em 0.5em;
|
292
|
-
padding-top: 1em;
|
293
|
-
}
|
294
|
-
}
|
295
|
-
|
296
|
-
@media (min-width: 600px) and (max-width: 992px) {
|
297
|
-
.mc {
|
298
|
-
grid-template-columns: 1fr 1fr;
|
299
|
-
}
|
300
|
-
}
|
301
|
-
</style>
|
302
|
-
</head>
|
303
|
-
<body class=\"dark\" id=\"app\">
|
304
|
-
<div class=\"wrapper\">
|
305
|
-
<div class=\"header\">
|
306
|
-
<h1 id=\"app-title\"></h1>
|
307
|
-
<div class=\"button-wrapper\">
|
308
|
-
<button id=\"theme-switch\" onclick=\"handleThemeSwitch()\">
|
309
|
-
<i class=\"material-icons\" id=\"theme-switch-icon\">brightness_2</i>
|
310
|
-
</button>
|
311
|
-
</div>
|
312
|
-
</div>
|
313
|
-
<div class=\"mc\">
|
314
|
-
#{htmlize(@features)}
|
315
|
-
</div>
|
316
|
-
<div class=\"footer\">
|
317
|
-
<p>
|
318
|
-
Developed by
|
319
|
-
<span
|
320
|
-
><a
|
321
|
-
href=\"https://www.linkedin.com/in/balabharathijayaraman\"
|
322
|
-
rel=\"nofollow\"
|
323
|
-
target=\"_blank\"
|
324
|
-
>Balabharathi Jayaraman</a
|
325
|
-
></span
|
326
|
-
>
|
327
|
-
</p>
|
328
|
-
</div>
|
329
|
-
</div>
|
330
|
-
</body>
|
331
|
-
<script>
|
332
|
-
var appTitle = \"#{@title}\";
|
333
|
-
var theme = \"dark\";
|
334
|
-
|
335
|
-
window.onload = function () {
|
336
|
-
document.getElementById(
|
337
|
-
\"meta-app-title\"
|
338
|
-
).innerHTML = `Home | ${appTitle}`;
|
339
|
-
document.getElementById(\"app-title\").innerHTML = appTitle;
|
340
|
-
};
|
341
|
-
|
342
|
-
function handleThemeSwitch() {
|
343
|
-
if (theme === \"dark\") {
|
344
|
-
theme = \"light\";
|
345
|
-
document.getElementById(\"app\").classList.remove(\"dark\");
|
346
|
-
document.getElementById(\"theme-switch-icon\").innerHTML = \"wb_sunny\";
|
347
|
-
document.getElementById(\"theme-switch-icon\");
|
348
|
-
return;
|
349
|
-
}
|
350
|
-
if (theme === \"light\") {
|
351
|
-
theme = \"dark\";
|
352
|
-
document.getElementById(\"app\").classList.add(\"dark\");
|
353
|
-
document.getElementById(\"theme-switch-icon\").innerHTML = \"brightness_2\";
|
354
|
-
}
|
355
|
-
}
|
356
|
-
</script>
|
357
|
-
</html>
|
358
|
-
")
|
359
|
-
template.close()
|
360
|
-
end
|
361
|
-
|
362
|
-
private :log, :clean, :write, :htmlize, :report_success
|
363
|
-
end
|
364
|
-
|
365
|
-
$NxgReport = NxgReport.new()
|
5
|
+
$NxgReport = NxgCore.new().instance()
|