-
Notifications
You must be signed in to change notification settings - Fork 27
Scopes
Scopes are a very powerful feature of Peridot. All tests and suites in Peridot have a Scope associated with them.
A scope's most basic use is a place to safely store state for a test without causing collisions with tests themselves. When a test or suite makes a reference to $this
it is actually referring to the Scope
of that test or suite.
Scope
objects are passed from parent nodes to their children.
##Extending functionality with scopes
Since $this
refers to a Scope
inside of a test or suite, it gives us the ability to add additional state and behavior to that Scope
.
How can we do this? Peridot uses a concept of child scopes to mix specialized behavior into an existing scope. This is exactly how the HttpKernel plugin adds BrowserKit functionality to tests, and how the Prophecy plugin is able to automatically inject mocks into tests.
Consider the following custom scope:
class WebDriverScope extends Scope
{
protected $driver;
protected $emitter;
public function __construct(RemoteWebDriver $driver, EventEmitterInterface $emitter)
{
$this->driver = $driver;
$this->emitter = $emitter;
$this->emitter->on('runner.end', function() {
$this->driver->quit();
});
}
public function getPage($url)
{
$this->driver->get($url);
}
public function findElementById($id)
{
return $this->driver->findElement(\WebDriverBy::id($id));
}
}
We can leverage this new behavior by adding it as a child scope:
###Adding via a plugin:
One possible way to mix this scope in is via the peridot.php
file using events
//peridot.php
return function(EventEmitterInterface $emitter) {
$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome());
$driverScope = new WebDriverScope($driver);
//add this scope into every suite
$emitter->on('suite.start', function($test) use ($driverScope) {
$test->getScope()->peridotAddChildScope($driverScope);
});
}
###Adding manually Another possible way to mix a child scope in is to do so manually on a test or suite:
describe('The home page', function() {
$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome());
$driverScope = new WebDriverScope($driver);
$this->peridotAddChildScope($scope);
it('should have a greeting', function() {
$this->getPage('http://localhost:4000'); //getPage is made available by child scope
$greeting = $this->findElementById('greeting'); //so is findElementById
assert($greeting->getText() === "Hello", "should be Hello");
});
});
###How child scopes work If a request for a method or property is made in a test or suite, and it does not exist on the root scope of that test or suite, the root scope will search all of it's descendants for a match.
This method allows us to build a hierarchy of child scopes containing specialized behavior and state without using traditional inheritance. We can visualize such a hierarchy like this:
+-----------+
| Test |
+-----+-----+
|
|
+-----+-----+
| Scope |
+-----------+
| |
+-------+--------+--+ +--+-----------------+
| WebDriverScope | | MockObjectScope |
+-------+--------+ +-----------------+
|
|
+-----------+-----------+
| SpecialWebDriverScope |
+-----------------------+
##Plugins that leverage scopes
-
Prophecy plugin - auto inject mocks into scope and adds
getProphet()
method to tests. -
HttpKernel plugin - adds a
$client
property to tests that leverages BrowserKit functionality.