Behat steps for Organic Groups

Here are a few Behat steps that I found useful for organic groups. Note that I placed this in a subcontext, and so have a number of calls to getMainContext() which may not be relevant to your implementation.

Example usages:

  Given I am logged in as a user with the "authenticated user" role
  And I am viewing an "organization" node
  And I am a "member" of the current group
  Then I should not see the link "Group" in the "content" region
  Given I am logged in as a user with the "authenticated user" role
  And I create a "blog_entry" node with title "First Group Blog Entry"
  And I visit the parent group node
  Then ...
  Given I am logged in as a user with the " administrator" role
  And I create an "organization" node with title "Test Org"
  And I create a "page" node belonging to the current organic group
  Then ...

The step definitions:

<?php
 
/**
   * @Given /^I am (?:a|an) "([^"]*)" of the current group$/
   */
 
public function iAmAnOfTheCurrentGroup($group_role) {
   
$group = $this->getCurrentGroupFromURL();
   
$this->addMembertoGroup($group_role, $group);
   
$this->getMainContext()->softReload();
  }


 
/**
   * Adds a member to an organic group with the specified role.
   *
   * @param string $group_role
   *   The machine name of the group role.
   *
   * @param object $group
   *   The group node.
   *
   * @param string $group_type
   *   (optional) The group's entity type.
   *
   * @throws \Exception
   */
 
public function addMembertoGroup($group_role, $group, $group_type = 'node') {
   
$user = $this->getMainContext()->user;
    list(
$gid, $vid, $bundle) = entity_extract_ids($group_type, $group);

   
$membership = og_group($group_type, $gid, array(
     
"entity type" => 'user',
     
"entity" => $user,
    ));

    if (!
$membership) {
      throw new \
Exception("The Organic Group membership could not be created.");
    }

   
// Add role for membership.
   
$roles = og_roles($group_type, $group->type, $gid);
   
$rid = array_search($group_role, $roles);

    if (!
$rid) {
      throw new \
Exception("'$group_role' is not a valid group role.");
    }

   
og_role_grant($group_type, $gid, $user->uid, $rid);

  }

 
/**
   * Gets current Organic Group context from URL.
   */
 
public function getCurrentGroupFromURL() {
   
// Get group context using node from current URL. Note that we cannot rely
    // on menu_get_item(), or og_context_determine_context() due to $_GET['q']
    // not being set correctly.
   
$group_type = 'node';
   
$node = $this->getMainContext()->getNodeFromUrl();
   
$context = _group_context_handler_entity($group_type, $node);
    if (!
$context) {
      throw new \
Exception("No active organic group context could be found.");
    }
   
$gid = reset($context[$group_type]);
   
$group = entity_load_single($group_type, $gid);

    return
$group;
  }

 
/**
   * @Given /^I visit the parent group node$/
   */
 
public function iVisitTheParentGroupNode() {
   
$group = $this->getCurrentGroupFromURL();
   
$this->getSession()->visit($this->getMainContext()->locatePath('/node/' . $group->nid));
  }

 
/**
   * @Given /^I create a "([^"]*)" node belonging to the current organic group$/
   */
 
public function iCreateANodeBelongingToTheCurrentOrganicGroup($content_entity_type) {
   
// Get the current group.
   
$group = $this->getCurrentGroupFromURL();

   
// Create the group content.
   
$properties = array('og_group_ref' => $group->nid);
   
// Creating the node will automatically redirect the browser to view it.
   
$this->getMainContext()->createNode($content_entity_type, $properties);
  }
?>

A few required methods from the parent context:

<?php
 
/**
   * Returns node currently being viewed. Assumes /node/[nid] URL.
   *
   * Using path-based loaders, like menu_load_object(), will not work.
   *
   * @return object
   *   The currently viewed node.
   *
   * @throws Exception
   */
 
public function getNodeFromUrl() {

   
$path = $this->getCurrentPath();
   
$system_path = drupal_lookup_path('source', $path);
    if (!
$system_path) {
     
$system_path = $path;
    }
   
$menu_item = menu_get_item($system_path);
    if (
$menu_item['path'] == 'node/%') {
     
$node = node_load($menu_item['original_map'][1]);
    }
    else {
      throw new \
Exception(sprintf("Node could not be loaded from URL '%s'", $path));
    }
    return
$node;
  }

 
/**
   * @Given /^I am viewing (?:a|an) "([^"]*)" node$/
   * @Given /^I create (?:a|an) "([^"]*)" node$/
   *
   * This overrides the parent createNode() method, allowing node properties
   * to be passes via $properties argument.
   *
   * @override
   */
 
public function createNode($type, $properties = array()) {

   
$node = (object) array(
     
'title' => Random::name(25),
     
'type' => $type,
     
'uid' => 1,
    );

    if (
$properties) {
      foreach (
$properties as $key => $value) {
       
$node->$key = $value;
      }
    }

   
$this->dispatcher->dispatch('beforeNodeCreate', new EntityEvent($this, $node));
   
$saved = $this->getDriver()->createNode($node);
   
$this->dispatcher->dispatch('afterNodeCreate', new EntityEvent($this, $saved));
   
$this->nodes[] = $saved;

   
// Set internal page on the new node.
   
$this->getSession()->visit($this->locatePath('/node/' . $saved->nid));

    return
$saved;
  }

 
/**
   * Returns the most recently created node.
   *
   * @return object
   *   The most recently created node.
   */
 
public function getLastCreatedNode() {
    return
end($this->nodes);
  }
?>

Specifically note the following method, which automatically creates a parent organic group for any new node that may act as group content. This example assumes that you have a node type called 'group.'

<?php
 
/**
   * Create a parent organic group for all group content nodes.
   *
   * For group content, automatically create the parent group and assign
   * it to the og_group_ref field. To prevent an infinite loop, we do not do
   * this for nodes can also act as groups.
   *
   * @param obj $node
   *   A node that is about to be saved.
   */
 
public function createParentGroup($node) {
    if (
og_is_group_content_type('node', $node->type) && !og_is_group_type('node', $node->type)) {
      if (empty(
$node->og_group_ref)) {
       
$this->createNode('group');
       
$group = $this->getLastCreatedNode();
       
$node->og_group_ref = $group->nid;
      }
    }
  }
?>

These are great - thank you! - but isn't Behat 3.0.x indicated for use with Drupal 7.x?

Hi, thank you very much for sharing this. I'm hoping to do something similar but I've never worked with Behat before and I'm having trouble figuring out how to create custom steps like yours. The documentation on custom steps for 3rd party modules is scant and not very helpful for a newbie developer like myself.

I was wondering if you could share more information on the behat setup you're using. Would you be willing to post your behat.yml and your featurecontext file?

I wrote a custom module that extends OG a little bit, but I'm finding that the drupal behat extension just doesn't have the steps I need to test certain things for the module, while I see in your example is is possible to use some of drupal and OG's functions to create those steps,I'm having trouble getting my behat installation to recognize those functions. I'd be very grateful if the information in your behat.yml and featurecontext would help point me in the right direction.

Thanks!

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.