<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Element 34</title>
	
	<link>http://element34.ca</link>
	<description>Your Link to Selenium Success</description>
	<lastBuildDate>Sat, 05 May 2012 18:52:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Element34" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="element34" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Snakes &amp; [Web] Services</title>
		<link>http://element34.ca/blog/snakes-web-services?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=snakes-web-services</link>
		<comments>http://element34.ca/blog/snakes-web-services#comments</comments>
		<pubDate>Sat, 05 May 2012 18:52:39 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=601</guid>
		<description><![CDATA[The other week I did a half-day tutorial at the Targeting Quality conference on using Python for automating Web Service testing. The rationale for this is that too many people are testing too much stuff in the browser &#8212; which is big and slow. Yes, the person who makes a living automating browsers says that [...]]]></description>
			<content:encoded><![CDATA[<p>The other week I did a half-day tutorial at the <a href="http://www.kwsqa.org/conference/">Targeting Quality</a> conference on using Python for automating Web Service testing. The rationale for this is that too many people are testing too much stuff in the browser &#8212; which is big and slow. Yes, the person who makes a living automating browsers says that it is big and slow. A <i>key</i> point of working with Selenium is knowing when not to use it.</p>
<p>Anyhow. The workshop was ok, and the main thing I would change was entirely my fault. The original idea was to show some code then have people work on their own services on their laptops. But I didn&#8217;t state that; at all, let alone not clearly enough. As a result, it was just me talking about code for the whole time. It still &#8216;worked&#8217; but could have been much better I think as more of a workshop.</p>
<p>There were no slides, but we started talking about HTTP. If you are testing anything on the web, you really need to have a handle on how information flows back and forth between the bits.</p>
<ul>
<li><a href="http://tools.ietf.org/wg/httpbis/">The HTTP Standard</a> at the IETF</li>
<li><a href="http://www.flickr.com/photos/girliemac/sets/72157628409467125/">HTTP Response Codes as cats</a>
</ul>
<p>The response codes are especially important when doing web services since they tend to be how information is communicated. Especially with REST based ones.</p>
<p>And speaking of <a href="https://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a>, it is one of the two types of web services that I talked about. For this I part I used the <a href="http://www.flickr.com/services/api/flickr.photos.search.html">Flickr Photo Search API</a>.</p>
<ul>
<li><a href="http://www.flickr.com/services/api/request.rest.html">Request format</a></li>
<li><a href="http://www.flickr.com/services/api/response.rest.html">Response format</a></li>
</ul>
<p>For automating this web service I used <a href="http://pytest.org">Py.Test</a> with (so incredibly) awesome <a href="http://docs.python-requests.org/en/latest/index.html#">Requests</a> module. Web service automation is one of those places where data driving becomes an excellent strategy. Because every runner does runtime data injection differently, one needs to look at Py.Test&#8217;s <a href="http://pytest.org/latest/example/parametrize.html">parametrize</a> documentation. Once you have your brain wrapped around how to data drive it, I suggest you look at driving it via an external means so you can update the test data without having to touch the script itself; <a href="http://docs.python.org/library/csv.html#">csv</a>, <a href="http://www.python.org/dev/peps/pep-0249/">Python Database API Specification v2.0</a>. When driving from a database, I try to reach into the actual database being used for testing to grab random data that meets the characteristics that I am trying to use. If I am using something like <a href="http://hexawise.com/">Hexawise</a> to reduce my combinatorial complexity down I would store that in a csv.</p>
<p>Whether your data-drive it or not, you need to parse the response and decide whether or not you got the information you expected. Python comes with XML parsing tools, but are not quite a joy to work with. <a href="http://www.crummy.com/software/BeautifulSoup/bs4/doc">Beautiful Soup</a> may not be a complete joy, but it is better than the built-in stuff and is pretty pythonic in its implementation.</p>
<p>All the scripts are available on <a href="https://github.com/adamgoucher/snakesandservices/tree/master/rest">Github</a> but here is the &#8216;basic&#8217; example.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> py
<span style="color: #ff7700;font-weight:bold;">import</span> pytest
<span style="color: #ff7700;font-weight:bold;">import</span> requests
<span style="color: #ff7700;font-weight:bold;">from</span> bs4 <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup
&nbsp;
key = <span style="color: #483d8b;">&quot;994124a9812d7a63972e89fc2145b9bc&quot;</span>
secret = <span style="color: #483d8b;">&quot;d8761d47cb245888&quot;</span>
&nbsp;
url = <span style="color: #483d8b;">&quot;http://api.flickr.com/services/rest/&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TestPhotoSearch<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> setup_method<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">payload</span> = <span style="color: black;">&#123;</span>
            <span style="color: #808080; font-style: italic;"># required for everything</span>
            <span style="color: #483d8b;">&quot;method&quot;</span>: <span style="color: #483d8b;">&quot;flickr.photos.search&quot;</span>,
            <span style="color: #808080; font-style: italic;"># required for this method</span>
            <span style="color: #483d8b;">&quot;api_key&quot;</span>: key
        <span style="color: black;">&#125;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> test_thumbtack<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">payload</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;text&quot;</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">&quot;thumbtack&quot;</span> 
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">payload</span><span style="color: black;">&#41;</span>
        r = requests.<span style="color: black;">get</span><span style="color: black;">&#40;</span>url, params=<span style="color: #008000;">self</span>.<span style="color: black;">payload</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>r<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>r.<span style="color: black;">text</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> r.<span style="color: black;">status_code</span> == requests.<span style="color: black;">codes</span>.<span style="color: black;">ok</span>:
            soup = BeautifulSoup<span style="color: black;">&#40;</span>r.<span style="color: black;">text</span>, features=<span style="color: #483d8b;">&quot;xml&quot;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> soup.<span style="color: black;">rsp</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'stat'</span><span style="color: black;">&#93;</span> == <span style="color: #483d8b;">'ok'</span>:
                <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span>soup.<span style="color: black;">photos</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;total&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                pytest.<span style="color: black;">fail</span><span style="color: black;">&#40;</span>msg = <span style="color: #483d8b;">'Did not get OK from Flickr'</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            pytest.<span style="color: black;">fail</span><span style="color: black;">&#40;</span>msg = <span style="color: #483d8b;">'Did not get OK from server'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Oh. And I disabled my API key so it won&#8217;t work by just cloning the repo without first getting your own key. Were these actually part of a &#8216;real&#8217; project I would externalize the keys to some common file so all your scripts don&#8217;t have to change if the keys change.</p>
<p>The other category of web service we did was the SOAP/WSDL-y type. These are not nearly as fun to interact with but have a bunch of features like encryption and digital payload signatures which are appealing in certain situations. And it occurred to me that their popularity in Java/.NET is not unsurprising since they are static typed languages and WSDLs enforce the type of parameters passed around in the request/response.</p>
<p>My original idea was to use the same API for for both types of web service but that didn&#8217;t really pan out. So for this I used the <a href="http://msdn.microsoft.com/en-us/library/dd251056.aspx">Bing API, Version 2</a>. The trick for dealing with this type of service is to limit how much SOAP Envelope construction you have to do by hand. To hopefully zero. In Python the module I use for this is Suds which actually has some <a href="https://fedorahosted.org/suds/wiki/Documentation">tragically [newbie] unfriendly documentation</a>. But seeing an example is useful. So <a href="https://github.com/adamgoucher/snakesandservices/tree/master/soap">here is the example</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> pytest
<span style="color: #ff7700;font-weight:bold;">from</span> suds.<span style="color: black;">client</span> <span style="color: #ff7700;font-weight:bold;">import</span> Client
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">logging</span>
<span style="color: #dc143c;">logging</span>.<span style="color: black;">basicConfig</span><span style="color: black;">&#40;</span>level=<span style="color: #dc143c;">logging</span>.<span style="color: black;">INFO</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'suds.client'</span><span style="color: black;">&#41;</span>.<span style="color: black;">setLevel</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">logging</span>.<span style="color: black;">DEBUG</span><span style="color: black;">&#41;</span>
&nbsp;
application_id = <span style="color: #483d8b;">&quot;0E100A06A5C6822E953B7F954C568BA6437FA918&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TestBingSearch<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> setup_method<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, method<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">client</span> = Client<span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://api.bing.net/search.wsdl?AppID=%s&amp;Version=2.2'</span> <span style="color: #66cc66;">%</span> application_id<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">SearchRequest</span> = <span style="color: #008000;">self</span>.<span style="color: black;">client</span>.<span style="color: black;">factory</span>.<span style="color: black;">create</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'SearchRequest'</span><span style="color: black;">&#41;</span>.<span style="color: black;">parameters</span>
        <span style="color: #808080; font-style: italic;"># print(self.SearchRequest)</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">SearchRequest</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;AppId&quot;</span><span style="color: black;">&#93;</span>= application_id
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> test_thumbtack<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">SearchRequest</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Query&quot;</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">&quot;thumbtack&quot;</span>
&nbsp;
        adult = <span style="color: #008000;">self</span>.<span style="color: black;">client</span>.<span style="color: black;">factory</span>.<span style="color: black;">create</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'AdultOption'</span><span style="color: black;">&#41;</span>
        adult = <span style="color: #483d8b;">&quot;Strict&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">SearchRequest</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Adult&quot;</span><span style="color: black;">&#93;</span> = adult
&nbsp;
        source_types = <span style="color: #008000;">self</span>.<span style="color: black;">client</span>.<span style="color: black;">factory</span>.<span style="color: black;">create</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ArrayOfSourceType'</span><span style="color: black;">&#41;</span>
        source_types.<span style="color: black;">SourceType</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Web&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">SearchRequest</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Sources&quot;</span><span style="color: black;">&#93;</span> = source_types
        <span style="color: #808080; font-style: italic;"># print(self.SearchRequest)</span>
        SearchResponse = <span style="color: #008000;">self</span>.<span style="color: black;">client</span>.<span style="color: black;">service</span>.<span style="color: black;">Search</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">SearchRequest</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># print(SearchResponse)</span>
        <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span>SearchResponse.<span style="color: black;">Web</span>.<span style="color: black;">Total</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Data driving this type of service is exactly the same as with a REST one so I didn&#8217;t write that.</p>
<p>At this point it is just about practice. And even if your application doesn&#8217;t have web services now, it will likely grow them at some point so learning how to do it useful. The <a href="http://www.programmableweb.com">programmable web</a> is a useful resource for free APIs that you can mess about with.</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/snakes-web-services/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML5 Media, WebDriver and Python</title>
		<link>http://element34.ca/blog/html5-media-webdriver-and-python?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=html5-media-webdriver-and-python</link>
		<comments>http://element34.ca/blog/html5-media-webdriver-and-python#comments</comments>
		<pubDate>Fri, 13 Apr 2012 13:00:09 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=598</guid>
		<description><![CDATA[So again I was chatting with Jim Holmes and he asked me if I knew how to script HTML5&#8242;s video tag. I had never even looked at it so had a look. One thing lead to another to another and I had some code. But before I get that; The video tag is a Media [...]]]></description>
			<content:encoded><![CDATA[<p>So again I was chatting with <a href="http://frazzleddad.com">Jim Holmes</a> and he asked me if I knew how to script HTML5&#8242;s video tag. I had never even looked at it so had a look. One thing lead to another to another and I <a href="https://gist.github.com/2325034">had some code</a>. But before I get that;</p>
<ul>
<li>The video tag is a <a href="http://www.w3.org/TR/html5/media-elements.html">Media Element</a></li>
<li>So is the audio tag</li>
<li>Actually, the implementation of an audio tag is exactly the same as the base media element type</li>
<li>The video tag has a viewable section so has dimensions aside from those specified as media elements</li>
<li>Interaction with the video and audio element is done entirely through JavaScript</li>
<li>Which means that there is bound to be differences between browsers as they interpret the standards slightly different</li>
<li>There are also a growing number of non-native implementations of players which override the native implementations <i>and will need their own WebDriver implementation</i></li>
</ul>
<p>Rather than paste the entire code for dealing with HTML5 media elements, I&#8217;ll just explain some of the important parts.</p>
<p>I hope to convince <a href="http://theautomatedtester.co.uk/">David Burns</a> to include this as part of the Python WebDriver bindings as part of the support package (I suspect I need to write tests for it and document it first) so I took a queue from the Select class in creating the constructor.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Video<span style="color: black;">&#40;</span>HTML5Media<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, webelement<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;
        Constructor. A check is made that the given element is, indeed, a VIDEO tag. If it is not,
        then an UnexpectedTagNameException is thrown.
&nbsp;
        :Args:
         - webelement - element VIDEO element to wrap
&nbsp;
        Example:
            from selenium.webdriver.support.ui import Select <span style="color: #000099; font-weight: bold;">\n</span>
            Video(driver.find_element_by_tag_name(&quot;video&quot;)).play()
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> webelement.<span style="color: black;">tag_name</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= <span style="color: #483d8b;">&quot;video&quot;</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> UnexpectedTagNameException<span style="color: black;">&#40;</span>
                <span style="color: #483d8b;">&quot;Video only works on &lt;video&gt; elements, not on &lt;%s&gt;&quot;</span> <span style="color: #66cc66;">%</span> 
                webelement.<span style="color: black;">tag_name</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>._el = webelement
        <span style="color: #008000;">self</span>.<span style="color: black;">changed</span> = <span style="color: #008000;">False</span></pre></div></div>

<p>My initial thought was to include this sort of tag inclusion in the find_by_* methods but the diversity of third party players made me rethink this.</p>
<p>Next, remember than control of these elements is through JavaScript. This means that that any WebDriver control is going to be through the JavaScript Executor interface. One feature of the executor is that you can pass in a WebDriver WebElement object as an argument and it is available [somehow] to the JavaScript being run.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@<span style="color: #008000;">property</span>
@stale
<span style="color: #ff7700;font-weight:bold;">def</span> loop<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._el._parent.<span style="color: black;">execute_script</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;return arguments[0].loop&quot;</span>, <span style="color: #008000;">self</span>._el<span style="color: black;">&#41;</span>
&nbsp;
@loop.<span style="color: black;">setter</span>
<span style="color: #ff7700;font-weight:bold;">def</span> loop<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, value<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>value, <span style="color: #008000;">bool</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>._el._parent.<span style="color: black;">execute_script</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;arguments[0].loop = arguments[1]&quot;</span>, <span style="color: #008000;">self</span>._el, value<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">changed</span> = <span style="color: #008000;">True</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;value needs to be a boolean&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>A few things to point out&#8230;</p>
<ul>
<li>Script execution is done at the page, not element level so have to use _parent which is the actual driver instance</li>
<li>When you manipulate (or have manipulated) an element in WebDriver, normally it will trigger a Stale Element Exception, but the manipulations this way were not triggering it, so I had to cobble it in with the self.changed stuff</li>
<li>Rather than have a check in every property I created a @stale decorator to do it</li>
</ul>
<p>So what does it look like in a script?</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> selenium <span style="color: #ff7700;font-weight:bold;">import</span> webdriver
&nbsp;
driver = webdriver.<span style="color: black;">Firefox</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
driver.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://html5demos.com/video&quot;</span><span style="color: black;">&#41;</span>
e = driver.<span style="color: black;">find_element_by_css_selector</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;video&quot;</span><span style="color: black;">&#41;</span>
v = Video<span style="color: black;">&#40;</span>e<span style="color: black;">&#41;</span>
v.<span style="color: black;">play</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ended?: {0}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>v.<span style="color: black;">ended</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
driver.<span style="color: black;">quit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Easy-peasy.</p>
<p>As I mentioned, I hope to get this into the official distro, but until then it is <a href="https://gist.github.com/2325034">up on github</a></p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/html5-media-webdriver-and-python/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Enabling logging in Selenium IDE</title>
		<link>http://element34.ca/blog/enabling-logging-in-selenium-ide?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=enabling-logging-in-selenium-ide</link>
		<comments>http://element34.ca/blog/enabling-logging-in-selenium-ide#comments</comments>
		<pubDate>Wed, 11 Apr 2012 13:00:16 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=594</guid>
		<description><![CDATA[One of the things I never really figured out while I was maintaining Selenium IDE was to get all the log messages (and there are a lot!) to appear in the Firefox log. Or more accurately I suppose, I never bothered to figure it out. But thankfully Dave Hunt did figure it out. More for [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things I never really figured out while I was maintaining Selenium IDE was to get all the log messages (and there are a lot!) to appear in the Firefox log. Or more accurately I suppose, I never bothered to figure it out. But thankfully Dave Hunt did figure it out.</p>
<blockquote class="twitter-tweet"><p>More for myself than anyone else. If you want to see the Selenium IDE debug log set extensions.selenium-ide.internalLogThreshold to DEBUG</p>
<p>&mdash; Dave Hunt (@davehunt82) <a href="https://twitter.com/davehunt82/status/167735209897365505" data-datetime="2012-02-09T22:22:45+00:00">February 9, 2012</a></p></blockquote>
<p><script src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>If you are developing a plugin getting the messages to appear is only half the story. You of course have to get them into the log in the first place. This is made slightly more complicated by the fact there are two different logging implementations in Selenium IDE. (<a href="http://code.google.com/p/selenium/source/browse/trunk/ide/main/src/content/tools.js#28">here</a> and <a href="http://code.google.com/p/selenium/source/browse/trunk/ide/main/src/content/selenium-runner.js#210">here</a>). </p>
<p>What I have done in a customer plugin I&#8217;m developing is take the first implementation and extracted it <a href="https://gist.github.com/2339024">to its own file</a>. With that file included in your project somewhere, here is how you use it.</p>

<div class="wp_syntax"><div class="code"><pre class="js" style="font-family:monospace;">var loader = Components.classes[&quot;@mozilla.org/moz/jssubscript-loader;1&quot;].getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript(&quot;chrome://your_plugin/content/js/log.js&quot;, this);
&nbsp;
function Foo() {
    this.logger = new Log(&quot;Foo&quot;);
}
&nbsp;
Foo.prototype.do_something = function() {
  // do somethng
  this.logger.log(this.logger.DEBUG, 'a message!');
};</pre></div></div>

<p>It is on my &#8216;to do&#8217; list to back port this extraction into the main Selenium IDE project, but its down the list a bit.</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/enabling-logging-in-selenium-ide/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HAR, JSON Schema and PHP</title>
		<link>http://element34.ca/blog/har-json-schema-and-php?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=har-json-schema-and-php</link>
		<comments>http://element34.ca/blog/har-json-schema-and-php#comments</comments>
		<pubDate>Mon, 09 Apr 2012 13:00:30 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=591</guid>
		<description><![CDATA[One of the many projects I&#8217;m working on that are starting to weave together into something cohesive is a PHP wrapper for the BrowserMob Proxy. What is interesting with that from an automation perspective is inspecting the HTTP response codes when loading a page; WebDriver will not grow this feature so you need to get [...]]]></description>
			<content:encoded><![CDATA[<p>One of the many projects I&#8217;m working on that are starting to weave together into something cohesive is a <a href="https://github.com/Element-34/PHPBrowserMobProxy">PHP wrapper for the BrowserMob Proxy</a>. What is interesting with that from an automation perspective is inspecting the HTTP response codes when loading a page; WebDriver <i>will not</i> grow this feature so you need to get them via a proxy. That information is returned to the calling script a HAR (<i>H</i>TTP <i>AR</i>chive) which is a <a href="http://www.softwareishard.com/blog/har-12-spec/">specifically formatted JSON file</a>.</p>
<p>As with when dealing with any file format, the first thing when parsing it is to make sure that it is in the right format. For XML we use DTDs or XML Schemas and for JSON we use <a href="http://tools.ietf.org/html/draft-zyp-json-schema-03">JSON Schemas</a>.</p>
<p>Determining that we want to do that is a lot easier than actually doing it. Especially in PHP. As usual, there are a handful of projects, all with a different level of compatibility/completeness with with the JSON Schema RFC, missing license information and not packaged for easy inclusion in projects. Ah. The joys of PHP.</p>
<p>One thing I didn&#8217;t want to do was write a schema from scratch; that is just no fun at all. So I looked to Jari Bakken&#8217;s HAR project for help. There he has schema for HAR files in <a href="https://github.com/jarib/har/blob/master/lib/har/viewer/scripts/preview/harSchema.js">JavaScript</a> and in <a href="https://github.com/jarib/har/blob/master/schema.json">raw JSON</a>. Awesome. I can recycle the latter one.</p>
<p>Except.</p>
<p>Remember I mentioned the varying degree of completeness in PHP validation projects? Ya. The use of $ref is the area they all seem to be lacking. Which meant a couple hours of copy-paste and debugging to remove those and make one huge schema file the results of which can be <a href="https://gist.github.com/2316754">seen here</a>.</p>
<p>Armed with a working schema I decided to use the <a href="https://github.com/hasbridge/php-json-schema">php-json-schema</a> project to validate my har file.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">namespace</span> PHPHAR<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../src/Json/Validator.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> HARTest <span style="color: #000000; font-weight: bold;">extends</span> \PHPUnit_Framework_TestCase <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testGoodHar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$validator</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \Json\Validator<span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../src/har_schema.json'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$validator</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validate</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">json_decode</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">file_get_contents</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'hars/good.har'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
   * @expectedException \Json\ValidationException
   */</span>
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testBadHar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     <span style="color: #000088;">$validator</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \Json\Validator<span style="color: #009900;">&#40;</span><span style="color: #990000;">dirname</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/../src/har_schema.json'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     <span style="color: #000088;">$validator</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validate</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">json_decode</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">file_get_contents</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'hars/bad.har'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>What I like about this particular schema project is that you load the schema once and then validate any number of time with it. Of course, it uses a different license than the one I use for my stuff and is distributed by composer and not pear, but those can be worked around. In the meantime, I hope the schema is useful to people.</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/har-json-schema-and-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implicit Waits, Implicit Evil?</title>
		<link>http://element34.ca/blog/implicit-waits-implicit-evil?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=implicit-waits-implicit-evil</link>
		<comments>http://element34.ca/blog/implicit-waits-implicit-evil#comments</comments>
		<pubDate>Wed, 04 Apr 2012 17:30:37 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=586</guid>
		<description><![CDATA[I was in a vendor talk by Jim Holmes of Telerik[1] last week where he was showing how to do some simple things in both his product and Selenium. One of things was the use of implicit waits. I mentioned to him afterwards that I actually try to avoid them in my code. This was [...]]]></description>
			<content:encoded><![CDATA[<p>I was in a vendor talk by Jim Holmes of Telerik[1] last week where he was showing how to do some simple things in both his product and Selenium. One of things was the use of implicit waits. I mentioned to him afterwards that I actually try to <i>avoid</i> them in my code. This was an unexpected comment to him which means I need to write about my current thinking.</p>
<p>Implicit waits are where an upper bounded polling action happens looking for an element in the page before throwing an exception saying it wasn&#8217;t there. This would seem like a good thing as you will have less scripts failing due to synchronization problems which in turn means that you have to spend less time maintaining and repairing scripts.</p>
<p>But.</p>
<p>What it is actually doing is <i>masking</i> synchronization problems.</p>
<p>When I am writing scripts I want the synchronization to be as tight as absolutely possible. Taking a line from the Tao of Python, <i>Explicit is better than implicit</i>. Disabling implicit waits in an existing script set often leads to two things</p>
<ul>
<li>Wholesale breakage due to places you were being lazy with the synch</li>
<li>Some bug reports with the application because you now notice which things are appearing when, in what order and in how long</li>
</ul>
<p>One of the knocks against automation is that, unlike humans, it doesn&#8217;t have emotions. Confusion, frustration, etc. What you can teach your scripts to be though is impatient. And you do that by disabling implicit waits.</p>
<p>Writing automation with explicit waits is without question more work and forces you to not take convenient shortcuts. The resulting code however will be tighter, run more efficiently and be half a step closer to the end-user&#8217;s perspective than without.</p>
<p>All that said, when automating against a moving target implicit waits can save the day. The trick though is to continually lower the wait duration until it is off. Fixing problems as you go.</p>
<p>[1] It was actually billed as a vendor talk and is not a slag on Jim&#8217;s other talk at the conference which was very un-vendor-like</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/implicit-waits-implicit-evil/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Starting from Scratch with RC, Python and Py.Saunter</title>
		<link>http://element34.ca/blog/starting-from-scratch-with-rc-python-and-py-saunter?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=starting-from-scratch-with-rc-python-and-py-saunter</link>
		<comments>http://element34.ca/blog/starting-from-scratch-with-rc-python-and-py-saunter#comments</comments>
		<pubDate>Thu, 15 Mar 2012 01:56:06 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=579</guid>
		<description><![CDATA[So the San Jose Selenium meetup featured Py.Saunter which is both awesome(!) and sad that someone else other than me publicly demoed my framework before I have. Here is some annotations to go along with Mary Ann&#8217;s presentation which was recorded using Adobe Connect and can be viewed from her blog. 1:40 &#8211; Why RC? [...]]]></description>
			<content:encoded><![CDATA[<p>So the San Jose Selenium meetup featured <a href="http://element34.ca/products/saunter/pysaunter">Py.Saunter</a> which is both awesome(!) and sad that someone else other than me publicly demoed my framework before I have. Here is some annotations to go along with Mary Ann&#8217;s presentation which was recorded using Adobe Connect and can be viewed from <a href="http://maryannmp.wordpress.com/2012/03/01/starting-from-scratch-with-rc-python-and-pysaunter-san-jose-selenium-meetup/">her blog</a>.</p>
<ul>
<li>1:40 &#8211; <i>Why RC?</i> &#8211; Now, the decision between RC and WebDriver is much easier. Use WebDriver unless you have a large investment in RC. And, well, even then, just stop writing RC scripts and start using WebDriver.</li>
<li>2:40 &#8211; <i>Dropping Perl and PHP</i> &#8211; It wasn&#8217;t for anything malicious; more that no one stood up and said that they wanted to maintain drivers for it. No maintainer, no driver.</li>
<li>6:05 &#8211; <i>Flags</i> &#8211; I personally would also add in either a &#8216;shallow&#8217; or &#8216;deep&#8217; tag. She uses &#8216;smoke&#8217; or &#8216;regression&#8217; to indication the same, but I like things that are logical opposites.</li>
<li>11:11 &#8211; <i>Why the modules directory?</i> &#8211; Why not? I could have called it &#8216;lib&#8217; or &#8216;stuff&#8217; or something else. But it holds modules (and packages&#8230;) so modules it is</li>
<li>12:30 &#8211; <i>Asserting in loops</i> &#8211; For a script like this, you really want a soft assert (verify) rather than a hard assert. The way the script is written here, as soon as a key is missing the script will end and the remainder will not be checked</li>
<li>15:08 &#8211; <i>Link locators</i> &#8211; See <a href="http://element34.ca/blog/death-to-visible-content-as-locators-in-automated-tests">death to visible content as locators in automated tests</a> for what Mary Ann is talking about</li>
<li>16:32 &#8211; <i>Locator Generation</i> &#8211; Re Eliza&#8217;s question, you the scripter need to generate the locators. One of the knocks on Se-IDE is that it tries to generate locators but they can be pretty darn brittle.</li>
<li>18:04 &#8211; <i>files dir</i> &#8211; I would put this in support/*</li>
<li>19:42 &#8211; <i>Screenshots</i> &#8211; The commands that get snapshots taken in them can be seen in <a href="https://github.com/Element-34/py.saunter/blob/master/saunter/SaunterSelenium.py">SaunterSelenium.py</a></li>
<li>21:30 &#8211; <i>Viewing Screenshots</i> &#8211; An idea would be to use a photo album tool and point its root directory at the logs directory</li>
<li>22:55 &#8211; <i>Can&#8217;t find things its not looking for</i> &#8211; People should remember that automation will happily pass something that is &#8216;wrong&#8217; that it isn&#8217;t expecting</li>
<li>27:40 &#8211; <i>Directories</i> &#8211; Yes. If you have 1000 tests and are taking screenshots you will end up with 1000 directories. Run it in ci; then zip up the directory and store it as an run artifact</li>
<li>31:40 &#8211; <i>TestLink integration</i> &#8211; It&#8217;s manual, but baby-steps. I could see a situation where it launches things and reports failures back to the system automatically</li>
<li>34:50 &#8211; <i>FogBugz integration</i> &#8211; FogBugz has a nice API, so things could get logged automatically that fail</li>
<li>41:15 &#8211; <i>Testing the Test</i> &#8211; Nice trick! pdb is black magic&#8230;</li>
<li>45:50 &#8211; <i>Mailing List</i> &#8211; Ask and you <a href="http://groups.google.com/group/saunter">shall receive</a> (first post moderation is enabled for spam trapping&#8230;)</li>
<li>45:55 &#8211; <i>Future of Py.Saunter</i> &#8211; I don&#8217;t expect it to go away since <i>I</i> use it. But its also <a href="https://github.com/Element-34/py.saunter">open source&#8230;</a></li>
<li>46:00 &#8211; <i>Future of RC</i> &#8211; Details of this are starting to
<li>46:30 &#8211; <i>Docs no good?</i> &#8211; Where do I need better information? These are the <a href="http://element34.ca/products/saunter/pysaunter">official ones</a></li>
</ul>
<p>Thanks Mary Ann! Oh and I&#8217;ll be speaking at the July meetup.</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/starting-from-scratch-with-rc-python-and-py-saunter/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Okay. Maybe a Singleton wasn’t such a hot idea</title>
		<link>http://element34.ca/blog/okay-maybe-a-singleton-wasnt-such-a-hot-idea?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=okay-maybe-a-singleton-wasnt-such-a-hot-idea</link>
		<comments>http://element34.ca/blog/okay-maybe-a-singleton-wasnt-such-a-hot-idea#comments</comments>
		<pubDate>Mon, 12 Mar 2012 01:58:28 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=572</guid>
		<description><![CDATA[For Page Objects to work, there needs to be a way for each class to get a reference to the current browser instance. When I first needed a single, globally available &#8216;thing&#8217; I learned about the Singleton pattern and latched on it. Yes, the Singleton pattern has a poor reputation in some circles but it [...]]]></description>
			<content:encoded><![CDATA[<p>For Page Objects to work, there needs to be a way for each class to get a reference to the current browser instance. When I first needed a single, globally available &#8216;thing&#8217; I learned about the Singleton pattern and latched on it.</p>
<p>Yes, the Singleton pattern has a poor reputation in some circles but it worked well for almost two years since my scripts tend to be built around ideas that include not running things in parallel, not using the runner to manage execution distribution (through the use of something like Se-Grid) and using a single browser per stack.</p>
<p>A couple different conversations with customers [and potential ones] have made me rethink the first idea. It turns out that running a single browser, in parallel is perfectly in my &#8216;acceptable&#8217; idea set. In fact, its a pretty good idea. [I know. Duh.] You can still have a single browser (controlled from a config file) that is distributed through a CI server &#8212; or better still into something like Sauce Labs&#8217; OnDemand service.</p>
<p>But.</p>
<p>That doesn&#8217;t work in a world where you get a browser from a Singleton. For that, you need to use Dependency Injection. That is where you pass into the constructor of an object what it needs to know in order to behave. In the Page Object context we pass in the reference that this particular script has to the Se server.</p>
<p>And while a lot of this can be change can be hidden at the framework level, there is some user-side code changes as well.</p>
<p>If you are using Py.Saunter 0.39 or newer with WebDriver, you will have to make the following changes. The Se-RC implementation remains using the Singleton approach. SaunterPHP users will notice that this is how their WebDriver Page Objects have always been written.</p>
<ol>
<li><i>update conftest.py</i> &#8211; conftest.py is a &#8216;magic&#8217; file that gets used by Py.Saunter&#8217;s underlying runner (py.test) which can augment py.test&#8217;s behaviour at various points in the execution lifecycle. Remove the contents that came with the installation and replace them with the following.

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> py
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> pytest_runtest_makereport<span style="color: black;">&#40;</span>__multicall__, item, call<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> call.<span style="color: black;">when</span> == <span style="color: #483d8b;">&quot;call&quot;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span> == item._testcase.<span style="color: black;">verificationErrors</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">AssertionError</span>:
            call.<span style="color: black;">excinfo</span> = py.<span style="color: #dc143c;">code</span>.<span style="color: black;">ExceptionInfo</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    rep = __multicall__.<span style="color: black;">execute</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> rep</pre></div></div>

</li>
<li><i>modules/tailored/webdriver.py</i> &#8211; While I was reworking how browsers get launched I made it a lot easier to add or customize WebDriver methods by putting in proper inheritance rather than just having static class methods.
<p>Create a new file called <i>modules/tailored/webdriver.py</i> with the following.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;&quot;
=========
WebDriver
=========
&quot;&quot;&quot;</span>
<span style="color: #ff7700;font-weight:bold;">from</span> saunter.<span style="color: black;">SaunterWebDriver</span> <span style="color: #ff7700;font-weight:bold;">import</span> SaunterWebDriver
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> WebDriver<span style="color: black;">&#40;</span>SaunterWebDriver<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
    Modifications to the core WebDriver API are done in this class
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>WebDriver, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span></pre></div></div>

<p>This class is where you would add methods to handle your special control behaviours.</li>
<li><i>de-static</i> &#8211; As a result of SaunterWebDriver no longer being an object with a bunch of static methods on it, you need to change references from it to self.driver. So change

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">SaunterWebDriver.<span style="color: black;">is_element_present</span><span style="color: black;">&#40;</span>locator<span style="color: black;">&#41;</span>:</pre></div></div>

<p>to</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">self</span>.<span style="color: black;">driver</span>.<span style="color: black;">is_element_present</span><span style="color: black;">&#40;</span>locator<span style="color: black;">&#41;</span>:</pre></div></div>

</li>
<li><i>self.driver (1)</i> &#8211; Each Page Object should now be created with with a driver instance as it starting parameter. <i>self.driver</i> is set on a script when the browser is opened.

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@pytest.<span style="color: black;">marks</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'shallow'</span>, <span style="color: #483d8b;">'ebay'</span>, <span style="color: #483d8b;">'shirts'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> test_collar_style<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    s = ShirtPage<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    s.<span style="color: black;">go_to_mens_dress_shirts</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    s.<span style="color: black;">change_collar_style</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Banded (Collarless)&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span>s.<span style="color: black;">is_collar_selected</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Banded (Collarless)&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>becomes</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@pytest.<span style="color: black;">marks</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'shallow'</span>, <span style="color: #483d8b;">'ebay'</span>, <span style="color: #483d8b;">'shirts'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> test_collar_style<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    s = ShirtPage<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">driver</span><span style="color: black;">&#41;</span>
    s.<span style="color: black;">go_to_mens_dress_shirts</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    s.<span style="color: black;">change_collar_style</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Banded (Collarless)&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span>s.<span style="color: black;">is_collar_selected</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Banded (Collarless)&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>If you miss a location is will throw and exception about an incorrect number of arguments.</li>
<li><i>self.driver (2)</i> &#8211; Page Objects likely already have self.driver being set in the __init__ method, but make sure that it now uses the passed in driver information.

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: black;">driver</span> = se_wrapper<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">connection</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">config</span> = cfg_wrapper<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">config</span></pre></div></div>

<p>vs.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, driver<span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: black;">driver</span> = driver
    <span style="color: #008000;">self</span>.<span style="color: black;">config</span> = cfg_wrapper<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">config</span></pre></div></div>

</li>
<li><i>elements</i> &#8211; since Element classes are created at object instantiation time they don&#8217;t have access in their constructor to the session information. But they do have access to it through their &#8216;obj&#8217; parameter. Which means to access the browser in an Element class you need obj.driver. Here is the before and after from an Element that gets clicked.

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__set__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, obj, val<span style="color: black;">&#41;</span>:
    e = SaunterWebDriver.<span style="color: black;">find_element_by_locator</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">locator</span><span style="color: black;">&#41;</span>
    e.<span style="color: black;">click</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__set__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, obj, val<span style="color: black;">&#41;</span>:
    e = obj.<span style="color: black;">driver</span>.<span style="color: black;">find_element_by_locator</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">locator</span><span style="color: black;">&#41;</span>
    e.<span style="color: black;">click</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

</ol>
<p>This is unfortunately not a trivial amount of code to change, but it is pretty straight forward and puts things into a nicer place. </p>
<p>I expect to publish the version of Py.Saunter with this change on Tuesday morning and I converted two projects in order to get the steps figured out but if you run into any problems, please <a href="mailto:contact@element34.ca">email me</a> and I&#8217;ll see if I can help you out.</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/okay-maybe-a-singleton-wasnt-such-a-hot-idea/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Soft Asserts and py.test</title>
		<link>http://element34.ca/blog/soft-asserts-and-py-test?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=soft-asserts-and-py-test</link>
		<comments>http://element34.ca/blog/soft-asserts-and-py-test#comments</comments>
		<pubDate>Mon, 05 Mar 2012 22:16:41 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=566</guid>
		<description><![CDATA[def pytest_runtest_makereport&#40;__multicall__, item, call&#41;: if call.when == &#34;call&#34;: try: assert&#40;&#91;&#93; == item._testcase.verificationErrors&#41; except AssertionError: call.excinfo = py.code.ExceptionInfo&#40;&#41; rep = __multicall__.execute&#40;&#41; return rep This &#8216;clever&#8217; function took me almost two days to figure out how to do. And meant that I had to learn waaay too much about how py.test behaves behind the scenes so this [...]]]></description>
			<content:encoded><![CDATA[
<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> pytest_runtest_makereport<span style="color: black;">&#40;</span>__multicall__, item, call<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> call.<span style="color: black;">when</span> == <span style="color: #483d8b;">&quot;call&quot;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span> == item._testcase.<span style="color: black;">verificationErrors</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">AssertionError</span>:
            call.<span style="color: black;">excinfo</span> = py.<span style="color: #dc143c;">code</span>.<span style="color: black;">ExceptionInfo</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    rep = __multicall__.<span style="color: black;">execute</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> rep</pre></div></div>

<p>This &#8216;clever&#8217; function took me almost two days to figure out how to do. And meant that I had to learn waaay too much about how py.test behaves behind the scenes so this post is partly to share those findings with others and partly [largely] for my own reference later.</p>
<p>First, background.</p>
<p>I first came across the notion or <i>hard</i> and <i>soft</i> asserts exporting code from Se-IDE. A hard assert is your normal one where if the condition fails the script stops immediately whereas a soft assert will collect failures and ultimately fail the script but will proceed as if nothing happened.</p>
<p>Normally this soft assert pattern is implemented like this where you create a list in the setup, catch any hard assert fails and append them to the list, then check that the list is empty in the teardown.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> SomeTest<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
  <span style="color: #ff7700;font-weight:bold;">def</span> setUp<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: black;">verification_errors</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> testSomething<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
      <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">AssertionError</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">verification_errors</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Some soft assert failed&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> tearDown<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span> == <span style="color: #008000;">self</span>.<span style="color: black;">verification_errors</span><span style="color: black;">&#41;</span></pre></div></div>

<p>py.test&#8217;s workflow is a bit, erm, unique though so that doesn&#8217;t really work.</p>
<p>py.test treats each of these three methods as completely separate and atomic <i>calls</i>. Each call is implemented as a <i>hook</i> that can be overridden (pytest_runtest_setup, pytest_runtest_call, pytest_runtest_teardown). Due to implementation, the executing code knows only about its locally scoped information and not some of the meta information you might have access to in a pure UnitTest2 script &#8212; like current script status. (Likely explained wrong, but that&#8217;s what it &#8216;feels&#8217; like.) That useful bit of information is calculated in the reporting step (pytest_runtest_makereport) which is called after each of the other three steps which means that we can&#8217;t make the pass/fail determination in teardown.</p>
<p>But we also cannot make the determination after teardown is complete, because it then looks like the failure is happening in the teardown &#8212; which is wasn&#8217;t; the &#8216;call&#8217; step was what failed. Thus the &#8216;if call.when == &#8220;call&#8221;&#8216; condition. Once in there, we can check if any of our soft asserts failed (the list isn&#8217;t empty) and then add it to the &#8216;item&#8217; (everything in py.test is an item) as if it had happened during the script execution.</p>
<p>(The __multicall__ argument is a bit of deep, dark py.test black magic I borrowed from their mailing list archives.)</p>
<p>If you drop this function in your <i>conftest.py</i> you will be able to make use of the soft assert pattern with py.test and have it report correctly. Just remember not to put the check in the teardown as well&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> SomeTest<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
  <span style="color: #ff7700;font-weight:bold;">def</span> setUp<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #008000;">self</span>.<span style="color: black;">verification_errors</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">def</span> testSomething<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
      <span style="color: #ff7700;font-weight:bold;">assert</span><span style="color: black;">&#40;</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">AssertionError</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">verification_errors</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Some soft assert failed&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/soft-asserts-and-py-test/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Looking for a SaunterPHP Beta site</title>
		<link>http://element34.ca/blog/looking-for-a-saunterphp-beta-site?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=looking-for-a-saunterphp-beta-site</link>
		<comments>http://element34.ca/blog/looking-for-a-saunterphp-beta-site#comments</comments>
		<pubDate>Mon, 27 Feb 2012 15:53:54 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=559</guid>
		<description><![CDATA[I am happy to announce that SaunterPHP has been made available to the world. For a lot of teams, getting started and getting all the infrastructure in place for automation is often harder and more time consuming than the actual automation. SaunterPHP addresses this problem for PHP through convention-over-configuration. These conventions include Page Objects Easy [...]]]></description>
			<content:encoded><![CDATA[<p>I am happy to announce that <a href="http://element34.ca/products/saunter/saunterphp">SaunterPHP</a> has been made available to the world.</p>
<p>For a lot of teams, getting started and getting all the infrastructure in place for automation is often harder and more time consuming than the actual automation. SaunterPHP addresses this problem for PHP through convention-over-configuration. These conventions include</p>
<ul>
<li>Page Objects</li>
<li>Easy CI integration</li>
<li><a href="http://saucelabs.com">Sauce Labs OnDemand</a> integration</li>
<li>Dynamic suite generation through groups</li>
</ul>
<p>SaunterPHP is Open Source and free to install and use. Support and Feature Requests are available for a cost.</p>
<p>But.</p>
<p>Since SaunterPHP is just launching I am looking for 1 (maybe 2) beta sites for the month of March. In exchange for bug reports and feedback I&#8217;ll waive bug fixing and support fees. Email <a href="mailto:adam@element34.ca">adam@element34.ca</a> for details.</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/looking-for-a-saunterphp-beta-site/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Not All Huge XPath is Evil XPath</title>
		<link>http://element34.ca/blog/not-all-huge-xpath-is-evil-xpath?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=not-all-huge-xpath-is-evil-xpath</link>
		<comments>http://element34.ca/blog/not-all-huge-xpath-is-evil-xpath#comments</comments>
		<pubDate>Wed, 15 Feb 2012 12:26:38 +0000</pubDate>
		<dc:creator>adam</dc:creator>
				<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://element34.ca/?p=542</guid>
		<description><![CDATA[There is a lot of XPath hate in the Selenium world. Some of it justifiable, but a lot of it is bandwagon-ism and results in hatred for all things XPath. Here&#8217;s the rub though, sometimes you really do need XPath and when you do, its power is pretty impressive. Yes, more powerful than CSS Selectors. [...]]]></description>
			<content:encoded><![CDATA[<p>There is a lot of XPath hate in the Selenium world. Some of it justifiable, but a lot of it is bandwagon-ism and results in hatred for all things XPath. Here&#8217;s the rub though, sometimes you really do need XPath and when you do, its power is pretty impressive. Yes, more powerful than CSS Selectors.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">x <span style="color: #339933;">=</span><span style="color: #3366CC;">'//td[@class=&quot;ql-account-requests-title_author&quot;]/a[contains(translate(text(), &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;, &quot;abcdefghijklmnopqrstuvwxyz&quot;), translate(&quot;'</span> <span style="color: #339933;">+</span>  material_row.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;author&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'&quot;, &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;, &quot;abcdefghijklmnopqrstuvwxyz&quot;))]/../../td[@class=&quot;ql-account-requests-pickup_location&quot; and contains(text(), &quot;'</span> <span style="color: #339933;">+</span> branch_row.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;branch&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'&quot;)]/..//input[@class=&quot;ql-account-select-checkbox&quot;]'</span><span style="color: #339933;">;</span></pre></div></div>

<p>Yes. That is a 408 character XPath. And it is awesome.</p>
<p>Context.</p>
<p>This is from a <a href="http://browsermob.com">BrowserMob</a> script for a library site revamp. At the end of the script I needed to find the material I had reserved and cancel that reservation. The list of reservations is a tabular data and so was logically in a table. But the accounts are reused during the run so I needed to find the material by the author and title that was randomly chosen for this run. This meant that I needed to find a cell, go back up and over, find a cell, got back up and over and click a checkbox.</p>
<p><i>This is not a time machine; its a locator. It can&#8217;t go back.</i>[1]</p>
<p>When you need a plain top-to-bottom structural locator then CSS Selectors should be your default approach, but it cannot go back up the DOM. XPath can.</p>
<p>CSS cannot also deal with the inevitable matching problems that come from using real-life data. And unfortunately Firefox&#8217;s implementation of XPath does not have the <i>lower-case</i> function so you have to use the nasty looking <i>translate</i>. CSS Selectors do not also have substring matching for of descendent text in the standard. <a href="http://sizzlejs.com">Sizzle</a> solves that, but that is not standard. XPath has <i>contains</i> though.</p>
<p>Circling back to this particular XPath.</p>
<ul>
<li>Does it solve the problem? <i>Yes</i></li>
<li>Is it more inherently brittle than another structural locator? <i>No</i></li>
<li>Does it provide guards around case differences in data? <i>Yes</i></li>
<li>Would it be pretty easy to modify if the way that the identifying bits change? <i>Yes</i>
</ul>
<p>Awesome.</p>
<p>The point of this little rant is to not be afraid of large XPath when it is the proper locator for the task and reserve your judgemental sneers for those use of bad used XPath poorly.</p>
<p>Oh, and remember, your &#8216;but it relies on the structure of the HTML&#8217; hatred should really be directed at <i>both</i> XPath and CSS Selectors. They are both structural location schemes and therefore suffer the same problems.</p>
<p>[1] Stolen blatantly from <a href="http://www.youtube.com/watch?v=GE_IlFid560">Back To The Future</a> by Pagano</p>
]]></content:encoded>
			<wfw:commentRss>http://element34.ca/blog/not-all-huge-xpath-is-evil-xpath/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

