🔥 **Cleanup & Tests:** Removed the obsolete auth.register component and its related route, feature tests, and browser tests. Disabled public registration and added tests to ensure /register returns a 404. Added new tests for service, lecturer, city, venue, and meetup CRUD flows.

This commit is contained in:
BT
2026-05-03 20:09:07 +02:00
parent a4cbb10604
commit a363c99453
13 changed files with 344 additions and 120 deletions
-6
View File
@@ -7,9 +7,3 @@ it('renders the login page with QR code and language selector', function () {
->assertSee('Bitcoin, not blockchain')
->assertNoJavaScriptErrors();
});
it('renders the registration page', function () {
$page = visit('/register');
$page->assertNoJavaScriptErrors();
});
@@ -0,0 +1,67 @@
<?php
use App\Models\City;
use App\Models\Country;
use App\Models\Venue;
beforeEach(function () {
$this->country = Country::factory()->create(['code' => 'de', 'name' => 'Deutschland']);
});
it('creates a new city end-to-end with valid coordinates', function () {
actingAsUser();
$page = visit('/de/city-create');
$page->fill('[wire\\:model="name"]', 'BrowserTestCity')
->fill('[wire\\:model="latitude"]', '52.520008')
->fill('[wire\\:model="longitude"]', '13.404954')
->click('[data-flux-button][type="submit"]')
->wait(2)
->assertNoJavaScriptErrors();
expect(City::query()->where('name', 'BrowserTestCity')->exists())->toBeTrue();
});
it('shows validation errors when city form is submitted empty', function () {
actingAsUser();
$page = visit('/de/city-create');
$page->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(City::query()->count())->toBe(0);
});
it('creates a new venue connected to an existing city', function () {
actingAsUser();
$city = City::factory()->create(['country_id' => $this->country->id, 'name' => 'VenueTestCity']);
$page = visit('/de/venue-create');
$page->fill('[wire\\:model="name"]', 'BrowserTestVenue')
->fill('[wire\\:model="street"]', 'Teststraße 1');
$page->script("Livewire.getByName('venues.create')[0].set('city_id', {$city->id})");
$page->wait(0.5)
->click('[data-flux-button][type="submit"]')
->wait(2)
->assertNoJavaScriptErrors();
expect(Venue::query()->where('name', 'BrowserTestVenue')->exists())->toBeTrue();
});
it('shows a validation error when creating a venue without a name', function () {
actingAsUser();
City::factory()->create(['country_id' => $this->country->id]);
$page = visit('/de/venue-create');
$page->fill('[wire\\:model="street"]', 'No-Name Street')
->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(Venue::query()->count())->toBe(0);
});
@@ -0,0 +1,58 @@
<?php
use App\Models\Lecturer;
it('creates a new lecturer end-to-end with valid data', function () {
actingAsUser();
$page = visit('/de/lecturer-create');
$page->fill('[wire\\:model="name"]', 'BrowserTester Saylor')
->fill('[wire\\:model="subtitle"]', 'Browser Test Subject')
->fill('[wire\\:model="intro"]', 'A short intro line.')
->click('[data-flux-button][type="submit"]')
->wait(2)
->assertNoJavaScriptErrors();
expect(Lecturer::query()->where('name', 'BrowserTester Saylor')->exists())->toBeTrue();
});
it('shows a required error when submitting without a lecturer name', function () {
actingAsUser();
$page = visit('/de/lecturer-create');
$page->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(Lecturer::query()->count())->toBe(0);
});
it('rejects creation when the lecturer name already exists', function () {
actingAsUser();
Lecturer::factory()->create(['name' => 'Existing Saylor']);
$page = visit('/de/lecturer-create');
$page->fill('[wire\\:model="name"]', 'Existing Saylor')
->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(Lecturer::query()->where('name', 'Existing Saylor')->count())->toBe(1);
});
it('rejects creation with an invalid website URL', function () {
actingAsUser();
$page = visit('/de/lecturer-create');
$page->fill('[wire\\:model="name"]', 'Bad URL Lecturer')
->fill('[wire\\:model="website"]', 'not-a-url')
->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(Lecturer::query()->where('name', 'Bad URL Lecturer')->exists())->toBeFalse();
});
@@ -0,0 +1,60 @@
<?php
use App\Models\City;
use App\Models\Country;
use App\Models\Meetup;
beforeEach(function () {
$this->country = Country::factory()->create(['code' => 'de', 'name' => 'Deutschland']);
$this->city = City::factory()->create([
'country_id' => $this->country->id,
'name' => 'BrowserMeetupTestCity',
]);
});
it('creates a new meetup end-to-end via the create form', function () {
actingAsUser();
$cityId = $this->city->id;
$page = visit('/de/meetup-create');
$page->fill('[wire\\:model="name"]', 'BrowserSeeded Meetup');
$page->script("Livewire.getByName('meetups.create')[0].set('city_id', {$cityId})");
$page->wait(0.5)
->select('[wire\\:model="community"]', 'einundzwanzig');
$page->script("Livewire.getByName('meetups.create')[0].call('createMeetup')");
$page->wait(2)
->assertNoJavaScriptErrors();
expect(Meetup::query()->where('name', 'BrowserSeeded Meetup')->exists())->toBeTrue();
});
it('blocks meetup creation when the name is missing', function () {
actingAsUser();
$cityId = $this->city->id;
$page = visit('/de/meetup-create');
$page->script("Livewire.getByName('meetups.create')[0].set('city_id', {$cityId})");
$page->wait(0.5)
->select('[wire\\:model="community"]', 'einundzwanzig');
$page->script("Livewire.getByName('meetups.create')[0].call('createMeetup')");
$page->wait(1)
->assertNoJavaScriptErrors();
expect(Meetup::query()->count())->toBe(0);
});
it('blocks meetup creation when no city is selected', function () {
actingAsUser();
$page = visit('/de/meetup-create');
$page->fill('[wire\\:model="name"]', 'NoCityMeetup')
->select('[wire\\:model="community"]', 'einundzwanzig');
$page->script("Livewire.getByName('meetups.create')[0].call('createMeetup')");
$page->wait(1)
->assertNoJavaScriptErrors();
expect(Meetup::query()->where('name', 'NoCityMeetup')->exists())->toBeFalse();
});
@@ -0,0 +1,57 @@
<?php
use App\Enums\SelfHostedServiceType;
use App\Models\City;
use App\Models\Country;
use App\Models\Meetup;
use App\Models\SelfHostedService;
/**
* NOTE: The Search-Inputs of the index pages use Postgres `ilike`, which the
* SQLite test database does not support. We therefore exercise the type-badge
* filter (uses plain `=`) instead and assert the index list itself reacts
* to it.
*/
beforeEach(function () {
$this->country = Country::factory()->create(['code' => 'de']);
$this->city = City::factory()->create(['country_id' => $this->country->id]);
});
it('renders all seeded services on the public services index', function () {
SelfHostedService::factory()->create(['name' => 'NodeAlpha', 'type' => SelfHostedServiceType::Mempool]);
SelfHostedService::factory()->create(['name' => 'BetaService', 'type' => SelfHostedServiceType::Other]);
$page = visit('/de/services');
$page->assertSee('NodeAlpha')
->assertSee('BetaService')
->assertNoJavaScriptErrors();
});
it('filters services by clicking a type-badge in the type-cloud', function () {
SelfHostedService::factory()->create(['name' => 'OnlyMempoolNode', 'type' => SelfHostedServiceType::Mempool]);
SelfHostedService::factory()->create(['name' => 'OnlyOtherThing', 'type' => SelfHostedServiceType::Other]);
$page = visit('/de/services');
$page->assertSee('OnlyMempoolNode')
->assertSee('OnlyOtherThing')
->click('[wire\\:click="filterByType(\'mempool\')"]')
->wait(1)
->assertSee('OnlyMempoolNode')
->assertDontSee('OnlyOtherThing')
->assertNoJavaScriptErrors();
});
it('shows seeded meetups on the public meetups index', function () {
Meetup::factory()->create([
'city_id' => $this->city->id,
'name' => 'BrowserSeeded Meetup XYZ',
'visible_on_map' => true,
]);
$page = visit('/de/meetups');
$page->assertSee('BrowserSeeded Meetup XYZ')
->assertNoJavaScriptErrors();
});
@@ -0,0 +1,49 @@
<?php
use App\Enums\SelfHostedServiceType;
use App\Models\SelfHostedService;
it('creates a new SelfHostedService end-to-end and shows it on the index', function () {
actingAsUser();
$page = visit('/de/service-create');
$page->fill('[wire\\:model="form.name"]', 'BrowserTestNode')
->select('[wire\\:model="form.type"]', SelfHostedServiceType::Mempool->value)
->fill('[wire\\:model="form.url_clearnet"]', 'https://browsertest.example.com')
->fill('[wire\\:model="form.intro"]', 'A node spun up by a browser test.')
->click('[data-flux-button][type="submit"]')
->wait(2)
->assertNoJavaScriptErrors()
->assertSee('BrowserTestNode');
expect(SelfHostedService::query()->where('name', 'BrowserTestNode')->exists())->toBeTrue();
});
it('blocks submission without a name and shows a required error', function () {
actingAsUser();
$page = visit('/de/service-create');
$page->select('[wire\\:model="form.type"]', SelfHostedServiceType::Other->value)
->fill('[wire\\:model="form.url_clearnet"]', 'https://no-name.example.com')
->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(SelfHostedService::query()->count())->toBe(0);
});
it('rejects submission when no URL or IP is provided', function () {
actingAsUser();
$page = visit('/de/service-create');
$page->fill('[wire\\:model="form.name"]', 'NoUrlService')
->select('[wire\\:model="form.type"]', SelfHostedServiceType::Other->value)
->click('[data-flux-button][type="submit"]')
->wait(1)
->assertNoJavaScriptErrors();
expect(SelfHostedService::query()->where('name', 'NoUrlService')->exists())->toBeFalse();
});
@@ -0,0 +1,46 @@
<?php
use App\Models\User;
it('lets an authenticated user update their profile name and persists it', function () {
$user = actingAsUser(['name' => 'Old Name']);
$page = visit('/de/settings/profile');
$page->assertSee('Old Name')
->fill('name', 'New Browser Name')
->click('Save')
->wait(1)
->assertSee('Saved.')
->assertNoJavaScriptErrors();
expect($user->refresh()->name)->toBe('New Browser Name');
});
it('shows a validation error when the profile name is cleared', function () {
actingAsUser(['name' => 'Original']);
$page = visit('/de/settings/profile');
$page->fill('name', '')
->click('Save')
->wait(1)
->assertNoJavaScriptErrors();
expect(User::query()->where('name', '')->exists())->toBeFalse();
});
it('still shows the updated name after a full page reload', function () {
$user = actingAsUser(['name' => 'Before Reload']);
$page = visit('/de/settings/profile');
$page->fill('name', 'After Reload')
->click('Save')
->wait(1);
$reloaded = visit('/de/settings/profile');
$reloaded->assertSee('After Reload')
->assertNoJavaScriptErrors();
expect($user->refresh()->name)->toBe('After Reload');
});
-1
View File
@@ -20,7 +20,6 @@ it('loads all listed public pages without console errors or JS errors', function
$pages = visit([
'/welcome',
'/login',
'/register',
'/forgot-password',
'/de/meetups',
'/de/courses',