Como requisitos necesitaremos tener instalado Drupal y Behat con las extensiones necesarias para la integración con Drupal.
Prerequisitos
- Instalación de Drupal
- php 5.3.5 o más
- Java (necesario para Selenium)
- Selenium Server
Para más información visitar la pagina oficial: Drupal Extension to Behat and Mink
Instalación drupalextension (Behat + dependencias)
Para instalar Behat y las extensiones necesarias, nos basaremos en instalarlo mediante composer.
Instalación de Behat integrado directamente con Drupal a través de drupalextensión.
# create folder for drush for example opt:
mkdir /opt/behat && cd /opt/behat
# require drupal-extension
composer require drupal/drupal-extension
# Symlink to /usr/bin
ln -s /opt/behat/vendor/bin/behat /usr/local/bin/behat
# check version:
behat --version
Básicamente descargaremos drupal-extension más las dependencias necesarias, para ver más en concreto que dependencias se instala podremos ver todas desde este URL
https://packagist.org/packages/drupal/drupal-extension
Existen varios métodos de instalación tenemos más información en la documentación oficial que nos proporciona Behat.
http://docs.behat.org/en/stable/quick_start.html
Estructura base
Representaremos la estructura que tendrá al terminar el artículo, no es necesario saber exactamente cada elemento, solo la tendremos para identificar de manera más fácil la .
Este será el aspecto que tendrá al finalizar este artículo nuestro directorio dentro de un Drupal. De momento no entraremos en detalle de cada elemento, pero está estructura, nos servirá para visualizar todos los archivos que iremos generando a lo largo del artículo.
Drupal
├─sites
│ ├─all
│ │ └─test
│ │ └─behat
│ │ └─features
│ │ ├─*.feature
│ │ └─bootstrap
│ │ └─FeatureContext.php
│ └─default
│ └─default.behat.yml
Primeros pasos
Una vez tengamos lo requisitos previos, esto quiere decir que partimos de tener instalado un Drupal y Behat como sus dependencias.
Empezaremos yendo al directorio donde esta instalado nuestro Drupal, una vez aquí generaremos la primero la estructura base.
# Vamos al directorio sites/all
cd sites/all
# Generamos una carpeta llamada test
mkdir test
# Generamos una carpeta llamada behat dentro de test
mkdir test/behat
# Vamos a test/behat
cd test/behat
Una vez estamos dentro de este directorio ejecutaremos el siguiente comando de Behat.
behat --init
Después de ejecutar este comando Behat generará la siguiente estructura de archivos.
Un directorio llamado features, dentro nuestro proyecto.
Este directorio contendrá tanto los archivos .features, con nuestros pasos, como una subcarpeta llamada bootstrap el cual contendrá todos los contextos que integremos y un archivo base donde podremos extender nuestras funcionalidades, hacer pasos custom, ...
Contexto base generada
<?php
use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
/**
* Defines application features from the specific context.
*/
class FeatureContext implements Context, SnippetAcceptingContext
{
/**
* Initializes context.
*
* Every scenario gets its own context instance.
* You can also pass arbitrary arguments to the
* context constructor through behat.yml.
*/
public function __construct()
{
}
}
Llegados a este punto ya podremos ejecutar Behat y comprobar que lo tenemos instalado todo lo necesario.
# Ejecutamos behat para comprobar que funciona
behat
Como vemos Behat se ejecuta pero no encuentra ningún Step o paso que ejecutar, vamos a generar nuestro primer archivo .feature.
Crearemos un archivo llamado anonymous.homepage.feature, está nomenclatura esta basada en BDD (Desarrollo guiado por comportamiento), es una buena practica y nos basaremos en ella, no entraremos en detalle pero es una buena practica a seguir.
Feature: Como usuario anónimo puedo acceder a la homepage
Scenario: Anónimo navega a la homepage
When I should see "Drupal"
Si volvemos a ejecutar ahora Behat de nuevo está vez si parará por el primer Step que hemos definido
Feature: Como usuario anónimo puedo acceder a la homepage
Scenario: Anónimo navega a la homepage # features/anonymous.homepage.feature:3
Given I go to "/"
1 scenario (1 undefined)
1 step (1 undefined)
0m0.01s (7.05Mb)
--- FeatureContext has missing steps. Define them with these snippets:
/**
* @Given I go to :arg1
*/
public function iGoTo($arg1)
{
throw new PendingException();
}
Como muestra está respuesta esta ejecutando el primero paso que hemos agregado a nuestro fichero.
Pero aquí nos surge un duda, como le digo a Behat la URL donde esta montado, que pasos ejecuta, Behat no me proporciona pasos ya definidos, ...
Todas estás dudas son solventadas con un archivo, nuestro archivo YAML o .yml que tendrá toda la configuración pertinente.
Este es el archivo base .yml, en el llamaremos a los contextos más utilizados y que se nos descargó drupalextension
default:
suites:
default:
contexts:
- FeatureContext
- Drupal\DrupalExtension\Context\DrupalContext
- Drupal\DrupalExtension\Context\MinkContext
- Drupal\DrupalExtension\Context\MessageContext
- Drupal\DrupalExtension\Context\DrushContext
extensions:
Behat\MinkExtension:
goutte: ~
selenium2: ~
base_url: http://seven.l
Drupal\DrupalExtension:
blackbox: ~
No vamos a entrar en detalle ya que para definir todos los aspectos configurables por cada contexto añadido, ... No podría llevar mucho tiempo solo definiremos los más importantes y agregaremos un par de archivos y como generar un archivo YAML que nos proporciona Behat
Behat nos proporciona una manera de generar un archivo genérico
# Move to sites/default into the project
cd sites/default
# Create default.behat.yml
behat --config-reference > default.behat.yml
Este seria el archivo default.behat.yml generado
testwork:
argument: []
autoload:
# Default:
: %paths.base%/features/bootstrap
suites:
# Prototype
name:
# Enables/disables suite
enabled: true
# Specifies suite type
type: null
# Specifies suite extra settings
settings:
# Prototype
name: ~
formatters:
# Prototype
name:
# Prototype
name: ~
exceptions:
# Output verbosity
verbosity: 1 # Example: 1, 2, 3, 4
gherkin:
# Sets the gherkin parser cache folder
cache: /tmp/behat_gherkin_cache
# Sets the gherkin filters (overridable by CLI options)
filters:
# Prototype
name: ~
calls:
# Call executor will catch exceptions matching this level
error_reporting: 32767
translation:
# Sets output locale for the tester
locale: en
# Sets fallback output locale for the tester
fallback_locale: en
gherkin_translations: []
testers:
# Sets the strict mode for result interpretation
strict: false
# Tells tester to skip all tests
skip: false
# Sets the rerun cache path
rerun_cache: /tmp/behat_rerun_cache
cli: []
environments: []
specifications: []
filesystem: []
contexts: []
snippets: []
definitions: []
events: []
hooks: []
transformations: []
ordering: []
mink:
mink_loader: null
base_url: null
files_path: null
show_auto: false
show_cmd: null
show_tmp_dir: /tmp
# Defaults to the first non-javascript session if any, or the first session otherwise
default_session: null
...
Recortamos la salida ya que el archivo nos agrega todo lo configuráble contextos,.. aunque no lo usemos.
Esta sería una configuración un poco más detallada de un archivo .yml final
Todos los path que definamos cogerán de base el directorio desde donde este nuestro archivo .yml en nuestro caso en sites/defult
default:
autoload:
'': %paths.base%/[path-to-boostrap-dir]
suites:
default:
paths:
- %paths.base%/[path-to-feature-dir]
contexts: # Contexts used
- FeatureContext: # Default
- Drupal\DrupalExtension\Context\MinkContext: # Context Drupal extension
- Drupal\DrupalExtension\Context\MessageContext:
- Drupal\DrupalExtension\Context\DrushContext:
extensions:
Behat\MinkExtension:
goutte: ~
sessions:
default:
goutte:
guzzle_parameters:
verify: false
selenium2:
wd_host: "http://127.0.0.1:9000/wd/hub"
base_url: '[url-website]'
show_cmd: lynx %s
files_path: "%paths.base%/[path-files-dir]" # Define path to file, use to attachment file to drupal
Drupal\DrupalExtension:
blackbox: ~
drush_driver: "drush"
drush:
root: "[path-run-drush]" # Define path of being able to execute drush commands
api_driver: "drupal"
drupal:
drupal_root: "[path-index-site]" # Define path to index.php
region_map: # Define region use in steps
content: "#content"
selectors: # Use in MessageContext, define type message
message_selector: '.messages'
error_message_selector: '.messages.error'
success_message_selector: '.messages.status'
warning_message_selector: '.messages.warning'
text: # Default text find
password_field: "edit-pass"
username_field: "edit-name"
log_in: "Iniciar sesión"
log_out: "Cerrar sesión"
Para más información sobre las configuraciones tenemos unos artículos muy interesantes:
Configuración básica (y no tan básica) de behat 2.x para Drupal Extension
Behat 3.x y Drupal: cambios respecto a Behat 2.x
Y para terminar volveremos a ejecutar Behat pero esta vez le pasamos un parámetro --config para especificar que configuración utilizar.
behat --config=[path_to_yml]
# Example
behat --config=sites/default/default.behat.yml
Y si los pasos anteriores