WebDriver and Meta Tags

Meta elements are the HTML or XHTML <meta … > element used to provide structured metadata about a Web page.Wikipedia

Often functional scripts using Selenium worry only about the flows of an app, but sometimes the non-interaction parts are just as important — or more so. One such example is the meta tags that are part of an organization’s SEO strategy. So how do you check these with WebDriver? I’m glad you asked, and so let’s use eBay as our illustrative site.

First, we need some Page Objects.

<?php
class Page {
  function __construct($session) {
    $this->session = $session;
  }
 
  function get_all_meta_tags($custom = array()) {
    $html401 = array("lang", "dir", "http-equiv", "name", "content", "scheme");
    $html5 = array("charset");
    $attributes = array_merge($html401, $html5, $custom);
 
    $bin = array();
 
    $metas = $this->session->elements("tag name", "meta");
    foreach ($metas as $meta) {
      $bucket = array();
      foreach ($attributes as $attribute) {
        $fetched = $meta->attribute($attribute);
        if ($fetched) {
          $bucket[$attribute] = $fetched;
        }
      }
      $bin[] = $bucket;
    }
    return $bin;
  }
 
  function get_named_meta_tag($named, $custom = array()) {
    $metas = $this->get_all_meta_tags($custom);
    foreach ($metas as $meta) {
      if (array_key_exists("name", $meta) && $meta["name"] == $named) {
        return $meta;        
      }
    }
  }
}
?>
<?php
require_once 'page.php';
 
class Home extends Page {
  function __construct($session) {
      parent::__construct($session);
  }
}
?>

Nothing too too fancy here; just two plain Page Objects with the Home one inheriting from Page. The only interesting bit is the passing in of an array of custom properties; more on that below. And here is the script I’m using which shows how to call them.

<?php
require_once 'PHPUnit/Framework/TestCase.php';
require_once 'PHPWebDriver/WebDriver.php';
require_once 'po/home.php';
 
class MetaTagsTest extends PHPUnit_Framework_TestCase {
  public function setUp() {
    $web_driver = new PHPWebDriver_WebDriver("http://localhost:4444/wd/hub");
    $this->session = $web_driver->session();
    $this->session->open("http://www.ebay.com");
    $this->home = new Home($this->session);
  }
 
  public function tearDown() {
    $this->session->close();
  }
 
  /**
  * @test
  * @group all
  */
  public function get_all_meta_tags() {
    $metas = $this->home->get_all_meta_tags(array("property"));
    $this->assertEquals(8, count($metas));
  }
 
  /**
  * @test
  * @group one
  */
  public function get_named_meta_tag() {
    $y_key = $this->home->get_named_meta_tag("y_key", array("property"));
    $this->assertEquals("acf32e2a69cbc2b0", $y_key["content"]);
  }
}
?>

It would be nice if WebDriver provided something like /session/:sessions/element/:element/attributes rather than just fetching one by name but since it doesn’t there is a bit of abstraction that needs to happen. But since it doesn’t we have to loop over a set of known attributes for this particular type of element (meta) and create our own object that represents each tag. We could just return the raw WebDriver object but that threatens to leak API stuff into the script which is something to try and avoid.

While on the topic of a known set of attributes, it is not enough to just go by what the w3c says should be there. You have to tune it to your application’s invalid usage of HTML. For instance, in this example eBay is using meta tags that have a ‘property’ attribute. Though to their defence, it is Facebook that is adding this bit of html (see Meta tag invalid property attribute) — but eBay still doesn’t declare the namespace properly.

Anyhow.

Fetching only the meta elements is something too specific for the core WebDriver protocol to support but is well in the realm of responsibility of a Framework which is why Py.Saunter SaunterPHP will be growing this in their base Page classes.

Post a Comment

Your email is never published nor shared. Required fields are marked *