200 lines
8.8 KiB
PHP
200 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\SiteProfile;
|
|
|
|
use App\Providers\SettingServiceProvider;
|
|
use App\Support\Setting;
|
|
use App\Support\SiteProfile;
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
use Illuminate\Foundation\Bootstrap\RegisterProviders;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Tests\TestCase;
|
|
|
|
class SiteProfileTest extends TestCase
|
|
{
|
|
private array $environmentSnapshot;
|
|
|
|
public function createApplication()
|
|
{
|
|
$app = require dirname(__DIR__, 3).'/bootstrap/app.php';
|
|
$app->beforeBootstrapping(RegisterProviders::class, function ($app) {
|
|
$app['config']->set(['database.default'=>'sqlite', 'database.connections.sqlite.database'=>':memory:',
|
|
'cache.default'=>'array', 'cache.stores.redis'=>['driver'=>'array'], 'queue.default'=>'sync',
|
|
'app.key'=>'base64:'.base64_encode(str_repeat('t',32)), 'site.profile'=>'dpl']);
|
|
});
|
|
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
|
return $app;
|
|
}
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->environmentSnapshot = [$_ENV, $_SERVER];
|
|
Schema::create('v2_plugins', fn (Blueprint $t) => [$t->id(), $t->boolean('is_enabled')->default(false)]);
|
|
Schema::create('v2_settings', fn (Blueprint $t) => [$t->id(),$t->string('name'),$t->text('value')->nullable(),$t->timestamps()]);
|
|
Cache::store('redis')->flush();
|
|
$this->app->forgetInstance(Setting::class);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
[$_ENV, $_SERVER] = $this->environmentSnapshot;
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_dpl_can_render_its_existing_bundled_frontend(): void
|
|
{
|
|
admin_setting(['frontend_theme'=>'Xboard']);
|
|
$this->get('/')->assertOk()->assertSee('/theme/Xboard', false);
|
|
}
|
|
|
|
public function test_public_hostname_never_loads_local_dev_scripts(): void
|
|
{
|
|
try {
|
|
$assets = \App\Support\EzAssets::scripts(\Illuminate\Http\Request::create('https://hardnerd.net/'));
|
|
foreach ($assets['scripts'] as $script) $this->assertStringStartsWith('/theme/EZ/assets/', $script);
|
|
} catch (\RuntimeException $e) {
|
|
$this->assertStringContainsString('EZ assets missing', $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function test_default_dpl_keeps_database_brand_and_theme(): void
|
|
{
|
|
admin_setting(['frontend_theme'=>'Stellar','app_name'=>'Deep Link','logo'=>'/dpl.svg','app_description'=>'original']);
|
|
$before = DB::table('v2_settings')->get()->toJson();
|
|
$this->assertSame([], SiteProfile::publicSettings());
|
|
$this->assertSame('Stellar',admin_setting('frontend_theme'));
|
|
SiteProfile::assertSettingsWritable(['frontend_theme'=>'Xboard']);
|
|
$this->assertSame($before, DB::table('v2_settings')->get()->toJson());
|
|
}
|
|
|
|
public function test_hn_uses_ez_without_rewriting_stored_settings_or_cached_values(): void
|
|
{
|
|
admin_setting(['frontend_theme'=>'Stellar','app_name'=>'Deep Link','logo'=>'/dpl.svg','app_description'=>'original']);
|
|
$before = DB::table('v2_settings')->get()->toJson();
|
|
config(['site.profile'=>'hn']);
|
|
$this->app->forgetInstance(Setting::class);
|
|
(new SettingServiceProvider($this->app))->boot();
|
|
$this->assertSame('EZ',admin_setting('frontend_theme'));
|
|
$this->assertSame('hardnerd',admin_setting('app_name'));
|
|
$this->assertSame('hardnerd',config('app.name'));
|
|
$this->assertSame('hardnerd.net',config('app.full_name'));
|
|
$this->assertSame('/brand/hn/logo.svg',admin_setting('logo'));
|
|
$this->assertSame('Stellar', Cache::store('redis')->get(Setting::CACHE_KEY)['frontend_theme']);
|
|
$this->assertSame($before, DB::table('v2_settings')->get()->toJson());
|
|
$this->withoutExceptionHandling();
|
|
$this->getJson('/api/v1/guest/comm/config')->assertOk()->assertJsonPath('data.app_name','hardnerd');
|
|
config(['site.profile'=>'dpl']);
|
|
$this->app->forgetInstance(Setting::class);
|
|
$this->assertSame('Stellar',admin_setting('frontend_theme'));
|
|
}
|
|
|
|
public function test_hn_rejects_an_admin_theme_switch_before_writing(): void
|
|
{
|
|
config(['site.profile'=>'hn']);
|
|
$this->expectException(ValidationException::class);
|
|
(new \App\Services\ThemeService)->switch('Xboard');
|
|
}
|
|
|
|
public function test_admin_save_rejects_profile_changes_before_any_setting_write(): void
|
|
{
|
|
config(['site.profile'=>'hn']);
|
|
admin_setting(['currency'=>'CNY']);
|
|
$request = \Mockery::mock(\App\Http\Requests\Admin\ConfigSave::class);
|
|
$request->shouldReceive('validated')->once()->andReturn(['currency'=>'USD','frontend_theme'=>'Stellar']);
|
|
try {
|
|
(new \App\Http\Controllers\V2\Admin\ConfigController)->save($request);
|
|
$this->fail('hn must reject another profile theme');
|
|
} catch (ValidationException $exception) {
|
|
$this->assertArrayHasKey('frontend_theme', $exception->errors());
|
|
$this->assertSame('CNY',admin_setting('currency'));
|
|
}
|
|
}
|
|
|
|
public function test_missing_selector_defaults_to_dpl(): void
|
|
{
|
|
$old = getenv('SITE_PROFILE');
|
|
unset($_ENV['SITE_PROFILE'],$_SERVER['SITE_PROFILE']);
|
|
putenv('SITE_PROFILE');
|
|
try {
|
|
$this->assertSame('dpl',(require base_path('config/site.php'))['profile']);
|
|
} finally {
|
|
if ($old === false) putenv('SITE_PROFILE'); else putenv('SITE_PROFILE='.$old);
|
|
}
|
|
}
|
|
|
|
public function test_hn_admin_api_still_rejects_guests_and_regular_users(): void
|
|
{
|
|
config(['site.profile'=>'hn']);
|
|
$url = '/api/v2/'.hash('crc32b', config('app.key')).'/config/fetch';
|
|
$this->getJson($url)->assertForbidden();
|
|
\Laravel\Sanctum\Sanctum::actingAs(new \App\Models\User(['is_admin'=>false]));
|
|
$this->getJson($url)->assertForbidden();
|
|
}
|
|
|
|
public function test_ez_is_available_as_an_explicit_hn_comparison_theme(): void
|
|
{
|
|
config(['site.profile'=>'hn','site.theme'=>'EZ']);
|
|
$this->assertSame('EZ', SiteProfile::publicSettings()['frontend_theme']);
|
|
SiteProfile::assertSettingsWritable(['frontend_theme'=>'EZ']);
|
|
}
|
|
|
|
public function test_custom_theme_never_uses_dev_assets_for_a_public_hostname(): void
|
|
{
|
|
try {
|
|
$assets = \App\Support\HardnerdAssets::scripts(\Illuminate\Http\Request::create('https://hardnerd.net/'));
|
|
foreach ($assets['scripts'] as $script) $this->assertStringStartsWith('/theme/Hardnerd/assets/', $script);
|
|
} catch (\RuntimeException $exception) {
|
|
$this->assertStringContainsString('Hardnerd assets missing', $exception->getMessage());
|
|
}
|
|
}
|
|
|
|
public function test_hn_rejects_an_unknown_theme_selector(): void
|
|
{
|
|
$_ENV['SITE_PROFILE']=$_SERVER['SITE_PROFILE']='hn';
|
|
$_ENV['SITE_THEME']=$_SERVER['SITE_THEME']='Stellar';
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
require base_path('config/site.php');
|
|
}
|
|
|
|
public function test_dpl_does_not_apply_the_hn_theme_selector(): void
|
|
{
|
|
$_ENV['SITE_PROFILE']=$_SERVER['SITE_PROFILE']='dpl';
|
|
$_ENV['SITE_THEME']=$_SERVER['SITE_THEME']='Stellar';
|
|
$this->assertSame('dpl',(require base_path('config/site.php'))['profile']);
|
|
$this->assertSame([], SiteProfile::publicSettings());
|
|
}
|
|
|
|
public function test_invalid_selector_fails_instead_of_silently_selecting_dpl(): void
|
|
{
|
|
$old = $_ENV['SITE_PROFILE'] ?? null;
|
|
$_SERVER['SITE_PROFILE']=$_ENV['SITE_PROFILE']='typo';
|
|
try {
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
require base_path('config/site.php');
|
|
} finally {
|
|
if ($old === null) unset($_SERVER['SITE_PROFILE'],$_ENV['SITE_PROFILE']); else $_SERVER['SITE_PROFILE']=$_ENV['SITE_PROFILE']=$old;
|
|
}
|
|
}
|
|
|
|
public function test_hn_namespace_defaults_do_not_reuse_dpl_defaults(): void
|
|
{
|
|
$_SERVER['APP_NAME']=$_ENV['APP_NAME']='Shared';
|
|
foreach (['dpl','hn'] as $profile) {
|
|
$_SERVER['SITE_PROFILE']=$_ENV['SITE_PROFILE']=$profile;
|
|
$values[$profile] = [
|
|
(require base_path('config/cache.php'))['prefix'],
|
|
(require base_path('config/database.php'))['redis']['options']['prefix'],
|
|
(require base_path('config/session.php'))['cookie'],
|
|
(require base_path('config/horizon.php'))['prefix'],
|
|
];
|
|
}
|
|
$this->assertSame(['shared_cache','shared_database_','shared_session','shared_horizon:'],$values['dpl']);
|
|
$this->assertSame(['hn_cache','hn_database_','hn_session','hn_horizon:'],$values['hn']);
|
|
unset($_SERVER['APP_NAME'],$_SERVER['SITE_PROFILE'],$_ENV['APP_NAME'],$_ENV['SITE_PROFILE']);
|
|
}
|
|
}
|