1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package io.wcm.qa.glnm.reporting;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.UUID;
29 import java.util.function.Consumer;
30
31 import org.apache.commons.io.FileUtils;
32 import org.apache.commons.lang3.RandomStringUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.openqa.selenium.OutputType;
35 import org.openqa.selenium.TakesScreenshot;
36 import org.openqa.selenium.WebDriver;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.galenframework.config.GalenConfig;
41 import com.galenframework.config.GalenProperty;
42 import com.galenframework.reports.GalenTestInfo;
43 import com.galenframework.reports.HtmlReportBuilder;
44 import com.galenframework.utils.GalenUtils;
45 import com.google.common.html.HtmlEscapers;
46
47 import io.qameta.allure.Allure;
48 import io.qameta.allure.AllureLifecycle;
49 import io.qameta.allure.model.Attachment;
50 import io.qameta.allure.model.Status;
51 import io.qameta.allure.model.StepResult;
52 import io.wcm.qa.glnm.configuration.GaleniumConfiguration;
53 import io.wcm.qa.glnm.context.GaleniumContext;
54 import io.wcm.qa.glnm.exceptions.GaleniumException;
55
56
57
58
59
60
61 public final class GaleniumReportUtil {
62
63 private static final List<GalenTestInfo> GLOBAL_GALEN_RESULTS = new ArrayList<GalenTestInfo>();
64
65 private static final Logger LOG = LoggerFactory.getLogger(GaleniumReportUtil.class);
66 private static final String PATH_GALEN_REPORT = GaleniumConfiguration.getReportDirectory() + "/galen";
67 private static final String PATH_SCREENSHOTS_ROOT = GaleniumConfiguration.getReportDirectory() + "/screenshots";
68
69 private GaleniumReportUtil() {
70
71 }
72
73
74
75
76
77
78
79 public static void addGalenResult(GalenTestInfo galenTestInfo) {
80 if (isAddResult(galenTestInfo)) {
81 GLOBAL_GALEN_RESULTS.add(galenTestInfo);
82 }
83 }
84
85
86
87
88
89
90
91
92
93
94 public static void addImageComparisonResult(File actual, File expected, File diff) {
95 if (LOG.isDebugEnabled()) {
96 LOG.debug("attaching screendiff results.");
97 }
98 if (LOG.isTraceEnabled()) {
99 LOG.trace("actual: " + actual);
100 LOG.trace("expected: " + actual);
101 LOG.trace("diff: " + actual);
102 }
103
104
105 addLabel("testType", "screenshotDiff");
106
107
108
109 addPngAttachment("diff", diff, true);
110
111 addPngAttachment("actual", actual, true);
112
113 addPngAttachment("expected", expected, true);
114
115 }
116
117
118
119
120
121
122
123 public static void addLabel(String key, String value) {
124 Allure.label(key, value);
125 }
126
127
128
129
130
131
132
133 public static void addPngAttachment(String name, File file) {
134 addPngAttachment(name, file, false);
135 }
136
137
138
139
140
141
142
143
144 public static void addPngAttachment(String name, File file, boolean attachToTestCase) {
145 FileInputStream inputStream;
146 try {
147 inputStream = new FileInputStream(file);
148 addAttachment(
149 name,
150 "image/png",
151 inputStream,
152 ".png", attachToTestCase);
153 inputStream.close();
154 }
155 catch (IOException ex) {
156 throw new GaleniumException("When adding PNG attachment from: " + file, ex);
157 }
158 }
159
160
161
162
163
164
165
166 @SuppressWarnings("PMD.AvoidCatchingNPE")
167 public static void createGalenHtmlReport(List<GalenTestInfo> testInfos) {
168 try {
169 new HtmlReportBuilder().build(testInfos, PATH_GALEN_REPORT);
170 }
171 catch (IOException | NullPointerException ex) {
172 LOG.error("could not generate Galen report.", ex);
173 }
174 }
175
176
177
178
179
180
181 public static void createGalenReports() {
182 createGalenHtmlReport(GLOBAL_GALEN_RESULTS);
183 }
184
185
186
187
188
189
190
191
192 public static String escapeHtml(String string) {
193 String escapedString = HtmlEscapers.htmlEscaper().escape(StringUtils.stripToEmpty(string));
194 return StringUtils.replace(escapedString, "\n", "</br>");
195 }
196
197
198
199
200
201
202
203 public static void failStep(String step) {
204 if (LOG.isTraceEnabled()) {
205 LOG.trace("fail step: " + step);
206 }
207 Allure.getLifecycle().updateStep(step, new FailStep());
208 }
209
210
211
212
213
214
215
216 public static void passStep(String step) {
217 if (LOG.isTraceEnabled()) {
218 LOG.trace("pass step: " + step);
219 }
220 Allure.getLifecycle().updateStep(step, new PassStep());
221 }
222
223
224
225
226
227
228
229
230 public static String startStep(String name) {
231 if (LOG.isTraceEnabled()) {
232 LOG.trace("start step: " + name);
233 }
234 String uuid = UUID.randomUUID().toString();
235 StepResult result = new StepResult().setName(name);
236 Allure.getLifecycle().startStep(uuid, result);
237 return uuid;
238 }
239
240
241
242
243
244
245
246
247
248 public static String startStep(String parentStep, String stepName) {
249 if (LOG.isTraceEnabled()) {
250 LOG.trace("start step: " + stepName);
251 }
252 String uuid = UUID.randomUUID().toString();
253 StepResult result = new StepResult().setName(stepName);
254 Allure.getLifecycle().startStep(parentStep, uuid, result);
255 return uuid;
256 }
257
258
259
260
261
262
263
264 public static void step(String stepName) {
265 if (LOG.isInfoEnabled()) {
266 LOG.info("STEP(" + stepName + ")");
267 }
268 Allure.step(stepName);
269 }
270
271
272
273
274
275
276
277 public static void stepFailed(String stepName) {
278 if (LOG.isInfoEnabled()) {
279 LOG.info("FAILED_STEP(" + stepName + ")");
280 }
281 Allure.step(stepName, Status.FAILED);
282 }
283
284
285
286
287
288
289 public static void stopStep() {
290 if (LOG.isTraceEnabled()) {
291 LOG.trace("stop step");
292 }
293 Allure.getLifecycle().stopStep();
294 }
295
296
297
298
299
300
301
302 public static void takeFullScreenshot() {
303 String step = startStep("taking full page screenshot");
304 GalenConfig galenConfig = GalenConfig.getConfig();
305 boolean fullPageScreenshotActivatedInGalen = galenConfig.getBooleanProperty(GalenProperty.SCREENSHOT_FULLPAGE);
306 if (!fullPageScreenshotActivatedInGalen) {
307 if (LOG.isTraceEnabled()) {
308 LOG.trace("activate full page screenshot in Galen before screenshot");
309 }
310 galenConfig.setProperty(GalenProperty.SCREENSHOT_FULLPAGE, "true");
311 }
312 try {
313 File screenshotFile = GalenUtils.makeFullScreenshot(GaleniumContext.getDriver());
314 attachScreenshotFile(screenshotFile);
315 passStep(step);
316 }
317 catch (IOException | InterruptedException ex) {
318 LOG.error("Could not take full screenshot.", ex);
319 }
320 finally {
321 if (!fullPageScreenshotActivatedInGalen) {
322 if (LOG.isTraceEnabled()) {
323 LOG.trace("deactivate full page screenshot in Galen after screenshot");
324 }
325 galenConfig.setProperty(GalenProperty.SCREENSHOT_FULLPAGE, "false");
326 }
327 stopStep();
328 }
329 }
330
331
332
333
334
335
336 public static void takeScreenshot() {
337 String randomAlphanumeric = RandomStringUtils.randomAlphanumeric(12);
338 takeScreenshot(randomAlphanumeric, getTakesScreenshot());
339 }
340
341
342
343
344
345
346
347
348 public static void takeScreenshot(String resultName, TakesScreenshot takesScreenshot) {
349 takeScreenshot(resultName, takesScreenshot, true);
350 }
351
352
353
354
355
356
357
358
359
360 public static void takeScreenshot(String resultName, TakesScreenshot takesScreenshot, boolean dedicatedStep) {
361 String step = null;
362 if (dedicatedStep) {
363 step = startStep("taking screenshot: " + takesScreenshot);
364 }
365 File screenshotFile = takesScreenshot.getScreenshotAs(OutputType.FILE);
366 attachScreenshotFile(resultName, screenshotFile);
367 if (dedicatedStep) {
368 passStep(step);
369 stopStep();
370 }
371 }
372
373
374
375
376
377
378
379 public static void takeScreenshot(TakesScreenshot takesScreenshot) {
380 String randomAlphanumeric = RandomStringUtils.randomAlphanumeric(12);
381 takeScreenshot(randomAlphanumeric, takesScreenshot);
382 }
383
384
385
386
387
388
389
390
391
392
393 public static void updateStep(String step, Consumer<StepResult> update) {
394 Allure.getLifecycle().updateStep(step, update);
395 }
396
397
398
399
400
401
402
403
404 public static void updateStepName(String step, String updatedStepName) {
405 if (LOG.isTraceEnabled()) {
406 LOG.trace("update step name: " + step + " -> " + updatedStepName);
407 }
408 updateStep(step, new Consumer<StepResult>() {
409
410 @Override
411 public void accept(StepResult result) {
412 result.setName(updatedStepName);
413 }
414 });
415 }
416
417 private static void addAttachment(String name, String type, FileInputStream inputStream, String extension, boolean attachToTestCase) {
418 if (attachToTestCase) {
419 attachToTestCase(name, type, inputStream, extension);
420 return;
421 }
422 attachToCurrentStep(name, type, inputStream, extension);
423 }
424
425 private static void attachScreenshotFile(File screenshotFile) {
426 attachScreenshotFile(screenshotFile.getName(), screenshotFile);
427 }
428
429 private static void attachScreenshotFile(String resultName, File screenshotFile) {
430 if (screenshotFile != null) {
431 if (LOG.isTraceEnabled()) {
432 LOG.trace("screenshot taken: " + screenshotFile.getPath());
433 }
434 try {
435 String destFilename = System.currentTimeMillis() + "_" + resultName + ".png";
436 File destFile = new File(PATH_SCREENSHOTS_ROOT, destFilename);
437 FileUtils.copyFile(screenshotFile, destFile);
438 if (LOG.isTraceEnabled()) {
439 LOG.trace("copied screenshot: " + destFile.getPath());
440 }
441 addPngAttachment("Screenshot: " + resultName, destFile);
442 if (FileUtils.deleteQuietly(screenshotFile)) {
443 if (LOG.isTraceEnabled()) {
444 LOG.trace("deleted screenshot file: " + screenshotFile.getPath());
445 }
446 }
447 else if (LOG.isTraceEnabled()) {
448 LOG.trace("could not delete screenshot file: " + screenshotFile.getPath());
449 }
450 }
451 catch (IOException ex) {
452 LOG.error("Cannot copy screenshot.", ex);
453 }
454 }
455 else if (LOG.isDebugEnabled()) {
456 LOG.debug("screenshot file is null.");
457 }
458 }
459
460 private static void attachToCurrentStep(String name, String type, FileInputStream inputStream, String extension) {
461 Allure.addAttachment(name, type, inputStream, extension);
462 }
463
464 @SuppressWarnings("deprecation")
465 private static void attachToTestCase(String name, String type, FileInputStream inputStream, String extension) {
466 AllureLifecycle lifecycle = Allure.getLifecycle();
467 String source = lifecycle.prepareAttachment(name, type, extension);
468 lifecycle.writeAttachment(source, inputStream);
469 Attachment attachment = new Attachment();
470 attachment.setName(name);
471 attachment.setSource(source);
472 lifecycle.updateTestCase(result -> result.getAttachments().add(attachment));
473 }
474
475 private static TakesScreenshot getTakesScreenshot() {
476 WebDriver driver = GaleniumContext.getDriver();
477 TakesScreenshot takesScreenshot = getTakesScreenshot(driver);
478 return takesScreenshot;
479 }
480
481 private static TakesScreenshot getTakesScreenshot(WebDriver driver) {
482 TakesScreenshot takesScreenshot;
483 if (driver instanceof TakesScreenshot) {
484 takesScreenshot = (TakesScreenshot)driver;
485 }
486 else {
487 throw new GaleniumException("driver cannot take screenshot");
488 }
489 return takesScreenshot;
490 }
491
492 private static boolean isAddResult(GalenTestInfo galenTestInfo) {
493 if (galenTestInfo == null) {
494 return false;
495 }
496 if (GaleniumConfiguration.isOnlyReportGalenErrors()) {
497 if ((!galenTestInfo.isFailed()) && (galenTestInfo.getReport().fetchStatistic().getWarnings() == 0)) {
498 return false;
499 }
500 }
501 return true;
502 }
503
504 private static final class FailStep implements Consumer<StepResult> {
505
506 @Override
507 public void accept(StepResult t) {
508 t.setStatus(Status.FAILED);
509 }
510 }
511
512 private static final class PassStep implements Consumer<StepResult> {
513
514 @SuppressWarnings("deprecation")
515 @Override
516 public void accept(StepResult t) {
517 if (t.getStatus() == null) {
518 t.setStatus(Status.PASSED);
519 }
520 }
521 }
522 }