'array']); } private function makePoll(array $attributes = []): Poll { // Inserted directly: Post is Searchable and would sync to Elasticsearch $postId = DB::table('posts')->insertGetId([ 'postable_id' => 1, 'postable_type' => 'App\Models\Admin', 'created_at' => now(), 'updated_at' => now(), ]); return Poll::create(array_merge(['post_id' => $postId, 'status' => Poll::STATUS_OPEN], $attributes)); } private function vote(Poll $poll, $profile, User $user): PollResponse { return PollResponse::create([ 'poll_id' => $poll->id, 'voter_id' => $profile->id, 'voter_type' => get_class($profile), 'user_id' => $user->id, 'dedupe_key' => $poll->dedupeKey($profile, $user->id), 'submitted_at' => now(), ]); } public function test_relations_and_casts(): void { $poll = $this->makePoll(['target_profile_types' => [User::class]]); $question = PollQuestion::create([ 'poll_id' => $poll->id, 'type' => 'single_choice', 'label' => ['en' => 'Which day?', 'nl' => 'Welke dag?'], 'settings' => ['options' => ['mon' => 'Monday']], ]); $user = User::factory()->create(); $response = $this->vote($poll, $user, $user); PollAnswer::create([ 'poll_response_id' => $response->id, 'poll_question_id' => $question->id, 'value' => ['mon'], ]); $post = Post::find($poll->post_id); $this->assertTrue($post->poll->is($poll)); $this->assertSame([User::class], $poll->fresh()->target_profile_types); $this->assertSame('Welke dag?', $question->labelFor('nl')); $this->assertSame('Which day?', $question->labelFor('de')); // fallback locale $this->assertTrue($response->voter->is($user)); $this->assertSame(['mon'], $poll->responses->first()->answers->first()->value); $this->assertTrue($poll->hasResponses()); } public function test_is_open_respects_status_and_window(): void { $this->assertTrue($this->makePoll()->isOpen()); $this->assertFalse($this->makePoll(['status' => Poll::STATUS_DRAFT])->isOpen()); $this->assertFalse($this->makePoll(['opens_at' => now()->addDay()])->isOpen()); $this->assertFalse($this->makePoll(['closes_at' => now()->subMinute()])->isOpen()); } public function test_per_profile_poll_allows_one_vote_per_organization(): void { $poll = $this->makePoll(['vote_scope' => Poll::VOTE_SCOPE_PER_PROFILE]); $organization = Organization::factory()->create(); [$manager1, $manager2] = User::factory()->count(2)->create(); $this->vote($poll, $organization, $manager1); $this->expectException(QueryException::class); $this->vote($poll, $organization, $manager2); } public function test_per_user_poll_allows_one_vote_per_user_behind_organization(): void { $poll = $this->makePoll(['vote_scope' => Poll::VOTE_SCOPE_PER_USER]); $organization = Organization::factory()->create(); [$manager1, $manager2] = User::factory()->count(2)->create(); $this->vote($poll, $organization, $manager1); $this->vote($poll, $organization, $manager2); $this->assertSame(2, $poll->responses()->count()); $this->expectException(QueryException::class); $this->vote($poll, $organization, $manager1); } public function test_deleting_user_or_post_removes_votes(): void { $poll = $this->makePoll(); $user = User::factory()->create(); $this->vote($poll, $user, $user); DB::table('users')->where('id', $user->id)->delete(); $this->assertSame(0, $poll->responses()->count()); $this->vote($poll, $other = User::factory()->create(), $other); DB::table('posts')->where('id', $poll->post_id)->delete(); $this->assertSame(0, PollResponse::where('user_id', $other->id)->count()); $this->assertNull(Poll::withTrashed()->find($poll->id)); } }