create(); $response = $this ->actingAs($user) ->get(route('teams.index')); $response->assertOk(); }); test('teams can be created', function () { $user = User::factory()->create(); $response = $this ->actingAs($user) ->post(route('teams.store'), [ 'name' => 'Test Team', ]); $response->assertRedirect(); $this->assertDatabaseHas('teams', [ 'name' => 'Test Team', 'is_personal' => false, ]); }); test('team slug uses next available suffix', function () { $user = User::factory()->create(); Team::factory()->create(['name' => 'Acme', 'slug' => 'acme']); Team::factory()->create(['name' => 'Acme One', 'slug' => 'acme-1']); Team::factory()->create(['name' => 'Acme Ten', 'slug' => 'acme-10']); $this ->actingAs($user) ->post(route('teams.store'), [ 'name' => 'Acme', ]); $this->assertDatabaseHas('teams', [ 'name' => 'Acme', 'slug' => 'acme-11', ]); }); test('the team edit page can be rendered', function () { $user = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($user, ['role' => TeamRole::Owner->value]); $response = $this ->actingAs($user) ->get(route('teams.edit', $team)); $response->assertOk(); }); test('teams can be updated by owners', function () { $user = User::factory()->create(); $team = Team::factory()->create(['name' => 'Original Name']); $team->members()->attach($user, ['role' => TeamRole::Owner->value]); $response = $this ->actingAs($user) ->patch(route('teams.update', $team), [ 'name' => 'Updated Name', ]); $response->assertRedirect(route('teams.edit', $team->fresh())); $this->assertDatabaseHas('teams', [ 'id' => $team->id, 'name' => 'Updated Name', ]); }); test('teams cannot be updated by members', function () { $owner = User::factory()->create(); $member = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($owner, ['role' => TeamRole::Owner->value]); $team->members()->attach($member, ['role' => TeamRole::Member->value]); $response = $this ->actingAs($member) ->patch(route('teams.update', $team), [ 'name' => 'Updated Name', ]); $response->assertForbidden(); }); test('teams can be deleted by owners', function () { $user = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($user, ['role' => TeamRole::Owner->value]); $response = $this ->actingAs($user) ->delete(route('teams.destroy', $team), [ 'name' => $team->name, ]); $response->assertRedirect(); $this->assertSoftDeleted('teams', [ 'id' => $team->id, ]); }); test('team deletion requires name confirmation', function () { $user = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($user, ['role' => TeamRole::Owner->value]); $response = $this ->actingAs($user) ->delete(route('teams.destroy', $team), [ 'name' => 'Wrong Name', ]); $response->assertSessionHasErrors('name'); $this->assertDatabaseHas('teams', [ 'id' => $team->id, 'deleted_at' => null, ]); }); test('deleting current team switches to alphabetically first remaining team', function () { $user = User::factory()->create(['name' => 'Mike']); $zuluTeam = Team::factory()->create(['name' => 'Zulu Team']); $zuluTeam->members()->attach($user, ['role' => TeamRole::Owner->value]); $alphaTeam = Team::factory()->create(['name' => 'Alpha Team']); $alphaTeam->members()->attach($user, ['role' => TeamRole::Owner->value]); $betaTeam = Team::factory()->create(['name' => 'Beta Team']); $betaTeam->members()->attach($user, ['role' => TeamRole::Owner->value]); $user->update(['current_team_id' => $zuluTeam->id]); $response = $this ->actingAs($user) ->delete(route('teams.destroy', $zuluTeam), [ 'name' => $zuluTeam->name, ]); $response->assertRedirect(); $this->assertSoftDeleted('teams', [ 'id' => $zuluTeam->id, ]); expect($user->fresh()->current_team_id)->toEqual($alphaTeam->id); }); test('deleting current team falls back to personal team when alphabetically first', function () { $user = User::factory()->create(); $personalTeam = $user->personalTeam(); $team = Team::factory()->create(['name' => 'Zulu Team']); $team->members()->attach($user, ['role' => TeamRole::Owner->value]); $user->update(['current_team_id' => $team->id]); $response = $this ->actingAs($user) ->delete(route('teams.destroy', $team), [ 'name' => $team->name, ]); $response->assertRedirect(); $this->assertSoftDeleted('teams', [ 'id' => $team->id, ]); expect($user->fresh()->current_team_id)->toEqual($personalTeam->id); }); test('deleting non current team leaves current team unchanged', function () { $user = User::factory()->create(); $personalTeam = $user->personalTeam(); $team = Team::factory()->create(); $team->members()->attach($user, ['role' => TeamRole::Owner->value]); $user->update(['current_team_id' => $personalTeam->id]); $response = $this ->actingAs($user) ->delete(route('teams.destroy', $team), [ 'name' => $team->name, ]); $response->assertRedirect(); $this->assertSoftDeleted('teams', [ 'id' => $team->id, ]); expect($user->fresh()->current_team_id)->toEqual($personalTeam->id); }); test('deleting team switches other affected users to their personal team', function () { $owner = User::factory()->create(); $member = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($owner, ['role' => TeamRole::Owner->value]); $team->members()->attach($member, ['role' => TeamRole::Member->value]); $owner->update(['current_team_id' => $team->id]); $member->update(['current_team_id' => $team->id]); $response = $this ->actingAs($owner) ->delete(route('teams.destroy', $team), [ 'name' => $team->name, ]); $response->assertRedirect(); expect($member->fresh()->current_team_id)->toEqual($member->personalTeam()->id); }); test('personal teams cannot be deleted', function () { $user = User::factory()->create(); $personalTeam = $user->personalTeam(); $response = $this ->actingAs($user) ->delete(route('teams.destroy', $personalTeam), [ 'name' => $personalTeam->name, ]); $response->assertForbidden(); $this->assertDatabaseHas('teams', [ 'id' => $personalTeam->id, 'deleted_at' => null, ]); }); test('teams cannot be deleted by non owners', function () { $owner = User::factory()->create(); $member = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($owner, ['role' => TeamRole::Owner->value]); $team->members()->attach($member, ['role' => TeamRole::Member->value]); $response = $this ->actingAs($member) ->delete(route('teams.destroy', $team), [ 'name' => $team->name, ]); $response->assertForbidden(); }); test('users can switch teams', function () { $user = User::factory()->create(); $team = Team::factory()->create(); $team->members()->attach($user, ['role' => TeamRole::Member->value]); $response = $this ->actingAs($user) ->post(route('teams.switch', $team)); $response->assertRedirect(); expect($user->fresh()->current_team_id)->toEqual($team->id); }); test('users cannot switch to team they dont belong to', function () { $user = User::factory()->create(); $team = Team::factory()->create(); $response = $this ->actingAs($user) ->post(route('teams.switch', $team)); $response->assertForbidden(); }); test('guests cannot access teams', function () { $response = $this->get(route('teams.index')); $response->assertRedirect(route('login')); });