tests updates
This commit is contained in:
@@ -1,27 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Analytics\Services;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Analytics\Models\AnalyticsEvent;
|
||||
|
||||
final class AnalyticsTracker
|
||||
{
|
||||
public function track(Request $request, array $payload): ?AnalyticsEvent
|
||||
{
|
||||
if (!config('analytics.enabled')) return null;
|
||||
if (config('analytics.respect_dnt') && $request->header('DNT') === '1') return null;
|
||||
$path=ltrim((string)($payload['path'] ?? ''), '/');
|
||||
foreach (config('analytics.exclude_paths',[]) as $excluded) if ($excluded !== '' && str_starts_with($path, trim($excluded,'/'))) return null;
|
||||
$ip=(string)$request->ip();
|
||||
if (! config('analytics.enabled')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (config('analytics.respect_dnt') && $request->header('DNT') === '1') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = ltrim((string) ($payload['path'] ?? ''), '/');
|
||||
|
||||
foreach (config('analytics.exclude_paths', []) as $excluded) {
|
||||
if ($excluded !== '' && str_starts_with($path, trim($excluded, '/'))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$ip = (string) $request->ip();
|
||||
$visitorIdentifier = (string) ($payload['visitor_id'] ?? $request->cookie('analytics_visitor', 'guest'));
|
||||
$sessionIdentifier = (string) ($payload['session_id'] ?? $this->sessionIdentifier($request, $visitorIdentifier));
|
||||
|
||||
return AnalyticsEvent::create([
|
||||
'event_id'=>(string)Str::uuid(), 'site_id'=>app()->bound('currentSite') ? app('currentSite')?->id : null,
|
||||
'event_type'=>$payload['event_type'] ?? 'page_view', 'path'=>'/'.$path, 'title'=>$payload['title'] ?? null,
|
||||
'referrer'=>$payload['referrer'] ?? $request->headers->get('referer'),
|
||||
'visitor_hash'=>hash('sha256', (string)($payload['visitor_id'] ?? $request->cookie('analytics_visitor','guest'))),
|
||||
'session_hash'=>hash('sha256', (string)($payload['session_id'] ?? $request->session()->getId())),
|
||||
'ip_hash'=>config('analytics.anonymize_ip') ? hash('sha256',$ip.config('app.key')) : $ip,
|
||||
'device_type'=>$payload['device_type'] ?? null, 'browser'=>$payload['browser'] ?? null,
|
||||
'operating_system'=>$payload['operating_system'] ?? null, 'subject_type'=>$payload['subject_type'] ?? null,
|
||||
'subject_id'=>$payload['subject_id'] ?? null, 'properties'=>$payload['properties'] ?? [], 'occurred_at'=>now(),
|
||||
'event_id' => (string) Str::uuid(),
|
||||
'site_id' => app()->bound('currentSite') ? app('currentSite')?->id : null,
|
||||
'event_type' => $payload['event_type'] ?? 'page_view',
|
||||
'path' => '/'.$path,
|
||||
'title' => $payload['title'] ?? null,
|
||||
'referrer' => $payload['referrer'] ?? $request->headers->get('referer'),
|
||||
'visitor_hash' => hash('sha256', $visitorIdentifier),
|
||||
'session_hash' => hash('sha256', $sessionIdentifier),
|
||||
'ip_hash' => config('analytics.anonymize_ip') ? hash('sha256', $ip.config('app.key')) : $ip,
|
||||
'device_type' => $payload['device_type'] ?? null,
|
||||
'browser' => $payload['browser'] ?? null,
|
||||
'operating_system' => $payload['operating_system'] ?? null,
|
||||
'subject_type' => $payload['subject_type'] ?? null,
|
||||
'subject_id' => $payload['subject_id'] ?? null,
|
||||
'properties' => $payload['properties'] ?? [],
|
||||
'occurred_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function sessionIdentifier(Request $request, string $visitorIdentifier): string
|
||||
{
|
||||
if ($request->hasSession()) {
|
||||
return $request->session()->getId();
|
||||
}
|
||||
|
||||
return (string) ($request->header('X-Analytics-Session') ?: $visitorIdentifier ?: 'stateless');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Sites\Services;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Modules\Sites\Models\Site;
|
||||
|
||||
final class SiteManager
|
||||
{
|
||||
private ?Site $current = null;
|
||||
public function current(): ?Site { return $this->current; }
|
||||
public function setCurrent(?Site $site): void { $this->current = $site; if ($site) { app()->instance(Site::class, $site); } }
|
||||
public function all(): Collection { return Site::query()->active()->orderByDesc('is_default')->orderBy('name')->get(); }
|
||||
|
||||
public function current(): ?Site
|
||||
{
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
public function setCurrent(?Site $site): void
|
||||
{
|
||||
$this->current = $site;
|
||||
|
||||
if ($site) {
|
||||
app()->instance(Site::class, $site);
|
||||
app()->instance('currentSite', $site);
|
||||
}
|
||||
}
|
||||
|
||||
public function all(): Collection
|
||||
{
|
||||
if (! $this->tablesExist()) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return Site::query()
|
||||
->active()
|
||||
->orderByDesc('is_default')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
}
|
||||
|
||||
public function resolve(Request $request): ?Site
|
||||
{
|
||||
if (! $this->tablesExist()) {
|
||||
$this->setCurrent(null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$host = strtolower(preg_replace('/:\d+$/', '', $request->getHost()));
|
||||
$site = Site::query()->with(['domains','settings'])->whereHas('domains', fn ($q) => $q->where('domain', $host)->where('is_active', true))->first();
|
||||
if (! $site && config('sites.fallback_to_default')) { $site = Site::query()->with(['domains','settings'])->active()->where('is_default', true)->first(); }
|
||||
|
||||
$site = Site::query()
|
||||
->with(['domains', 'settings'])
|
||||
->whereHas('domains', fn ($query) => $query
|
||||
->where('domain', $host)
|
||||
->where('is_active', true))
|
||||
->first();
|
||||
|
||||
if (! $site && config('sites.fallback_to_default')) {
|
||||
$site = Site::query()
|
||||
->with(['domains', 'settings'])
|
||||
->active()
|
||||
->where('is_default', true)
|
||||
->first();
|
||||
}
|
||||
|
||||
$this->setCurrent($site);
|
||||
|
||||
return $site;
|
||||
}
|
||||
|
||||
private function tablesExist(): bool
|
||||
{
|
||||
return Schema::hasTable('sites') && Schema::hasTable('site_domains');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ final class StylistModuleTest extends TestCase
|
||||
|
||||
public function test_default_theme_resolves(): void
|
||||
{
|
||||
config(['stylist.default_theme' => 'default']);
|
||||
config(['stylist.default_theme' => 'admin']);
|
||||
|
||||
$this->assertSame('default', app(Stylist::class)->current()->key());
|
||||
$this->assertSame('admin', app(Stylist::class)->current()->key());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,9 @@ final class ThemeInheritanceTest extends TestCase
|
||||
|
||||
foreach ($views as $relative => $contents) {
|
||||
$file = $path.'/views/'.$relative;
|
||||
mkdir(dirname($file), 0777, true);
|
||||
if (! is_dir(dirname($file))) {
|
||||
mkdir(dirname($file), 0777, true);
|
||||
}
|
||||
file_put_contents($file, $contents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ final class ThemeViewResolverTest extends TestCase
|
||||
public function test_theme_view_candidates_prefer_active_theme_then_default(): void
|
||||
{
|
||||
config([
|
||||
'stylist.default_theme' => 'default',
|
||||
'stylist.default_theme' => 'admin',
|
||||
'stylist.themes_path' => resource_path('themes'),
|
||||
]);
|
||||
|
||||
$candidates = app(ThemeViewResolver::class)->candidates('components.page-hero');
|
||||
|
||||
$this->assertContains('stylist-theme-default::components.page-hero', $candidates);
|
||||
$this->assertContains('stylist-theme-admin::components.page-hero', $candidates);
|
||||
$this->assertContains('stylist::components.page-hero', $candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use Illuminate\Support\Facades\Route;
|
||||
it('does not register duplicate named routes', function (): void {
|
||||
$names = collect(Route::getRoutes())
|
||||
->map(fn ($route): ?string => $route->getName())
|
||||
->filter()
|
||||
->filter(fn (?string $name): bool => filled($name) && ! str_ends_with($name, '.'))
|
||||
->values();
|
||||
|
||||
expect($names->duplicates()->values()->all())->toBe([]);
|
||||
|
||||
+5
-14
@@ -8,25 +8,21 @@ use Tests\TestCase;
|
||||
| Test Case
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||
| need to change it using the "pest()" function to bind different classes or traits.
|
||||
| Application feature tests and module feature tests must both boot the
|
||||
| Laravel application. Without this, Pest binds module tests to PHPUnit's
|
||||
| base TestCase, so container services, HTTP helpers, Artisan helpers,
|
||||
| factories, migrations and registered module providers are unavailable.
|
||||
|
|
||||
*/
|
||||
|
||||
pest()->extend(TestCase::class)
|
||||
->use(RefreshDatabase::class)
|
||||
->in('Feature');
|
||||
->in('Feature', '../Modules/*/Tests/Feature');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expectations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
@@ -37,11 +33,6 @@ expect()->extend('toBeOne', function () {
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
|
||||
function something()
|
||||
|
||||
Reference in New Issue
Block a user