The first step to put in place an interactive bootstrap process for WPBrowser.
It’s complicated
I’ll admit to myself wp-browser bootstrap and following configuration could prove challenging for some users.
To cope with that and nicely integrate with wp-cli I’m putting in place an interactive bootstrap process.
“Interactive” is still a term that applies to a CLI command, the wpcept bootstrap
one, and that could help first time users to get up and running with WPBrowser and Codeception.
The interactive mode will be available running the command with the interactive
option like
wpcept bootstrap --interactive
the option comes in the -i
short form too.
So what do you want to ask me?
To make an example of how this interactive mode could help this is the drill I usually go through when scaffolding tests for a new WordPress plugin or theme:
- run
wpcept bootstrap
- check some path and memory settings in
codeception.yml
file, this is usually good to go out of the box - edit the
acceptance.suite.yml
file to match my local setup - edit the
functional.suite.yml
file to match my local setup - edit the
integration.suite.yml
file to match my local setup - check the
unit.suite.yml
, this file too is usually good to go out of the box
The difficult might rise while trying to configure one of the more complex configuration files like functional.suite.yml
:
class_name: FunctionalTester
modules:
enabled:
- FunctionalHelper
- Filesystem
- WPDb
- WordPress
config:
WPDb:
dsn: 'mysql:host=mysql;dbname=wpFuncTests'
user: root
password: ''
dump: tests/_data/dump.sql
populate: true
cleanup: true
url: 'http://wp.dev'
tablePrefix: wp_
WordPress:
depends: WPDb
wpRootFolder: /Users/Luca/Sites/wp
adminUsername: admin
adminPassword: admin
In order I edit:
- the database host to
mysql
- the database name to
wpFuncTests
- the url to
http://wp.dev
- the WordPress installation root folder to
/Users/Luca/Sites/wp
- the administrator username and password
I will go through the same drill, with variations, for acceptance and integration suites.
That’s not all though: under the hood I’ve created new databases and tested some connection settings; the database creation especially seems to be a point escaping to many wp-browser users that expect the suite to “do it all”.
While I won’t move in that direction I think some help and guidance along the way could help and make things clear.
Starting with a test
The wp-browser is a module library for Codeception and adding code without tests would do it a bad service.
I’ve added some unit testing for the suite config file template generation but the interesting part is the one where the whole bootstrap
command is put under test: I’m checking on its side effects of the file structure.
<?php
use Codeception\Command\WPBootstrap;
use Ofbeaton\Console\Tester\QuestionTester;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Yaml\Yaml;
class WPBootstrapTest extends \Codeception\Test\Unit
{
use QuestionTester;
protected static $path;
protected static $cwdBackup;
/**
* @var Application
*/
public $application;
/**
* @var OutputInterface
*/
protected $outputInterface;
/**
* @var InputInterface
*/
protected $inputInterface;
/**
* @var \IntegrationTester
*/
protected $tester;
public static function setUpBeforeClass()
{
self::$cwdBackup = getcwd();
self::$path = codecept_data_dir('folder-structures/wpbootstrap-test-root');
}
protected function _before()
{
self::clean();
}
public static function tearDownAfterClass()
{
self::clean();
chdir(self::$cwdBackup);
}
protected function testDir($relative = '')
{
$frag = $relative ? '/' . ltrim($relative, '/') : '';
return self::$path . $frag;
}
protected static function clean()
{
rrmdir(self::$path . '/tests');
foreach (glob(self::$path . '/*.*') as $file) {
unlink($file);
}
}
// removed some tests for brevity
/**
* @param $command
* @param $questionsAndAnswers
*/
protected function mockAnswers($command, $questionsAndAnswers)
{
$this->mockQuestionHelper($command, function ($text, $order, Question $question) use ($questionsAndAnswers) {
foreach ($questionsAndAnswers as $key => $value) {
if (strpos($text, $key) !== false) {
return $value;
}
}
// no question matched, fail
throw new PHPUnit_Framework_AssertionFailedError();
});
}
/**
* @test
* it should allow user to specify params through question for functional suite
*/
public function it_should_allow_user_to_specify_params_through_question_for_functional_suite()
{
$app = new Application();
$app->add(new WPBootstrap('bootstrap'));
$command = $app->find('bootstrap');
$commandTester = new CommandTester($command);
$questionsAndAnswers = [
'MySQL database host?' => 'mysql'
];
$this->mockAnswers($command, $questionsAndAnswers);
$commandTester->execute([
'command' => $command->getName(),
'path' => $this->testDir(),
'--no-build' => true,
'--interactive' => true
]);
$file = $this->testDir('tests/functional.suite.yml');
$this->assertFileExists($file);
$fileContents = file_get_contents($file);
$this->assertNotEmpty($fileContents);
$decoded = Yaml::parse($fileContents);
$this->assertNotEmpty($decoded['modules']['config']['WPDb']['dsn']);
$this->assertContains('mysql:host=mysql', $decoded['modules']['config']['WPDb']['dsn']);
}
}
Some things to note here:
- Codeception is a Symfony Console command and as such I’m testing it the same way the Symfony site shows; not much difference here but the application and command setup might be confusing
- the
use QuestionTester
statement uses a trait defined in the console-tester package - the
mockAnswers
method “mocks” the user answers setting those up as I need - I’m using the
path
argument of thebootstrap
command to avoid Codeception overwriting its own configuration during the tests; given the possibility I would not use the real filesystem and would rather rely on vfsStream but Codeception use of thechdir
function makes it impossible; as such I’m working in thetests/_data
folder.
Next
I’ve been able to pass the test method above and will move on to cover all the fields a user might need to reasonably change and could use help with; so far a smooth ride.