ThemeTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. /**
  7. * Test theme model
  8. */
  9. namespace Magento\Theme\Test\Unit\Model;
  10. use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
  11. use Magento\Framework\View\Design\ThemeInterface;
  12. use Magento\Theme\Model\Theme;
  13. /**
  14. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  15. */
  16. class ThemeTest extends \PHPUnit\Framework\TestCase
  17. {
  18. /**
  19. * @var \Magento\Theme\Model\Theme|\PHPUnit_Framework_MockObject_MockObject
  20. */
  21. protected $_model;
  22. /**
  23. * @var \PHPUnit_Framework_MockObject_MockObject
  24. */
  25. protected $_imageFactory;
  26. /**
  27. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\View\Design\Theme\FlyweightFactory
  28. */
  29. protected $themeFactory;
  30. /**
  31. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Theme\Model\ResourceModel\Theme\Collection
  32. */
  33. protected $resourceCollection;
  34. /**
  35. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\View\Design\Theme\Domain\Factory
  36. */
  37. protected $domainFactory;
  38. /**
  39. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\View\Design\Theme\Validator
  40. */
  41. protected $validator;
  42. /**
  43. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\View\Design\Theme\CustomizationFactory
  44. */
  45. protected $customizationFactory;
  46. /**
  47. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\State
  48. */
  49. protected $appState;
  50. /**
  51. * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Theme\Model\ThemeFactory
  52. */
  53. private $themeModelFactory;
  54. protected function setUp()
  55. {
  56. $customizationConfig = $this->createMock(\Magento\Theme\Model\Config\Customization::class);
  57. $this->customizationFactory = $this->createPartialMock(
  58. \Magento\Framework\View\Design\Theme\CustomizationFactory::class,
  59. ['create']
  60. );
  61. $this->resourceCollection = $this->createMock(\Magento\Theme\Model\ResourceModel\Theme\Collection::class);
  62. $this->_imageFactory = $this->createPartialMock(
  63. \Magento\Framework\View\Design\Theme\ImageFactory::class,
  64. ['create']
  65. );
  66. $this->themeFactory = $this->createPartialMock(
  67. \Magento\Framework\View\Design\Theme\FlyweightFactory::class,
  68. ['create']
  69. );
  70. $this->domainFactory = $this->createPartialMock(
  71. \Magento\Framework\View\Design\Theme\Domain\Factory::class,
  72. ['create']
  73. );
  74. $this->themeModelFactory = $this->createPartialMock(\Magento\Theme\Model\ThemeFactory::class, ['create']);
  75. $this->validator = $this->createMock(\Magento\Framework\View\Design\Theme\Validator::class);
  76. $this->appState = $this->createMock(\Magento\Framework\App\State::class);
  77. $objectManagerHelper = new ObjectManager($this);
  78. $arguments = $objectManagerHelper->getConstructArguments(
  79. \Magento\Theme\Model\Theme::class,
  80. [
  81. 'customizationFactory' => $this->customizationFactory,
  82. 'customizationConfig' => $customizationConfig,
  83. 'imageFactory' => $this->_imageFactory,
  84. 'resourceCollection' => $this->resourceCollection,
  85. 'themeFactory' => $this->themeFactory,
  86. 'domainFactory' => $this->domainFactory,
  87. 'validator' => $this->validator,
  88. 'appState' => $this->appState,
  89. 'themeModelFactory' => $this->themeModelFactory
  90. ]
  91. );
  92. $this->_model = $objectManagerHelper->getObject(\Magento\Theme\Model\Theme::class, $arguments);
  93. }
  94. protected function tearDown()
  95. {
  96. $this->_model = null;
  97. }
  98. /**
  99. * @covers \Magento\Theme\Model\Theme::getThemeImage
  100. */
  101. public function testThemeImageGetter()
  102. {
  103. $this->_imageFactory->expects($this->once())->method('create')->with(['theme' => $this->_model]);
  104. $this->_model->getThemeImage();
  105. }
  106. /**
  107. * @dataProvider isVirtualDataProvider
  108. * @param int $type
  109. * @param string $isVirtual
  110. * @covers \Magento\Theme\Model\Theme::isVirtual
  111. */
  112. public function testIsVirtual($type, $isVirtual)
  113. {
  114. $this->_model->setType($type);
  115. $this->assertEquals($isVirtual, $this->_model->isVirtual());
  116. }
  117. /**
  118. * @return array
  119. */
  120. public function isVirtualDataProvider()
  121. {
  122. return [
  123. ['type' => ThemeInterface::TYPE_VIRTUAL, 'isVirtual' => true],
  124. ['type' => ThemeInterface::TYPE_STAGING, 'isVirtual' => false],
  125. ['type' => ThemeInterface::TYPE_PHYSICAL, 'isVirtual' => false]
  126. ];
  127. }
  128. /**
  129. * @dataProvider isPhysicalDataProvider
  130. * @param int $type
  131. * @param string $isPhysical
  132. * @covers \Magento\Theme\Model\Theme::isPhysical
  133. */
  134. public function testIsPhysical($type, $isPhysical)
  135. {
  136. $this->_model->setType($type);
  137. $this->assertEquals($isPhysical, $this->_model->isPhysical());
  138. }
  139. /**
  140. * @return array
  141. */
  142. public function isPhysicalDataProvider()
  143. {
  144. return [
  145. ['type' => ThemeInterface::TYPE_VIRTUAL, 'isPhysical' => false],
  146. ['type' => ThemeInterface::TYPE_STAGING, 'isPhysical' => false],
  147. ['type' => ThemeInterface::TYPE_PHYSICAL, 'isPhysical' => true]
  148. ];
  149. }
  150. /**
  151. * @dataProvider isVisibleDataProvider
  152. * @param int $type
  153. * @param string $isVisible
  154. * @covers \Magento\Theme\Model\Theme::isVisible
  155. */
  156. public function testIsVisible($type, $isVisible)
  157. {
  158. $this->_model->setType($type);
  159. $this->assertEquals($isVisible, $this->_model->isVisible());
  160. }
  161. /**
  162. * @return array
  163. */
  164. public function isVisibleDataProvider()
  165. {
  166. return [
  167. ['type' => ThemeInterface::TYPE_VIRTUAL, 'isVisible' => true],
  168. ['type' => ThemeInterface::TYPE_STAGING, 'isVisible' => false],
  169. ['type' => ThemeInterface::TYPE_PHYSICAL, 'isVisible' => true]
  170. ];
  171. }
  172. /**
  173. * Test id deletable
  174. *
  175. * @dataProvider isDeletableDataProvider
  176. * @param string $themeType
  177. * @param bool $isDeletable
  178. * @covers \Magento\Theme\Model\Theme::isDeletable
  179. */
  180. public function testIsDeletable($themeType, $isDeletable)
  181. {
  182. $themeModel = $this->createPartialMock(\Magento\Theme\Model\Theme::class, ['getType']);
  183. $themeModel->expects($this->once())->method('getType')->will($this->returnValue($themeType));
  184. /** @var $themeModel \Magento\Theme\Model\Theme */
  185. $this->assertEquals($isDeletable, $themeModel->isDeletable());
  186. }
  187. /**
  188. * @return array
  189. */
  190. public function isDeletableDataProvider()
  191. {
  192. return [
  193. [ThemeInterface::TYPE_VIRTUAL, true],
  194. [ThemeInterface::TYPE_STAGING, true],
  195. [ThemeInterface::TYPE_PHYSICAL, false]
  196. ];
  197. }
  198. /**
  199. * @param mixed $originalCode
  200. * @param string $expectedCode
  201. * @dataProvider getCodeDataProvider
  202. */
  203. public function testGetCode($originalCode, $expectedCode)
  204. {
  205. $this->_model->setCode($originalCode);
  206. $this->assertSame($expectedCode, $this->_model->getCode());
  207. }
  208. /**
  209. * @return array
  210. */
  211. public function getCodeDataProvider()
  212. {
  213. return [
  214. 'string code' => ['theme/code', 'theme/code'],
  215. 'null code' => [null, ''],
  216. 'number code' => [10, '10']
  217. ];
  218. }
  219. /**
  220. * @test
  221. * @return void
  222. */
  223. public function testGetInheritedThemes()
  224. {
  225. $inheritedTheme = $this->getMockBuilder(\Magento\Framework\View\Design\ThemeInterface::class)->getMock();
  226. $this->_model->setParentId(10);
  227. $this->themeFactory->expects($this->once())
  228. ->method('create')
  229. ->with(10)
  230. ->willReturn($inheritedTheme);
  231. $this->assertContainsOnlyInstancesOf(
  232. \Magento\Framework\View\Design\ThemeInterface::class,
  233. $this->_model->getInheritedThemes()
  234. );
  235. $this->assertCount(2, $this->_model->getInheritedThemes());
  236. }
  237. /**
  238. * @test
  239. * @return void
  240. */
  241. public function testAfterDelete()
  242. {
  243. $expectId = 101;
  244. $theme = $this->getMockBuilder(\Magento\Framework\View\Design\ThemeInterface::class)
  245. ->setMethods(['delete', 'getId'])
  246. ->getMockForAbstractClass();
  247. $theme->expects($this->once())
  248. ->method('getId')
  249. ->willReturn($expectId);
  250. $theme->expects($this->once())
  251. ->method('delete')
  252. ->willReturnSelf();
  253. $this->_model->setId(1);
  254. $this->resourceCollection->expects($this->at(0))
  255. ->method('addFieldToFilter')
  256. ->with('parent_id', 1)
  257. ->willReturnSelf();
  258. $this->resourceCollection->expects($this->at(1))
  259. ->method('addFieldToFilter')
  260. ->with('type', Theme::TYPE_STAGING)
  261. ->willReturnSelf();
  262. $this->resourceCollection->expects($this->once())
  263. ->method('getFirstItem')
  264. ->willReturn($theme);
  265. $this->resourceCollection->expects($this->once())
  266. ->method('updateChildRelations')
  267. ->with($this->_model);
  268. $this->assertInstanceOf(get_class($this->_model), $this->_model->afterDelete());
  269. }
  270. /**
  271. * @test
  272. * @return void
  273. */
  274. public function testGetStagingVersion()
  275. {
  276. $theme = $this->getMockBuilder(\Magento\Framework\View\Design\ThemeInterface::class)
  277. ->setMethods(['getId'])
  278. ->getMockForAbstractClass();
  279. $theme->expects($this->once())
  280. ->method('getId')
  281. ->willReturn(null);
  282. $this->_model->setId(1);
  283. $this->resourceCollection->expects($this->at(0))
  284. ->method('addFieldToFilter')
  285. ->with('parent_id', 1)
  286. ->willReturnSelf();
  287. $this->resourceCollection->expects($this->at(1))
  288. ->method('addFieldToFilter')
  289. ->with('type', Theme::TYPE_STAGING)
  290. ->willReturnSelf();
  291. $this->resourceCollection->expects($this->once())
  292. ->method('getFirstItem')
  293. ->willReturn($theme);
  294. $this->assertNull($this->_model->getStagingVersion());
  295. }
  296. /**
  297. * @test
  298. * @return void
  299. */
  300. public function testGetStagingVersionWithoutTheme()
  301. {
  302. $this->assertNull($this->_model->getStagingVersion());
  303. }
  304. /**
  305. * @test
  306. * @return void
  307. */
  308. public function testGetDomainModel()
  309. {
  310. $result = 'res';
  311. $this->domainFactory->expects($this->once())
  312. ->method('create')
  313. ->with($this->_model)
  314. ->willReturn($result);
  315. $this->assertEquals($result, $this->_model->getDomainModel());
  316. }
  317. /**
  318. * @test
  319. * @expectedException \InvalidArgumentException
  320. * @return void
  321. */
  322. public function testGetDomainModelWithIncorrectType()
  323. {
  324. $this->_model->getDomainModel('bla-bla-bla');
  325. }
  326. /**
  327. * @test
  328. * @expectedException \Magento\Framework\Exception\LocalizedException
  329. * @expectedExceptionMessage testMessage
  330. * @return void
  331. */
  332. public function testValidate()
  333. {
  334. $this->validator->expects($this->once())
  335. ->method('validate')
  336. ->with($this->_model)
  337. ->willReturn(false);
  338. $this->validator->expects($this->once())
  339. ->method('getErrorMessages')
  340. ->willReturn([[__('testMessage')]]);
  341. $this->assertInstanceOf(get_class($this->_model), $this->_model->beforeSave());
  342. }
  343. /**
  344. * @test
  345. * @return void
  346. */
  347. public function testValidatePass()
  348. {
  349. $this->validator->expects($this->once())
  350. ->method('validate')
  351. ->with($this->_model)
  352. ->willReturn(true);
  353. $this->assertInstanceOf(get_class($this->_model), $this->_model->beforeSave());
  354. }
  355. /**
  356. * @test
  357. * @return void
  358. */
  359. public function testHasChildThemes()
  360. {
  361. $this->_model->setId(1);
  362. $this->resourceCollection->expects($this->once())
  363. ->method('addTypeFilter')
  364. ->with(Theme::TYPE_VIRTUAL)
  365. ->willReturnSelf();
  366. $this->resourceCollection->expects($this->once())
  367. ->method('addFieldToFilter')
  368. ->with('parent_id', ['eq' => 1])
  369. ->willReturnSelf();
  370. $this->resourceCollection->expects($this->once())
  371. ->method('getSize')
  372. ->willReturn(10);
  373. $this->assertTrue($this->_model->hasChildThemes());
  374. }
  375. /**
  376. * @test
  377. * @return void
  378. */
  379. public function testGetCustomization()
  380. {
  381. $this->customizationFactory->expects($this->once())
  382. ->method('create')
  383. ->willReturn(
  384. $this->getMockBuilder(\Magento\Framework\View\Design\Theme\CustomizationInterface::class)->getMock()
  385. );
  386. $this->assertInstanceOf(
  387. \Magento\Framework\View\Design\Theme\CustomizationInterface::class,
  388. $this->_model->getCustomization()
  389. );
  390. }
  391. /**
  392. * @test
  393. * @return void
  394. */
  395. public function testIsEditable()
  396. {
  397. $this->_model->setType(Theme::TYPE_VIRTUAL);
  398. $this->assertTrue($this->_model->isEditable());
  399. $this->_model->setType(Theme::TYPE_PHYSICAL);
  400. $this->assertFalse($this->_model->isEditable());
  401. }
  402. /**
  403. * @test
  404. * @return void
  405. */
  406. public function getFullThemePath()
  407. {
  408. $areaCode = 'frontend';
  409. $this->appState->expects($this->once())
  410. ->method('getAreaCode')
  411. ->willReturn($areaCode);
  412. $path = 'some/path';
  413. $this->_model->setThemePath($path);
  414. $this->assertEquals($areaCode . Theme::PATH_SEPARATOR . $path, $this->_model->getFullPath());
  415. }
  416. /**
  417. * @test
  418. * @return void
  419. */
  420. public function getParentTheme()
  421. {
  422. $this->_model->setParentTheme('parent_theme');
  423. $this->assertEquals('parent_theme', $this->_model->getParentTheme());
  424. }
  425. /**
  426. * @param array $themeData
  427. * @param array $expected
  428. * @dataProvider toArrayDataProvider
  429. */
  430. public function testToArray(array $themeData, array $expected)
  431. {
  432. $this->_model->setData($themeData);
  433. $this->assertEquals($expected, $this->_model->toArray());
  434. }
  435. /**
  436. * @return array
  437. */
  438. public function toArrayDataProvider()
  439. {
  440. $parentTheme = $this->getMockBuilder(\Magento\Theme\Model\Theme::class)
  441. ->disableOriginalConstructor()
  442. ->getMock();
  443. $childTheme = clone $parentTheme;
  444. $parentTheme->expects($this->once())
  445. ->method('toArray')
  446. ->willReturn('parent_theme');
  447. $childTheme->expects($this->exactly(2))
  448. ->method('toArray')
  449. ->willReturn('child_theme');
  450. return [
  451. 'null' => [[], []],
  452. 'valid' => [
  453. ['theme_data' => 'theme_data'],
  454. ['theme_data' => 'theme_data']
  455. ],
  456. 'valid with parent' => [
  457. [
  458. 'theme_data' => 'theme_data',
  459. 'parent_theme' => $parentTheme
  460. ],
  461. [
  462. 'theme_data' => 'theme_data',
  463. 'parent_theme' => 'parent_theme'
  464. ]
  465. ],
  466. 'valid with children' => [
  467. [
  468. 'theme_data' => 'theme_data',
  469. 'inherited_themes' => [
  470. 'key1' => $childTheme,
  471. 'key2' => $childTheme
  472. ]
  473. ],
  474. [
  475. 'theme_data' => 'theme_data',
  476. 'inherited_themes' => [
  477. 'key1' => 'child_theme',
  478. 'key2' => 'child_theme'
  479. ]
  480. ]
  481. ]
  482. ];
  483. }
  484. /**
  485. * @param array $value
  486. * @param array $expected
  487. * @param int $expectedCallCount
  488. *
  489. * @dataProvider populateFromArrayDataProvider
  490. */
  491. public function testPopulateFromArray(array $value, array $expected, $expectedCallCount = 0)
  492. {
  493. $themeMock = $this->getMockBuilder(\Magento\Theme\Model\Theme::class)
  494. ->disableOriginalConstructor()
  495. ->getMock();
  496. $themeMock->expects($this->exactly($expectedCallCount))
  497. ->method('populateFromArray')
  498. ->willReturn('theme_instance');
  499. $this->themeModelFactory->expects($this->exactly($expectedCallCount))
  500. ->method('create')
  501. ->willReturn($themeMock);
  502. $this->_model->populateFromArray($value);
  503. $this->assertEquals($expected, $this->_model->getData());
  504. }
  505. /**
  506. * @return array
  507. */
  508. public function populateFromArrayDataProvider()
  509. {
  510. return [
  511. 'valid data' => [
  512. 'value' => ['theme_data' => 'theme_data'],
  513. 'expected' => ['theme_data' => 'theme_data']
  514. ],
  515. 'valid data with parent' => [
  516. 'value' => [
  517. 'theme_data' => 'theme_data',
  518. 'parent_theme' => [
  519. 'theme_data' => 'theme_data'
  520. ]
  521. ],
  522. 'expected' => [
  523. 'theme_data' => 'theme_data',
  524. 'parent_theme' => 'theme_instance'
  525. ],
  526. 'expected call count' => 1
  527. ],
  528. 'valid data with children' => [
  529. 'value' => [
  530. 'theme_data' => 'theme_data',
  531. 'inherited_themes' => [
  532. 'key1' => ['theme_data' => 'theme_data'],
  533. 'key2' => ['theme_data' => 'theme_data']
  534. ]
  535. ],
  536. 'expected' => [
  537. 'theme_data' => 'theme_data',
  538. 'inherited_themes' => [
  539. 'key1' => 'theme_instance',
  540. 'key2' => 'theme_instance'
  541. ]
  542. ],
  543. 'expected call count' => 2
  544. ]
  545. ];
  546. }
  547. }