1 package net.avcompris.guixer.core;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static net.avcompris.guixer.core.Validations.assertValidLabel;
5 import static org.apache.commons.lang3.StringUtils.normalizeSpace;
6 import static org.apache.commons.lang3.StringUtils.split;
7 import static org.junit.jupiter.api.Assertions.assertFalse;
8 import static org.junit.jupiter.api.Assertions.assertTrue;
9 import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;
10 import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;
11
12 import java.io.File;
13 import java.io.IOException;
14
15 import javax.annotation.Nullable;
16
17 import org.apache.commons.io.FileUtils;
18 import org.apache.commons.lang3.ArrayUtils;
19 import org.openqa.selenium.OutputType;
20 import org.openqa.selenium.TakesScreenshot;
21 import org.openqa.selenium.WebDriver;
22 import org.openqa.selenium.WebDriverException;
23 import org.openqa.selenium.WebElement;
24 import org.openqa.selenium.support.ui.Select;
25 import org.openqa.selenium.support.ui.WebDriverWait;
26
27 final class CommandSeleniumImpl implements Command {
28
29 private final WebDriver driver;
30 private final String baseURL;
31 private final Context context;
32
33 public CommandSeleniumImpl(
34 final WebDriver driver,
35 final String baseURL,
36 final Context context) {
37
38 this.driver = checkNotNull(driver, "driver");
39 this.baseURL = checkNotNull(baseURL, "baseURL");
40 this.context = checkNotNull(context, "context");
41 }
42
43 @Override
44 public Command waitFor(final String locator) {
45
46 return waitFor(locator, 10);
47 }
48
49 @Override
50 public Command waitFor(final String locator, final int timeOutSeconds) {
51
52 checkNotNull(locator, "locator");
53
54 final WebDriverWait wait = new WebDriverWait(driver, timeOutSeconds);
55
56 wait.until(presenceOfElementLocated(LocatorUtils.by(locator)));
57
58 return this;
59 }
60
61 @Override
62 public Command waitForVisible(final String locator) {
63
64 return waitForVisible(locator, 10);
65 }
66
67 @Override
68 public Command waitForVisible(final String locator, final int timeOutSeconds) {
69
70 checkNotNull(locator, "locator");
71
72 final WebDriverWait wait = new WebDriverWait(driver, timeOutSeconds);
73
74 wait.until(visibilityOfElementLocated(LocatorUtils.by(locator)));
75
76 return this;
77 }
78
79 @Override
80 public Command sleep(final int ms) {
81
82 try {
83
84 Thread.sleep(ms);
85
86 } catch (final InterruptedException e) {
87
88 throw new RuntimeException(e);
89 }
90
91 return this;
92 }
93
94 @Override
95 public Command takeScreenshot() throws IOException {
96
97 return takeScreenshotWithSuffix(".png");
98 }
99
100 private Command takeScreenshotWithSuffix(final String suffix) throws IOException {
101
102 context.incStepCount();
103
104 final File file;
105
106 try {
107
108 file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
109
110 } catch (final WebDriverException e) {
111
112 e.printStackTrace();
113
114 throw e;
115 }
116
117 final File testDir = context.getSubDir();
118
119 FileUtils.copyFile(file, new File(testDir, context.formatStepCount() + suffix));
120
121 return this;
122 }
123
124 @Override
125 public Command takeScreenshot(final String label) throws IOException {
126
127 assertValidLabel(label);
128
129 return takeScreenshotWithSuffix("-" + label + ".png");
130 }
131
132 @Override
133 public Command get() {
134
135 driver.get(baseURL);
136
137 return this;
138 }
139
140 @Override
141 public SwitchTo switchTo() {
142
143 return new SwitchToSeleniumImpl(
144 driver.switchTo(),
145 this);
146 }
147
148 @Override
149 public Command log(@Nullable final String text) {
150
151
152
153 return this;
154 }
155
156 private WebElement findElement(final String locator) {
157
158 return driver.findElement(LocatorUtils.by(locator));
159 }
160
161 @Override
162 public Command clear(final String locator) {
163
164 findElement(locator).clear();
165
166 return this;
167 }
168
169 @Override
170 public Command click(final String locator) {
171
172 findElement(locator).click();
173
174 return this;
175 }
176
177 @Override
178 public Command submit(final String locator) {
179
180 findElement(locator).submit();
181
182 return this;
183 }
184
185 @Override
186 public Command assertHasClass(final String locator, final String className) {
187
188 return wrapAssertion(locator, className, () -> {
189
190 final String classNames = findElement(locator).getAttribute("class");
191
192 final String normalizedClassNames = normalizeSpace(classNames);
193
194 assertTrue(ArrayUtils.contains(split(normalizedClassNames, " "), className),
195 "Classes should include: " + className + ", but was: " + normalizedClassNames);
196 });
197 }
198
199 @Override
200 public Command assertDoesntHaveClass(final String locator, final String className) {
201
202 return wrapAssertion(locator, className, () -> {
203
204 final String classNames = findElement(locator).getAttribute("class");
205
206 final String normalizedClassNames = normalizeSpace(classNames);
207
208 assertFalse(ArrayUtils.contains(split(normalizedClassNames, " "), className),
209 "Classes should not include: " + className + ", but was: " + normalizedClassNames);
210 });
211 }
212
213 private Command wrapAssertion(final String arg0, final String arg1, final Runnable runnable) {
214
215 final String assertionName = extractAssertMethodName();
216
217 final Assertionn.html#Assertion">Assertion assertion = new Assertion(assertionName, arg0, arg1);
218
219 context.addAssertion(assertion);
220
221 try {
222
223 runnable.run();
224
225 assertion.setSuccess();
226
227 } catch (final RuntimeException | Error e) {
228
229 e.printStackTrace();
230
231 assertion.setException(e);
232 }
233
234 return this;
235 }
236
237 private static String extractAssertMethodName() {
238
239 for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
240
241 final String methodName = ste.getMethodName();
242
243 if (methodName.startsWith("assert")) {
244
245 return methodName;
246 }
247 }
248
249 throw new IllegalStateException("Cannot extract assertMethodName");
250 }
251
252 @Override
253 public Command sendKeys(final String locator, final CharSequence... keys) {
254
255 findElement(locator).sendKeys(keys);
256
257 return this;
258 }
259
260 @Override
261 public Command sendKeysSecret(final String locator, final String secret) {
262
263 findElement(locator).sendKeys(secret);
264
265 return this;
266 }
267
268 @Override
269 public Command select(final String location, final int value) throws IOException {
270
271 return select(location, Integer.toString(value));
272 }
273
274 @Override
275 public Command select(final String location, final String value) throws IOException {
276
277 final Select select = new Select(findElement(location));
278
279 select.selectByValue(value);
280
281 return this;
282 }
283
284 @Override
285 public Command skip() throws IOException {
286
287 throw new IllegalStateException();
288 }
289
290 @Override
291 public Command when(final String label, final boolean condition) throws IOException {
292
293 throw new IllegalStateException();
294 }
295
296 @Override
297 public Command when(final boolean condition) throws IOException {
298
299 throw new IllegalStateException();
300 }
301 }