Introducing WPFilesystem module

Getting to know wp-browser latest module.

Striking out items

I've laid down a list of the things to come in wp-browser and I'm striking out the items.
Today I'm shipping a new module aimed at making interaction with WordPress file structure easier; extending Codeception Filesystem module here is the WPFilesystem module.

Some code examples

The module aims at resolving some basic navigation issues in WordPress well know file and folder structure and requires, at a minimum, just one argument:

modules:
    enabled:
        - WPFilesystem
    config:
        WPFilesystem:
            wpRootFolder: /var/www/html

Relative paths to the uploads, themes, plugins and must-use plugins folders can be specified to cover non-standard WordPress installations.
Once the module has been provided this information moving into the WordPress installation files becomes a one-line work; if I had to test that a plugin or theme is correctly handling the file.txt file upload to the my-plugin folder in WordPress uploads folder I could write this:

$I->seeUploadedFileFound('my-plugin/file.txt');

In place of an assertion I might need to put a known file structure in place in the uploads folder as part of the testing fixture:

$source = codecept_data_dir('my-plugin-files');
$I->copyDirToUploads($source, 'my-plugin-files');

This will create a my-plugin-files folder in the WordPress installation uploads folder.
The module will deal with WordPress default uploads organization system where files are filed in a year/month folder hierarchy; if today was 2017-07-12 then any file uploaded today would end up, by default, in the uploads/2017/07 folder.
Any method provided by the module dealing with uploads supports a date argument to make sure that structure is respected.
Rewriting the examples above:

$I->seeUploadedFileFound('my-plugin/file.txt', 'today');

and

$I->copyDirToUploads($source, 'my-plugin-files', '-4 months');

In the first case, assuming today is 2017-07-12, the module will make sure an uploads/2017/07/my-plugin/file.txt file exists; in the second case the source folder will be copied to the uploads/2017/03 folder.
Since I'm lazy the module $date argument can be a UNIX timestamp, a formatted date or a string in a format supported by the strtotime function.
This is not nearly the end of it but it's a quick overview.

Themes, plugins and must-use plugin files

The module provides methods similar to those dedicated to uploads for plugins, must-use plugins and themes too.
If I had to make sure my theme preferences could be set using a preferences.json file placed in the theme root folder I could write this:

$preferences = json_encode(['showAds' => false]);
$I->writeToThemeFile('my-theme/preferences.json', $preferences);

$I->amOnPage('/');

$I->dontSeeElement('.ad');

The same applies to plugins and must-use plugins:

$license = 'luca::' . $this->generateLicenseFor('luca');

$I->writeToPluginFile('my-plugin/license', $license);

Each method provided by the WPFilesytem module that is creating files or folder will take care of removing those at the end of the test.

Sudo themes and plugins

Baked into the module is another feature I've wanted for a long time: ad-hoc creation of "sudo" test plugins and themes.
As an example I might have developed a plugin that hides plugins in the plugin administration screen for certain users; the list of the plugins that should be hidden is a plugin setting; I now want to make sure that the plugins that should be hidden for the user are, in fact, hidden:

$userId = $I->haveUserInDatabase('user','administrator', ['user_pass' => 'secret']);
$I->haveOptionInDatabase('my-plugin-hide-plugins',[$userId => ['foo','baz']]);

$code = '<?php echo "Hello there!";';
$I->havePlugin('foo/plugin.php', $code);
$I->havePlugin('baz/plugin.php', $code);
$I->havePlugin('bar/plugin.php', $code);


$I->loginAs('user','secret');
$I->amOnPluginsPage();

$I->dontSeeElement('tr[data-slug="foo"]');
$I->dontSeeElement('tr[data-slug="baz"]');
$I->seeElement('tr[data-slug="bar"]');

The module will create the plugin files but will not activate the plugins in the installation; for that dedicated methods like WPBrowser::activatePlugin() or the activate_plugin function are available.
On the same note the module allows scaffolding must-use plugins:

$I->haveMuPlugin('mu-plugin-1', $code);

And themes:

$I->haveTheme('test-theme', $indexCode, $functionsCode);

Themes are not activated but just created.
Any theme, plugin and must-use plugin created this way will be removed after the test.

Next

I have a bunch of fixes to put in place on wp-browser; after that I will tackled dedicated attachment support in the WPDb module and work on some ideas I've got for next features.