objectManager = Bootstrap::getObjectManager(); } protected function mockModel($filesystem = null) { if (!$filesystem) { $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); } $this->mail = $this->getMockBuilder(\Zend_Mail::class) ->setMethods(['send', 'addTo', 'addBcc', 'setReturnPath', 'setReplyTo']) ->setConstructorArgs(['utf-8']) ->getMock(); $this->model = $this->getMockBuilder(\Magento\Email\Model\Template::class) ->setMethods(['_getMail']) ->setConstructorArgs([ $this->objectManager->get(\Magento\Framework\Model\Context::class), $this->objectManager->get(\Magento\Framework\View\DesignInterface::class), $this->objectManager->get(\Magento\Framework\Registry::class), $this->objectManager->get(\Magento\Store\Model\App\Emulation::class), $this->objectManager->get(\Magento\Store\Model\StoreManager::class), $this->objectManager->create(\Magento\Framework\View\Asset\Repository::class), $filesystem, $this->objectManager->create(\Magento\Framework\App\Config\ScopeConfigInterface::class), $this->objectManager->get(\Magento\Email\Model\Template\Config::class), $this->objectManager->get(\Magento\Email\Model\TemplateFactory::class), $this->objectManager->get(\Magento\Framework\Filter\FilterManager::class), $this->objectManager->get(\Magento\Framework\UrlInterface::class), $this->objectManager->get(\Magento\Email\Model\Template\FilterFactory::class), ]) ->getMock(); $this->objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); $this->model->expects($this->any())->method('_getMail')->will($this->returnCallback([$this, 'getMail'])); $this->model->setSenderName('sender')->setSenderEmail('sender@example.com')->setTemplateSubject('Subject'); } /** * Return a disposable \Zend_Mail instance * * @return \PHPUnit_Framework_MockObject_MockObject|\Zend_Mail */ public function getMail() { return clone $this->mail; } public function testSetGetTemplateFilter() { $this->mockModel(); $filter = $this->model->getTemplateFilter(); $this->assertSame($filter, $this->model->getTemplateFilter()); $this->assertEquals( $this->objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId(), $filter->getStoreId() ); $filter = $this->objectManager->create(\Magento\Email\Model\Template\Filter::class); $this->model->setTemplateFilter($filter); $this->assertSame($filter, $this->model->getTemplateFilter()); } public function testLoadDefault() { $this->mockModel(); $this->model->loadDefault('customer_create_account_email_template'); $this->assertNotEmpty($this->model->getTemplateText()); $this->assertNotEmpty($this->model->getTemplateSubject()); $this->assertNotEmpty($this->model->getOrigTemplateVariables()); $this->assertInternalType('array', json_decode($this->model->getOrigTemplateVariables(), true)); } /** * @magentoAppIsolation enabled * @magentoDataFixture Magento/Store/_files/core_fixturestore.php */ public function testGetProcessedTemplate() { $this->mockModel(); $this->objectManager->get(\Magento\Framework\App\AreaList::class) ->getArea(Area::AREA_FRONTEND) ->load(); $expectedViewUrl = '/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; $this->model->setDesignConfig([ 'area' => 'frontend', 'store' => $this->objectManager->get(\Magento\Store\Model\StoreManagerInterface::class) ->getStore('fixturestore') ->getId(), ]); $this->model->setTemplateText('{{view url="Magento_Theme::favicon.ico"}}'); $this->setNotDefaultThemeForFixtureStore(); $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplate()); $this->setDefaultThemeForFixtureStore(); $this->assertStringEndsWith($expectedViewUrl, $this->model->getProcessedTemplate()); } /** * Test template directive to ensure that templates can be loaded from modules * * @param string $area * @param string $templateId * @param string $expectedOutput * @param bool $mockThemeFallback * * @magentoDataFixture Magento/Store/_files/core_fixturestore.php * @magentoComponentsDir Magento/Email/Model/_files/design * @magentoAppIsolation enabled * @magentoDbIsolation enabled * @dataProvider templateFallbackDataProvider */ public function testTemplateFallback($area, $templateId, $expectedOutput, $mockThemeFallback = false) { $this->mockModel(); if ($mockThemeFallback == BackendFrontNameResolver::AREA_CODE) { $this->setUpAdminThemeFallback(); } elseif ($mockThemeFallback == Area::AREA_FRONTEND) { $this->setUpThemeFallback($area); } $this->model->setId($templateId); $this->assertContains($expectedOutput, $this->model->processTemplate()); } /** * @return array */ public function templateFallbackDataProvider() { return [ 'Template from module - admin' => [ BackendFrontNameResolver::AREA_CODE, 'customer_create_account_email_template', 'To sign in to our site, use these credentials during checkout', ], 'Template from module - frontend' => [ Area::AREA_FRONTEND, 'customer_create_account_email_template', 'To sign in to our site, use these credentials during checkout', ], 'Template from theme - frontend' => [ Area::AREA_FRONTEND, 'customer_create_account_email_template', 'customer_create_account_email_template template from Vendor/custom_theme', Area::AREA_FRONTEND, ], 'Template from parent theme - frontend' => [ Area::AREA_FRONTEND, 'customer_create_account_email_confirmation_template', 'customer_create_account_email_confirmation_template template from Vendor/default', Area::AREA_FRONTEND, ], 'Template from grandparent theme - frontend' => [ Area::AREA_FRONTEND, 'customer_create_account_email_confirmed_template', 'customer_create_account_email_confirmed_template template from Magento/default', Area::AREA_FRONTEND, ], 'Template from grandparent theme - adminhtml' => [ BackendFrontNameResolver::AREA_CODE, 'catalog_productalert_cron_error_email_template', 'catalog_productalert_cron_error_email_template template from Magento/default', BackendFrontNameResolver::AREA_CODE, ], ]; } /** * Test template directive to ensure that templates can be loaded from modules, overridden in backend, and * overridden in themes * * @magentoDataFixture Magento/Store/_files/core_fixturestore.php * @magentoComponentsDir Magento/Email/Model/_files/design * @magentoAppIsolation enabled * @magentoDbIsolation enabled * @dataProvider templateDirectiveDataProvider * * @param string $area * @param int $templateType * @param string $templateText * @param string $assertContains * @param string $assertNotContains * @param string $storeConfigPath * @param bool $mockAdminTheme */ public function testTemplateDirective( $area, $templateType, $templateText, $assertContains, $assertNotContains = null, $storeConfigPath = null, $mockAdminTheme = false ) { $this->mockModel(); if ($mockAdminTheme) { $this->setUpAdminThemeFallback(); } else { $this->setUpThemeFallback($area); } $this->model->setTemplateType($templateType); $this->model->setTemplateText($templateText); // Allows for testing of templates overridden in backend if ($storeConfigPath) { $template = $this->objectManager->create(\Magento\Email\Model\Template::class); $templateData = [ 'template_code' => 'some_unique_code', 'template_type' => $templateType, 'template_text' => $assertContains, ]; $template->setData($templateData); $template->save(); // Store the ID of the newly created template in the system config so that this template will be loaded $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class) ->setValue($storeConfigPath, $template->getId(), ScopeInterface::SCOPE_STORE, 'fixturestore'); } $this->assertContains($assertContains, $this->model->getProcessedTemplate()); if ($assertNotContains) { $this->assertNotContains($assertNotContains, $this->model->getProcessedTemplate()); } } /** * @return array */ public function templateDirectiveDataProvider() { return [ 'Template from module folder - adminhtml' => [ BackendFrontNameResolver::AREA_CODE, TemplateTypesInterface::TYPE_HTML, '{{template config_path="design/email/footer_template"}}', "\n", ], 'Template from module folder - frontend' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="design/email/footer_template"}}', "\n", ], 'Template from module folder - plaintext' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_TEXT, '{{template config_path="design/email/footer_template"}}', 'Thank you', "\n", ], 'Template overridden in backend - adminhtml' => [ BackendFrontNameResolver::AREA_CODE, TemplateTypesInterface::TYPE_HTML, '{{template config_path="design/email/footer_template"}}', 'Footer configured in backend - email loaded via adminhtml', null, 'design/email/footer_template', ], 'Template overridden in backend - frontend' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="design/email/footer_template"}}', 'Footer configured in backend - email loaded via frontend', null, 'design/email/footer_template', ], 'Template from theme - frontend' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="customer/create_account/email_template"}}', 'customer_create_account_email_template template from Vendor/custom_theme', ], 'Template from parent theme - frontend' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="customer/create_account/email_confirmation_template"}}', 'customer_create_account_email_confirmation_template template from Vendor/default [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="customer/create_account/email_confirmed_template"}}', 'customer_create_account_email_confirmed_template template from Magento/default [ BackendFrontNameResolver::AREA_CODE, TemplateTypesInterface::TYPE_HTML, '{{template config_path="catalog/productalert_cron/error_email_template"}}', 'catalog_productalert_cron_error_email_template template from Magento/default or the "Template Styles" * textarea in backend, depending on whether template was loaded from filesystem or DB. * * @magentoDataFixture Magento/Store/_files/core_fixturestore.php * @magentoComponentsDir Magento/Email/Model/_files/design * @magentoAppIsolation enabled * @magentoDbIsolation enabled * @dataProvider templateStylesVariableDataProvider * * @param string $area * @param string $expectedOutput * @param array $unexpectedOutputs * @param array $templateForDatabase */ public function testTemplateStylesVariable($area, $expectedOutput, $unexpectedOutputs, $templateForDatabase = []) { if (count($templateForDatabase)) { $this->mockModel(); $this->setUpThemeFallback($area); $template = $this->objectManager->create(\Magento\Email\Model\Template::class); $template->setData($templateForDatabase); $template->save(); $templateId = $template->getId(); $this->model->load($templateId); } else { // parsing only via the loadDefault method. Since email template files won't contain // @styles comments by default, it is necessary to mock an object to return testable contents $themeDirectory = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\ReadInterface::class) ->disableOriginalConstructor() ->setMethods([ 'readFile', ]) ->getMockForAbstractClass(); $themeDirectory->expects($this->once()) ->method('readFile') ->will($this->returnValue(' {{var template_styles}}')); $filesystem = $this->getMockBuilder(\Magento\Framework\Filesystem::class) ->disableOriginalConstructor() ->setMethods(['getDirectoryRead']) ->getMock(); $filesystem->expects($this->once()) ->method('getDirectoryRead') ->with(DirectoryList::ROOT) ->will($this->returnValue($themeDirectory)); $this->mockModel($filesystem); $this->model->loadDefault('design_email_header_template'); } $processedTemplate = $this->model->getProcessedTemplate(); foreach ($unexpectedOutputs as $unexpectedOutput) { $this->assertNotContains($unexpectedOutput, $processedTemplate); } $this->assertContains($expectedOutput, $processedTemplate); } /** * @return array */ public function templateStylesVariableDataProvider() { return [ 'Styles from comment - adminhtml' => [ BackendFrontNameResolver::AREA_CODE, 'p { color: #111; }', [ ' comment - frontend' => [ Area::AREA_FRONTEND, 'p { color: #111; }', [ '