Initial Commit
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
|
||||
final class LegacyThemeNamespaceAliasTest extends TestCase
|
||||
{
|
||||
public function test_legacy_theme_namespace_resolves_to_application_theme_directory(): void
|
||||
{
|
||||
$this->assertTrue(view()->exists('stylist-module-theme-backend::dashboard'));
|
||||
$this->assertTrue(view()->exists('stylist-theme-backend::dashboard'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Modules\Stylist\Theme\Stylist;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class StylistModuleTest extends TestCase
|
||||
{
|
||||
public function test_stylist_service_resolves(): void
|
||||
{
|
||||
$this->assertInstanceOf(Stylist::class, app(Stylist::class));
|
||||
}
|
||||
|
||||
public function test_default_theme_resolves(): void
|
||||
{
|
||||
config(['stylist.default_theme' => 'backend']);
|
||||
|
||||
$this->assertSame('backend', app(Stylist::class)->current()->key());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Stylist\Services\TenantThemeResolver;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class TenantThemeResolverTest extends TestCase
|
||||
{
|
||||
public function test_dashboard_request_uses_backend_context(): void
|
||||
{
|
||||
$request = Request::create('/dashboard', 'GET');
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
$this->assertSame('backend', app(TenantThemeResolver::class)->context());
|
||||
}
|
||||
|
||||
public function test_settings_request_uses_backend_context(): void
|
||||
{
|
||||
$request = Request::create('/settings/profile', 'GET');
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
$this->assertSame('backend', app(TenantThemeResolver::class)->context());
|
||||
}
|
||||
|
||||
public function test_admin_request_uses_backend_context(): void
|
||||
{
|
||||
$request = Request::create('/admin', 'GET');
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
$this->assertSame('backend', app(TenantThemeResolver::class)->context());
|
||||
}
|
||||
|
||||
public function test_admin_helpdesk_request_uses_backend_context(): void
|
||||
{
|
||||
$request = Request::create('/admin/helpdesk', 'GET');
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
$this->assertSame('backend', app(TenantThemeResolver::class)->context());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Modules\Stylist\Services\ThemeAccessibilityValidator;
|
||||
use Modules\Stylist\Theme\Theme;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ThemeAccessibilityValidatorTest extends TestCase
|
||||
{
|
||||
private string $themePath;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->themePath = storage_path('framework/testing/stylist-accessibility-'.uniqid());
|
||||
mkdir($this->themePath.'/views', 0777, true);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
app(Filesystem::class)->deleteDirectory($this->themePath);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_blade_object_access_does_not_break_image_alt_detection(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themePath.'/views/page.blade.php',
|
||||
'<img src="{{ $post->featuredImageUrl() }}" alt="{{ $post->title }}">'
|
||||
);
|
||||
|
||||
$this->assertSame([], $this->validate());
|
||||
}
|
||||
|
||||
public function test_image_without_alt_is_reported(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themePath.'/views/page.blade.php',
|
||||
'<img src="{{ $post->featuredImageUrl() }}">'
|
||||
);
|
||||
|
||||
$issues = $this->validate();
|
||||
|
||||
$this->assertCount(1, $issues);
|
||||
$this->assertSame('error', $issues[0]['severity']);
|
||||
$this->assertSame('1 image(s) missing alt text.', $issues[0]['message']);
|
||||
}
|
||||
|
||||
public function test_aria_labelled_icon_button_is_not_reported(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themePath.'/views/page.blade.php',
|
||||
'<button type="button" aria-label="Open navigation"><span></span><span></span></button>'
|
||||
);
|
||||
|
||||
$this->assertSame([], $this->validate());
|
||||
}
|
||||
|
||||
public function test_button_with_visible_text_is_not_reported(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themePath.'/views/page.blade.php',
|
||||
'<button type="submit"><span>Save</span></button>'
|
||||
);
|
||||
|
||||
$this->assertSame([], $this->validate());
|
||||
}
|
||||
|
||||
public function test_empty_unlabelled_button_is_reported(): void
|
||||
{
|
||||
file_put_contents(
|
||||
$this->themePath.'/views/page.blade.php',
|
||||
'<button type="button"><span></span></button>'
|
||||
);
|
||||
|
||||
$issues = $this->validate();
|
||||
|
||||
$this->assertCount(1, $issues);
|
||||
$this->assertSame('warning', $issues[0]['severity']);
|
||||
$this->assertSame('1 button(s) may lack an accessible name.', $issues[0]['message']);
|
||||
}
|
||||
|
||||
/** @return array<int, array{severity:string,message:string,file:string}> */
|
||||
private function validate(): array
|
||||
{
|
||||
$theme = new Theme('test', 'Test', $this->themePath);
|
||||
|
||||
return app(ThemeAccessibilityValidator::class)->validate($theme);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Modules\Stylist\Theme\Loader;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ThemeAssetControllerTest extends TestCase
|
||||
{
|
||||
public function test_active_theme_css_is_served(): void
|
||||
{
|
||||
config(['stylist.themes_path' => resource_path('themes')]);
|
||||
app(Loader::class)->flush();
|
||||
|
||||
$this->get(route('stylist.theme.asset', [
|
||||
'theme' => 'frontend',
|
||||
'path' => 'css/theme.css',
|
||||
]))->assertOk()->assertHeader('X-Content-Type-Options', 'nosniff');
|
||||
}
|
||||
|
||||
public function test_asset_url_uses_public_themes_path(): void
|
||||
{
|
||||
$url = route('stylist.theme.asset', [
|
||||
'theme' => 'frontend',
|
||||
'path' => 'images/example.jpg',
|
||||
], false);
|
||||
|
||||
$this->assertSame('/themes/frontend/images/example.jpg', $url);
|
||||
}
|
||||
|
||||
public function test_non_asset_theme_files_are_not_served(): void
|
||||
{
|
||||
config(['stylist.themes_path' => resource_path('themes')]);
|
||||
app(Loader::class)->flush();
|
||||
|
||||
$this->get(route('stylist.theme.asset', [
|
||||
'theme' => 'frontend',
|
||||
'path' => 'views/home.blade.php',
|
||||
]))->assertNotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Modules\Stylist\Html\ThemeHtmlBuilder;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ThemeHtmlBuilderTest extends TestCase
|
||||
{
|
||||
public function test_css_variables_are_rendered(): void
|
||||
{
|
||||
config(['stylist.fallback_variables.brand-primary' => '#111827']);
|
||||
|
||||
$html = app(ThemeHtmlBuilder::class)->variables()->toHtml();
|
||||
|
||||
$this->assertStringContainsString('--brand-primary: #111827;', $html);
|
||||
}
|
||||
|
||||
public function test_appearance_does_not_overwrite_theme_identity(): void
|
||||
{
|
||||
$html = app(ThemeHtmlBuilder::class)->variables()->toHtml();
|
||||
|
||||
$this->assertStringContainsString('d.dataset.theme=k', $html);
|
||||
$this->assertStringContainsString('d.dataset.appearance=dark?', $html);
|
||||
$this->assertStringNotContainsString("d.dataset.theme=dark?'dark':'light'", $html);
|
||||
}
|
||||
|
||||
public function test_appearance_variables_use_data_appearance_selector(): void
|
||||
{
|
||||
$html = app(ThemeHtmlBuilder::class)->variables()->toHtml();
|
||||
|
||||
if (str_contains($html, 'data-appearance')) {
|
||||
$this->assertStringNotContainsString(':root[data-theme="dark"]', $html);
|
||||
} else {
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Modules\Stylist\Diagnostics\ThemeInspector;
|
||||
use Modules\Stylist\Theme\Loader;
|
||||
use Modules\Stylist\View\ThemeViewResolver;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ThemeInheritanceTest extends TestCase
|
||||
{
|
||||
private string $themesPath;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->themesPath = storage_path('framework/testing/stylist-inheritance-'.uniqid());
|
||||
mkdir($this->themesPath, 0777, true);
|
||||
config([
|
||||
'stylist.themes_path' => $this->themesPath,
|
||||
'stylist.default_theme' => 'common',
|
||||
]);
|
||||
app(Loader::class)->flush();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
app(Filesystem::class)->deleteDirectory($this->themesPath);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_child_theme_resolves_views_through_parent_without_copying_them(): void
|
||||
{
|
||||
$this->theme('common', null, ['components/layouts/app.blade.php' => '<main>{{ $slot }}</main>']);
|
||||
$this->theme('admin', 'common', ['dashboard.blade.php' => '<h1>Dashboard</h1>']);
|
||||
app(Loader::class)->flush();
|
||||
|
||||
$candidates = app(ThemeViewResolver::class)->candidatesForTheme('admin', 'components.layouts.app');
|
||||
|
||||
$this->assertSame('stylist-theme-admin::components.layouts.app', $candidates[0]);
|
||||
$this->assertContains('stylist-theme-common::components.layouts.app', $candidates);
|
||||
$this->assertLessThan(
|
||||
array_search('stylist-theme-common::components.layouts.app', $candidates, true),
|
||||
array_search('stylist-theme-admin::components.layouts.app', $candidates, true),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_parent_alias_is_normalised_to_extends(): void
|
||||
{
|
||||
$path = $this->themesPath.'/child';
|
||||
mkdir($path, 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode([
|
||||
'name' => 'Child',
|
||||
'parent' => 'common',
|
||||
]));
|
||||
|
||||
$theme = app(Loader::class)->fromPath($path);
|
||||
|
||||
$this->assertSame('common', $theme->parent());
|
||||
}
|
||||
|
||||
public function test_duplicate_view_ownership_is_reported(): void
|
||||
{
|
||||
$this->theme('common', null, ['livewire/auth/login.blade.php' => 'common']);
|
||||
$this->theme('admin', 'common', ['livewire/auth/login.blade.php' => 'admin']);
|
||||
app(Loader::class)->flush();
|
||||
|
||||
$duplicates = app(ThemeInspector::class)->duplicateViews();
|
||||
|
||||
$this->assertArrayHasKey('livewire/auth/login.blade.php', $duplicates);
|
||||
$this->assertEqualsCanonicalizing(['common', 'admin'], array_column($duplicates['livewire/auth/login.blade.php'], 'theme'));
|
||||
}
|
||||
|
||||
/** @param array<string, string> $views */
|
||||
private function theme(string $key, ?string $parent, array $views): void
|
||||
{
|
||||
$path = $this->themesPath.'/'.$key;
|
||||
mkdir($path.'/views', 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode(array_filter([
|
||||
'name' => ucfirst($key),
|
||||
'slug' => $key,
|
||||
'extends' => $parent,
|
||||
], fn ($value) => $value !== null)));
|
||||
|
||||
foreach ($views as $relative => $contents) {
|
||||
$file = $path.'/views/'.$relative;
|
||||
if (! is_dir(dirname($file))) {
|
||||
mkdir(dirname($file), 0777, true);
|
||||
}
|
||||
file_put_contents($file, $contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Modules\Stylist\Theme\Exceptions\InvalidThemeManifestException;
|
||||
use Modules\Stylist\Theme\Loader;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ThemeManifestTest extends TestCase
|
||||
{
|
||||
private string $themesPath;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->themesPath = storage_path('framework/testing/stylist-themes-'.uniqid());
|
||||
mkdir($this->themesPath, 0777, true);
|
||||
config(['stylist.themes_path' => $this->themesPath]);
|
||||
app(Loader::class)->flush();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
app(Filesystem::class)->deleteDirectory($this->themesPath);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_manifest_is_normalised(): void
|
||||
{
|
||||
$path = $this->themesPath.'/sample';
|
||||
mkdir($path.'/css', 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode(['name' => 'Sample']));
|
||||
file_put_contents($path.'/css/theme.css', 'body{}');
|
||||
|
||||
$theme = app(Loader::class)->fromPath($path);
|
||||
|
||||
$this->assertSame('sample', $theme->key());
|
||||
$this->assertSame('css/theme.css', $theme->stylesheet());
|
||||
$this->assertSame('js/app.js', $theme->script());
|
||||
$this->assertSame('home', $theme->entryView());
|
||||
}
|
||||
|
||||
public function test_unsafe_manifest_path_is_rejected(): void
|
||||
{
|
||||
$path = $this->themesPath.'/unsafe';
|
||||
mkdir($path, 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode([
|
||||
'name' => 'Unsafe',
|
||||
'stylesheet' => '../secret.css',
|
||||
]));
|
||||
|
||||
$this->expectException(InvalidThemeManifestException::class);
|
||||
app(Loader::class)->fromPath($path);
|
||||
}
|
||||
|
||||
public function test_phase_one_manifest_optional_capabilities_are_normalised(): void
|
||||
{
|
||||
$path = $this->themesPath.'/design-gallery';
|
||||
mkdir($path.'/css', 0777, true);
|
||||
mkdir($path.'/js', 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode([
|
||||
'key' => 'design-gallery',
|
||||
'name' => 'Design Gallery',
|
||||
'stylesheet' => 'css/app.css',
|
||||
'script' => 'js/app.js',
|
||||
'appearances' => ['light', 'dark', 'system'],
|
||||
'accents' => ['blue', 'emerald', 'neutral'],
|
||||
'default_appearance' => 'system',
|
||||
'default_accent' => 'neutral',
|
||||
// Phase 1 incorrectly duplicated accents here; Stylist must not
|
||||
// reject the whole theme because of that compact legacy list.
|
||||
'variants' => ['blue', 'emerald', 'neutral'],
|
||||
]));
|
||||
file_put_contents($path.'/css/app.css', 'body{}');
|
||||
file_put_contents($path.'/js/app.js', '');
|
||||
|
||||
$theme = app(Loader::class)->fromPath($path);
|
||||
|
||||
$this->assertSame(['light', 'dark', 'system'], array_keys($theme->appearances()));
|
||||
$this->assertSame(['blue', 'emerald', 'neutral'], array_keys($theme->accents()));
|
||||
$this->assertSame([], $theme->variants());
|
||||
$this->assertSame('system', $theme->defaultAppearance());
|
||||
$this->assertSame('neutral', $theme->defaultAccent());
|
||||
}
|
||||
|
||||
public function test_legacy_manifest_does_not_gain_appearance_or_accent_capabilities(): void
|
||||
{
|
||||
$path = $this->themesPath.'/legacy';
|
||||
mkdir($path.'/css', 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode(['name' => 'Legacy']));
|
||||
file_put_contents($path.'/css/theme.css', 'body{}');
|
||||
|
||||
$theme = app(Loader::class)->fromPath($path);
|
||||
|
||||
$this->assertSame([], $theme->appearances());
|
||||
$this->assertSame([], $theme->accents());
|
||||
$this->assertSame('', $theme->defaultAppearance());
|
||||
$this->assertSame('', $theme->defaultAccent());
|
||||
}
|
||||
|
||||
public function test_defaults_must_reference_declared_optional_capabilities(): void
|
||||
{
|
||||
$path = $this->themesPath.'/invalid-default';
|
||||
mkdir($path, 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode([
|
||||
'name' => 'Invalid Default',
|
||||
'appearances' => ['light', 'dark'],
|
||||
'default_appearance' => 'system',
|
||||
]));
|
||||
|
||||
$this->expectException(InvalidThemeManifestException::class);
|
||||
app(Loader::class)->fromPath($path);
|
||||
}
|
||||
|
||||
public function test_manifest_version_and_capabilities_are_normalised(): void
|
||||
{
|
||||
$path = $this->themesPath.'/capable';
|
||||
mkdir($path.'/css', 0777, true);
|
||||
mkdir($path.'/js', 0777, true);
|
||||
mkdir($path.'/views', 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode([
|
||||
'manifest_version' => 1,
|
||||
'name' => 'Capable',
|
||||
'appearances' => ['light', 'dark'],
|
||||
'accents' => ['blue'],
|
||||
'capabilities' => ['marketplace' => true],
|
||||
]));
|
||||
file_put_contents($path.'/css/theme.css', 'body{}');
|
||||
file_put_contents($path.'/js/app.js', '');
|
||||
file_put_contents($path.'/views/home.blade.php', '<div>Capable</div>');
|
||||
|
||||
$theme = app(Loader::class)->fromPath($path);
|
||||
|
||||
$this->assertSame(1, $theme->manifestVersion());
|
||||
$this->assertTrue($theme->hasCapability('appearances'));
|
||||
$this->assertTrue($theme->hasCapability('accents'));
|
||||
$this->assertTrue($theme->hasCapability('marketplace'));
|
||||
$this->assertFalse($theme->hasCapability('preview'));
|
||||
}
|
||||
|
||||
public function test_unknown_manifest_fields_are_preserved_without_preventing_loading(): void
|
||||
{
|
||||
$path = $this->themesPath.'/future';
|
||||
mkdir($path.'/css', 0777, true);
|
||||
file_put_contents($path.'/theme.json', json_encode([
|
||||
'name' => 'Future',
|
||||
'future_builder_metadata' => ['anything' => true],
|
||||
]));
|
||||
file_put_contents($path.'/css/theme.css', 'body{}');
|
||||
|
||||
$theme = app(Loader::class)->fromPath($path);
|
||||
|
||||
$this->assertSame(['anything' => true], $theme->meta()['future_builder_metadata']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Modules\Stylist\Services\ThemePackageManager;
|
||||
use Modules\Stylist\Theme\Loader;
|
||||
use Tests\TestCase;
|
||||
use ZipArchive;
|
||||
|
||||
final class ThemePackageRoundTripTest extends TestCase
|
||||
{
|
||||
private string $themesPath;
|
||||
|
||||
private string $workspace;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->themesPath = storage_path('framework/testing/stylist-installed-'.uniqid());
|
||||
$this->workspace = storage_path('framework/testing/stylist-package-'.uniqid());
|
||||
mkdir($this->themesPath, 0777, true);
|
||||
mkdir($this->workspace, 0777, true);
|
||||
config(['stylist.themes_path' => $this->themesPath]);
|
||||
app(Loader::class)->flush();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
app(Filesystem::class)->deleteDirectory($this->themesPath);
|
||||
app(Filesystem::class)->deleteDirectory($this->workspace);
|
||||
app(Loader::class)->flush();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_generated_theme_zip_installs_discovers_and_renders(): void
|
||||
{
|
||||
$source = $this->workspace.'/design-gallery';
|
||||
mkdir($source.'/css', 0777, true);
|
||||
mkdir($source.'/js', 0777, true);
|
||||
mkdir($source.'/views', 0777, true);
|
||||
|
||||
file_put_contents($source.'/theme.json', json_encode([
|
||||
'manifest_version' => 1,
|
||||
'key' => 'design-gallery',
|
||||
'name' => 'Design Gallery',
|
||||
'stylesheet' => 'css/app.css',
|
||||
'script' => 'js/app.js',
|
||||
'entry_view' => 'home',
|
||||
'appearances' => ['light', 'dark', 'system'],
|
||||
'accents' => ['blue', 'neutral'],
|
||||
'default_appearance' => 'system',
|
||||
'default_accent' => 'neutral',
|
||||
]));
|
||||
file_put_contents($source.'/css/app.css', 'body{}');
|
||||
file_put_contents($source.'/js/app.js', '');
|
||||
file_put_contents($source.'/views/home.blade.php', '<main>Design Gallery works</main>');
|
||||
|
||||
$zipPath = $this->workspace.'/design-gallery.zip';
|
||||
$zip = new ZipArchive;
|
||||
$this->assertTrue($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE));
|
||||
foreach (app(Filesystem::class)->allFiles($source) as $file) {
|
||||
$zip->addFile($file->getPathname(), 'design-gallery/'.$file->getRelativePathname());
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
$upload = new UploadedFile($zipPath, 'design-gallery.zip', 'application/zip', null, true);
|
||||
$theme = app(ThemePackageManager::class)->install($upload);
|
||||
|
||||
$this->assertSame('design-gallery', $theme->key());
|
||||
$this->assertTrue(app(Loader::class)->all()->has('design-gallery'));
|
||||
$this->assertStringContainsString(
|
||||
'Design Gallery works',
|
||||
stylist_theme_view('design-gallery', 'home')->render(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Modules\Stylist\View\ThemeViewResolver;
|
||||
use Tests\TestCase;
|
||||
|
||||
final class ThemeViewResolverTest extends TestCase
|
||||
{
|
||||
public function test_theme_view_candidates_prefer_active_theme_then_default(): void
|
||||
{
|
||||
config([
|
||||
'stylist.default_theme' => 'backend',
|
||||
'stylist.themes_path' => resource_path('themes'),
|
||||
]);
|
||||
|
||||
$candidates = app(ThemeViewResolver::class)->candidates('components.page-hero');
|
||||
|
||||
$this->assertContains('stylist-theme-backend::components.page-hero', $candidates);
|
||||
$this->assertContains('stylist::components.page-hero', $candidates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Stylist\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
|
||||
final class WelcomeThemeViewTest extends TestCase
|
||||
{
|
||||
public function test_bundled_frontend_theme_view_namespace_is_registered(): void
|
||||
{
|
||||
$this->assertTrue(view()->exists('stylist-theme-frontend::welcome'));
|
||||
}
|
||||
|
||||
public function test_dashboard_view_is_owned_by_the_backend_theme(): void
|
||||
{
|
||||
$this->assertStringContainsString(
|
||||
resource_path('themes/backend/views/dashboard.blade.php'),
|
||||
view('dashboard')->getPath(),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_home_route_renders_from_the_frontend_theme(): void
|
||||
{
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertOk()->assertViewIs('welcome');
|
||||
$this->assertStringContainsString(
|
||||
resource_path('themes/frontend/views/welcome.blade.php'),
|
||||
view('welcome')->getPath(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user