create(); $ws = Workspace::factory()->create(['owner_id' => $user->id]); WorkspaceMember::create([ 'workspace_id' => $ws->id, 'user_id' => $user->id, 'role' => 'owner', 'joined_at' => now(), ]); return [$user, $ws]; } // ConfirmAction it('renders confirm modal', function () { [$user] = makeWsUser(); Livewire::actingAs($user)->test(ConfirmAction::class, [ 'title' => 'Are you sure?', 'message' => 'This cannot be undone.', 'confirmEvent' => 'testConfirmed', ])->assertSee('Are you sure?'); }); it('dispatches confirmEvent on confirm', function () { [$user] = makeWsUser(); Livewire::actingAs($user)->test(ConfirmAction::class, [ 'confirmEvent' => 'testConfirmed', ])->call('confirm') ->assertDispatched('testConfirmed'); }); // InviteMember it('renders invite member modal', function () { [$user, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); Livewire::actingAs($user)->test(InviteMember::class) ->assertSee('Invite Team Member'); }); it('validates email on invite member', function () { [$user, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); Livewire::actingAs($user)->test(InviteMember::class) ->set('email', 'not-an-email') ->call('invite') ->assertHasErrors(['email']); }); it('creates invitation and dispatches memberInvited', function () { [$user, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); Livewire::actingAs($user)->test(InviteMember::class) ->set('email', 'new@example.com') ->set('role', 'editor') ->call('invite') ->assertDispatched('memberInvited'); expect(WorkspaceInvitation::where('workspace_id', $ws->id)->where('email', 'new@example.com')->exists())->toBeTrue(); }); // EditMemberRole it('renders edit member role and updates role', function () { [$owner, $ws] = makeWsUser(); $member = User::factory()->create(); $membership = WorkspaceMember::create([ 'workspace_id' => $ws->id, 'user_id' => $member->id, 'role' => 'editor', 'joined_at' => now(), ]); app()->instance('current_workspace', $ws); Livewire::actingAs($owner)->test(EditMemberRole::class, ['memberId' => $membership->id]) ->assertSee('Change Role') ->set('role', 'admin') ->call('save') ->assertDispatched('memberRoleUpdated'); expect($membership->fresh()->role)->toBe('admin'); }); it('rejects edit member role for wrong workspace', function () { [$owner, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); $otherOwner = User::factory()->create(); $otherWs = Workspace::factory()->create(['owner_id' => $otherOwner->id]); $membership = WorkspaceMember::create([ 'workspace_id' => $otherWs->id, 'user_id' => $otherOwner->id, 'role' => 'owner', 'joined_at' => now(), ]); expect(fn () => Livewire::actingAs($owner)->test(EditMemberRole::class, ['memberId' => $membership->id])) ->toThrow(ModelNotFoundException::class); }); // RemoveMember it('removes member and dispatches memberRemoved', function () { [$owner, $ws] = makeWsUser(); $member = User::factory()->create(); $membership = WorkspaceMember::create([ 'workspace_id' => $ws->id, 'user_id' => $member->id, 'role' => 'editor', 'joined_at' => now(), ]); app()->instance('current_workspace', $ws); Livewire::actingAs($owner)->test(RemoveMember::class, ['memberId' => $membership->id]) ->call('remove') ->assertDispatched('memberRemoved'); expect(WorkspaceMember::find($membership->id))->toBeNull(); }); // CreateApiToken it('renders create api token modal', function () { [$user] = makeWsUser(); Livewire::actingAs($user)->test(CreateApiToken::class) ->assertSee('Create API Token'); }); it('creates token and shows it once', function () { [$user] = makeWsUser(); $component = Livewire::actingAs($user)->test(CreateApiToken::class) ->set('name', 'Test token') ->call('create') ->assertDispatched('apiTokenCreated'); expect($component->get('plainTextToken'))->not->toBeNull(); }); it('validates token name is required', function () { [$user] = makeWsUser(); Livewire::actingAs($user)->test(CreateApiToken::class) ->call('create') ->assertHasErrors(['name' => 'required']); }); // RevokeApiToken it('revokes token and dispatches apiTokenRevoked', function () { [$user] = makeWsUser(); $token = $user->createToken('My token'); $pat = $token->accessToken; Livewire::actingAs($user)->test(RevokeApiToken::class, ['tokenId' => $pat->id]) ->call('revoke') ->assertDispatched('apiTokenRevoked'); expect(\Laravel\Sanctum\PersonalAccessToken::find($pat->id))->toBeNull(); }); // CreateWebhook it('creates webhook and dispatches webhookCreated', function () { [$user, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); Livewire::actingAs($user)->test(CreateWebhook::class) ->set('url', 'https://example.com/hook') ->set('selectedEvents', ['link.clicked']) ->call('save') ->assertDispatched('webhookCreated'); expect(Webhook::where('workspace_id', $ws->id)->where('url', 'https://example.com/hook')->exists())->toBeTrue(); }); it('validates url and events on create webhook', function () { [$user, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); Livewire::actingAs($user)->test(CreateWebhook::class) ->call('save') ->assertHasErrors(['url', 'selectedEvents']); }); // DeleteWebhook it('deletes webhook and dispatches webhookDeleted', function () { [$user, $ws] = makeWsUser(); app()->instance('current_workspace', $ws); $webhook = Webhook::factory()->create(['workspace_id' => $ws->id]); Livewire::actingAs($user)->test(DeleteWebhook::class, ['webhookId' => $webhook->id]) ->call('delete') ->assertDispatched('webhookDeleted'); expect(Webhook::find($webhook->id))->toBeNull(); }); // CreateWorkspace it('creates workspace and dispatches workspaceCreated', function () { [$user] = makeWsUser(); Livewire::actingAs($user)->test(CreateWorkspace::class) ->set('name', 'New Workspace') ->call('create') ->assertDispatched('workspaceCreated'); expect(Workspace::where('owner_id', $user->id)->where('name', 'New Workspace')->exists())->toBeTrue(); }); it('validates workspace name is required', function () { [$user] = makeWsUser(); Livewire::actingAs($user)->test(CreateWorkspace::class) ->call('create') ->assertHasErrors(['name' => 'required']); }); // DeleteWorkspace it('requires confirmation to delete workspace', function () { [$user, $ws] = makeWsUser(); Livewire::actingAs($user)->test(DeleteWorkspace::class, ['workspaceUlid' => $ws->ulid]) ->set('confirmation', 'Wrong name') ->call('delete') ->assertHasErrors(['confirmation']); expect(Workspace::find($ws->id))->not->toBeNull(); }); it('soft-deletes workspace with correct confirmation', function () { [$user, $ws] = makeWsUser(); Livewire::actingAs($user)->test(DeleteWorkspace::class, ['workspaceUlid' => $ws->ulid]) ->set('confirmation', $ws->name) ->call('delete') ->assertDispatched('workspaceDeleted'); expect(Workspace::withTrashed()->find($ws->id)->deleted_at)->not->toBeNull(); });