'owner-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', ]); $abo = UserAbo::create([ 'user_id' => $owner->id, 'member_id' => $owner->id, 'shopping_user_id' => 1, 'is_for' => 'me', 'email' => $owner->email, 'payone_userid' => 900300, 'clearingtype' => 'cc', 'active' => true, 'status' => 3, 'abo_interval' => 5, 'next_date' => now()->toDateString(), ]); return ['owner' => $owner, 'abo' => $abo]; } it('führt den User-Retry für den eigenen Abo aus und leitet zur Detailseite zurück', function () { // Domain-Routen werden hostabhängig geladen; Stub für den Redirect der Methode. Route::get('/user/abos/detail/{view}/{id}', fn () => '')->name('user_abos_detail'); app('router')->getRoutes()->refreshNameLookups(); $fixture = makeRetryOwnerAbo(); $this->actingAs($fixture['owner']); mock(AboRetryPaymentService::class) ->shouldReceive('retry') ->once() ->andReturn(['success' => true, 'message' => 'OK']); $controller = new AboController(app(AboRepository::class)); $response = $controller->retryPayment('me', $fixture['abo']->id, app(AboRetryPaymentService::class)); expect($response->getTargetUrl())->toContain('/user/abos/detail/me/'.$fixture['abo']->id); expect(session('alert-success'))->toBe('OK'); }); it('verhindert den User-Retry für ein fremdes Abo (403)', function () { $fixture = makeRetryOwnerAbo(); $stranger = User::forceCreate([ 'email' => 'stranger-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', ]); $this->actingAs($stranger); $service = mock(AboRetryPaymentService::class); $service->shouldNotReceive('retry'); $controller = new AboController(app(AboRepository::class)); expect(fn () => $controller->retryPayment('me', $fixture['abo']->id, $service)) ->toThrow(HttpException::class); });