1 package com.atlassian.webdriver.testing.rule;
2
3 import com.atlassian.webdriver.browsers.WebDriverBrowserAutoInstall;
4 import com.atlassian.webdriver.debug.DefaultJavaScriptErrorRetriever;
5 import com.atlassian.webdriver.debug.JavaScriptErrorInfo;
6 import com.atlassian.webdriver.debug.JavaScriptErrorRetriever;
7 import com.google.common.annotations.VisibleForTesting;
8 import com.google.common.base.Joiner;
9 import com.google.common.base.Supplier;
10 import com.google.common.base.Suppliers;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.collect.ImmutableSet;
13 import org.junit.rules.TestWatcher;
14 import org.junit.runner.Description;
15 import org.openqa.selenium.WebDriver;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import javax.inject.Inject;
20 import java.util.List;
21 import java.util.Set;
22
23 import static com.google.common.base.Preconditions.checkNotNull;
24
25
26
27
28
29
30
31
32
33 public class JavaScriptErrorsRule extends TestWatcher
34 {
35 private static final Logger DEFAULT_LOGGER = LoggerFactory.getLogger(JavaScriptErrorsRule.class);
36
37 private final Logger logger;
38 private final Supplier<? extends WebDriver> webDriver;
39 private final ImmutableSet<String> errorsToIgnore;
40 private final boolean failOnJavaScriptErrors;
41 private final JavaScriptErrorRetriever errorRetriever;
42
43 public JavaScriptErrorsRule(Supplier<? extends WebDriver> webDriver)
44 {
45 this(webDriver, DEFAULT_LOGGER);
46 }
47
48 public JavaScriptErrorsRule(Supplier<? extends WebDriver> webDriver, Logger logger)
49 {
50 this(new DefaultJavaScriptErrorRetriever(webDriver), webDriver, logger, ImmutableSet.<String>of(), false);
51 }
52
53 @Inject
54 public JavaScriptErrorsRule(WebDriver webDriver)
55 {
56 this(Suppliers.ofInstance(checkNotNull(webDriver, "webDriver")), DEFAULT_LOGGER);
57 }
58
59 public JavaScriptErrorsRule(WebDriver webDriver, Logger logger)
60 {
61 this(Suppliers.ofInstance(checkNotNull(webDriver, "webDriver")));
62 }
63
64 public JavaScriptErrorsRule()
65 {
66 this(WebDriverBrowserAutoInstall.driverSupplier());
67 }
68
69 protected JavaScriptErrorsRule(JavaScriptErrorRetriever errorRetriever,
70 Supplier<? extends WebDriver> webDriver,
71 Logger logger,
72 Set<String> errorsToIgnore,
73 boolean failOnJavaScriptErrors)
74 {
75 this.errorRetriever = checkNotNull(errorRetriever, "errorRetriever");
76 this.webDriver = checkNotNull(webDriver, "webDriver");
77 this.logger = checkNotNull(logger, "logger");
78 this.errorsToIgnore = ImmutableSet.copyOf(checkNotNull(errorsToIgnore, "errorsToIgnore"));
79 this.failOnJavaScriptErrors = failOnJavaScriptErrors;
80 }
81
82
83
84
85
86
87
88 public JavaScriptErrorsRule errorRetriever(JavaScriptErrorRetriever errorRetriever)
89 {
90 return new JavaScriptErrorsRule(errorRetriever, this.webDriver, this.logger, this.errorsToIgnore,
91 this.failOnJavaScriptErrors);
92 }
93
94
95
96
97
98
99
100 public JavaScriptErrorsRule errorsToIgnore(Set<String> errorsToIgnore)
101 {
102 return new JavaScriptErrorsRule(this.errorRetriever, this.webDriver, this.logger, errorsToIgnore,
103 this.failOnJavaScriptErrors);
104 }
105
106
107
108
109
110
111 public JavaScriptErrorsRule logger(Logger logger)
112 {
113 return new JavaScriptErrorsRule(this.errorRetriever, this.webDriver, logger, this.errorsToIgnore,
114 this.failOnJavaScriptErrors);
115 }
116
117
118
119
120
121
122
123 public JavaScriptErrorsRule failOnJavaScriptErrors(boolean failOnJavaScriptErrors)
124 {
125 return new JavaScriptErrorsRule(this.errorRetriever, this.webDriver, this.logger, this.errorsToIgnore,
126 failOnJavaScriptErrors);
127 }
128
129 @Override
130 @VisibleForTesting
131 public void finished(final Description description)
132 {
133 if (errorRetriever.isErrorRetrievalSupported())
134 {
135 List<String> errors = getErrors();
136 if (errors.isEmpty())
137 {
138
139 logger.info("----- Test '{}' finished with 0 JS errors. ", description.getMethodName());
140 }
141 else
142 {
143
144 logger.warn("----- Test '{}' finished with {} JS error(s). ", description.getMethodName(), getErrors().size());
145 logger.warn("----- START CONSOLE OUTPUT DUMP\n\n{}\n", getConsoleOutput(errors));
146 logger.warn("----- END CONSOLE OUTPUT DUMP");
147 if (failOnJavaScriptErrors)
148 {
149 throw new RuntimeException("Test failed due to javascript errors being detected: \n" + getConsoleOutput());
150 }
151 }
152 }
153 else
154 {
155 logger.info("Unable to provide console output. Console output is currently only supported on Firefox.");
156 }
157 }
158
159 @VisibleForTesting
160 public String getConsoleOutput()
161 {
162 return getConsoleOutput(getErrors());
163 }
164
165 private String getConsoleOutput(List<String> errors)
166 {
167 return Joiner.on("\n").join(errors);
168 }
169
170
171
172
173
174
175 @VisibleForTesting
176 protected List<String> getErrors()
177 {
178 final ImmutableList.Builder<String> ret = ImmutableList.builder();
179 for (JavaScriptErrorInfo error : errorRetriever.getErrors())
180 {
181 if (errorsToIgnore.contains(error.getMessage()))
182 {
183 logger.debug("Ignoring JS error: {}", error);
184 }
185 else
186 {
187 ret.add(error.getDescription());
188 }
189 }
190 return ret.build();
191 }
192 }