133 lines
4.8 KiB
PHP
133 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Polls;
|
|
|
|
use App\Models\Organization;
|
|
use App\Models\Poll;
|
|
use App\Models\PollAnswer;
|
|
use App\Models\PollQuestion;
|
|
use App\Models\PollResponse;
|
|
use App\Models\Post;
|
|
use App\Models\User;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Relations, cascades and the one-vote unique index of the poll tables.
|
|
*/
|
|
class PollModelTest extends TestCase
|
|
{
|
|
use DatabaseTransactions;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// phpunit.xml configures Redis, which is the dev site's cache too
|
|
config(['cache.default' => '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));
|
|
}
|
|
}
|