1 module selenium.session;
2 
3 import selenium.api;
4 import std.stdio;
5 import vibe.data.json;
6 
7 
8 auto findOneIn(immutable ElementLocator locator, immutable SeleniumSession session) {
9 	return session.findOne(locator);
10 }
11 
12 auto findMany(immutable ElementLocator locator, immutable SeleniumSession session) {
13 	return session.findMany(locator);
14 }
15 
16 immutable class SeleniumSession
17 {
18 	SeleniumApi api;
19 
20 	this(string serverUrl, Capabilities desiredCapabilities,
21 			Capabilities requiredCapabilities = Capabilities(), Capabilities session = Capabilities())
22 	{
23 		auto connector = new SeleniumApiConnector(serverUrl,
24 				desiredCapabilities, requiredCapabilities, session);
25 		api = connector.api;
26 	}
27 
28 	@property
29 	{
30 		immutable(SeleniumWindow) currentWindow()
31 		{
32 			return new immutable SeleniumWindow(api, this);
33 		}
34 
35 		immutable(SeleniumNavigation) navigation()
36 		{
37 			return new immutable SeleniumNavigation(api, this);
38 		}
39 
40 		immutable(SeleniumCookie) cookie()
41 		{
42 			return new immutable SeleniumCookie(api, this);
43 		}
44 
45 		auto windowHandles()
46 		{
47 			return api.windowHandles;
48 		}
49 	}
50 
51 	immutable(Element) findOne(immutable ElementLocator locator)
52 	{
53 		return Element.findOne(api, locator);
54 	}
55 
56 	immutable(Element)[] findMany(immutable ElementLocator locator)
57 	{
58 		return Element.findMany(api, locator);
59 	}
60 
61 	immutable(Element) getActiveElement()
62 	{
63 		return Element.getActive(api);
64 	}
65 
66 	auto frame(string id)
67 	{
68 		api.frame(id);
69 		return this;
70 	}
71 
72 	auto frame(long id)
73 	{
74 		api.frame(id);
75 		return this;
76 	}
77 
78 	auto frame(WebElement element)
79 	{
80 		api.frame(element);
81 		return this;
82 	}
83 
84 	auto frameParent()
85 	{
86 		api.frameParent;
87 		return this;
88 	}
89 
90 	void close()
91 	{
92 		api.connection.disconnect;
93 	}
94 }
95 
96 class SeleniumCookie
97 {
98 	immutable
99 	{
100 		SeleniumApi api;
101 		SeleniumSession parent;
102 	}
103 
104 	this(immutable SeleniumApi api, immutable SeleniumSession parent) immutable
105 	{
106 		this.api = api;
107 		this.parent = parent;
108 	}
109 
110 	@property immutable
111 	{
112 		auto all() {
113 			return api.cookie;
114 		}
115 
116 		auto set(string name, string value) {
117 			api.setCookie(Cookie(name, value));
118 			return parent;
119 		}
120 
121 		auto set(Cookie cookie) {
122 			api.setCookie(cookie);
123 			return parent;
124 		}
125 
126 		auto deleteAll() {
127 			api.deleteAllCookies();
128 			return parent;
129 		}
130 
131 		auto deleteByName(string name) {
132 			api.deleteCookie(name);
133 			return parent;
134 		}
135 	}
136 }
137 
138 immutable class SeleniumNavigation
139 {
140 	immutable
141 	{
142 		SeleniumApi api;
143 		SeleniumSession parent;
144 	}
145 
146 	this(immutable SeleniumApi api, immutable SeleniumSession parent)
147 	{
148 		this.api = api;
149 		this.parent = parent;
150 	}
151 
152 	@property
153 	{
154 		auto url(string url)
155 		{
156 			api.url(url);
157 			return parent;
158 		}
159 
160 		auto url()
161 		{
162 			return api.url;
163 		}
164 
165 		auto forward()
166 		{
167 			api.forward;
168 			return parent;
169 		}
170 
171 		auto back()
172 		{
173 			api.back;
174 			return parent;
175 		}
176 
177 		auto refresh()
178 		{
179 			api.refresh;
180 			return parent;
181 		}
182 	}
183 }
184 
185 immutable class SeleniumWindow
186 {
187 	SeleniumApi api;
188 	SeleniumSession parent;
189 
190 	this(immutable SeleniumApi api, immutable SeleniumSession parent)
191 	{
192 		this.api = api;
193 		this.parent = parent;
194 	}
195 
196 	immutable
197 	{
198 		auto select(string name)
199 		{
200 			api.selectWindow(name);
201 			return parent;
202 		}
203 
204 		auto handle()
205 		{
206 			return api.windowHandle;
207 		}
208 
209 		auto size()
210 		{
211 			return api.windowSize;
212 		}
213 
214 		auto size(Size value)
215 		{
216 			api.windowSize(value);
217 			return parent;
218 		}
219 
220 		auto maximize()
221 		{
222 			api.windowMaximize;
223 			return parent;
224 		}
225 
226 		auto screenshot()
227 		{
228 			return api.screenshot;
229 		}
230 
231 		auto close()
232 		{
233 			api.windowClose;
234 			return parent;
235 		}
236 
237 		auto source()
238 		{
239 			return api.source;
240 		}
241 
242 		auto title()
243 		{
244 			return api.title;
245 		}
246 
247 		auto execute(T = string)(string script, Json args = Json.emptyArray)
248 		{
249 			return api.execute!T(script, args);
250 		}
251 
252 		auto executeAsync(T = string)(string script, Json args = Json.emptyArray)
253 		{
254 			return api.executeAsync!T(script, args);
255 		}
256 	}
257 }
258 
259 @("Session currentWindow")
260 unittest
261 {
262 	auto session = new immutable SeleniumSession("http://127.0.0.1:4444/wd/hub", Capabilities.chrome);
263 
264 	session.currentWindow.size = Size(400, 500);
265 	assert(session.currentWindow.size == Size(400, 500));
266 
267 	session.currentWindow.maximize;
268 
269 	session.currentWindow.screenshot;
270 	session.currentWindow.source;
271 	session.currentWindow.title;
272 
273 	session.currentWindow.close;
274 
275 	session.close;
276 }
277 
278 class Element
279 {
280 	alias opEquals = Object.opEquals;
281 
282 	private immutable
283 	{
284 		SeleniumApi api;
285 		WebElement element;
286 	}
287 
288 	this(immutable SeleniumApi api, immutable WebElement element) immutable
289 	{
290 		this.api = api;
291 		this.element = element;
292 	}
293 
294 	static
295 	{
296 		immutable(Element) findOne(immutable SeleniumApi api, immutable ElementLocator locator)
297 		{
298 			return new immutable Element(api, api.element(locator));
299 		}
300 
301 		immutable(Element)[] findMany(immutable SeleniumApi api, immutable ElementLocator locator)
302 		{
303 			immutable(Element)[] elements;
304 
305 			foreach (webElement; api.elements(locator))
306 			{
307 				elements ~= new immutable Element(api, webElement);
308 			}
309 
310 			return elements;
311 		}
312 
313 		immutable(Element) getActive(immutable SeleniumApi api)
314 		{
315 			return new immutable Element(api, api.activeElement);
316 		}
317 
318 		void sendKeysToActive(immutable SeleniumApi api, const string[] value)
319 		{
320 			api.sendKeysToActiveElement(value);
321 		}
322 	}
323 
324 	inout
325 	{
326 		immutable(Element) findOne(ElementLocator locator)
327 		{
328 			return new immutable Element(api, api.elementFromElement(element.ELEMENT, locator));
329 		}
330 
331 		immutable(Element)[] findMany(ElementLocator locator)
332 		{
333 			immutable(Element)[] elements;
334 
335 			foreach (webElement; api.elementsFromElement(element.ELEMENT, locator))
336 			{
337 				elements ~= new immutable Element(api, webElement);
338 			}
339 
340 			return elements;
341 		}
342 
343 		inout(Element) click()
344 		{
345 			api.clickElement(element.ELEMENT);
346 
347 			return this;
348 		}
349 
350 		inout(Element) submit()
351 		{
352 			api.submitElement(element.ELEMENT);
353 			return this;
354 		}
355 
356 		inout(Element) sendKeys(string[] value)
357 		{
358 			api.sendKeys(element.ELEMENT, value);
359 			return this;
360 		}
361 
362 		inout(Element) sendKeys(string value)
363 		{
364 			return sendKeys([value]);
365 		}
366 
367 		inout(Element) clear()
368 		{
369 			api.clearElementValue(element.ELEMENT);
370 			return this;
371 		}
372 
373 		@property
374 		{
375 			string text()
376 			{
377 				return api.elementText(element.ELEMENT);
378 			}
379 
380 			string name()
381 			{
382 				return api.elementName(element.ELEMENT);
383 			}
384 
385 			bool isSelected()
386 			{
387 				return api.elementSelected(element.ELEMENT);
388 			}
389 
390 			bool isEnabled()
391 			{
392 				return api.elementSelected(element.ELEMENT);
393 			}
394 
395 			bool isDisplayed()
396 			{
397 				return api.elementDisplayed(element.ELEMENT);
398 			}
399 
400 			Position position()
401 			{
402 				return api.elementLocation(element.ELEMENT);
403 			}
404 
405 			Position positionInView()
406 			{
407 				return api.elementLocationInView(element.ELEMENT);
408 			}
409 
410 			Size size()
411 			{
412 				return api.elementSize(element.ELEMENT);
413 			}
414 
415 			string seleniumId() inout
416 			{
417 				return element.ELEMENT;
418 			}
419 		}
420 
421 		string attribute(string name)
422 		{
423 			return api.elementValue(element.ELEMENT, name);
424 		}
425 
426 		string elementCssPropertyName(string name)
427 		{
428 			return api.elementValue(element.ELEMENT, name);
429 		}
430 
431 		bool opEquals(ref Element other) const
432 		{
433 			return api.elementEqualsOther(element.ELEMENT, other.seleniumId);
434 		}
435 
436 		bool opEquals(Element other) const
437 		{
438 			return api.elementEqualsOther(element.ELEMENT, other.seleniumId);
439 		}
440 	}
441 }
442 
443 @("Session find one element")
444 unittest
445 {
446 	auto session = new immutable SeleniumSession("http://127.0.0.1:4444/wd/hub", Capabilities.chrome);
447 	session.navigation.url("https://www.amazon.com/All-Light-We-Cannot-See/dp/1476746583/");
448 
449 	session.findOne(ElementLocator(LocatorStrategy.ClassName, "contributorNameID")).click;
450 
451 	assert(session.navigation.url
452 			== "https://www.amazon.com/Anthony-Doerr/e/B000APOX62/ref=dp_byline_cont_book_1");
453 
454 	session.close;
455 }
456 
457 @("Session find many elements")
458 unittest
459 {
460 	auto session = new immutable SeleniumSession("http://127.0.0.1:4444/wd/hub", Capabilities.chrome);
461 	session.navigation.url("https://www.amazon.com/All-Light-We-Cannot-See/dp/1476746583/");
462 
463 	assert(session.findMany(ElementLocator(LocatorStrategy.TagName, "img")).length > 0);
464 
465 	session.close;
466 }