325 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
<?php
 | 
						|
/**
 | 
						|
 * Set of tests of layout directives handling behavior
 | 
						|
 *
 | 
						|
 * Copyright © Magento, Inc. All rights reserved.
 | 
						|
 * See COPYING.txt for license details.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Magento\Framework\View;
 | 
						|
 | 
						|
use Magento\Framework\App\State;
 | 
						|
 | 
						|
/**
 | 
						|
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
						|
 */
 | 
						|
class LayoutDirectivesTest extends \PHPUnit\Framework\TestCase
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var \Magento\Framework\View\LayoutFactory
 | 
						|
     */
 | 
						|
    protected $layoutFactory;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var \Magento\Framework\View\Layout\BuilderFactory
 | 
						|
     */
 | 
						|
    protected $builderFactory;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var \Magento\Framework\ObjectManagerInterface
 | 
						|
     */
 | 
						|
    protected $objectManager;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var \Magento\Framework\App\State
 | 
						|
     */
 | 
						|
    protected $state;
 | 
						|
 | 
						|
    protected function setUp(): void
 | 
						|
    {
 | 
						|
        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
 | 
						|
        $this->layoutFactory = $this->objectManager->get(\Magento\Framework\View\LayoutFactory::class);
 | 
						|
        $this->state = $this->objectManager->get(\Magento\Framework\App\State::class);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Prepare a layout model with pre-loaded fixture of an update XML
 | 
						|
     *
 | 
						|
     * @param string $fixtureFile
 | 
						|
     * @return \Magento\Framework\View\LayoutInterface
 | 
						|
     */
 | 
						|
    protected function _getLayoutModel($fixtureFile)
 | 
						|
    {
 | 
						|
        $this->objectManager->get(\Magento\Framework\App\Cache\Type\Layout::class)->clean();
 | 
						|
        $layout = $this->layoutFactory->create();
 | 
						|
        /** @var $xml \Magento\Framework\View\Layout\Element */
 | 
						|
        $xml = simplexml_load_file(
 | 
						|
            __DIR__ . "/_files/layout_directives_test/{$fixtureFile}",
 | 
						|
            \Magento\Framework\View\Layout\Element::class
 | 
						|
        );
 | 
						|
        $layout->loadString($xml->asXml());
 | 
						|
        $layout->generateElements();
 | 
						|
 | 
						|
        return $layout;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Test scheduled operations in the rendering of elements
 | 
						|
     *
 | 
						|
     * Expected behavior:
 | 
						|
     * 1) block1 was not declared at the moment when "1" invocation declared. The operation is scheduled
 | 
						|
     * 2) block1 creation directive schedules adding "2" as well
 | 
						|
     * 3) block2 is generated with "3"
 | 
						|
     * 4) yet another action schedules replacing value of block2 into "4"
 | 
						|
     * 5) when entire layout is read, all scheduled operations are executed in the same order as declared
 | 
						|
     *    (blocks are instantiated first, of course)
 | 
						|
     * The end result can be observed in container1
 | 
						|
     *
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testRenderElement()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('render.xml');
 | 
						|
        $this->assertEquals('124', $layout->renderElement('container_one'));
 | 
						|
        $this->assertEquals('12', $layout->renderElement('block_one'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testRenderNonExistentElementShouldThrowException()
 | 
						|
    {
 | 
						|
        $this->expectException(\OutOfBoundsException::class);
 | 
						|
 | 
						|
        $layout = $this->_getLayoutModel('render.xml');
 | 
						|
        $this->assertEmpty($layout->renderElement('nonexisting_element'));
 | 
						|
 | 
						|
        $this->expectExceptionMessage(
 | 
						|
            'The element with the "nonexisting_element" ID wasn\'t found. Verify the ID and try again.'
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Invoke getBlock() while layout is being generated
 | 
						|
     *
 | 
						|
     * Assertions in this test are pure formalism. The point is to emulate situation where block refers to other block
 | 
						|
     * while the latter hasn't been generated yet, and assure that there is no crash
 | 
						|
     */
 | 
						|
    public function testGetBlockUnscheduled()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('get_block.xml');
 | 
						|
        $this->assertInstanceOf(\Magento\Framework\View\Element\Text::class, $layout->getBlock('block_first'));
 | 
						|
        $this->assertInstanceOf(\Magento\Framework\View\Element\Text::class, $layout->getBlock('block_second'));
 | 
						|
    }
 | 
						|
 | 
						|
    public function testLayoutArgumentsDirective()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('arguments.xml');
 | 
						|
        $this->assertEquals('1', $layout->getBlock('block_with_args')->getOne());
 | 
						|
        $this->assertEquals('two', $layout->getBlock('block_with_args')->getTwo());
 | 
						|
        $this->assertEquals('3', $layout->getBlock('block_with_args')->getThree());
 | 
						|
    }
 | 
						|
 | 
						|
    public function testLayoutArgumentsDirectiveIfComplexValues()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('arguments_complex_values.xml');
 | 
						|
        $this->assertEquals(
 | 
						|
            ['parameters' => ['first' => '1', 'second' => '2']],
 | 
						|
            $layout->getBlock('block_with_args_complex_values')->getOne()
 | 
						|
        );
 | 
						|
        $this->assertEquals('two', $layout->getBlock('block_with_args_complex_values')->getTwo());
 | 
						|
        $this->assertEquals(
 | 
						|
            ['extra' => ['key1' => 'value1', 'key2' => 'value2']],
 | 
						|
            $layout->getBlock('block_with_args_complex_values')->getThree()
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    public function testLayoutObjectArgumentsDirective()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('arguments_object_type.xml');
 | 
						|
        $this->assertInstanceOf(
 | 
						|
            \Magento\Framework\Data\Collection::class,
 | 
						|
            $layout->getBlock('block_with_object_args')->getOne()
 | 
						|
        );
 | 
						|
        $this->assertInstanceOf(
 | 
						|
            \Magento\Framework\Data\Collection::class,
 | 
						|
            $layout->getBlock('block_with_object_args')->getTwo()
 | 
						|
        );
 | 
						|
        $this->assertEquals(3, $layout->getBlock('block_with_object_args')->getThree());
 | 
						|
    }
 | 
						|
 | 
						|
    public function testLayoutUrlArgumentsDirective()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('arguments_url_type.xml');
 | 
						|
        $this->assertStringContainsString('customer/account/login', $layout->getBlock('block_with_url_args')->getOne());
 | 
						|
        $this->assertStringContainsString(
 | 
						|
            'customer/account/logout',
 | 
						|
            $layout->getBlock('block_with_url_args')->getTwo()
 | 
						|
        );
 | 
						|
        $this->assertStringContainsString('customer_id/3', $layout->getBlock('block_with_url_args')->getTwo());
 | 
						|
    }
 | 
						|
 | 
						|
    public function testLayoutObjectArgumentUpdatersDirective()
 | 
						|
    {
 | 
						|
        $this->markTestSkipped('Will be fixed after MAGETWO-33840 will be done');
 | 
						|
        $layout = $this->_getLayoutModel('arguments_object_type_updaters.xml');
 | 
						|
 | 
						|
        $expectedObjectData = [0 => 'updater call', 1 => 'updater call'];
 | 
						|
 | 
						|
        $expectedSimpleData = 1;
 | 
						|
 | 
						|
        $dataSource = $layout->getBlock('block_with_object_updater_args')->getOne();
 | 
						|
        $this->assertInstanceOf(\Magento\Framework\Data\Collection::class, $dataSource);
 | 
						|
        $this->assertEquals($expectedObjectData, $dataSource->getUpdaterCall());
 | 
						|
        $this->assertEquals($expectedSimpleData, $layout->getBlock('block_with_object_updater_args')->getTwo());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testMoveSameAlias()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('move_the_same_alias.xml');
 | 
						|
        $this->assertEquals('container1', $layout->getParentName('no_name3'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testMoveNewAlias()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('move_new_alias.xml');
 | 
						|
        $this->assertEquals('new_alias', $layout->getElementAlias('no_name3'));
 | 
						|
    }
 | 
						|
 | 
						|
    public function testActionAnonymousParentBlock()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('action_for_anonymous_parent_block.xml');
 | 
						|
        $this->assertEquals('schedule_block0', $layout->getParentName('test.block.insert'));
 | 
						|
        $this->assertEquals('schedule_block1', $layout->getParentName('test.block.append'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testRemove()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('remove.xml');
 | 
						|
        $this->assertFalse($layout->getBlock('no_name2'));
 | 
						|
        $this->assertFalse($layout->getBlock('child_block1'));
 | 
						|
        $this->assertTrue($layout->isBlock('child_block2'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testRemoveCancellation()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('remove_cancellation.xml');
 | 
						|
        $this->assertTrue($layout->isContainer('container1'));
 | 
						|
        $this->assertTrue($layout->isBlock('child_block1'));
 | 
						|
        $this->assertTrue($layout->isBlock('no_name2'));
 | 
						|
        $this->assertFalse($layout->getBlock('not_exist'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testMove()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('move.xml');
 | 
						|
        $this->assertEquals('container2', $layout->getParentName('container1'));
 | 
						|
        $this->assertEquals('container1', $layout->getParentName('no.name2'));
 | 
						|
        $this->assertEquals('block_container', $layout->getParentName('no_name3'));
 | 
						|
 | 
						|
        // verify `after` attribute
 | 
						|
        $this->assertEquals('block_container', $layout->getParentName('no_name'));
 | 
						|
        $childrenOrderArray = array_keys($layout->getChildBlocks($layout->getParentName('no_name')));
 | 
						|
        $positionAfter = array_search('child_block1', $childrenOrderArray);
 | 
						|
        $positionToVerify = array_search('no_name', $childrenOrderArray);
 | 
						|
        $this->assertEquals($positionAfter, --$positionToVerify);
 | 
						|
 | 
						|
        // verify `before` attribute
 | 
						|
        $this->assertEquals('block_container', $layout->getParentName('no_name4'));
 | 
						|
        $childrenOrderArray = array_keys($layout->getChildBlocks($layout->getParentName('no_name4')));
 | 
						|
        $positionBefore = array_search('child_block2', $childrenOrderArray);
 | 
						|
        $positionToVerify = array_search('no_name4', $childrenOrderArray);
 | 
						|
        $this->assertEquals($positionBefore, ++$positionToVerify);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     */
 | 
						|
    public function testMoveBroken()
 | 
						|
    {
 | 
						|
        $this->expectException(\Magento\Framework\Exception\LocalizedException::class);
 | 
						|
 | 
						|
        $this->_getLayoutModel('move_broken.xml');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     */
 | 
						|
    public function testMoveAliasBroken()
 | 
						|
    {
 | 
						|
        $this->expectException(\Magento\Framework\Exception\LocalizedException::class);
 | 
						|
 | 
						|
        $this->_getLayoutModel('move_alias_broken.xml');
 | 
						|
    }
 | 
						|
 | 
						|
    public function testRemoveBroken()
 | 
						|
    {
 | 
						|
        if ($this->state->getMode() === State::MODE_DEVELOPER) {
 | 
						|
            $this->expectException('OutOfBoundsException');
 | 
						|
        }
 | 
						|
        $this->_getLayoutModel('remove_broken.xml');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param string $case
 | 
						|
     * @param string $expectedResult
 | 
						|
     * @dataProvider sortSpecialCasesDataProvider
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testSortSpecialCases($case, $expectedResult)
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel($case);
 | 
						|
        $this->assertEquals($expectedResult, $layout->renderElement('root'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function sortSpecialCasesDataProvider()
 | 
						|
    {
 | 
						|
        return [
 | 
						|
            'Before element which is after' => ['sort_before_after.xml', '312'],
 | 
						|
            'Before element which is previous' => ['sort_before_before.xml', '213'],
 | 
						|
            'After element which is after' => ['sort_after_after.xml', '312'],
 | 
						|
            'After element which is previous' => ['sort_after_previous.xml', '321']
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoConfigFixture current_store true_options 1
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testIfConfigForBlock()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('ifconfig.xml');
 | 
						|
        $this->assertFalse($layout->getBlock('block1'));
 | 
						|
        $this->assertFalse($layout->getBlock('block2'));
 | 
						|
        $this->assertInstanceOf(\Magento\Framework\View\Element\BlockInterface::class, $layout->getBlock('block3'));
 | 
						|
        $this->assertFalse($layout->getBlock('block4'));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @magentoConfigFixture current_store true_options 1
 | 
						|
     * @magentoAppIsolation enabled
 | 
						|
     */
 | 
						|
    public function testBlockGroups()
 | 
						|
    {
 | 
						|
        $layout = $this->_getLayoutModel('group.xml');
 | 
						|
        $childNames = $layout->getBlock('block1')->getGroupChildNames('group1');
 | 
						|
        $this->assertEquals(['block2', 'block3'], $childNames);
 | 
						|
    }
 | 
						|
}
 |