View Javadoc
1   package io.guixer.tools.monkey;
2   
3   import static com.google.common.base.Preconditions.checkNotNull;
4   import static com.google.common.collect.Lists.newArrayList;
5   import static io.guixer.tools.Locators.inferLocator;
6   import static org.apache.commons.lang3.StringUtils.isBlank;
7   import static org.apache.commons.lang3.StringUtils.substringAfterLast;
8   
9   import java.io.IOException;
10  import java.util.List;
11  import java.util.Locale;
12  
13  import javax.annotation.Nullable;
14  
15  import org.apache.commons.lang3.ArrayUtils;
16  import org.apache.commons.lang3.NotImplementedException;
17  import org.apache.commons.lang3.RandomUtils;
18  import org.openqa.selenium.By;
19  import org.openqa.selenium.WebDriver;
20  import org.openqa.selenium.WebElement;
21  
22  import io.guixer.tools.GuixerConsumer;
23  import io.guixer.tools.RunnerContext;
24  import io.guixer.types.AttributeScope;
25  
26  public class MonkeySteps implements GuixerConsumer {
27  
28  	private final int stepCount;
29  
30  	public MonkeySteps(
31  		final int stepCount
32  	) {
33  
34  		this.stepCount = stepCount;
35  	}
36  
37  	@Override
38  	public void accept(
39  		final RunnerContext context
40  	) throws IOException {
41  
42  		checkNotNull(context, "context");
43  
44  		for (int stepIndex = 1; stepIndex <= stepCount; ++stepIndex) {
45  
46  			final WebDriver driver = context.getDriver();
47  
48  			final List<WebElement> anchors = driver.findElements(By.tagName("a"));
49  
50  			final List<WebElement> buttons = driver.findElements(By.tagName("button"));
51  
52  			final List<WebElement> inputs = driver.findElements(By.tagName("input"));
53  
54  			final List<Interactable> interactables = newArrayList();
55  
56  			for (final WebElement anchor : anchors) {
57  
58  				@Nullable
59  				final Interactable interactable = Interactable.fromAnchor(driver, anchor);
60  
61  				if (interactable != null) {
62  
63  					interactables.add(interactable);
64  				}
65  			}
66  
67  			for (final WebElement button : buttons) {
68  
69  				@Nullable
70  				final Interactable interactable = Interactable.fromButton(driver, button);
71  
72  				if (interactable != null) {
73  
74  					interactables.add(interactable);
75  				}
76  			}
77  
78  			for (final WebElement input : inputs) {
79  
80  				@Nullable
81  				final Interactable interactable = Interactable.fromInput(driver, input);
82  
83  				if (interactable != null) {
84  
85  					interactables.add(interactable);
86  				}
87  			}
88  
89  			if (interactables.isEmpty()) {
90  
91  				// context.failure("No more interactable elements");
92  
93  				// context.message("No more interactable elements");
94  
95  				// break;
96  
97  				context.intent("Monkey " + stepIndex + "/" + stepCount + ": No more interactable elements: We go back");
98  
99  				context.tag(AttributeScope.STEP, "no_more_interactables");
100 
101 				context.executeScript("history.back()");
102 
103 				context.sleep(2);
104 
105 				context.takeScreenshot();
106 
107 			} else {
108 
109 				final Interactable interactable = interactables.get(RandomUtils.nextInt(0, interactables.size()));
110 
111 				context.intent("Monkey " + stepIndex + "/" + stepCount + ": We click at random: " + interactable.label);
112 
113 				interactable.interact(context);
114 
115 				context.sleep(2);
116 
117 				context.takeScreenshot();
118 			}
119 		}
120 	}
121 
122 	private static abstract class Interactable {
123 
124 		public final String label;
125 
126 		private Interactable(
127 			final String label
128 		) {
129 
130 			this.label = checkNotNull(label, "label");
131 		}
132 
133 		public abstract void interact(
134 			RunnerContext context
135 		) throws IOException;
136 
137 		@Nullable
138 		public static Interactable fromAnchor(
139 			final WebDriver driver,
140 			final WebElement anchor
141 		) {
142 
143 			if (!anchor.isDisplayed() || !anchor.isEnabled()) {
144 
145 				return null;
146 			}
147 
148 			@Nullable
149 			final String href = anchor.getAttribute("href");
150 
151 			if (href == null) {
152 
153 				return null;
154 			}
155 
156 			final String label;
157 
158 			@Nullable
159 			final String text = anchor.getText();
160 
161 			if (!isBlank(text)) {
162 
163 				label = text;
164 
165 			} else {
166 
167 				final List<WebElement> imgs = anchor.findElements(By.tagName("img"));
168 
169 				if (!imgs.isEmpty()) {
170 
171 					label = substringAfterLast(imgs.get(0).getAttribute("src"), "/");
172 
173 				} else {
174 
175 					throw new NotImplementedException("<a> without text or <img>, href: " + href + ": " + anchor);
176 				}
177 			}
178 
179 			// final String locator = inferLocator(driver, anchor);
180 
181 			return new Interactable(label) {
182 
183 				@Override
184 				public void interact(
185 					final RunnerContext context
186 				) throws IOException {
187 
188 					final String locator = inferLocator(driver, anchor);
189 
190 					context.click(locator);
191 				}
192 			};
193 		}
194 
195 		@Nullable
196 		public static Interactable fromButton(
197 			final WebDriver driver,
198 			final WebElement button
199 		) {
200 
201 			if (!button.isDisplayed() || !button.isEnabled()) {
202 
203 				return null;
204 			}
205 
206 			final String label;
207 
208 			@Nullable
209 			final String text = button.getText();
210 
211 			if (!isBlank(text)) {
212 
213 				label = text;
214 
215 			} else {
216 
217 				throw new NotImplementedException("<button> without text: " + button);
218 			}
219 
220 			// final String locator = inferLocator(driver, button);
221 
222 			return new Interactable(label) {
223 
224 				@Override
225 				public void interact(
226 					final RunnerContext context
227 				) throws IOException {
228 
229 					final String locator = inferLocator(driver, button);
230 
231 					context.click(locator);
232 				}
233 			};
234 		}
235 
236 		@Nullable
237 		public static Interactable fromInput(
238 			final WebDriver driver,
239 			final WebElement input
240 		) {
241 
242 			if (!input.isDisplayed() || !input.isEnabled()) {
243 
244 				return null;
245 			}
246 
247 			@Nullable
248 			final String type = input.getAttribute("type");
249 
250 			if (type == null || !ArrayUtils.contains(new String[] { //
251 					"button", //
252 					"checkbox", "radio", //
253 					"submit" //
254 			}, type.toLowerCase(Locale.ENGLISH))) {
255 
256 				return null;
257 			}
258 
259 			final String label;
260 
261 			@Nullable
262 			final String value = input.getAttribute("value");
263 
264 			if (!isBlank(value)) {
265 
266 				label = value;
267 
268 			} else {
269 
270 				throw new NotImplementedException("<input> without value: " + input);
271 			}
272 
273 			// final String locator = inferLocator(driver, input);
274 
275 			return new Interactable(label) {
276 
277 				@Override
278 				public void interact(
279 					final RunnerContext context
280 				) throws IOException {
281 
282 					final String locator = inferLocator(driver, input);
283 
284 					context.click(locator);
285 				}
286 			};
287 		}
288 	}
289 }