Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
178 lines
5.1 KiB
PHP
178 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace Cms\Tests\Classes;
|
|
|
|
use System\Tests\Bootstrap\TestCase;
|
|
use Cms\Classes\Theme;
|
|
use Cms\Models\ThemeData;
|
|
use Config;
|
|
use Event;
|
|
use Winter\Storm\Exception\ApplicationException;
|
|
|
|
class ThemeTest extends TestCase
|
|
{
|
|
public function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Config::set('cms.activeTheme', 'test');
|
|
Config::set('cms.themesPath', '/modules/cms/tests/fixtures/themes');
|
|
|
|
Event::flush('cms.theme.getActiveTheme');
|
|
Theme::resetCache();
|
|
}
|
|
|
|
protected function countThemePages($path)
|
|
{
|
|
$result = 0;
|
|
$it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
|
|
$it->setMaxDepth(1);
|
|
$it->rewind();
|
|
|
|
while ($it->valid()) {
|
|
if (!$it->isDot() && !$it->isDir() && $it->getExtension() == 'htm') {
|
|
$result++;
|
|
}
|
|
|
|
$it->next();
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function testGetPath()
|
|
{
|
|
if (PHP_OS_FAMILY === 'Windows') {
|
|
$this->markTestIncomplete('Need to fix Windows testing here');
|
|
}
|
|
|
|
$theme = Theme::load('test');
|
|
|
|
$this->assertEquals(base_path('modules/cms/tests/fixtures/themes/test'), $theme->getPath());
|
|
}
|
|
|
|
public function testListPages()
|
|
{
|
|
$theme = Theme::load('test');
|
|
|
|
$pageCollection = $theme->listPages();
|
|
$pages = array_values($pageCollection->all());
|
|
$this->assertIsArray($pages);
|
|
|
|
$expectedPageNum = $this->countThemePages(base_path() . '/modules/cms/tests/fixtures/themes/test/pages');
|
|
$this->assertCount($expectedPageNum, $pages);
|
|
|
|
$this->assertInstanceOf('\Cms\Classes\Page', $pages[0]);
|
|
$this->assertNotEmpty($pages[0]->url);
|
|
$this->assertInstanceOf('\Cms\Classes\Page', $pages[1]);
|
|
$this->assertNotEmpty($pages[1]->url);
|
|
}
|
|
|
|
public function testGetActiveTheme()
|
|
{
|
|
$activeTheme = Theme::getActiveTheme();
|
|
|
|
$this->assertNotNull($activeTheme);
|
|
$this->assertEquals('test', $activeTheme->getDirName());
|
|
}
|
|
|
|
public function testNoActiveTheme()
|
|
{
|
|
$this->expectException(\Winter\Storm\Exception\SystemException::class);
|
|
$this->expectExceptionMessage('The active theme is not set.');
|
|
|
|
Config::set('cms.activeTheme', null);
|
|
Theme::getActiveTheme();
|
|
}
|
|
|
|
public function testApiTheme()
|
|
{
|
|
Event::flush('cms.theme.getActiveTheme');
|
|
Event::listen('cms.theme.getActiveTheme', function () {
|
|
return 'apitest';
|
|
});
|
|
|
|
$activeTheme = Theme::getActiveTheme();
|
|
$this->assertNotNull($activeTheme);
|
|
$this->assertEquals('apitest', $activeTheme->getDirName());
|
|
}
|
|
|
|
public function testChildThemeConfig()
|
|
{
|
|
Config::set('cms.activeTheme', 'childtest');
|
|
|
|
$theme = Theme::getActiveTheme();
|
|
$config = $theme->getConfig();
|
|
|
|
$this->assertArrayHasKey('parent', $config);
|
|
$this->assertEquals('test', $config['parent']);
|
|
}
|
|
|
|
public function testChildThemeAssetUrl()
|
|
{
|
|
Config::set('cms.activeTheme', 'childtest');
|
|
|
|
$theme = Theme::getActiveTheme();
|
|
|
|
$this->assertStringContainsString(
|
|
'modules/cms/tests/fixtures/themes/test/assets/css/style1.css',
|
|
$theme->assetUrl('assets/css/style1.css')
|
|
);
|
|
|
|
$this->assertStringContainsString(
|
|
'modules/cms/tests/fixtures/themes/childtest/assets/css/style2.css',
|
|
$theme->assetUrl('assets/css/style2.css')
|
|
);
|
|
}
|
|
|
|
public function dirNameValidityProvider(): array
|
|
{
|
|
return [
|
|
// Valid names
|
|
'lowercase' => ['mytheme', true],
|
|
'uppercase' => ['MYTHEME', true],
|
|
'mixed case' => ['MyTheme', true],
|
|
'with digits' => ['theme123', true],
|
|
'with hyphens' => ['my-theme', true],
|
|
'with underscores' => ['my_theme', true],
|
|
'all allowed' => ['My-Theme_123', true],
|
|
'single char' => ['a', true],
|
|
|
|
// Invalid names
|
|
'empty string' => ['', false],
|
|
'dot' => ['.', false],
|
|
'dot dot' => ['..', false],
|
|
'path traversal' => ['../etc', false],
|
|
'forward slash' => ['foo/bar', false],
|
|
'backslash' => ['foo\\bar', false],
|
|
'spaces' => ['my theme', false],
|
|
'special chars' => ['theme!@#', false],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dirNameValidityProvider
|
|
*/
|
|
public function testIsValidDirName(string $dirName, bool $expected): void
|
|
{
|
|
$this->assertSame($expected, Theme::isValidDirName($dirName));
|
|
}
|
|
|
|
public function testLoadRejectsPathTraversal()
|
|
{
|
|
$this->expectException(ApplicationException::class);
|
|
|
|
Theme::load('../../etc');
|
|
}
|
|
|
|
public function testResetCacheClearsThemeData()
|
|
{
|
|
$themeData = new ThemeData(['theme' => 'test']);
|
|
self::setProtectedProperty($themeData, 'instances', ['test' => $themeData]);
|
|
|
|
Theme::resetCache();
|
|
|
|
$this->assertEmpty(self::getProtectedProperty($themeData, 'instances'));
|
|
}
|
|
}
|