nxgreport 0.7.0 → 0.8.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nxgcore.rb +420 -0
  3. data/lib/nxgcss.rb +335 -0
  4. data/lib/nxgreport.rb +3 -547
  5. metadata +6 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee73dbd088457ecad4c7ed59c99a742695751cb67023d46277f414f931a52bc8
4
- data.tar.gz: 3c983d5cf26640573530d1a4e53341687ad4caf4728d91b89a5878537760b362
3
+ metadata.gz: 2248123c4fd3dd1b0f9f8b51be96a58d7ce3d936037bbd536fc6fb46f84d248a
4
+ data.tar.gz: 0e59c0545599b7d868a890cbca5f88f69bab7fa2bbf4f78870b2272fc64a91e7
5
5
  SHA512:
6
- metadata.gz: e8ec091e72cce90ba3a24fc7a469a9fd70a023bdd6461fc173057598b15a086ac73ebbcb0790ec0fb628f9bf3a53a7cf9f131dcd3d2487eb7cb0c4ca6a0992ef
7
- data.tar.gz: '059139b83469493d20bd83ebb5c2f621084f959b0c2a040c710b1c9b2a010982b6c92af1cb383966f21e2f39f3607fbd0bef2b23878abff1b2aa4b3a0f02cd6f'
6
+ metadata.gz: f7cae8d3cd35d9015a2ec8ec04ab928d87217efb6cc0df27a2c13671bd8155470b761cf547f46103be22cf243cebd3fe75a895b786ed709c38abe2da1e14c89c
7
+ data.tar.gz: 55206eb129ccb97ce771fcd7b67a90948e3bad1ba1117baab58ce3cfea7d8e7b18931f651231aafdb4f384e06d934fa5ec64dc362464fad76b9d951ea213a43d
@@ -0,0 +1,420 @@
1
+ require 'fileutils'
2
+
3
+ require 'nxgcss.rb'
4
+
5
+ class NxgCore
6
+ class NxgReport
7
+
8
+ include NxgCss
9
+
10
+ def initialize(data_provider)
11
+ @data_provider = data_provider
12
+ @data_provider[:pass] = 0
13
+ @data_provider[:fail] = 0
14
+ @data_provider[:total] = 0
15
+ end
16
+
17
+ def setup(location: "./NxgReport.html", title: "Features Summary")
18
+ @data_provider[:report_path] = location.empty? ? "./NxgReport.html" : location
19
+ folder_check()
20
+ @data_provider[:title] = title
21
+ @data_provider[:title_color] = "background: linear-gradient(to bottom right, #ff644e, #cb3018);"
22
+ @data_provider[:open_on_completion] = false
23
+ @data_provider[:features] = Hash.new()
24
+ @start_time = Time.now.to_f
25
+ end
26
+
27
+ def set_title_color(hex_color: "")
28
+ if hex_color.strip().empty?() || hex_color.strip()[0] != "#"
29
+ log("set_title_color method is called with empty color. please check the code.")
30
+ return
31
+ end
32
+ @data_provider[:title_color] = "background-color: #{hex_color.strip().downcase()};"
33
+ end
34
+
35
+ def open_upon_execution(value: true)
36
+ return if !value
37
+
38
+ @data_provider[:open_on_completion] = value
39
+ end
40
+
41
+ def set_environment(name: "")
42
+ return if name.empty?()
43
+
44
+ @data_provider[:environment] = name
45
+ end
46
+
47
+ def set_app_version(no: "")
48
+ return if no.empty?()
49
+
50
+ version_no = no.downcase.gsub("app", "").gsub("version", "").strip
51
+ @data_provider[:app_version] = "App Version #{version_no}"
52
+ end
53
+
54
+ def set_release(name: "")
55
+ return if name.empty?()
56
+
57
+ @data_provider[:release_name] = name
58
+ end
59
+
60
+ def set_os(name: "")
61
+ return if name.empty?()
62
+
63
+ @data_provider[:os] = name
64
+ end
65
+
66
+ def set_device(name: "")
67
+ return if name.empty?()
68
+
69
+ @data_provider[:device] = name
70
+ end
71
+
72
+ def set_execution(date: "")
73
+ return if date.empty?()
74
+
75
+ @data_provider[:execution_date] = date
76
+ end
77
+
78
+ def log_test(feature_name: "", test_status: "")
79
+ if feature_name.nil?() || feature_name.strip.empty?()
80
+ log("Feature name cannot be empty.")
81
+ return
82
+ end
83
+
84
+ if test_status.nil?() || test_status.strip.empty?()
85
+ log("Test status cannot be empty.")
86
+ return
87
+ end
88
+
89
+ test_pass = test_status.downcase.include?('pass')
90
+ name = feature_name.strip()
91
+
92
+ if !@data_provider[:features].key?(name)
93
+ @data_provider[:features][name]=[0,0,0]
94
+ end
95
+
96
+ @data_provider[:features][name][0]+=1
97
+ @data_provider[:total]+=1
98
+ @data_provider[:features][name][(test_pass) ? 1 : 2]+=1
99
+ @data_provider[(test_pass) ? :pass : :fail]+=1
100
+ end
101
+
102
+ def build(execution_time: 0)
103
+ set_execution_time(execution_time)
104
+ write()
105
+ if @data_provider[:open_on_completion]
106
+ system("open #{@data_provider[:report_path]}") if File.file?(@data_provider[:report_path])
107
+ end
108
+ end
109
+
110
+ # Private methods
111
+ def log(message)
112
+ puts("🤖- #{message}")
113
+ end
114
+
115
+ def folder_check()
116
+ folder = File.dirname(@data_provider[:report_path])
117
+ FileUtils.mkdir_p(folder) unless File.directory?(folder)
118
+ end
119
+
120
+ def clean()
121
+ File.delete(@data_provider[:report_path]) if File.file?(@data_provider[:report_path])
122
+ end
123
+
124
+ def write()
125
+ clean()
126
+ if @data_provider[:features].length == 0
127
+ log("No tests logged, cannot build empty report.")
128
+ return
129
+ end
130
+ template = File.new(@data_provider[:report_path], 'w')
131
+ template.puts("<html lang=\"en\">
132
+ #{head()}
133
+ #{body()}
134
+ #{javascript()}
135
+ </html>")
136
+ template.close()
137
+ end
138
+
139
+ def head()
140
+ "<head>
141
+ <meta charset=\"UTF-8\" />
142
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
143
+ <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js\"></script>
144
+ <title>Home | #{@data_provider[:title]}</title>
145
+ #{google_fonts_link()}
146
+ #{icons_link()}
147
+ #{css(@data_provider)}
148
+ </head>"
149
+ end
150
+
151
+ def google_fonts_link()
152
+ "<link
153
+ 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\"
154
+ rel=\"stylesheet\"
155
+ />"
156
+ end
157
+
158
+ def icons_link()
159
+ "<link
160
+ href=\"https://fonts.googleapis.com/icon?family=Material+Icons\"
161
+ rel=\"stylesheet\"
162
+ />"
163
+ end
164
+
165
+ def body()
166
+ "<body class=\"dark\" id=\"app\" onload=\"onStart()\">
167
+ <div class=\"body-wrapper\">
168
+ #{header()}
169
+ #{config()}
170
+ #{features()}
171
+ #{footer()}
172
+ </div>
173
+ </body>"
174
+ end
175
+
176
+ def header()
177
+ "<div class=\"header\">
178
+ <h1>#{@data_provider[:title]}</h1>
179
+ <div class=\"button-wrapper\">
180
+ <button id=\"theme-switch\" onclick=\"handleThemeSwitch()\">
181
+ <i class=\"material-icons\" id=\"theme-switch-icon\">brightness_2</i>
182
+ </button>
183
+ </div>
184
+ </div>"
185
+ end
186
+
187
+ def features()
188
+ "<div class=\"mc\"></div>"
189
+ end
190
+
191
+ def features_js_array()
192
+ js_array = ''
193
+ @data_provider[:features].each do |name, metrics|
194
+ js_array += "{ name: \"#{name}\", total: #{metrics[0]}, pass: #{metrics[1]}, fail: #{metrics[2]} },"
195
+ end
196
+ return js_array
197
+ end
198
+
199
+ def footer()
200
+ "<div class=\"footer\">
201
+ <p>
202
+ Developed by
203
+ <span>
204
+ <a
205
+ href=\"https://www.linkedin.com/in/balabharathijayaraman\"
206
+ rel=\"nofollow\"
207
+ target=\"_blank\"
208
+ >Balabharathi Jayaraman</a
209
+ >
210
+ </span>
211
+ </p>
212
+ </div>"
213
+ end
214
+
215
+ def javascript()
216
+ "<script>
217
+ var theme = \"dark\";
218
+ var displayAllTests = true;
219
+
220
+ var features = [
221
+ #{features_js_array()}
222
+ ]
223
+
224
+ function onStart() {
225
+ displayAll();
226
+ }
227
+
228
+ function handleThemeSwitch() {
229
+ if (theme === \"dark\") {
230
+ theme = \"light\";
231
+ document.getElementById(\"app\").classList.remove(\"dark\");
232
+ document.getElementById(\"theme-switch-icon\").innerHTML = \"wb_sunny\";
233
+ document.getElementById(\"theme-switch-icon\");
234
+ return;
235
+ }
236
+ if (theme === \"light\") {
237
+ theme = \"dark\";
238
+ document.getElementById(\"app\").classList.add(\"dark\");
239
+ document.getElementById(\"theme-switch-icon\").innerHTML = \"brightness_2\";
240
+ }
241
+ }
242
+
243
+ function handleFilter() {
244
+ displayAllTests = !displayAllTests;
245
+ if (displayAllTests) {
246
+ displayAll();
247
+ } else {
248
+ displayFailuresOnly();
249
+ }
250
+ }
251
+
252
+ function displayAll() {
253
+ $(\"#filter h5\").text(\"All\");
254
+ $(\".banner-in-the-middle\").removeClass(\"banner-in-the-middle\").addClass(\"mc\");
255
+ $(\".mc\").empty();
256
+ features.forEach((item) => {
257
+ $(\".mc\").append(
258
+ `<div class=\"module dark ${
259
+ item.fail > 0 ? \"danger\" : \"\"
260
+ }\"><div class=\"funcname\"><h4>${
261
+ item.name
262
+ }</h4></div><div class=\"total\"><h6>Total</h6><h4>${
263
+ item.total
264
+ }</h4></div><div class=\"pass\"><h6>Passed</h6><h4>${
265
+ item.pass
266
+ }</h4></div><div class=\"fail\"><h6>Failed</h6><h4>${
267
+ item.fail
268
+ }</h4></div></div>`
269
+ );
270
+ });
271
+ }
272
+
273
+ function displayFailuresOnly() {
274
+ $(\"#filter h5\").text(\"Failures\");
275
+ $(\".banner-in-the-middle\").removeClass(\"banner-in-the-middle\").addClass(\"mc\");
276
+ $(\".mc\").empty();
277
+ failureCount = 0;
278
+ features.forEach((item) => {
279
+ if (item.fail > 0) {
280
+ failureCount++;
281
+ $(\".mc\").append(
282
+ `<div class=\"module dark danger\"><div class=\"funcname\"><h4>${item.name}</h4></div><div class=\"total\"><h6>Total</h6><h4>${item.total}</h4></div><div class=\"pass\"><h6>Passed</h6><h4>${item.pass}</h4></div><div class=\"fail\"><h6>Failed</h6><h4>${item.fail}</h4></div></div>`
283
+ );
284
+ }
285
+ });
286
+ if (failureCount === 0) {
287
+ $(\".mc\")
288
+ .removeClass(\"mc\")
289
+ .addClass(\"banner-in-the-middle\")
290
+ .append(
291
+ `<i class=\"banner-text material-icons\">done_all</i><h1>No Failures</>`
292
+ );
293
+ }
294
+ }
295
+ </script>"
296
+ end
297
+
298
+ def config()
299
+ return if @data_provider.length == 0
300
+
301
+ return "<div class=\"configuration-container\">
302
+ #{release_name()}
303
+ #{execution_date()}
304
+ #{device()}
305
+ #{os()}
306
+ #{app_version()}
307
+ #{environment()}
308
+ #{passed_tests()}
309
+ #{failed_tests()}
310
+ #{percentage_pass()}
311
+ #{execution_time()}
312
+ #{filter()}
313
+ </div>"
314
+ end
315
+
316
+ def execution_time()
317
+ return if !@data_provider.key?(:environment)
318
+
319
+ return config_item("Total execution time", @data_provider[:execution_time],'access_time')
320
+ end
321
+
322
+ def filter()
323
+ "<div class=\"configuration-wrapper\" onclick=\"handleFilter()\" id=\"filter\" title=\"Filter tests\">
324
+ <i class=\"configuration-icon material-icons\">filter_list</i>
325
+ <h5 id=\"configuration-text\">Failed</h5>
326
+ </div>"
327
+ end
328
+
329
+ def passed_tests()
330
+ "<div class=\"configuration-wrapper\" title=\"Passed tests\">
331
+ <i class=\"configuration-icon pass-total material-icons\">check_circle</i>
332
+ <h5 id=\"configuration-text\">#{@data_provider[:pass] == 0 ? "None" : @data_provider[:pass]}</h5>
333
+ </div>"
334
+ end
335
+
336
+ def failed_tests()
337
+ "<div class=\"configuration-wrapper\" title=\"Failed tests\">
338
+ <i class=\"configuration-icon fail-total material-icons\">cancel</i>
339
+ <h5 id=\"configuration-text\">#{@data_provider[:fail] == 0 ? "None" : @data_provider[:fail]}</h5>
340
+ </div>"
341
+ end
342
+
343
+ def percentage_pass()
344
+ pass_percentage = ((@data_provider[:pass]/@data_provider[:total].to_f) * 100).round(2)
345
+
346
+ return config_item("Pass percentage", pass_percentage,'equalizer')
347
+ end
348
+
349
+ def environment()
350
+ return if !@data_provider.key?(:environment)
351
+
352
+ return config_item("Test environment", @data_provider[:environment], "layers")
353
+ end
354
+
355
+ def app_version()
356
+ return if !@data_provider.key?(:app_version)
357
+
358
+ return config_item("App version tested", @data_provider[:app_version], "info")
359
+ end
360
+
361
+ def release_name()
362
+ return if !@data_provider.key?(:release_name)
363
+
364
+ return config_item("Release", @data_provider[:release_name], "bookmark")
365
+ end
366
+
367
+ def os()
368
+ return if !@data_provider.key?(:os)
369
+
370
+ return config_item("Os tested", @data_provider[:os], "settings")
371
+ end
372
+
373
+ def device()
374
+ return if !@data_provider.key?(:device)
375
+
376
+ return config_item("Device tested", @data_provider[:device], "devices")
377
+ end
378
+
379
+ def execution_date()
380
+ @data_provider[:execution_date] = Time.now().strftime("%b %d, %Y") if !@data_provider.key?(:execution_date)
381
+
382
+ return config_item("Execution date", @data_provider[:execution_date], "event")
383
+ end
384
+
385
+ def config_item(toot_tip, name, icon)
386
+ "<div class=\"configuration-wrapper\" title=\"#{toot_tip}\">
387
+ <i class=\"configuration-icon material-icons\">#{icon}</i>
388
+ <h5 id=\"configuration-text\">#{name}</h5>
389
+ </div>"
390
+ end
391
+
392
+ def set_execution_time(time)
393
+ time_diff_in_mins = 0
394
+ if time == 0
395
+ @end_time = Time.now.to_f
396
+ time_diff_in_mins = ((@end_time - @start_time) / 60).to_i
397
+ else
398
+ time_diff_in_mins = (time / 60).to_i
399
+ end
400
+
401
+ if time_diff_in_mins >= 60
402
+ time_diff_in_hrs = (time_diff_in_mins / 60.to_f).round(2)
403
+ @data_provider[:execution_time] = "#{time_diff_in_hrs} #{time_diff_in_hrs == 1 ? "hour" : "hours"}"
404
+ else
405
+ @data_provider[:execution_time] = "#{time_diff_in_mins} mins"
406
+ end
407
+ end
408
+
409
+ private :log, :clean, :write
410
+ private :execution_date, :device, :os, :release_name, :app_version, :environment
411
+ private :features, :config, :config_item, :features_js_array
412
+ private :head, :body, :header, :footer, :javascript
413
+ end
414
+
415
+ private_constant :NxgReport
416
+
417
+ def instance(data_provider: Hash.new())
418
+ NxgReport.new(data_provider)
419
+ end
420
+ end
@@ -0,0 +1,335 @@
1
+
2
+ module NxgCss
3
+
4
+ def has_environment_settings(data_provider)
5
+ data_provider.key?(:environment) || data_provider.key?(:app_version) || data_provider.key?(:release_name) || data_provider.key?(:os) || data_provider.key?(:device) || data_provider.key?(:execution_date)
6
+ end
7
+
8
+ def css(data_provider)
9
+ "<style>
10
+ :root {
11
+ --dark-bg: rgb(41, 40, 40);
12
+ --dark-primary: #050505;
13
+ --dark-secondary: #050505a9;
14
+ --dark-font: rgb(201, 201, 201);
15
+ --dark-blue: rgb(0, 225, 255);
16
+ --dark-green: rgba(115, 255, 0, 0.89);
17
+ --dark-red: rgb(255, 0, 0);
18
+ --dark-shadow: rgba(0, 0, 0, 0.5);
19
+
20
+ --light-bg: rgb(226, 226, 226);
21
+ --light-primary: #fff;
22
+ --light-secondary: rgba(255, 255, 255, 0.445);
23
+ --light-font: rgb(44, 44, 44);
24
+ --light-blue: rgb(1, 67, 165);
25
+ --light-green: rgb(14, 138, 2);
26
+ --light-red: rgb(255, 0, 0);
27
+ --light-shadow: rgba(245, 245, 245, 0.5);
28
+
29
+ --font: \"Open Sans\", sans-serif;
30
+ --danger-bg: rgba(255, 0, 0, 0.185);
31
+ --color-switch-animation: all 500ms ease;
32
+ }
33
+
34
+ body {
35
+ font-family: var(--font);
36
+ margin: auto;
37
+ transition: var(--color-switch-animation);
38
+ }
39
+
40
+ .body-wrapper {
41
+ display: grid;
42
+ grid-template-rows: auto auto 1fr;
43
+ height: 100vh;
44
+ width: 100vw;
45
+ }
46
+
47
+ .header {
48
+ display: grid;
49
+ grid-template-columns: 8fr 1fr;
50
+ text-align: center;
51
+ #{data_provider[:title_color]}
52
+ }
53
+
54
+ .configuration-container {
55
+ display: flex;
56
+ flex-wrap: wrap;
57
+ justify-content: space-between;
58
+ text-align: center;
59
+ padding: 1.5em 2em 1em 2em;
60
+ }
61
+
62
+ .configuration-wrapper {
63
+ display: flex;
64
+ place-items: center;
65
+ }
66
+
67
+ .configuration-icon {
68
+ font-size: 1.5em;
69
+ padding-right: 0.5em;
70
+ }
71
+
72
+ #configuration-text {
73
+ font-size: 0.85em;
74
+ }
75
+
76
+ #filter {
77
+ cursor: pointer;
78
+ border-radius: 1em;
79
+ width: 6em;
80
+ padding: 0.2em 0.8em;
81
+ background-color: var(--light-secondary);
82
+ -webkit-box-shadow: -1px 0px 5px 0px var(--light-shadow);
83
+ -moz-box-shadow: -1px 0px 5px 0px var(--light-shadow);
84
+ box-shadow: -1px 0px 5px 0px var(--light-shadow);
85
+ }
86
+
87
+ .mc {
88
+ display: grid;
89
+ grid-template-columns: 1fr 1fr 1fr;
90
+ grid-auto-rows: 70px;
91
+ grid-gap: 0.5em;
92
+ padding: 0.5em 2em;
93
+ }
94
+
95
+ .banner-in-the-middle {
96
+ text-align: center;
97
+ margin: auto;
98
+ }
99
+
100
+ .banner-text {
101
+ color: green;
102
+ font-size: 5em;
103
+ }
104
+
105
+ .banner-in-the-middle > h1 {
106
+ color: var(--light-font);
107
+ }
108
+
109
+ .footer {
110
+ margin-bottom: 0.5em;
111
+ padding: 3em 3em 1em 3em;
112
+ text-align: center;
113
+ font-size: 0.7rem;
114
+ font-weight: 600;
115
+ }
116
+
117
+ a {
118
+ cursor: pointer;
119
+ font-weight: 600;
120
+ }
121
+
122
+ .module {
123
+ display: grid;
124
+ place-items: center;
125
+ grid-template-columns: 3fr 1fr 1fr 1fr;
126
+ border-radius: 0.7rem;
127
+ padding: 10px 10px;
128
+ -webkit-box-shadow: -1px 0px 5px 0px var(--light-shadow);
129
+ -moz-box-shadow: -1px 0px 5px 0px var(--light-shadow);
130
+ box-shadow: -1px 0px 5px 0px var(--light-shadow);
131
+ }
132
+
133
+ .button-body-wrapper {
134
+ place-items: center;
135
+ }
136
+
137
+ #theme-switch {
138
+ width: 5em;
139
+ height: 5em;
140
+ background-color: Transparent;
141
+ background-repeat: no-repeat;
142
+ border: none;
143
+ cursor: pointer;
144
+ overflow: hidden;
145
+ outline: none;
146
+ margin: 0;
147
+ margin-right: 1em;
148
+ position: relative;
149
+ top: 50%;
150
+ -ms-transform: translateY(-50%);
151
+ transform: translateY(-50%);
152
+ }
153
+
154
+ h2,
155
+ h3,
156
+ h4,
157
+ h5,
158
+ h6 {
159
+ text-align: center;
160
+ margin: auto;
161
+ }
162
+
163
+ .total,
164
+ .pass,
165
+ .fail {
166
+ display: grid;
167
+ width: 100%;
168
+ height: 100%;
169
+ place-items: center;
170
+ }
171
+
172
+ body.dark {
173
+ background-color: var(--dark-bg);
174
+ color: var(--dark-font);
175
+ }
176
+
177
+ body.dark > .body-wrapper > .footer {
178
+ color: var(--dark-font);
179
+ }
180
+
181
+ body.dark > .body-wrapper > .mc > .module {
182
+ background-color: var(--dark-primary);
183
+ color: var(--dark-font);
184
+ -webkit-box-shadow: -1px 0px 5px 0px var(--dark-shadow);
185
+ -moz-box-shadow: -1px 0px 5px 0px var(--dark-shadow);
186
+ box-shadow: -1px 0px 5px 0px var(--dark-shadow);
187
+ }
188
+
189
+ body.dark > .body-wrapper > .mc > .module > .total {
190
+ color: var(--dark-blue);
191
+ }
192
+
193
+ body.dark > .body-wrapper > .mc > .module > .pass {
194
+ color: var(--dark-green);
195
+ }
196
+
197
+ body.dark > .body-wrapper > .mc > .module > .fail {
198
+ color: var(--dark-red);
199
+ }
200
+
201
+ body.dark > .body-wrapper > .configuration-container > .configuration-wrapper > .pass-total {
202
+ color: var(--dark-green);
203
+ }
204
+
205
+ body.dark > .body-wrapper > .configuration-container > .configuration-wrapper > .fail-total {
206
+ color: var(--dark-red);
207
+ }
208
+
209
+ body.dark > .body-wrapper > .mc > .module.danger {
210
+ background-color: rgba(255, 0, 0, 0.185);
211
+ }
212
+
213
+ body.dark > .body-wrapper > .banner-in-the-middle > h1 {
214
+ color: var(--dark-font);
215
+ }
216
+
217
+ body.dark > .body-wrapper > .header {
218
+ color: var(--dark-primary);
219
+ }
220
+
221
+ body.dark > .body-wrapper > .configuration-container > .configuration-wrapper {
222
+ color: var(--dark-font);
223
+ }
224
+
225
+ body.dark > .body-wrapper > .configuration-container > #filter {
226
+ background-color: var(--dark-secondary);
227
+ -webkit-box-shadow: -1px 0px 5px 0px var(--dark-shadow);
228
+ -moz-box-shadow: -1px 0px 5px 0px var(--dark-shadow);
229
+ box-shadow: -1px 0px 5px 0px var(--dark-shadow);
230
+ }
231
+
232
+ body.dark > .body-wrapper > .footer > p > span > a {
233
+ color: var(--dark-font);
234
+ }
235
+
236
+ body.dark > .body-wrapper > .header > div > button > #theme-switch-icon {
237
+ color: var(--dark-primary);
238
+ }
239
+
240
+ body {
241
+ background-color: var(--light-bg);
242
+ color: var(--dark-font);
243
+ }
244
+
245
+ body > .body-wrapper > .footer {
246
+ color: var(--light-font);
247
+ }
248
+
249
+ body > .body-wrapper > .mc > .module {
250
+ background-color: var(--light-primary);
251
+ color: var(--light-font);
252
+ }
253
+
254
+ body > .body-wrapper > .mc > .module > .total {
255
+ color: var(--light-blue);
256
+ }
257
+
258
+ body > .body-wrapper > .mc > .module > .pass {
259
+ color: var(--light-green);
260
+ }
261
+
262
+ body > .body-wrapper > .mc > .module > .fail {
263
+ color: var(--light-red);
264
+ }
265
+
266
+ body > .body-wrapper > .configuration-container > .configuration-wrapper > .pass-total {
267
+ color: var(--light-green);
268
+ }
269
+
270
+ body > .body-wrapper > .configuration-container > .configuration-wrapper > .fail-total {
271
+ color: var(--light-red);
272
+ }
273
+
274
+ body > .body-wrapper > .mc > .module.danger {
275
+ background-color: var(--danger-bg);
276
+ }
277
+
278
+ body > .body-wrapper > .header {
279
+ color: var(--light-primary);
280
+ }
281
+
282
+ body > .body-wrapper > .configuration-container > .configuration-wrapper {
283
+ color: var(--light-font);
284
+ }
285
+
286
+ body > .body-wrapper > .footer > p > span > a {
287
+ color: var(--light-font);
288
+ }
289
+
290
+ body > .body-wrapper > .header > div > button > #theme-switch-icon {
291
+ color: var(--light-primary);
292
+ }
293
+
294
+ @media only screen and (max-width: 600px) {
295
+ h1 {
296
+ font-size: 24px;
297
+ }
298
+
299
+ .mc {
300
+ grid-template-columns: 1fr;
301
+ padding: 0.5em 0.5em;
302
+ padding-top: 1em;
303
+ }
304
+
305
+ .configuration-container {
306
+ padding: 0.5em 0em;
307
+ }
308
+
309
+ .configuration-wrapper {
310
+ padding: 0.5em 1em;
311
+ }
312
+
313
+ .configuration-icon {
314
+ font-size: 1em;
315
+ }
316
+
317
+ #configuration-text {
318
+ font-size: 0.6em;
319
+ }
320
+
321
+ #filter {
322
+ width: 4em;
323
+ padding: 0.4em 0.4em;
324
+ margin: 0.3em 0.7em 0.3em 0.7em;
325
+ }
326
+ }
327
+
328
+ @media (min-width: 600px) and (max-width: 992px) {
329
+ .mc {
330
+ grid-template-columns: 1fr 1fr;
331
+ }
332
+ }
333
+ </style>"
334
+ end
335
+ end
@@ -1,549 +1,5 @@
1
- require 'fileutils'
2
-
3
- class NxgReport
4
-
5
- def setup(location: "./NxgReport.html", title: "Features Summary")
6
- @nxg_report_path = location.empty? ? "./NxgReport.html" : location
7
- folder_check()
8
- @title = title
9
- @title_color = ''
10
- @execution_configuration = Hash.new()
11
- @auto_open = false
12
- @features = Hash.new()
13
- end
14
-
15
- def open_upon_execution(value:true)
16
- @auto_open = value
17
- end
18
-
19
- def set_envrionment(name: "")
20
- if name.empty?()
21
- return
22
- end
23
- @execution_configuration[:environment] = name
24
- end
25
-
26
- def set_app_version(no: "")
27
- if no.empty?()
28
- return
29
- end
30
- version_no = no.downcase.gsub("app", "").gsub("version", "").strip
31
- @execution_configuration[:app_version] = "App Version #{version_no}"
32
- end
33
-
34
- def set_release(name: "")
35
- if name.empty?()
36
- return
37
- end
38
- @execution_configuration[:release_name] = name
39
- end
40
-
41
- def set_os(name: "")
42
- if name.empty?()
43
- return
44
- end
45
- @execution_configuration[:os] = name
46
- end
47
-
48
- def set_device(name: "")
49
- if name.empty?()
50
- return
51
- end
52
- @execution_configuration[:device] = name
53
- end
54
-
55
- def set_execution(date: "")
56
- if date.empty?()
57
- return
58
- end
59
- @execution_configuration[:execution_date] = date
60
- end
61
-
62
- def log_test(feature_name: "", test_status: "")
63
- if feature_name.nil?() || feature_name.strip.empty?()
64
- log("Feature name cannot be empty.")
65
- return
66
- end
67
-
68
- if test_status.nil?() || test_status.strip.empty?()
69
- log("Test status cannot be empty.")
70
- return
71
- end
72
-
73
- test_pass = test_status.downcase.include?('pass')
74
- name = feature_name.strip()
75
-
76
- if @features.key? name
77
- @features[name][0]+=1
78
- @features[name][(test_pass) ? 1 : 2]+=1
79
- else
80
- @features[name]=[0,0,0]
81
- @features[name][0]+=1
82
- @features[name][(test_pass) ? 1 : 2]+=1
83
- end
84
- end
85
-
86
- def build()
87
- write()
88
- if @auto_open && report_success()
89
- system("open #{@nxg_report_path}")
90
- end
91
- end
92
-
93
- # Private methods
94
- def log(message)
95
- puts("🤖- #{message}")
96
- end
97
-
98
- def folder_check()
99
- folder = File.dirname(@nxg_report_path)
100
- FileUtils.mkdir_p(folder) unless File.directory?(folder)
101
- end
102
-
103
- def report_success()
104
- return File.file?(@nxg_report_path)
105
- end
106
-
107
- def clean()
108
- File.delete(@nxg_report_path) if File.file?(@nxg_report_path)
109
- end
110
-
111
- def htmlize(features)
112
- html_content = ''
113
- features.each do |name, metrics|
114
- html_content += "\n<div class=\"module dark #{metrics[2] != 0 ? 'danger' : ''} \">
115
- <div class=\"funcname\">
116
- <h4>#{name}</h4>
117
- </div>
118
- <div class=\"total\">
119
- <h6>Total</h6>
120
- <h4>#{metrics[0]}</h4>
121
- </div>
122
- <div class=\"pass\">
123
- <h6>Passed</h6>
124
- <h4>#{metrics[1]}</h4>
125
- </div>
126
- <div class=\"fail\">
127
- <h6>Failed</h6>
128
- <h4>#{metrics[2]}</h4>
129
- </div>
130
- </div>"
131
- end
132
- return html_content
133
- end
134
-
135
- def write()
136
- if @features.length == 0
137
- log("No tests logged, cannot build empty report.")
138
- return
139
- end
140
- clean()
141
- template = File.new(@nxg_report_path, 'w')
142
- template.puts("<html lang=\"en\">
143
- <head>
144
- <meta charset=\"UTF-8\" />
145
- <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
146
- <title id=\"meta-app-title\"></title>
147
- <link
148
- 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\"
149
- rel=\"stylesheet\"
150
- />
151
- <link
152
- href=\"https://fonts.googleapis.com/icon?family=Material+Icons\"
153
- rel=\"stylesheet\"
154
- />
155
- <style>
156
- :root {
157
- --dark-bg: rgb(41, 40, 40);
158
- --dark-primary: #050505;
159
- --dark-font: rgb(201, 201, 201);
160
- --dark-blue: rgb(0, 225, 255);
161
- --dark-green: rgba(115, 255, 0, 0.89);
162
- --dark-red: rgb(255, 0, 0);
163
-
164
- --light-bg: rgb(226, 226, 226);
165
- --light-primary: #fff;
166
- --light-font: rgb(44, 44, 44);
167
- --light-blue: rgb(1, 67, 165);
168
- --light-green: rgb(14, 138, 2);
169
- --light-red: rgb(255, 0, 0);
170
-
171
- --font: \"Open Sans\", sans-serif;
172
- --danger-bg: rgba(255, 0, 0, 0.185);
173
- }
174
-
175
- body {
176
- font-family: var(--font);
177
- margin: auto;
178
- }
179
-
180
- .wrapper {
181
- display: grid;
182
- grid-template-rows: auto auto 1fr;
183
- height: 100vh;
184
- width: 100vw;
185
- }
186
-
187
- .header {
188
- display: grid;
189
- grid-template-columns: 6fr 1fr;
190
- text-align: center;
191
- #{@title_color.empty?() ? "background: linear-gradient(to bottom right, #ff644e, #cb3018);" : "background-color: #{@title_color}"}
192
- }
193
-
194
- .test-config-area {
195
- padding-top: 2em;
196
- display: flex;
197
- flex-wrap: wrap;
198
- justify-content: space-around;
199
- text-align: center;
200
- }
201
-
202
- .config-item {
203
- display: flex;
204
-
205
- }
206
1
 
207
- .config-item-icon {
208
- font-size: 2em;
209
- padding-right: 0.5em;
210
- }
211
-
212
- .mc {
213
- display: grid;
214
- grid-template-columns: 1fr 1fr 1fr;
215
- grid-auto-rows: 70px;
216
- grid-gap: 0.5em;
217
- padding: 0.5em 2em;
218
- padding-top: 2em;
219
- }
220
-
221
- .footer {
222
- margin-bottom: 1em;
223
- padding: 3em;
224
- text-align: center;
225
- font-size: 0.7rem;
226
- font-weight: 600;
227
- }
228
-
229
- a {
230
- cursor: pointer;
231
- font-weight: 600;
232
- }
233
-
234
- .module {
235
- display: grid;
236
- place-items: center;
237
- grid-template-columns: 3fr 1fr 1fr 1fr;
238
- border-radius: 0.7rem;
239
- padding: 10px 10px;
240
- }
241
-
242
- .button-wrapper {
243
- place-items: center;
244
- }
245
-
246
- #theme-switch {
247
- width: 5em;
248
- height: 5em;
249
- background-color: Transparent;
250
- background-repeat: no-repeat;
251
- border: none;
252
- cursor: pointer;
253
- overflow: hidden;
254
- outline: none;
255
- margin: 0;
256
- position: relative;
257
- top: 50%;
258
- -ms-transform: translateY(-50%);
259
- transform: translateY(-50%);
260
- }
261
-
262
- h2,
263
- h3,
264
- h4,
265
- h5,
266
- h6 {
267
- text-align: center;
268
- margin: auto;
269
- }
270
-
271
- .total,
272
- .pass,
273
- .fail {
274
- display: grid;
275
- width: 100%;
276
- height: 100%;
277
- place-items: center;
278
- }
279
-
280
- body.dark {
281
- background-color: var(--dark-bg);
282
- color: var(--dark-font);
283
- }
284
-
285
- body.dark > .wrapper > .footer {
286
- color: var(--dark-font);
287
- }
288
-
289
- body.dark > .wrapper > .mc > .module {
290
- background-color: var(--dark-primary);
291
- color: var(--dark-font);
292
- }
293
-
294
- body.dark > .wrapper > .mc > .module > .total {
295
- color: var(--dark-blue);
296
- }
297
-
298
- body.dark > .wrapper > .mc > .module > .pass {
299
- color: var(--dark-green);
300
- }
301
-
302
- body.dark > .wrapper > .mc > .module > .fail {
303
- color: var(--dark-red);
304
- }
305
-
306
- body.dark > .wrapper > .mc > .module.danger {
307
- background-color: rgba(255, 0, 0, 0.185);
308
- }
309
-
310
- body.dark > .wrapper > .header {
311
- color: var(--dark-primary);
312
- }
313
-
314
- body.dark > .wrapper > .test-config-area > .config-item {
315
- color: var(--dark-font);
316
- }
317
-
318
- body.dark > .wrapper > .footer > p > span > a {
319
- color: var(--dark-font);
320
- }
321
-
322
- body.dark > .wrapper > .header > div > button > #theme-switch-icon {
323
- color: var(--dark-primary);
324
- }
325
-
326
- body {
327
- background-color: var(--light-bg);
328
- color: var(--dark-font);
329
- }
330
-
331
- body > .wrapper > .footer {
332
- color: var(--light-font);
333
- }
334
-
335
- body > .wrapper > .mc > .module {
336
- background-color: var(--light-primary);
337
- color: var(--light-font);
338
- }
339
-
340
- body > .wrapper > .mc > .module > .total {
341
- color: var(--light-blue);
342
- }
343
-
344
- body > .wrapper > .mc > .module > .pass {
345
- color: var(--light-green);
346
- }
347
-
348
- body > .wrapper > .mc > .module > .fail {
349
- color: var(--light-red);
350
- }
351
-
352
- body > .wrapper > .mc > .module.danger {
353
- background-color: var(--danger-bg);
354
- }
355
-
356
- body > .wrapper > .header {
357
- color: var(--light-primary);
358
- }
359
-
360
- body > .wrapper > .test-config-area > .config-item {
361
- color: var(--light-font);
362
- }
363
-
364
- body > .wrapper > .footer > p > span > a {
365
- color: var(--light-font);
366
- }
367
-
368
- body > .wrapper > .header > div > button > #theme-switch-icon {
369
- color: var(--light-primary);
370
- }
371
-
372
- @media only screen and (max-width: 600px) {
373
- h1 {
374
- font-size: 24px;
375
- }
376
-
377
- .mc {
378
- grid-template-columns: 1fr;
379
- padding: 0.5em 0.5em;
380
- padding-top: 1em;
381
- }
382
- }
383
-
384
- @media (min-width: 600px) and (max-width: 992px) {
385
- .mc {
386
- grid-template-columns: 1fr 1fr;
387
- }
388
- }
389
- </style>
390
- </head>
391
- <body class=\"dark\" id=\"app\">
392
- <div class=\"wrapper\">
393
- <div class=\"header\">
394
- <h1 id=\"app-title\"></h1>
395
- <div class=\"button-wrapper\">
396
- <button id=\"theme-switch\" onclick=\"handleThemeSwitch()\">
397
- <i class=\"material-icons\" id=\"theme-switch-icon\">brightness_2</i>
398
- </button>
399
- </div>
400
- </div>
401
- #{config_htmlize()}
402
- <div class=\"mc\">
403
- #{htmlize(@features)}
404
- </div>
405
- <div class=\"footer\">
406
- <p>
407
- Developed by
408
- <span
409
- ><a
410
- href=\"https://www.linkedin.com/in/balabharathijayaraman\"
411
- rel=\"nofollow\"
412
- target=\"_blank\"
413
- >Balabharathi Jayaraman</a
414
- ></span
415
- >
416
- </p>
417
- </div>
418
- </div>
419
- </body>
420
- <script>
421
- var appTitle = \"#{@title}\";
422
- var theme = \"dark\";
423
-
424
- window.onload = function () {
425
- document.getElementById(
426
- \"meta-app-title\"
427
- ).innerHTML = `Home | ${appTitle}`;
428
- document.getElementById(\"app-title\").innerHTML = appTitle;
429
- };
430
-
431
- function handleThemeSwitch() {
432
- if (theme === \"dark\") {
433
- theme = \"light\";
434
- document.getElementById(\"app\").classList.remove(\"dark\");
435
- document.getElementById(\"theme-switch-icon\").innerHTML = \"wb_sunny\";
436
- document.getElementById(\"theme-switch-icon\");
437
- return;
438
- }
439
- if (theme === \"light\") {
440
- theme = \"dark\";
441
- document.getElementById(\"app\").classList.add(\"dark\");
442
- document.getElementById(\"theme-switch-icon\").innerHTML = \"brightness_2\";
443
- }
444
- }
445
- </script>
446
- </html>
447
- ")
448
- template.close()
449
- end
450
-
451
- def config_htmlize()
452
-
453
- if @execution_configuration.length == 0
454
- return
455
- end
456
-
457
- return "
458
- <div class=\"test-config-area\">
459
- #{execution_date_htmllize()}
460
- #{device_htmllize()}
461
- #{os_htmllize()}
462
- #{release_name_htmllize()}
463
- #{app_version_htmllize()}
464
- #{environment_htmllize()}
465
- </div>"
466
- end
467
-
468
- def environment_htmllize()
469
- if !@execution_configuration.key?(:environment)
470
- return
471
- end
472
-
473
- return "<div class=\"config-item\">
474
- <i class=\"config-item-icon material-icons\" id=\"theme-switch-icon\"
475
- >layers</i
476
- >
477
- <h5>#{@execution_configuration[:environment]}</h5>
478
- </div>"
479
- end
480
-
481
- def app_version_htmllize()
482
- if !@execution_configuration.key?(:app_version)
483
- return
484
- end
485
-
486
- return "<div class=\"config-item\">
487
- <i class=\"config-item-icon material-icons\" id=\"theme-switch-icon\"
488
- >info</i
489
- >
490
- <h5>#{@execution_configuration[:app_version]}</h5>
491
- </div>"
492
- end
493
-
494
- def release_name_htmllize()
495
- if !@execution_configuration.key?(:release_name)
496
- return
497
- end
498
-
499
- return "<div class=\"config-item\">
500
- <i class=\"config-item-icon material-icons\" id=\"theme-switch-icon\"
501
- >bookmark</i
502
- >
503
- <h5>#{@execution_configuration[:release_name]}</h5>
504
- </div>"
505
- end
506
-
507
- def os_htmllize()
508
- if !@execution_configuration.key?(:os)
509
- return
510
- end
511
-
512
- return "<div class=\"config-item\">
513
- <i class=\"config-item-icon material-icons\" id=\"theme-switch-icon\"
514
- >settings</i
515
- >
516
- <h5>#{@execution_configuration[:os]}</h5>
517
- </div>"
518
- end
519
-
520
- def device_htmllize()
521
- if !@execution_configuration.key?(:device)
522
- return
523
- end
524
-
525
- return "<div class=\"config-item\">
526
- <i class=\"config-item-icon material-icons\" id=\"theme-switch-icon\"
527
- >devices_other</i
528
- >
529
- <h5>#{@execution_configuration[:device]}</h5>
530
- </div>"
531
- end
532
-
533
- def execution_date_htmllize()
534
- if !@execution_configuration.key?(:execution_date)
535
- return
536
- end
537
-
538
- return "<div class=\"config-item\">
539
- <i class=\"config-item-icon material-icons\" id=\"theme-switch-icon\"
540
- >date_range</i
541
- >
542
- <h5>#{@execution_configuration[:execution_date]}</h5>
543
- </div>"
544
- end
545
-
546
- private :log, :clean, :write, :htmlize, :report_success, :config_htmlize
547
- end
2
+ require 'fileutils'
3
+ require 'nxgcore.rb'
548
4
 
549
- $NxgReport = NxgReport.new()
5
+ $NxgReport = NxgCore.new().instance()
metadata CHANGED
@@ -1,24 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nxgreport
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Balabharathi Jayaraman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-06 00:00:00.000000000 Z
11
+ date: 2020-09-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: "A simple light weighted gem to generate a beautiful emailable test report.
14
- \n\nIt displays a single view where tests (total, pass, fail) are grouped by functionality.
15
- The result is a single static HTML file with an option to switch between dark &
16
- light modes."
13
+ description: Generate a beautiful static test report.
17
14
  email: balabharathi.jayaraman@gmail.com
18
15
  executables: []
19
16
  extensions: []
20
17
  extra_rdoc_files: []
21
18
  files:
19
+ - lib/nxgcore.rb
20
+ - lib/nxgcss.rb
22
21
  - lib/nxgreport.rb
23
22
  homepage: https://rubygemspec.org/gems/nxgreport
24
23
  licenses:
@@ -42,7 +41,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
42
41
  - !ruby/object:Gem::Version
43
42
  version: '0'
44
43
  requirements: []
45
- rubygems_version: 3.0.3
44
+ rubygems_version: 3.1.4
46
45
  signing_key:
47
46
  specification_version: 4
48
47
  summary: Next Gen Report