Disinstalling a WordPress plugin in Codeception

In a previous post I’ve presented a WordPress plugin requirement check baked into the wp-utils package and while that’s on the production side I want to be able to test the behaviours related to missing or incomplete requirements as well.
Codeception makes it easy using a cest format test and the fact that WordPress will consider a plugin “installed” when a .php file with a proper header is found in the plugins folder or in a first level sub-folder; that means that simply renaming a plugin main file removing the .php extension “uninstalls it” when it comes to WordPress logic.

The scenario

Plugin B requires Plugin A to work and I want to test that an helpful wp_die message is shown to the administrator when he tries to activate Plugin B while Plugin A is not installed.
Since that’s a test I need a reliable and programmatic way to “install” and “uninstall” a plugin on a per-test-method base without having to do any manual operations.

The code

I will use a cest test file format here to leverage the possibility offered by the _before and _after methods (PHPUnit equivalent of setUp and tearDown methods).

<?php

class ActivationAndInstallationRequirementsCest
{
    protected  $shouldRestorePluginAMainFile = false;
    protected $pluginAMainFile;

    public function _before()
    {
        $this->pluginAMainFile = dirname(__FILE__) . '/../../../Plugin-A/plugin-A';
    }

    public function _after()
    {
        if(!file_exists($this->pluginAMainFile . '.php')){
            $this->shouldRestorePluginAMainFile = true;
        }
        if($this->shouldRestorePluginAMainFile){
            rename($this->pluginAMainFile, $this->pluginAMainFile. '.php');
        }
    }

    public function shouldShowWpDiePageIfPluginANotInstalled(AcceptanceTester $I)
    {
        // setup
        $this->disinstallPluginAPlugin();
        $I->loginAsAdmin();
        $I->amOnPluginsPage();
        $I->dontSeePluginInstalled('plugin-a');

        // exercise
        $I->activatePlugin('plugin-b');

        // verify
        $I->seeWpDiePage();
        // make sure the wp_die page contains a link to install Plugin A
        $I->seeElement('a#plugin-a-installation-link');
    }

   protected function disinstallPluginAPlugin(){

       if(file_exists($this->pluginAMainFile . '.php')){
           $this->shouldRestorePluginAMainFile = rename($this->pluginAMainFile . '.php', $this->pluginAMainFile);
       }

   }
}

That’s all self explanatory and I could get rid of the _before method entirely hardcoding the path to the required plugin main file to slim down the test case further.