Codeception, Javascript and Laravel Homestead
<p>You can use Codeception to test Javascript, like DOM manipulations and Ajax requests. Out of the box it can manipulate DOM elements but can't execute Javascript code, like most testing frameworks. But it gives you the option to use a WebDriver, to connect to a headless browser, and mimic a user browsing your website. It gives you some options: Selenium2, ZombieJS and, the easiest to configure, PhantomJS.</p> <p>This article covers the installation and usage of PhantomJS, and assumes you are using Laravel Homestead, but it will work on any relatively new Debian based distro, like Ubuntu 14.04.</p> <h3>Install PhantomJS</h3> <p>Just run those commands to install it:</p> <pre class="prettyprint"><code >sudo apt-get update sudo apt-get install --yes phantomjs </code></pre> <p>If you are not using Homestead, make sure you are installing PhantomJS 1.8+, because the WebDriver Wire Protocol is not available on versions below this one. You can check PhantomJS version by executing:</p> <pre class="prettyprint"><code >phantomjs -v </code></pre> <h3>Execute PhantomJS GhostDriver</h3> <p>While testing, Codeception will try to connect to a headless browser on port 4444, so you'll need to keep PhantomJS running. To do that open a new terminal window, execute the command below and keep that window open:</p> <pre class="prettyprint"><code >phantomjs --webdriver=4444 </code></pre> <h3>Configure your Test Suite</h3> <p>You basically have to add the <code class="spancode">WebDriver</code> module to your test suite:</p> <pre class="prettyprint"><code >enabled: [..., WebDriver] </code></pre> <p>And rebuild your actor classes:</p> <pre class="prettyprint"><code >vendor/bin/codecept build </code></pre> <p>You need to add some other items to properly configure the WebDriver, here's a suite with everything set:</p> <pre class="prettyprint"><code >class_name: FunctionalTester modules: enabled: [Filesystem, FunctionalHelper, Laravel4, Asserts, WebDriver] config: WebDriver: url: 'http://application.dev/' browser: phantomjs window_size: 1280x720 capabilities: webStorageEnabled: true </code></pre> <p>The <code class="spancode">url</code> item was a tricky one to me, because, when you access Homestead from your physical machine (browse), you use port 8000, but inside the Homestead virtual machine you would have to use it without that port (eg: http://localhost/), but this didn't worked for me so I had to add the host name to my Homestead VM's <code class="spancode">hosts</code> file:</p> <pre class="prettyprint"><code >127.0.0.1 application.dev </code></pre> <h3>Using It</h3> <p>Let's say you have a page wich requires authentication to do more stuff than simply browse it, and you have some Ajax requests built to improve user experience. Here's what you can now do:</p> <p>Tell Codeception to go to a "items" page:</p> <pre class="prettyprint"><code >$I->amOnPage('/items'); </code></pre> <p>It must see a particular item:</p> <pre class="prettyprint"><code >$I->seeElement('.item[data-id="1"]'); </code></pre> <p>Click on an ajax link, which will redirect to the login page:</p> <pre class="prettyprint"><code >$I->click('.item[data-id="1"] .item-delete'); </code></pre> <p>Tell Codeception to wait 10 seconds for a login button to appear on the page, using jQuery:</p> <pre class="prettyprint"><code >$I->waitForJs("return $('input[value=\"Sign In\"]').is(':visible');", 10); </code></pre> <p>Now it should be at <code class="spancode">/login</code>:</p> <pre class="prettyprint"><code >$I->seeCurrentUrlEquals('/login'); </code></pre> <p>Tell it to sign in:</p> <pre class="prettyprint"><code >$I->signIn(); </code></pre> <p>Go to the items page:</p> <pre class="prettyprint"><code >$I->amOnPage('/items'); </code></pre> <p>Check if the item element is present:</p> <pre class="prettyprint"><code >$I->seeElement('.item[data-id="1"]'); </code></pre> <p>Click on a delete link:</p> <pre class="prettyprint"><code >$I->click('.item[data-id="1"] .item-delete'); </code></pre> <p>Wait for the item to disappear:</p> <pre class="prettyprint"><code >$I->waitForJs("return $('.item').is(':hidden');", 10); </code></pre> <p>Reload the page, to make sure it was also removed from your database:</p> <pre class="prettyprint"><code >$I->reloadPage(); </code></pre> <p>And it should not see it:</p> <pre class="prettyprint"><code >$I->dontSeeElement('.item[data-id="1"]'); </code></pre> <p>Enjoy Codeception!</p>