Identity Platform for Laravel
Testing
Testing
Every module ships test ergonomics under a Testing/ namespace — the same helpers the package
uses to test itself, so they're proven, not aspirational. Compose the traits into your test
case (or uses() them in Pest).
use Cbox\Id\Kernel\Tenancy\Testing\InteractsWithTenancy;
use Cbox\Id\Organization\Testing\InteractsWithOrganizations;
use Cbox\Id\Identity\Testing\InteractsWithIdentity;
uses(InteractsWithTenancy::class, InteractsWithOrganizations::class, InteractsWithIdentity::class);
Setup helpers
| Trait | Helpers |
|---|---|
InteractsWithTenancy |
actingAsTenant(), runAsTenant(), actingAsTenants(), withoutTenantScope() |
InteractsWithOrganizations |
makeOrganization(name, slug?, parentId?) |
InteractsWithIdentity |
makeUser(email?, name?, password?) |
InteractsWithAccessControl |
grantRole(userId, orgId, roleName, permissions) |
InteractsWithEntitlements |
grantEntitlement(orgId, key, value?, mode?) |
InteractsWithAuthorization |
relate(Relationship), pdp() |
InteractsWithDirectory |
makeDirectory(orgId, name?) |
InteractsWithFederation |
makeConnection(orgId, type?, name?, config?, active?) |
InteractsWithWebhooks |
registerWebhook(orgId, url, eventTypes) |
it('scopes to the acting tenant', function () {
$org = $this->makeOrganization('Acme');
$user = $this->makeUser('[email protected]');
$this->grantRole($user->id, $org->id, 'admin', ['members.invite']);
expect(app(AccessChecker::class)->can($user->id, 'members.invite', $org->id))->toBeTrue();
});
Fakes and assertions
The Events and Audit kernels ship assertable fakes, in the spirit of Laravel's Event::fake():
$events = $this->fakeEvents(); // InteractsWithEvents
$audit = $this->fakeAudit(); // InteractsWithAudit
app(Organizations::class)->create(new NewOrganization('Acme', 'acme'));
$events->assertEmitted('organization.created', fn ($e) => $e->organizationId !== null);
$audit->assertRecorded('organization.created');
$events->assertNotEmitted('organization.deleted');
Mocking
Every contract is an interface, so mock it directly when you want full control:
$this->mock(Subjects::class)
->shouldReceive('findByEmail')
->andReturn(null);
Tenant isolation is testable
The most important test in a multi-tenant platform is that data can't leak across tenants. The
package proves this with a @group=isolation suite; write the same kind of test for your
tenant-owned models:
it('never leaks across tenants', function () {
$this->runAsTenant('org_a', fn () => Widget::create(['name' => 'secret']));
// acting as another tenant sees nothing
$this->runAsTenant('org_b', function () {
expect(Widget::count())->toBe(0);
});
// and no tenant at all is deny-by-default, not "everything"
expect(Widget::count())->toBe(0);
});