1

I'm writing an integration test for Magento 2 where I have to emulate the admin area.

To do so, I use the @magentoAppArea annotation:

/**
 * @magentoAppArea adminhtml
 */

However, some things did not work as expected and I found out that the current store id is set to "1" (default store) instead of "0" (admin store)

Here's a failing test as minimum example:

/**
 * @magentoAppArea adminhtml
 */
public function testAdminarea()
{
    $storeManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
        ->get(\Magento\Store\Model\StoreManagerInterface::class);
    $this->assertEquals(0, $storeManager->getStore()->getId());
}

How do I set up this test correctly?


What I found during debugging:

  1. Magento\TestFramework\Application::loadArea('adminhtml') is triggered correctly.

  2. The store id is first initialized in Magento\Store\Model\StoreResolver::getStoresData():

    $cacheKey = 'resolved_stores_' . md5($this->runMode . $this->scopeCode);
    $cacheData = $this->cache->load($cacheKey);
    

    Where $this->runMode is "website" and $this->scopeCode is "null".

2

I think the assumption that the admin store is always active in the adminhtml scope might no longer be true in Magento 2.
I have not found any constant with an admin store ID of zero anywhere. Probably that should also no longer be assumed to be the case.

The app state and the scope are both set to adminhtml by the annotation test listener, which probably is enough to trigger complete backend behavior.
I'm not sure though. What do you want to actually test?

/**
 * @magentoAppArea adminhtml
 */
public function testBackendScopeIsSet()
{
    /** @var ObjectManager $objectManager */
    $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();

    /** @var \Magento\TestFramework\App\State $state */
    $state = $objectManager->get(\Magento\TestFramework\App\State::class);
    $this->assertSame(Area::AREA_ADMINHTML, $state->getAreaCode());

    /** @var \Magento\Framework\Config\Scope $scope */
    $scope = $objectManager->get(\Magento\Framework\Config\Scope::class);
    $this->assertSame(Area::AREA_ADMINHTML, $scope->getCurrentScope());
}

Should your test require the admin store to be active you will also need to set that up manually in the arrange section of the test:

    /** @var StoreManagerInterface $storeManager */
    $storeManager = $objectManager->get(StoreManagerInterface::class);
    $storeManager->setCurrentStore(Store::ADMIN_CODE);

    $this->assertEquals(0, $storeManager->getStore()->getId());
  • I'm testing store emulation and Magento\Store\Model\App\Emulation checks if the current store is equal to the store to be emulated and does nothing in this case. It does not check what the current area is. I'm going to try your suggestion. – Fabian Schmengler Jun 17 '16 at 6:34
  • Curious why you are testing core functionality; or is this exploratory testing? – Vinai Jun 17 '16 at 6:35
  • I guess you could call it exploratory. I need to ensure that design, translations and certain configurations are emulated correctly. In Magento 1 the app emulation model did not do that sufficiently and it looks like this is still the case in Magento 2. So with this test I ensure that I am pulling the right levers. It already helped me to find out that I'll also need Magento\Framework\App\State::emulateAreaCode() but now I'm a bit stuck. – Fabian Schmengler Jun 17 '16 at 6:43
  • It would be cool to have an api method that takes care of all that. Maybe your work can be channeled into a PR? Some kind of facade maybe once you have all the levers figured out. – Vinai Jun 17 '16 at 6:46
  • We'll see. I'm getting closer :) – Fabian Schmengler Jun 17 '16 at 7:44
0

I'm pretty sure it should work without anything else.

Basically the @magentoAppArea annotation is defined under /dev/tests/integration/framework/Magento/TestFramework/Annotation/AppArea.php so if I'm not sure if the annotation would work if the test class is sitting under app/code/Vendor/Module/TestFolder

What that class does is to reinitialize then load the area you specified:

public function startTest(\PHPUnit_Framework_TestCase $test)
{
    $area = $this->_getTestAppArea($test->getAnnotations());
    if ($this->_application->getArea() !== $area) {
        $this->_application->reinitialize();

        if ($this->_application->getArea() !== $area) {
            $this->_application->loadArea($area);
        }
    }
}

The loadArea method is defined under /dev/tests/integration/framework/Magento/TestFramework/Application.php and does the following:

  • change the scope
  • reconfigure the OM based on the area config
  • load the area

    public function loadArea($areaCode)
    {
        $this->_appArea = $areaCode;
        $scope = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Config\Scope');
        $scope->setCurrentScope($areaCode);
        \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->configure(
            \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
                'Magento\Framework\App\ObjectManager\ConfigLoader'
            )->load(
                $areaCode
            )
        );
        $app = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\App\AreaList');
        if ($areaCode == \Magento\TestFramework\Application::DEFAULT_APP_AREA) {
            $app->getArea($areaCode)->load(\Magento\Framework\App\Area::PART_CONFIG);
        } else {
            \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea($areaCode);
        }
    }
    

Maybe this is where you should start debugging.

  • 1
    Thanks for the hints, but unfortunately this does not seem to be enough. I added a breakpoint in loadArea() and it is indeed triggered with the parameter "adminhtml" (before that, a few times with "global") and never with "frontend". The store id must have been set somewhere else – Fabian Schmengler Jun 16 '16 at 15:49
  • @fschmengler interesting I've contacted Vinai maybe he'll be able to help us – Raphael at Digital Pianism Jun 16 '16 at 15:51

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.