test(Roles::class) ->assertSee('Buchhaltung') ->assertSee('Developer'); }); it('lets the owner give a role a capability', function () { $role = Role::findOrCreate('Buchhaltung', 'operator'); Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->set("granted.{$role->id}", ['console.view', 'billing.manage']) ->call('save', $role->id) ->assertHasNoErrors(); expect($role->fresh()->permissions->pluck('name')->sort()->values()->all()) ->toBe(['billing.manage', 'console.view']); }); it('takes a capability away again', function () { $role = Role::findOrCreate('Buchhaltung', 'operator'); $role->givePermissionTo('billing.manage', 'console.view'); Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->set("granted.{$role->id}", ['console.view']) ->call('save', $role->id); expect($role->fresh()->permissions->pluck('name')->all())->toBe(['console.view']); }); it('refuses to let Owner be stripped', function () { // Sonst sperrt sich der Betreiber mit einem Klick selbst aus, und es gibt // niemanden mehr, der es zurücknehmen könnte. Die einzige Rolle, die // dieser Bildschirm nicht anfassen darf. $owner = Role::where('name', 'Owner')->where('guard_name', 'operator')->firstOrFail(); $vorher = $owner->permissions->pluck('name')->sort()->values()->all(); Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->set("granted.{$owner->id}", ['console.view']) ->call('save', $owner->id) ->assertHasErrors(); expect($owner->fresh()->permissions->pluck('name')->sort()->values()->all())->toBe($vorher); }); it('creates a role', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->set('newRole', 'Buchhaltung') ->call('create') ->assertHasNoErrors(); expect(Role::where('name', 'Buchhaltung')->where('guard_name', 'operator')->exists())->toBeTrue(); }); it('never creates a role on the wrong guard', function () { // Genau der Fehler, der `dpa.manage` auf dem web-Guard hinterlassen hat: // ein Eintrag, den kein Betreiber je sieht, weil Operator gegen // `operator` auflöst. Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->set('newRole', 'Buchhaltung') ->call('create'); expect(Role::where('name', 'Buchhaltung')->where('guard_name', 'web')->exists())->toBeFalse(); }); it('will not delete a role somebody still holds', function () { $role = Role::findOrCreate('Buchhaltung', 'operator'); Operator::factory()->create()->assignRole($role); Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->call('delete', $role->id) ->assertHasErrors(); expect(Role::where('name', 'Buchhaltung')->exists())->toBeTrue(); }); it('deletes a role nobody holds', function () { $role = Role::findOrCreate('Buchhaltung', 'operator'); Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->call('delete', $role->id) ->assertHasNoErrors(); expect(Role::where('name', 'Buchhaltung')->exists())->toBeFalse(); }); it('is not reachable without staff.manage', function () { // Wer bestimmen darf, was eine Rolle kann, bestimmt alles andere gleich // mit. Dasselbe Recht wie das Einladen von Mitarbeitern. Livewire::actingAs(operator('Admin'), 'operator') ->test(Roles::class) ->assertForbidden(); }); it('keeps counting capabilities correctly past the first role', function () { // Ein Fehler, den ich beim Umbau selbst gebaut habe: die Ansicht nannte // die Zählvariable `$granted` — genauso wie die Eigenschaft des Bauteils. // Ab der zweiten Rolle war sie eine Zahl statt der Liste, und die Seite // starb an `count(int)`. Mit einer Rolle wäre es nie aufgefallen. Role::findOrCreate('Buchhaltung', 'operator')->givePermissionTo('console.view'); Role::findOrCreate('Werkstatt', 'operator'); Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->assertOk() ->assertSee('Buchhaltung') ->assertSee('Werkstatt'); }); it('groups the capabilities instead of listing twenty-one in a row', function () { $groups = Livewire::actingAs(operator('Owner'), 'operator') ->test(Roles::class) ->viewData('groups'); expect($groups)->toHaveKey('billing') ->and($groups)->toHaveKey('provisioning') ->and(count($groups))->toBeLessThan(21); }); /** * Die Rollenseite zeigte statt der Beschreibungen ihre eigenen Schlüssel: * „roles.can.billing.manage" stand da, wo „Rechnungen, Gutschriften, * Zahlungsprobleme" hingehört. * * Die Übersetzungen waren die ganze Zeit vorhanden. Der Aufruf lautete * `__('roles.can.'.$permission)`, und ein Berechtigungsname trägt selbst einen * Punkt — `__()` liest Punkte als Verschachtelung und suchte deshalb * `roles → can → billing → manage`, während in der Sprachdatei ein FLACHER * Schlüssel `'billing.manage'` steht. Gefunden wurde nie etwas. */ it('zeigt zu jeder Berechtigung ihre Beschreibung, nicht ihren Schluessel', function () { foreach (['de', 'en'] as $locale) { app()->setLocale($locale); $labels = (array) trans('roles.can'); // Aus der Datenbank, nicht aus einer Liste im Test: so kann eine neu // angelegte Berechtigung nicht ohne Beschreibung durchrutschen. $permissions = Permission::query() ->where('guard_name', 'operator')->pluck('name'); foreach ($permissions as $permission) { expect($labels[$permission] ?? null) ->not->toBeNull("„{$permission}“ hat in lang/{$locale}/roles.php keine Beschreibung.") // Und die Beschreibung ist keine Wiederholung des Schlüssels. ->not->toBe($permission); } } }); it('rendert die Beschreibungen wirklich auf der Seite', function () { // Gegen das ausgelieferte HTML, nicht gegen die Sprachdatei: der Fehler lag // nicht in den Texten, sondern darin, wie die Seite sie holte. $html = $this->actingAs(admin(), 'operator')->get(route('admin.roles'))->assertOk()->getContent(); expect($html)->toContain(e(trans('roles.can')['billing.manage'])) // Und kein roher Schlüssel mehr. ->and($html)->not->toContain('roles.can.billing.manage'); });